Telemetry
Events, metrics, and OpenTelemetry hooks.
Fabric Harness emits structured events for every meaningful step in an agent run. The full notes live at docs/telemetry.md.
Event types
agent_start
text_delta
prompt_start prompt_end
tool_start tool_end
command_start command_end
task_start task_end
approval_requested approval_granted approval_denied approval_expired
checkpoint_created checkpoint_restored
compaction
mount
metric
result_retry result
errorTransports
- SSE —
GET /agents/:name/:id/streamemits typedAgentEventvalues for any consumer (curl, fetch, downstream worker). - OpenTelemetry —
openTelemetryExporteradapts Fabric'sTelemetrySpanshape to any@opentelemetry/apiTracer (App Insights, Jaeger, Honeycomb, generic OTLP). Passconventions: 'foundry'to emitgen_ai.*span names matching Azure AI Foundry / OpenTelemetry Generative AI semantic conventions. - Langfuse —
langfuseExporterfor direct trace export (peer-depslangfuse). - Azure Monitor / App Insights —
applicationInsightsExporterfrom@fabric-harness/azure/app-insights(peer-depsapplicationinsights). - Console —
consoleTelemetryExporterfor local debugging.
import { openTelemetryExporter, langfuseExporter, eventToTelemetrySpan } from '@fabric-harness/sdk';
import { Langfuse } from 'langfuse';
const langfuse = new Langfuse({ publicKey, secretKey, baseUrl });
const exporter = langfuseExporter({ client: langfuse, attributes: { service: 'support-agent' } });
const session = await fabric.session(undefined, {
onEvent: async (event) => {
const span = eventToTelemetrySpan(event);
if (span) await exporter.export(span);
},
});Metrics from the CLI
fh metrics <session-id> [--json]Aggregates:
- token usage (input + output + total) and
costUsdif the provider reports it, - tool calls (with per-tool breakdown for the top 5),
- shell commands and durations,
- artifacts,
- mounts (count, total bytes, total files, top sources by bytes),
- model attempts.
Per-event hooks
Subscribe to events at agent or session scope via the onEvent callback. Wire any of the exporters above (or a custom one implementing TelemetryExporter) into the callback to forward spans.
Hierarchical OpenTelemetry observer
openTelemetryExporter emits one flat span per duration-bearing event. For a nested trace — a single parent span per operation, with turn, tool, and shell spans inside — use the observer instead:
import { trace } from '@opentelemetry/api';
import { createOpenTelemetryObserver } from '@fabric-harness/sdk/otel-observer';
const observe = createOpenTelemetryObserver({
tracer: trace.getTracer('fabric-harness'),
conventions: 'fabric', // or 'foundry' for gen_ai.* span names + attributes
});
const agent = await init({ onEvent: observe });It lives on the @fabric-harness/sdk/otel-observer subpath (not the main entry) because building parent spans needs @opentelemetry/api at runtime, while the main SDK keeps it an optional peer dependency. The tree is inferred from event start/end ordering; a task() sub-session traces separately with a wrapping task span, and an error event closes open spans with ERROR status.