How UModel Simplifies Observability with Unified Entity Search and Table/Object Modes
This article explains how UModel abstracts observability data into unified table and object models, hides complex routing and field‑mapping logic, provides a single SPL‑based query language, supports metadata reflection for AI agents, and offers SDK and dry‑run examples to streamline metric, log, and trace queries across multiple storage backends.
Background
UModel builds an observable data model where accessing metrics, logs, or traces requires understanding concepts such as EntitySet, DataSet, StorageLink, and Filter, leading to high development and maintenance costs.
Pain Points
Complex concepts create a steep learning curve.
Implementing complex scenarios is difficult.
Underlying storage syntax (PromQL vs SPL) cannot be avoided.
Multiple query interactions cause low efficiency and high error probability.
Design Goals
Hide underlying complexity and provide a unified access interface so that upper‑level applications can focus on business logic.
Core Design Principles
Automation: automatic routing, field mapping, and query conversion.
Unified SPL syntax for all data types.
Object‑oriented programming: entity methods and relationship navigation.
AI‑friendly reflection capability.
Two‑Layer Abstraction
Table Mode (Phase 1)
All data—metrics, logs, traces—are abstracted as tables; queries operate on these tables.
.metric_set with(domain='apm', name='service.request', query='service_id="xxx"') | stats avg(latency)Object Mode (Phase 2)
Entity‑centric mode where the system automatically handles field mapping, filters, and storage routing.
.entity_set with(domain='apm', name='apm.service', ids=['21d5ed421ae93973d67a04af551b48b8']) | entity-call get_metric('apm','apm.metric.apm.service','avg_request_latency_seconds','range','',false)Metadata Query & Reflection
Methods such as __list_method__(), list_data_set(), and __inspect__() enable developers and AI agents to discover entity capabilities, associated datasets, related entities, and validate configurations.
.entity_set with(domain='apm', name='apm.service') | entity-call __list_method__()Core Capabilities
Table mode – direct DataSet access for batch analysis.
Object mode – entity‑centric queries with zero‑configuration filtering and transparent field mapping.
Metadata query – dynamic discovery, configuration verification, and relationship navigation.
Query Examples
APM service request count (PromQL wrapped in SPL):
.metricstore with(region='cn-hangzhou',project='cms-xxx',metricstore='metricstore-apm') | prom-call promql_query_range('sum by (acs_arms_service_id) (rate(arms_app_requests_count_raw{acs_arms_service_id="xxx"}[1m]))','1m')Dry‑run mode returns the generated query without executing it:
.set umodel_paas_mode='dry_run'; .entity_set with(domain='apm',name='apm.service') | entity-call get_metric('apm','apm.metric.apm.service','avg_request_latency_seconds','range','',false)SDK Usage (Go)
package main
import (
"fmt"
cms20240330 "github.com/alibabacloud-go/cms-20240330/v3/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea"
credential "github.com/aliyun/credentials-go/credentials"
)
func CreateClient() (*cms20240330.Client, error) {
cred, err := credential.NewCredential(nil)
if err != nil { return nil, err }
cfg := &openapi.Config{Credential: cred}
cfg.Endpoint = tea.String("cms.cn-hangzhou.aliyuncs.com")
return cms20240330.NewClient(cfg)
}
func main() {
client, err := CreateClient()
if err != nil { panic(err) }
req := &cms20240330.GetEntityStoreDataRequest{
Query: tea.String(".entity_set with(domain='apm', name='apm.service', ids=['...']) | entity-call get_metric('apm','apm.metric.apm.service','avg_request_latency_seconds','range','',false)"),
From: tea.Int32(1762244123),
To: tea.Int32(1762244724),
}
resp, err := client.GetEntityStoreData(tea.String("o11y-demo-cn-hangzhou"), req)
if err != nil { panic(err) }
fmt.Printf("length: %d", len(resp.Body.Data))
}Integration with Custom LogStore
Join business logs with observability data using SPL join:
.let failed_log = .logstore with(project='xxx',logstore='xxxx',query='*') | project trace_id,msg;
let service_traces = .entity_set with(domain='apm',name='apm.service',ids=['xxxx']) | entity-call get_trace('apm','apm.trace.common');
$failed_log | join $service_traces on trace_id=$service_traces.traceId | project msgAI Agent Enablement
An AI agent first calls __list_method__() to discover actions such as get_metric, get_log, get_trace, and list_related_entity_set, then composes queries autonomously for root‑cause analysis.
.entity_set with(domain='apm', name='apm.service') | entity-call __list_method__()Supported Anomaly Types (Series Decompose)
SPIKE_UP / SPIKE_DOWN – sudden spikes.
TREND_SHIFT_UP / TREND_SHIFT_DOWN – trend changes.
LEVEL_SHIFT_UP / LEVEL_SHIFT_DOWN – level shifts.
References
Phase 1 Table Mode: https://help.aliyun.com/zh/cms/cloudmonitor-2-0/phase-1-table-mode
Phase 2 Object Mode: https://help.aliyun.com/zh/cms/cloudmonitor-2-0/phase-2-object-mode-service-discovery
Aliyun OpenAPI GetEntityStoreData: https://api.aliyun.com/api/Cms/2024-03-30/GetEntityStoreData
MCP Tools: https://modelcontextprotocol.io/docs/getting-started/intro
Alibaba Cloud Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
