Last reviewed: 2026-08-30

Direct answer

Use one root span for each coding-agent run, a client child span for every model request sent through CometAPI, and separate child spans for planning and tool execution. Propagate W3C trace context only across service boundaries you control or have explicitly verified. Export the resulting spans through a filtering pipeline, and record operational metadata from an allowlist instead of recording prompts, source code, tool arguments, response bodies, or credentials.

The CometAPI quickstart documentation establishes an OpenAI-compatible SDK and base-URL boundary. That is the point in your runtime where a model-call span can start and stop. The documentation does not establish that CometAPI forwards or returns distributed-tracing headers, so a safe design keeps the agent, model-client, and local tool spans correlated inside your runtime without claiming visibility into an unverified upstream service.

The following tree uses operation names described in the current OpenTelemetry GenAI agent span conventions . Those conventions are marked Development, so treat this as a versioned implementation contract rather than an immutable schema.

invoke_agent code-review
├── plan change
├── chat configured-model
└── execute_tool repository.search
    └── owned-tool-service request

The root span represents the outcome users care about: whether the agent completed its task. A model span measures one model request. A tool span measures one validated tool execution. If a tool calls a remote service you own, its downstream request can continue the trace after the receiver extracts the propagated context.

Happy-path operator workflow

  1. Start the invoke_agent root span before planning or model selection. Add a sanitized run reference such as run-42, the agent version, and gen_ai.operation.name=invoke_agent. Do not use the prompt, issue title, repository path, or user identity as a span name.
  2. Create a child span before the model SDK call. Record gen_ai.operation.name=chat, the configured model identifier, a low-cardinality gateway label such as app.gateway.name=cometapi, and the attempt number. Do not infer a hidden upstream provider. If provider identity is unknown, leave it unknown.
  3. Execute the model request with the client configured separately from the tracing code. End the child span when the complete response arrives or the call fails. Record a returned model identifier only when the client actually supplies one.
  4. Validate any proposed tool name and arguments before execution. Start an execute_tool span only when execution begins. Record a stable tool name and an outcome category, but omit arguments, command text, file contents, patches, and raw results.
  5. If the tool calls an owned remote service, inject the current context into that transport. On the receiving side, extract it and create a child span. The OpenTelemetry context-propagation guide explains how trace and parent identifiers preserve the causal relationship across processes.
  6. End the root span after the final agent outcome is known. Export the trace, then have the operator verify the parent-child structure, durations, status, and absence of sensitive payloads.

A minimal instrumentation skeleton can keep model content out of span attributes:

with tracer.start_as_current_span("invoke_agent code-review") as run_span:
    run_span.set_attribute("gen_ai.operation.name", "invoke_agent")
    run_span.set_attribute("app.agent.run_ref", "run-42")

    with tracer.start_as_current_span("chat configured-model") as model_span:
        model_span.set_attribute("gen_ai.operation.name", "chat")
        model_span.set_attribute("gen_ai.request.model", configured_model)
        model_span.set_attribute("app.gateway.name", "cometapi")
        try:
            response = model_client.chat.completions.create(
                model=configured_model,
                messages=prepared_messages,
            )
        except TimeoutError:
            model_span.set_attribute("error.type", "timeout")
            model_span.set_status(Status(StatusCode.ERROR))
            raise

Adapt exception types to the client library you deploy. The important boundary is that the span wraps the request while prepared_messages never becomes a telemetry attribute.

Error-path operator workflow

  1. Start the model span before the request so connection failures and timeouts are visible.
  2. On a rate-limit response, timeout, or server error, record a documented low-cardinality error.type, the response status when available, elapsed time, and attempt number. Mark the span as failed and close it.
  3. If policy permits a retry, create a distinct attempt span under the same agent run. Preserve the root trace, but do not overwrite the failed attempt or collapse several requests into one misleading duration.
  4. Do not send an incomplete or ambiguous model response to a side-effecting tool. If a tool may already have started, check its idempotency record before another attempt. The guide to preventing retried CometAPI calls from running tools twice covers that separate control.
  5. If the operation ultimately fails, end the root span with a stable failure category and attach the trace identifier to the incident record. Keep any exceptional payload capture outside the tracing pipeline and under a separately reviewed retention policy.

Sanitized logging fields

Use an allowlist that operators can review. A correlated event can be useful without storing model or repository content:

{
  "event": "model_call.completed",
  "trace_id": "trace-from-sdk",
  "span_id": "span-from-sdk",
  "agent_run_ref": "run-42",
  "gen_ai.operation.name": "chat",
  "gen_ai.request.model": "configured-model",
  "gateway": "cometapi",
  "http.status_code": 200,
  "duration_ms": 842,
  "retry_attempt": 0,
  "prompt_recorded": false,
  "response_body_recorded": false,
  "error.type": null
}

Keep request and response bodies, system instructions, tool arguments, tool output, full source paths, diffs, headers, cookies, and user-provided baggage off the allowlist. A field should be absent rather than filled with sensitive content and then redacted later.

Who this is for

This workflow is for developers and platform engineers who own a coding-agent runtime, route model requests through CometAPI, and need to distinguish model latency, planning time, tool time, retries, and exporter failures. It is especially useful when an agent spans a web service, a worker, and one or more owned tool services.

It is not evidence that an external gateway or model provider exposes internal spans. Client-side tracing can show when your application sent a request and received an outcome, but upstream visibility requires a separately verified provider contract.

