OpenTelemetry Tooling
Purpose and Scope
@flue/opentelemetry is Flue's bridge from runtime observations to the OpenTelemetry GenAI semantic conventions. Use it when you already have, or plan to add, an OpenTelemetry SDK and exporter in the deployment environment and want Flue workflows, agents, model calls, tools, shell operations, and compactions to appear as standard telemetry. The package is intentionally not an all-in-one observability stack: it does not configure an SDK, exporter, sampling, credentials, or deployment-specific flushing for you. That boundary keeps deployment ownership with the application while making Flue's live runtime observations portable across OpenTelemetry-compatible backends.
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
The integration is also versioned around explicit compatibility commitments. The docs state that the package implements the Development GenAI conventions pinned at commit 4c8addb53718b544134be47e256237026fe88875. They also identify a Flue-to-GenAI projection revision of 5 and a Flue extension revision of 3, while noting that the GenAI semantic-convention revision and schema remain unchanged. Treat those revision values as part of the interoperability contract: changing them should be a reviewed compatibility event, not an incidental implementation detail.
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Relevant Source Files
apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md- Defines the public documentation for the OpenTelemetry package, including installation, registration, trace mapping, privacy defaults, and content-capture controls.
Installation and Registration
Install the adapter together with the OpenTelemetry API package, then bring your own SDK and exporter for the runtime target. The documented install command is intentionally small because the exporter choice depends on where the Flue app runs and where telemetry should be delivered. For example, a Node deployment may configure a Node SDK and OTLP exporter, while another environment may use a different SDK setup. The Flue package only needs the OpenTelemetry API and a configured telemetry environment to project observations into.
pnpm add @flue/opentelemetry @opentelemetry/apiSources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Registration happens after the application has configured its OpenTelemetry SDK. Create one instrumentation instance with createOpenTelemetryInstrumentation() and register it with the runtime-level instrument(...) function from @flue/runtime. The returned value is a disposal function. Generated Node applications automatically dispose registrations created while evaluating app.ts after admissions and active work drain, so application code usually does not need to call the disposer in that generated lifecycle. If you register outside that lifecycle, call await disposeInstrumentation() yourself, then flush or shut down your application-owned SDK or exporter separately.
import { createOpenTelemetryInstrumentation } from '@flue/opentelemetry';
import { instrument } from '@flue/runtime';
const instrumentation = createOpenTelemetryInstrumentation();
const disposeInstrumentation = instrument(instrumentation);Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Trace Model
The trace model maps Flue concepts to GenAI-oriented span names. A workflow invocation becomes invoke_workflow <name>, while a prompt or skill invocation becomes invoke_agent <agent>. Delegated work is represented as one task-owned invoke_agent <agent> span, which helps distinguish subtask ownership from the parent agent operation. Provider inference is a client span named chat <requested-model>, and GenAI tool execution is represented as execute_tool <name>. Caller shell execution is represented as flue.operation shell, and context compaction appears as flue.compaction with child chat spans.
| Flue activity | OpenTelemetry representation |
|---|---|
| Workflow invocation | invoke_workflow <name> |
| Prompt or skill | invoke_agent <agent> |
| Delegated task | one task-owned invoke_agent <agent> |
| Provider inference | chat <requested-model> client span |
| GenAI tool execution | execute_tool <name> |
| Caller shell execution | flue.operation shell |
| Context compaction | flue.compaction with child chat spans |
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Provider chat spans are scoped to provider inference only. The projection reads canonical model telemetry directly: semantic request.providerName becomes gen_ai.provider.name, while request.providerId remains the Flue registration identity. The docs call out that the projection does not fall back to removed top-level event fields, which matters when comparing traces across Flue versions or custom observers. Local tools are sibling spans under the agent invocation, and they correlate with model output through gen_ai.tool.call.id. gen_ai.conversation.id identifies one persisted Flue session, not a workflow run, dispatch, operation, trace, session name, or provider-affinity key.
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Content Capture and Privacy
Content capture is disabled by default. With the default policy, the integration excludes implemented model messages, reasoning, system instructions, tool definitions, descriptions, arguments and results, exception messages, and external-content paths. Workflow values are not currently exported even when capture is enabled. This default is important because model and tool content can contain customer data, secrets, credentials, prompts, or internal operational details. The integration therefore makes telemetry structure available without assuming that raw content is safe for a shared tracing backend.
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
To capture content, configure one instrumentation-wide policy. The enabled flag is the global privacy ceiling, so downstream transforms cannot bypass a disabled setting. When a detached converted value is available, it passes through transform once. Returning undefined suppresses both destinations. The transform is trusted application code: Flue does not validate the returned GenAI shape. Structural limits run after the transform, with maxMessageParts retaining the first complete parts per input or output message and the first top-level system instructions, and maxToolDefinitions retaining the first definitions. Limit values must be finite nonnegative safe integers.
const instrumentation = createOpenTelemetryInstrumentation({
content: {
enabled: process.env.OTEL_GENAI_CAPTURE_CONTENT === 'true',
transform(content) {
return redactSecrets(content);
},
},
});Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
API Components
The documented public entrypoint is createOpenTelemetryInstrumentation from @flue/opentelemetry. It can be called with no options, or with configuration such as a content policy. The runtime registration entrypoint is instrument from @flue/runtime, which accepts the instrumentation instance and returns a disposer. The docs also note that applications may pass configured tracer, meter, or structural Logger instances when they own those OpenTelemetry objects. That gives advanced deployments a way to align Flue telemetry with existing SDK setup without making Flue responsible for exporter lifecycle.
| Component | Role |
|---|---|
@flue/opentelemetry | Package that projects Flue observations into OpenTelemetry GenAI spans and metrics. |
createOpenTelemetryInstrumentation() | Creates one instrumentation instance for registration with the runtime. |
@flue/runtime instrument(...) | Registers the instrumentation and returns an async disposal function. |
content.enabled | Global privacy ceiling for content capture. |
content.transform(content) | Application redaction or suppression hook for converted content. |
maxMessageParts | Structural limit for retained message parts and first top-level system instructions. |
maxToolDefinitions | Structural limit for retained tool definitions. |
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
Operational Guidance
Configure OpenTelemetry first, then register Flue instrumentation once. Avoid registering multiple instrumentation instances for the same application unless you have a deliberate reason to duplicate observations. In generated Node applications, prefer the built-in lifecycle for registrations created while evaluating app.ts; it waits for admissions and active work to drain before disposal. In custom lifecycles, dispose the Flue instrumentation before shutting down the SDK or exporter, then perform the exporter flush or shutdown using the SDK APIs your deployment selected.
Sources: apps/docs/src/content/docs/ecosystem/tooling/opentelemetry.md
When reviewing traces, keep the distinction between Flue correlation and standard GenAI attributes clear. Standard fields such as gen_ai.provider.name, gen_ai.conversation.id, and gen_ai.tool.call.id are used where they match the semantic model. Flue-specific correlation remains under documented flue.* attributes when no exact standard field exists. Next, read the observability guide for runtime observation concepts, the tools guide for how application tools become execute_tool spans, and deployment target pages for SDK and shutdown behavior in your chosen runtime.