Enabling OpenTelemetry for an Effect Agent

SkillMonitoring & ops

Enables OpenTelemetry export of traces, logs, and metrics for Effect-based Golem agents via a built-in plugin.

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

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Enabling OpenTelemetry for an Effect Agent skill

About this capability

Enabling the built-in OpenTelemetry (OTLP) exporter for Effect-based Golem agents. Use when exporting traces, logs, and metrics or adding Effect spans and structured log annotations.

What this skill tells your AI

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

The golem-otlp-exporter is a built-in Golem plugin that exports agent telemetry to an OTLP-compatible collector over OTLP/HTTP. Enable the plugin in golem.yaml; do not add a JavaScript OpenTelemetry exporter to the component.

@golemcloud/effect-golem automatically connects Effect's logger and tracer to the Golem host. Consequently, normal Effect.log*, Effect.withSpan, and Effect.annotateCurrentSpan calls are captured by the plugin without an application-provided logging or tracing Layer.

Enable the Plugin

Add the plugin to the Effect component 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, such as http://localhost:4318
signalsNoComma-separated traces, logs, and/or metrics; defaults to traces
headersNoComma-separated key=value HTTP headers, such as x-api-key=secret
service-name-modeNoagent-id (default) or agent-type

Deploy the updated application:

golem deploy --yes

New agents created from that component use the configured exporter. Existing plugin activation can also be managed per agent with golem agent activate-plugin and golem agent deactivate-plugin.

Add Effect Spans and Logs

Use Effect v4 APIs rather than mechanically translating the TypeScript SDK's golem:api/context span handles. Effect.withSpan scopes the host span around the Effect and finishes it on success, failure, or interruption. Initial attributes belong in the withSpan options; add attributes discovered during execution with Effect.annotateCurrentSpan.

import { Effect, Schema } from "effect";
import { defineAgent, method } from "@golemcloud/effect-golem";

export const TracedAgent = defineAgent({
  name: "TracedAgent",
  mode: "durable",
  id: {
    instanceName: Schema.String,
  },
  methods: {
    doTracedWork: method({
      input: { taskName: Schema.String },
      success: Schema.String,
    }),
  },
}).implement({
  init: ({ instanceName }) => Effect.succeed(instanceName),
  methods: (instanceName) => ({
    doTracedWork: ({ taskName }) =>
      Effect.gen(function* () {
        yield* Effect.logInfo(`processing: ${taskName}`).pipe(
          Effect.annotateLogs({ instanceName, taskName }),
        );

        return "traced";
      }).pipe(
        Effect.withSpan("process-task", {
          attributes: { task: taskName },
        }),
      ),
  }),
});

Import the implemented agent module from src/main.ts so its top-level registration runs:

import "./traced-agent.js";

When an attribute is only known after the span starts, annotate the current span inside its scoped Effect:

const processTask = Effect.gen(function* () {
  const queue = "priority";
  yield* Effect.annotateCurrentSpan({ queue, retryable: true });
  yield* Effect.logInfo("task accepted").pipe(Effect.annotateLogs({ queue }));
}).pipe(Effect.withSpan("process-task"));

The SDK converts Effect span attribute values to the string-valued attributes supported by golem:api/context@1.5.0. Effect log annotations and log spans are rendered with the active host trace and span IDs and emitted through wasi:logging; including logs in the plugin's signals forwards them to the collector.

What Gets Exported

Traces

Golem creates invocation and host-operation spans automatically. The Effect SDK chains Effect.withSpan spans under the invocation's host span, and Golem propagates trace context for supported inbound HTTP and RPC paths. Failed scoped Effects mark their host spans as errors.

Logs

Use Effect's logging APIs inside handlers:

const logRequest = Effect.gen(function* () {
  yield* Effect.logInfo("request received");
  yield* Effect.logDebug("cache lookup").pipe(
    Effect.annotateLogs({ cacheKey: "item-42" }),
    Effect.withLogSpan("lookup"),
  );
});

Prefer these over the lower-level Logging.log(...) SDK API so log annotations and Effect log spans are retained.

Metrics

When metrics is included in signals, the exporter sends Golem runtime metrics including:

MetricTypeDescription
golem_invocation_countCounterAgent method invocations
golem_invocation_duration_nsCounterInvocation duration
golem_invocation_fuel_consumedCounterFuel consumed by invocations
golem_invocation_pending_countCounterPending invocations
golem_host_call_countCounterInternal host calls
golem_log_countCounterEmitted log entries
golem_memory_initial_bytesGaugeInitially allocated memory
golem_memory_total_bytesGaugeTotal allocated memory
golem_memory_growth_bytesCounterMemory growth since start
golem_component_size_bytesGaugeComponent size
golem_error_countCounterRecorded errors
golem_interruption_countCounterInterrupt requests
golem_exit_countCounterProcess exit signals
golem_restart_countCounterFresh state creations
golem_resources_createdCounterInternal resources created
golem_resources_droppedCounterInternal resources dropped
golem_resources_activeGaugeActive internal resources
golem_update_success_countCounterSuccessful updates
golem_update_failure_countCounterFailed updates
golem_transaction_committedCounterCommitted database transactions
golem_transaction_rolled_backCounterRolled-back database transactions
golem_snapshot_size_bytesCounterSnapshot size
golem_oplog_processor_lagGaugeOplog processor delivery lag

Metrics include service.name, golem.agent.id, golem.component.id, and golem.component.version attributes.

Local Observability Stack

The Golem repository includes an OTLP Collector, Jaeger, Prometheus, Loki, and Grafana setup:

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

It exposes OTLP/HTTP on port 4318, Jaeger on port 16686, Prometheus on port 9090, and Grafana on port 3000. Point the plugin's endpoint at http://localhost:4318.

Per-Environment Configuration

Use presets when collector configuration differs by environment:

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 Constraints

  • Keep OTLP exporter setup in golem.yaml; @golemcloud/effect-golem has no OTLP or plugin installation helper.
  • Use Effect.withSpan and Effect.annotateCurrentSpan; there is no public Tracing.startSpan(...) wrapper.
  • Use Effect.logInfo, Effect.logDebug, and Effect.annotateLogs; do not invent Logging.info(...) or another SDK logger.
  • Do not manually finish an Effect span. Its scoped lifetime is managed by Effect.withSpan.
  • Do not provide Logging.layer or Tracing.layer in an agent. The SDK dispatcher installs both.
  • Do not add @effect/opentelemetry, a Node OpenTelemetry SDK, or a second OTLP exporter inside the QuickJS WebAssembly component.
  • Keep the generated effect and @golemcloud/effect-golem versions aligned, and do not edit files under golem-temp/.

Signals

GitHub stars
2k
Forks
211
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
golem-enable-otlp-effect
Source
github.com/golemcloud/golem