Module Ai_core.TelemetrySource
Telemetry configuration for AI SDK operations.
Mirrors the upstream AI SDK's TelemetrySettings. When enabled is false (the default), all instrumentation is skipped with zero overhead — Trace_core returns dummy spans and never serializes attribute data.
Quick start
(* 1. Install a trace collector in your application entrypoint *)
let () = Trace_core.setup_collector (my_otel_collector ())
(* 2. Pass telemetry settings to generate_text / stream_text *)
let telemetry =
Telemetry.create ~enabled:true ~function_id:"chat-completion"
~metadata:[ "user_id", `String "u-123" ]
()
let%lwt result = Generate_text.generate_text ~model ~messages ~telemetry ()
Span hierarchy
ai.generateText (root — full operation)
├── ai.generateText.doGenerate (per-step LLM call)
└── ai.toolCall (per tool execution)
ai.streamText (root — full streaming operation)
├── ai.streamText.doStream (per-step streaming call)
└── ai.toolCall (per tool execution)
Attribute selectivity
Attributes are classified as Input (prompts, tools), Output (responses, tool results), or Always (model info, usage). Input attributes are only recorded when record_inputs is true, Output when record_outputs is true. When enabled is false, no attributes are evaluated at all (zero serialization cost).
Upstream parity gaps
The following upstream attributes are not yet emitted:
ai.response.timestamp: our Generate_result.response_info does not carry timestamps.ai.response.id on stream step spans. ai.response.model is emitted when the provider supplies Stream_result.raw_response.ai.usage.inputTokenDetails.*, ai.usage.outputTokenDetails.*: our Usage.t only has input_tokens, output_tokens, total_tokens. When the provider-level type gains detail fields (Anthropic already returns them in provider metadata), the span attributes can be extended without API changes.onStepStart integration callback: upstream added this; we only have on_step_finish.gen_ai.response.finish_reasons: upstream emits a string array (["stop"]). Trace_core.user_data has no array variant, so we emit a plain string ("stop").ai.prompt on root spans: upstream serializes full message content (gated by record_inputs). We emit placeholder strings ("<message>") to avoid serializing large payloads into span data. The full messages are available via integration callbacks.
W3C Trace Context
Parse the W3C Trace Context {traceparent} header to link backend spans to an incoming frontend trace. The header format (version 00) is a stable W3C Recommendation:
00-{32 hex trace_id}-{16 hex parent_id}-{2 hex flags}When passed to create via ~traceparent, the parsed IDs are emitted as ai.trace_context.trace_id, ai.trace_context.parent_id, and ai.trace_context.sampled attributes on every root span, so any trace collector can reconstruct the parent link.
If the user also installs the opentelemetry-trace bridge with ambient context, the parenting happens automatically at the Trace_core level — the attributes are still present as a belt-and-suspenders fallback.
Sourcetype trace_context = {trace_id : string;parent_id : string;sampled : bool;
} Parsed W3C traceparent fields.
Parse a raw W3C {traceparent} header value. Returns None if the value is malformed, the wrong version, or contains all-zero trace/parent IDs (invalid per spec).
Types
Sourcetype model_info = {provider : string;model_id : string;
} Model info for callback events.
Lifecycle callbacks for telemetry events.
All callbacks are optional — implement only the ones you need. Errors in callbacks are caught and ignored (they must not break the generation pipeline). Callbacks are called in order: global integrations first, then per-call integrations (matching upstream).
Settings
Telemetry settings, enabling or disabling the logging of various pieces of information such as inputs or outputs or metadata
Sourceval create :
?enabled:bool ->
?record_inputs:bool ->
?record_outputs:bool ->
?function_id:string ->
?metadata:(string * Trace_core.user_data) list ->
?integrations:integration list ->
?traceparent:string ->
unit ->
t Sourceval record_outputs : t -> bool Sourceval function_id : t -> string option Attribute Selection
Attribute that may be conditionally recorded.
Always v: recorded whenever telemetry is enabledInput f: recorded only when record_inputs is true; f evaluated lazilyOutput f: recorded only when record_outputs is true; f evaluated lazily
Select attributes respecting telemetry settings. Returns [] immediately when enabled is false.
Operation Name Assembly
Builds the standard operation name attributes matching upstream: operation.name, resource.name, ai.operationId, ai.telemetry.functionId.
Base Telemetry Attributes
Model info, call settings, user metadata, and request headers. Used on every span.
Sourceval settings_attributes :
?max_output_tokens:int ->
?temperature:float ->
?top_p:float ->
?top_k:int ->
?stop_sequences:string list ->
?seed:int ->
?frequency_penalty:float ->
?presence_penalty:float ->
?max_retries:int ->
unit ->
(string * Trace_core.user_data) list Build settings attributes from call options. Only includes non-None values.
Optional Attribute Helpers
Build a single-element attribute list from an option value, or [] when None. Useful for building span data from optional call settings and response fields.
Lwt Span Helpers
An Lwt-aware ambient span provider (backed by Lwt.key) is installed at module load time. This makes Trace_core.current_span work across Lwt fibers, so nested with_span calls automatically form a parent-child hierarchy without explicit ~parent passing.
with_span ~__FILE__ ~__LINE__ ~data name f opens a span, sets it as the ambient current span (via Lwt.with_value), runs f span, and closes the span when the Lwt promise settles (via Lwt.on_termination).
When no Trace_core collector is installed, f receives a dummy span and no overhead is incurred.
Conditional Helpers
Convenience wrappers for use in generate_text and stream_text. When telemetry is None or enabled = false, these are zero-cost.
Conditionally wrap in a telemetry span. When telemetry is None or disabled, f is called with Trace_core.Collector.dummy_span.
Fire a telemetry notification when enabled; otherwise Lwt.return_unit.
Build a model_info from provider and model ID strings.
Serialize tool calls to a JSON string for telemetry attributes.
Precompute Helpers
One-shot telemetry setup shared by generate_text and stream_text. Extracts model info, settings, and base attributes. When telemetry is None or disabled, returns zero-cost defaults.
Precomputed telemetry values, extracted once per operation.
Sourceval precompute :
operation_id:string ->
model:(module Ai_provider.Language_model.S) ->
?max_output_tokens:int ->
?temperature:float ->
?top_p:float ->
?top_k:int ->
?stop_sequences:string list ->
?seed:int ->
?max_retries:int ->
?headers:(string * string) list ->
t option ->
precomputed Step Span Attribute Builders
Shared helpers that build span attributes for step spans (doGenerate / doStream) and tool call spans. These prevent attribute key drift between generate_text and stream_text.
Build request-side attributes for a step span.
Build response-side attributes for a step span.
Build final response attributes for the root span.
Build initial span data for a tool call span.
Build result attributes to add to a tool call span after execution.
Integration Values
An empty integration with no callbacks. Useful as a starting point for building partial integrations:
{ Telemetry.no_integration with
on_finish = Some (fun event -> ...);
}
Integration Notification
Notify all integrations (per-call + global) of an event. Errors are caught and logged to stderr.
Global Integration Registry
Register an integration that receives events from all AI SDK operations. Useful for application-wide logging or metrics.
Sourceval clear_global_integrations : unit -> unit Remove all global integrations. Primarily for testing.