moon add cybershang/agent-telemetry// Option 1: one-line initialization from environment variables.
// Reads OTEL_SERVICE_NAME, OTEL_STDOUT, and OTEL_EXPORTER_OTLP_ENDPOINT.
// Use ProcessUniqueRandom to avoid duplicate trace/span IDs across restarts.
let providers = @telemetry.init_from_env(
id_generator=@telemetry.ProcessUniqueRandom,
)
// Option 2: manually select an exporter.
let config = @telemetry.TelemetryConfig::new(service_name="my-agent")
let providers = @telemetry.init_telemetry(
config,
@telemetry.Otlp("http://localhost:4318"),
id_generator=@telemetry.ProcessUniqueRandom,
)
// Metrics and logs need background tasks.
@async.with_task_group((group) => {
providers.spawn_background_tasks(group)
// Create a GenAI chat span.
let tracer = @telemetry.tracer("my-agent/llm")
let meter = @telemetry.meter("my-agent/llm")
let span = @telemetry.start_chat_span(
tracer,
provider_name="stepfun",
model="step-3.7-flash",
max_tokens=1024,
)
// ... send the request and obtain response_json ...
@telemetry.record_llm_call(meter, "stepfun", "step-3.7-flash", success=true)
@telemetry.record_chat_response(span, response_json)
@telemetry.end_span_ok(span)
providers.force_flush()
providers.shutdown()
})| Scenario | Functions |
|---|---|
| General | TelemetryConfig::new, init_telemetry, init_from_env, TelemetryProviders, IdGeneratorOption, tracer, meter, logger, conversation_logger, start_span, end_span, end_span_ok, end_span_error, set_attributes, set_string_attribute, set_int_attribute, set_double_attribute, set_bool_attribute, set_json_attribute |
| LLM chat | start_chat_span, record_chat_usage, record_chat_response, set_chat_http_error |
| Tool | start_tool_span, record_tool_result, set_tool_error |
| Agent turn | start_agent_turn_span, record_turn_metrics, set_turn_max_tool_turns_error |
| Metrics | record_llm_call, record_llm_latency, record_tool_call, record_turn_count |
| Logs | emit_log, log_info, log_warn, log_error, log_conversation_message |
let span = @telemetry.start_span(tracer, "my.step")
@telemetry.set_string_attribute(span, "app.user.id", "user-42")
@telemetry.set_int_attribute(span, "app.retry.count", 3L)
@telemetry.set_double_attribute(span, "app.score", 0.95)
@telemetry.set_bool_attribute(span, "app.cached", true)
@telemetry.set_json_attribute(span, "app.metadata", { "source": "api", "depth": 2 })
@telemetry.end_span_ok(span)| Variable | Description | Default |
|---|---|---|
| OTEL_SERVICE_NAME | Service name | agent-telemetry |
| OTEL_STDOUT | Use the stdout exporter when set to true | false |
| OTEL_EXPORTER_OTLP_ENDPOINT | OTLP/HTTP endpoint | http://localhost:4318 |
| OTEL_EXPORTER_OTLP_HEADERS | Global OTLP headers, comma-separated key=value pairs | (empty) |
| OTEL_EXPORTER_OTLP_TRACES_HEADERS | Trace-specific OTLP headers | (empty, falls back to global) |
| OTEL_EXPORTER_OTLP_METRICS_HEADERS | Metric-specific OTLP headers | (empty, falls back to global) |
| OTEL_EXPORTER_OTLP_LOGS_HEADERS | Log-specific OTLP headers | (empty, falls back to global) |
| GREPTIME_TRACE_PIPELINE | GreptimeDB trace pipeline name | greptime_trace_v1 |
| GREPTIME_LOG_TABLE | Target table for conversation logs | genai_conversations |
OTEL_EXPORTER_OTLP_LOGS_HEADERS="Authorization=Bearer my-token, X-Scope-OrgID=tenant-1"providers.force_flush()
providers.shutdown()| Option | Description |
|---|---|
| @telemetry.SdkDefault | Use the SDK default RandomIdGenerator |
| @telemetry.ProcessUniqueRandom | Generate a process-unique seed from the current timestamp and a counter, avoiding duplicate trace/span IDs across restarts |
| @telemetry.Custom(generator) | Provide your own IdGenerator |
moon test -p cybershang/agent-telemetry --target nativepub struct TelemetryProviders {
tracer_provider : SdkTracerProvider
meter_provider : SdkMeterProvider
logger_provider : SdkLoggerProvider
conversation_logger_provider : SdkLoggerProvider
resource : Resource
}fn TelemetryProviders::spawn_background_tasks(self : TelemetryProviders, group : TaskGroup[Unit], allow_failure? : Bool) -> Unitasync fn emit_log(scope_name : String, severity : Severity, body : String, attributes? : Array[KeyValue], trace_context? : SpanContext?) -> Unitasync fn init_from_env(service_name? : String, id_generator? : IdGeneratorOption) -> TelemetryProvidersasync fn init_telemetry(config : TelemetryConfig, exporter_type : ExporterType, id_generator? : IdGeneratorOption) -> TelemetryProvidersasync fn log_conversation_message(scope_name : String, role : String, content : String, index? : Int, trace_context? : SpanContext?) -> Unitasync fn log_error(scope_name : String, body : String, attributes? : Array[KeyValue], trace_context? : SpanContext?) -> Unitasync fn log_info(scope_name : String, body : String, attributes? : Array[KeyValue], trace_context? : SpanContext?) -> Unitasync fn log_warn(scope_name : String, body : String, attributes? : Array[KeyValue], trace_context? : SpanContext?) -> Unitasync fn now_seconds() -> Doublefn record_llm_latency(meter : Meter, provider_name : String, model : String, seconds~ : Double) -> Unitfn record_llm_token_usage(meter : Meter, provider_name : String, model : String, token_type : String, value : Int64) -> Unitfn record_turn_metrics(span : Span, actual_turns : Int, tool_call_count : Int, output : String) -> UnitInstall
Download zip