agent-telemetry

    Download zip
    Version
    0.1.3
    License
    MulanPSL-2.0
    Last updated
    4 months ago
    Downloads
    148

    #agent-telemetry

    OpenTelemetry instrumentation library for MoonBit Agent / LLM / Tool scenarios.

    It wraps the boilerplate OTel tracer / span / attribute code into business-semantic helpers, so agent developers only need to decide when to create spans and what business data to record.

    #Design Layers

    • Thin wrapper (lib.mbt): provider initialization, tracer cache, span lifecycle helpers such as start_span / end_span.
    • Semantic wrapper (genai.mbt, tool.mbt, agent.mbt): sets attributes according to the OpenTelemetry GenAI semantic conventions, covering chat, tool execution, and agent turn spans.

    #Quick Start

    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 provider = @telemetry.init_from_env(
    id_generator=@telemetry.ProcessUniqueRandom,
    )

    // Option 2: manually select an exporter.
    let config = @telemetry.TelemetryConfig::new(service_name="my-agent")
    let provider = @telemetry.init_telemetry(
    config,
    @telemetry.Otlp("http://localhost:4318"),
    id_generator=@telemetry.ProcessUniqueRandom,
    )

    // Create a GenAI chat span.
    let tracer = @telemetry.tracer("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_chat_response(span, response_json)
    @telemetry.end_span_ok(span)

    #Main API

    ScenarioFunctions
    GeneralTelemetryConfig::new, init_telemetry, init_from_env, IdGeneratorOption, tracer, start_span, end_span, end_span_ok, end_span_error
    LLM chatstart_chat_span, record_chat_usage, record_chat_response, set_chat_http_error
    Toolstart_tool_span, record_tool_result, set_tool_error
    Agent turnstart_agent_turn_span, record_turn_metrics, set_turn_max_tool_turns_error

    #Environment Variables

    init_from_env reads the following variables:

    VariableDescriptionDefault
    OTEL_SERVICE_NAMEService nameagent-telemetry
    OTEL_STDOUTUse the stdout exporter when set to truefalse
    OTEL_EXPORTER_OTLP_ENDPOINTOTLP/HTTP endpointhttp://localhost:4318

    #Flushing and Shutting Down

    SdkTracerProvider::force_flush and shutdown return OTelSdkResult. The library intentionally leaves error handling to the application so you can decide whether to log, retry, or abort.

    A minimal CLI pattern is to print export failures to stdout:

    fn format_error(err : @error.OTelSdkError) -> String {
    match err {
    AlreadyShutdown => "AlreadyShutdown"
    Timeout(ms) => "Timeout(\{ms}ms)"
    InvalidArgument(msg) => "InvalidArgument(\{msg})"
    InternalFailure(msg) => "InternalFailure(\{msg})"
    ExportFailure(name, msg) => "ExportFailure(\{name}, \{msg})"
    }
    }

    match provider.force_flush() {
    Ok(_) => ()
    Err(err) => @stdio.stdout.write("Telemetry flush failed: " + format_error(err) + "\n")
    }

    match provider.shutdown() {
    Ok(_) => ()
    Err(err) => @stdio.stdout.write("Telemetry shutdown failed: " + format_error(err) + "\n")
    }

    Always call shutdown before the process exits so pending spans are exported.

    #ID Generator Option

    The id_generator parameter of init_telemetry / init_from_env supports:

    OptionDescription
    @telemetry.SdkDefaultUse the SDK default RandomIdGenerator
    @telemetry.ProcessUniqueRandomGenerate 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

    #Target Backend

    This library depends on opentelemetry/otlp, whose async/http and async/socket interfaces are native-only. Therefore moon.mod declares preferred_target = "native". Projects using this library should also run and test with --target native.

    #Example Project

    A complete agent example using this library can be found at:

    #Testing

    moon test -p cybershang/agent-telemetry --target native

    #License

    Mulan PSL v2

    ExporterType

    pub(all) enum ExporterType {
    Stdout
    Otlp(String)
    Custom(
    SpanExporter
    )
    NoOp
    }

    Exporter type for telemetry initialization.

    IdGeneratorOption

    pub(all) enum IdGeneratorOption {
    SdkDefault
    ProcessUniqueRandom
    Custom(
    IdGenerator
    )
    }

    ID generator option for telemetry initialization.

    TelemetryConfig

    pub struct TelemetryConfig {
    service_name : String
    } derive(
    Debug
    )

    Configuration for initializing OpenTelemetry in an agent application.

    TelemetryConfig::new

    fn TelemetryConfig::new(service_name? : String) -> TelemetryConfig

    Create a new telemetry configuration.

    end_span

    End a span, optionally setting a final status.

    end_span_error

    async fn end_span_error(span :
    Span
    , description~ : String) -> Unit

    End a span marking it as failed.

    end_span_ok

    End a span marking it as successful.

    init_from_env

    async fn init_from_env(service_name? : String, id_generator? : IdGeneratorOption) ->
    SdkTracerProvider

    Initialize the global tracer provider from standard environment variables.

    Reads:
    • OTEL_SERVICE_NAME (overrides service_name)
    • OTEL_STDOUT (true selects the stdout exporter)
    • OTEL_EXPORTER_OTLP_ENDPOINT (when OTEL_STDOUT is not true)

    Resolution order for each variable is: process environment > .env file > default value.

    init_telemetry

    Initialize the global OpenTelemetry tracer provider.

    Creates an exporter based on exporter_type, attaches it to a batch span processor, and installs the provider as the global tracer provider.

    make_random_id_generator

    Create an IdGenerator with a process-unique seed.

    This helper works around the SDK default RandomIdGenerator's fixed ChaCha8 seed, which produces duplicate trace/span IDs across process restarts.

    record_chat_response

    fn record_chat_response(span :
    Span
    , response_json : Json, output_messages? : Json?) -> Unit

    Record response metadata and optional output messages for a successful chat request.

    Extracts gen_ai.response.id, gen_ai.response.model and gen_ai.response.finish_reasons from response_json. Sets gen_ai.output.messages when output_messages is provided.

    record_chat_usage

    fn record_chat_usage(span :
    Span
    , usage_json : Json) -> Unit

    Record usage attributes from a GenAI response usage object.

    Sets gen_ai.usage.input_tokens and gen_ai.usage.output_tokens when present.

    record_tool_result

    fn record_tool_result(span :
    Span
    , result : String) -> Unit

    Record the result of a tool execution and mark the span as successful.

    record_turn_metrics

    fn record_turn_metrics(span :
    Span
    , actual_turns : Int, tool_call_count : Int, output : String) -> Unit

    Record turn-level metrics before ending an agent turn span.

    Sets:
    • agent.turn.actual_turns
    • agent.turn.tool_call_count
    • agent.turn.output

    set_attributes

    Set multiple attributes on a span.

    set_chat_http_error

    fn set_chat_http_error(span :
    Span
    , status_code : Int, message? : String) -> Unit

    Mark a chat span as failed due to an HTTP error.

    set_tool_error

    fn set_tool_error(span :
    Span
    , description : String) -> Unit

    Mark a tool span as failed with a description.

    set_turn_max_tool_turns_error

    fn set_turn_max_tool_turns_error(span :
    Span
    ) -> Unit

    Mark an agent turn span as failed due to reaching the maximum tool turns.

    start_agent_turn_span

    Start a span for a single agent turn.

    Sets:
    • agent.turn.input
    • agent.turn.max_tool_turns

    start_chat_span

    fn start_chat_span(tracer :
    Tracer
    , provider_name : String, model : String, max_tokens : Int, input_messages? : Json?, parent_context? :
    Context
    ) ->
    Span

    Start a span for a GenAI chat request following OpenTelemetry GenAI conventions.

    Sets:
    • gen_ai.operation.name = "chat"
    • gen_ai.provider.name
    • gen_ai.request.model
    • gen_ai.request.max_tokens
    • gen_ai.input.messages when input_messages is provided

    start_tool_span

    Start a span for a GenAI tool execution.

    Sets:
    • gen_ai.tool.name
    • gen_ai.tool.call.arguments

    tracer

    fn tracer(scope_name : String, version? : String) ->
    Tracer

    Get or create a tracer for the given scope name.

    Tracers are cached so repeated calls return the same instance.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io