Observability
The platform automatically collects full-link traces of calls from the Agent framework, model invocations, and tools by default with zero code intrusion. For business-defined metrics, manually report them using
context.tracer.Agent Framework Auto-Collection Support Matrix
The underlying mechanism is based on OpenInference instrumentation and is injected before user code loads. Calls from mainstream LLM SDKs and Agent frameworks automatically generate spans. These spans share the same traceId and are naturally nested with manual spans from
context.tracer.Framework | Python | Node |
Claude Agent SDK | ✅ | ✅ |
OpenAI Agents SDK | ✅ | ✅ |
DeepAgents | ✅ | ✅ |
LangGraph | ✅ | ✅ |
CrewAI | ✅ | - |
Collection Scope
Category | Content |
Model Invocation | Model name, input/output, token usage, and so on |
Agent Framework Link | Agent decision-making, node transition, sub-agent delegation |
Tool Invocation | Tool name, parameters, return value, time consumption |
Observability Data
The platform provides two panels: the Console and Local Debugging. Both panels share the same trace data contract, meaning their UI layout, field definitions, and filtering dimensions are identical. The only difference lies in the data source: the local panel only accesses data from the current dev process, while the console aggregates data from all online requests.
Observability Dashboard in the Console
Go to the console, select your Agent project, and switch to the Agent tab. Then, view the data on the Metrics and Traces subpages.
Metrics Data
You can view core metrics aggregated by time window, including number of Agent invocations, number of model invocations, model invocation error rate, average model invocation latency, total Token consumption, and average tokens/model invocation.

Traces Data
Each task execution corresponds to a trace tree, which can be used to precisely reconstruct a request:
Link Structure: Starting from the root request span, spans automatically generated by the Agent framework are attached, making the hierarchical nesting relationships immediately clear.
LLM Invocation Details: When you expand each LLM span, you can view the prompt, completion, model name, token usage, and latency.
Tool Invocation Details: You can expand a Tool span to view its input parameters, return value, and latency, which helps troubleshoot whether the tool was invoked correctly.
Error Stack: For spans marked as ERROR, the exception name and message are displayed directly, eliminating the need to search through logs.
Filtering and Search: You can filter by
run_id / conversation_id to locate the trace of a specific session or execution.
Local Debugging Panel
edgeone makes dev automatically launches the local debugging panel (default: http://localhost:8088/agent-metrics) upon startup, with zero configuration required:Data Source: It only collects traces generated by the current dev process, does not mix them with online data, and ensures clean debugging isolation.
Feature Parity: The Metrics / Traces subpages are fully consistent with the console, including link structure, LLM details, and attribute filtering.
Near-Zero Latency: Traces become visible as soon as they are written. You can modify a piece of code, run a request, and immediately view the trace differences in the panel.
Manual Instrumentation for context.tracer
The OpenInference instrumentor can cover mainstream LLM SDKs and frameworks, but it cannot collect data in some scenarios (such as unsupported frameworks, custom business logic, and internal service calls). For these scenarios, you can manually supplement reporting using
context.tracer.API Overview
API | Purpose |
tracer.span(name, fn, attrs?) | Creates a child span and executes fn, automatically managing its lifecycle and exceptions. |
tracer.startSpan(name, attrs?) | Creates a span and requires manually calling end(). |
tracer.setAttributes(attrs) | Batch sets attributes for the currently active span. |
Node / Python Naming Conventions: JavaScript uses camelCase (startSpan/setAttributes), while Python uses snake_case (start_span/set_attributes). All other aspects are consistent. Each API in the following sections includes both Node and Python examples.
span(name, fn, attrs?)
Create a span and execute
fn within it. When fn throws an exception, the exception is automatically recorded. Any span generated (automatically or manually) inside fn becomes its child node.Parameter
Parameter | Type | Required | Description |
name | string | Yes | span name |
fn | (span: Span) => Promise<T> | Yes | A function executed within the span context. The parameter span is used to append attributes within the block. |
attrs | Record<string, string | number | boolean> | No | Initial attributes when the span is created. |
Return Value
Pass through the return value of
fn.TS Example:
const intent = await context.tracer.span('classify_intent', async (span) => {const res = await openai.chat.completions.create({ /* ... */ });const label = res.choices[0].message.content.trim();span.setAttributes({ 'intent.label': label });return label;}, { 'agent.step': 'intent' });
Python example:
async def classify(span):res = await openai_client.chat.completions.create(...)label = res.choices[0].message.content.strip()span.set_attributes({"intent.label": label})return labelintent = await ctx.tracer.span("classify_intent", classify, {"agent.step": "intent"})
startSpan(name, attrs?)
When you create a span, you must explicitly call
span.end(). Other spans generated during this period are not automatically nested under it. To nest them, use span(). This approach is suitable for scenarios that cross asynchronous boundaries (for example, putting a task into a queue or ending it within a callback).Parameter
Parameter | Type | Required | Description |
name | string | Yes | span name |
attrs | Record<string, string | number | boolean> | No | Initial attributes when the span is created. |
Return Value
Span — A span object is returned synchronously. The caller must call span.end() in a paired manner; otherwise, the span will not be reported and will remain resident in memory.TS Example:
const span = context.tracer.startSpan('async_pipeline', { 'pipeline.stage': 'init' });try {await doStep1();await doStep2();} finally {span.end(); // This call is mandatory.}
Python example:
span = ctx.tracer.start_span("async_pipeline", {"pipeline.stage": "init"})try:await do_step_1()await do_step_2()finally:span.end()
setAttributes(attrs)
Batch set attributes for the currently active span. This can be used to add business tags to spans automatically created by the platform.
Parameter
Parameter | Type | Required | Description |
attrs | Record<string, string | number | boolean> | Yes | The attribute key-value pairs to be set. Complex objects must be serialized into JSON by the caller. |
TS Example:
context.tracer.setAttributes({'user.id': context.request.body.userId,'user.tier': 'premium','agent.scenario': 'customer_service',});// ... business logic
Python example:
context.tracer.set_attributes({"user.id": ctx.request.body.get("userId"),"user.tier": "premium","agent.scenario": "customer_service",})
To add attributes within thespan()fnor on the span returned bystartSpan(), directly callspan.setAttributes(...).
Use Constraints
Do not import the OpenTelemetry SDK, as it will disrupt the platform's automatic reporting and duplicate instrumentation.
The span created by
startSpan must be paired with end(); otherwise, it will not be reported and will remain resident in memory.Attribute values only support
string / number / boolean. Objects / arrays must be serialized into JSON strings.Do not use high-cardinality dynamic values for span names (such as userId and order number). Place dynamic values in attributes instead.
General Properties
The following attributes are shared by automatic + manual spans, serving as the core dimensions for filtering and aggregation in the console panel.
Required | Meaning |
agent.run_id | The unique ID for a handler execution, linking all spans within this execution. |
agent.conversation_id | Session ID for cross-run aggregation |
agent.route_path | The route for the current request |
llm.* / gen_ai.* / openinference.* | OpenInference standard LLM attributes (model, token usage, and so on) |