Key takeaways

  • Use a root agent span with model, planning, and tool children instead of one oversized span.
  • Treat the CometAPI SDK call as an observable client boundary without assuming unverified server-side propagation.
  • Use W3C traceparent and tracestate handling for verified distributed boundaries; do not invent a custom correlation header when standard propagation works.
  • Allowlist operational attributes and keep prompts, code, tool payloads, response bodies, and credentials out of telemetry.
  • Give every retry its own attempt evidence and block ambiguous tool re-execution.
  • Pin and review the Development-status GenAI semantic conventions before changing production field names.

Sources checked

Contract details to verify

Before rollout, write down which component owns each span and field.

  • Client boundary: Confirm the deployed client still uses the documented CometAPI-compatible configuration. Instrument the actual method invoked by the agent rather than an unused wrapper.
  • Propagation boundary: The checked CometAPI material does not state that the service participates in W3C Trace Context. Test header behavior before documenting it, and never make successful propagation a prerequisite for the client span to close.
  • Owned receivers: Confirm every owned downstream service extracts the same propagator that the sender injects. The W3C standard defines the wire format; it does not configure your frameworks for you.
  • Provider identity: A gateway may route to another provider. Do not derive gen_ai.provider.name from a guess. Keep a separate, documented gateway attribute and record request or response model fields only from known values.
  • Schema lifecycle: The agent conventions are marked Development. Pin the convention version used by dashboards, alerts, and tests, then review changes before renaming production attributes.
  • Sampling: Make failure sampling deliberate. A trace design that drops the rare failed run while retaining ordinary successes defeats incident diagnosis.
  • Content policy: Treat system instructions and model content as excluded by default. The conventions identify system instructions as opt-in; this workflow keeps them out entirely.
  • Export pipeline: Verify that the Collector deployment actually enables the processors, batching, retry behavior, encryption, and filtering your policy requires. Documentation of a capability is not proof that a particular deployment has enabled it.

For a field-by-field companion check, use the CometAPI telemetry-field review . That guide audits field evidence; this article focuses on building the causal span tree.

Failure modes

  • Disconnected child traces: A worker or tool service starts a new trace because context was not injected, extracted, or retained across an asynchronous boundary. Detect this by comparing the agent run reference with trace identifiers and verifying parentage in a controlled test.
  • Forged incoming context: An untrusted caller supplies trace headers designed to pollute or manipulate telemetry. Apply an explicit trust policy at public boundaries, following the security cautions in the OpenTelemetry propagation guidance.
  • Sensitive baggage leakage: Arbitrary baggage crosses into an external service or log sink. Do not place credentials, PII, repository content, prompts, or business-sensitive values in baggage.
  • Duplicate spans: Automatic client instrumentation and a manual model span both describe the same request. Keep one semantic model span and document whether lower-level HTTP spans are retained beneath it.
  • Misleading provider labels: The runtime labels a gateway request as a provider it merely expects the gateway to choose. Record only identities known at instrumentation time and keep gateway and provider concepts separate.
  • High-cardinality attributes: Prompt fragments, issue titles, file paths, exception messages, or user IDs become attributes, making queries expensive and exposing content. Replace them with bounded categories or omit them.
  • Retry ambiguity: Several attempts appear as one long model call, hiding which request failed and which incurred work. Emit separate attempt spans and retain a stable attempt number.
  • Repeated tool side effects: A retry consumes a partial response and executes a tool again. Require validated complete output and an idempotency decision before side-effecting execution.
  • Exporter blind spots: The agent succeeds while telemetry export fails, or export backpressure affects the workload. Monitor the telemetry pipeline separately and decide in advance whether data is queued, sampled, or dropped.
  • Logs that cannot join traces: Logs omit trace and span identifiers or use a different run reference. Test correlation with the workflow in reviewing coding-agent telemetry and logs .

FAQ

Does this prove CometAPI supports native OpenTelemetry propagation?

No. The checked quickstart establishes the compatible client boundary, not server-side tracing behavior. Instrument the client call and verify any header contract separately before claiming end-to-end upstream propagation.

Should prompts or completions be span attributes?

No for this workflow. Operational diagnosis can use model identifiers, operation names, durations, attempt numbers, status, error categories, and tool outcomes. Keeping content out reduces exposure and makes the allowlist easier to audit.

Should the trace identifier also be the permanent agent-run identifier?

Use the trace identifier for telemetry correlation and a separate sanitized run reference for application records. That lets tracing systems apply their own retention and sampling policies without redefining your application identity.

What should happen when a model call times out?

Close the failed attempt span with a bounded error category, prevent uncertain output from reaching tools, and apply the runtime’s retry or stop policy. If the agent is stopped, follow a cancellation path such as stopping coding agents without leaving CometAPI calls running .

Can tool arguments be hashed and logged?

Hashing does not automatically make sensitive or low-entropy values safe. Prefer a stable tool name, argument-schema version, validation outcome, and result category. Keep the actual arguments out of the tracing pipeline.

How should convention changes be handled?

Treat semantic conventions like any other telemetry contract: pin the adopted version, test dashboards and alerts against fixtures, and review migrations before changing emitted names. This is particularly important while the GenAI agent conventions remain in Development.

Reader next step

Build a non-production trace fixture with one successful run and one forced timeout. Confirm that the successful trace contains a root agent span, one model span, and a validated tool span. Confirm that the timeout trace retains the failed attempt, does not execute the tool, and ends with a useful root outcome. Search the exported events for prompt text, response content, headers, file paths, and tool payloads; all should be absent.

Then verify Collector behavior during an exporter interruption and document your sampling, retry, and retention choices. Once the trace contract passes those checks, Start with CometAPI and instrument the first real client call before expanding tracing to additional tools.