Enabling OpenTelemetry for a TypeScript Agent

SkillMonitoring & ops

Sends your TypeScript Golem agent's traces, logs, and metrics to an observability backend via OpenTelemetry.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Enabling OpenTelemetry for a TypeScript Agent skill

About this skill

Enabling the OpenTelemetry (OTLP) plugin for a TypeScript Golem agent, exporting traces, logs, and metrics to an OTLP collector, adding custom spans with the invocation context API or node:diagnostics_channel.

What this skill tells your AI

The instructions your AI receives, as published by golemcloud/golem in golem-skills/skills/ts/golem-enable-otlp-ts/SKILL.md and read by ahel’s review.

The golem-otlp-exporter is a built-in plugin that exports agent telemetry (traces, logs, metrics) to any OTLP-compatible collector via OTLP/HTTP. No plugin installation is needed — just enable it in the application manifest.

Step 1 — Enable the Plugin in golem.yaml

Add the plugin to the component (or agent) that should emit telemetry:

components:
  my-app:service:
    plugins:
      - name: golem-otlp-exporter
        version: "1.5.0"
        parameters:
          endpoint: "http://localhost:4318"
          signals: "traces,logs,metrics"

Plugin Parameters

ParameterRequiredDescription
endpointYesOTLP collector base URL (e.g., http://localhost:4318)
signalsNoComma-separated: traces, logs, metrics. Default: traces
headersNoComma-separated key=value HTTP headers (e.g., x-api-key=secret)
service-name-modeNoagent-id (default) or agent-type

Step 2 — Deploy

golem deploy --yes

After deployment, newly created agents from this component automatically send telemetry to the configured collector.

What Gets Exported

Traces

Spans are created automatically for:

  • Agent invocations
  • RPC calls to other agents
  • Outgoing HTTP requests

Trace and span IDs propagate from inbound HTTP requests (via code-first routes) and are included in outgoing HTTP request headers automatically.

Custom Spans

Use the golem:api/context API to create custom spans:

import { startSpan, currentContext } from 'golem:api/context@1.5.0';

const span = startSpan('my-operation');
span.setAttribute('env', { tag: 'string', val: 'production' });
span.setAttributes([
  { key: 'service', value: { tag: 'string', val: 'my-service' } },
  { key: 'version', value: { tag: 'string', val: '1.0' } },
]);

// ... do work ...

const ctx = currentContext();
console.log(`trace_id: ${ctx.traceId()}`);
span.finish();

Custom Spans via node:diagnostics_channel

TypeScript also supports the Node.js diagnostics_channel API, which automatically creates Golem spans:

import { tracingChannel } from 'node:diagnostics_channel';

const dc = tracingChannel('my-operation');
const result = dc.traceSync(
  () => {
    // ... do work ...
    return 42;
  },
  { method: 'GET', url: '/api/data', env: 'production' } // become span attributes
);

Logs

When logs is included in signals, all log output is forwarded to the OTLP collector. See the golem-logging-ts skill for full logging guidance.

console.log("Hello from TypeScript!");
console.debug("This is a debug log entry");

Metrics

When metrics is included in signals, the following metrics are exported:

MetricTypeDescription
golem_invocation_countCounterNumber of agent method invocations
golem_invocation_duration_nsCounterInvocation duration
golem_invocation_fuel_consumedCounterFuel consumed by invocations
golem_invocation_pending_countCounterNumber of pending invocations
golem_host_call_countCounterNumber of internal host calls
golem_log_countCounterNumber of log entries emitted
golem_memory_initial_bytesGaugeInitially allocated memory
golem_memory_total_bytesGaugeTotal allocated memory
golem_memory_growth_bytesCounterMemory growth since start
golem_component_size_bytesGaugeComponent size in bytes
golem_error_countCounterNumber of recorded errors
golem_interruption_countCounterNumber of interrupt requests
golem_exit_countCounterNumber of process exit signals
golem_restart_countCounterNumber of times a fresh state was created
golem_resources_createdCounterNumber of internal resources created
golem_resources_droppedCounterNumber of internal resources dropped
golem_resources_activeGaugeNumber of active internal resources
golem_update_success_countCounterNumber of successful updates
golem_update_failure_countCounterNumber of failed updates
golem_transaction_committedCounterNumber of committed database transactions
golem_transaction_rolled_backCounterNumber of rolled back database transactions
golem_snapshot_size_bytesCounterSnapshot size in bytes
golem_oplog_processor_lagGaugeOplog processor delivery lag

Each metric includes service.name, golem.agent.id, golem.component.id, and golem.component.version attributes.

Export Semantics

  • Durable Start, End, and Cancelled metadata drives span lifecycle. Long-lived spans retain their origin trace across invocations; failed or retrying attempts do not prematurely close the logical span. Logs use their recorded trace context.
  • Stream summaries use bounded event/outcome metric labels and aggregate item counts; they do not emit a span per item. Active resource and memory values are gauges, and metric labels avoid resource IDs and payload values.
  • In agent-type service-name mode, service.name excludes constructor parameters and phantom instance IDs; golem.agent.id remains the full identity.
  • Collector export is best effort. Accepted source state advances when a send fails, and traces, logs, and metrics are still attempted independently. Exactly-once plugin batch delivery is not exactly-once collector delivery.
  • Fork/revert cannot retract telemetry already accepted by a collector. Source deletion does not provide a terminal signal, so no successful close is invented. Switching plugin instances can lose open-span state; continuity is deferred to GOL-667.

Local Observability Stack

The Golem repository includes a ready-made Docker Compose setup at docker-examples/otlp-collector/:

docker compose -f docker-examples/otlp-collector/docker-compose.yml up -d

This starts:

Configure the plugin with endpoint: "http://localhost:4318" to use this stack.

Per-Environment Configuration

Use presets to vary the endpoint across environments:

components:
  my-app:service:
    plugins:
      - name: golem-otlp-exporter
        version: "1.5.0"
        parameters:
          endpoint: "http://localhost:4318"
          signals: "traces,logs,metrics"
    presets:
      production:
        pluginsMergeMode: replace
        plugins:
          - name: golem-otlp-exporter
            version: "1.5.0"
            parameters:
              endpoint: "https://otel.prod.example.com:4318"
              headers: "x-api-key={{ OTLP_API_KEY }}"
              signals: "traces,logs,metrics"

Key Points

  • Built-in — no golem plugin register needed, just add to golem.yaml
  • Deploy required — run golem deploy after adding the plugin configuration
  • Trace context propagates automatically through HTTP routes and RPC calls
  • Use startSpan from golem:api/context@1.5.0 or tracingChannel from node:diagnostics_channel for custom spans
  • Plugin can be activated/deactivated per agent with golem agent activate-plugin / golem agent deactivate-plugin

Related Skills

  • Load golem-manage-plugins for the general plugin installation model (manifest sections, CLI commands, priority, per-environment configuration)

Signals

GitHub stars
2k
Forks
210
Last commit
Sep 2026
Advanced
Item type
skill
Key
golem-enable-otlp-ts
Source
github.com/golemcloud/golem