/** * Optional OpenTelemetry bridge over `diagnostics_channel` and the agent * event stream. * * Subscribes to every `@weareikko/code-review:*` tracing channel, opens an * OTel span on `start`, and closes it on `asyncEnd`/`error`. The `reviewer.run` * phase additionally carries OpenTelemetry GenAI semantic-convention * attributes (`gen_ai.*`) and emits the standardized GenAI client metrics * (`gen_ai.client.operation.duration`, `gen_ai.client.token.usage`, * `code_review_llm_cost_usd`, `gen_ai.client.operation.time_to_first_chunk`) so * metrics-driven AI observability surfaces auto-discover the service. * * Per-turn and per-tool-call telemetry is captured via `createAgentTelemetry`, * which subscribes to the agent's live event stream and emits: * - `gen_ai.agent.turn` child spans under `invoke_agent code-review` * - `execute_tool ` grandchild spans under each turn * - Per-turn `gen_ai.client.token.usage` and `code_review_llm_cost_usd` metrics * - `gen_ai.client.operation.time_to_first_chunk` when streaming events fire * * Opt-in: set `CODE_REVIEW_OTEL=1`. Exporter selection and endpoint follow * the standard `OTEL_*` env vars (`OTEL_EXPORTER_OTLP_ENDPOINT`, * `OTEL_EXPORTER_OTLP_HEADERS`, …). * * **Content capture**: set `CODE_REVIEW_OTEL_CAPTURE_CONTENT=1` to attach * LLM output text and tool arguments/results to spans as `gen_ai.output.messages`, * `gen_ai.tool.call.arguments`, and `gen_ai.tool.call.result`. These attributes * may contain code diffs and review commentary — only enable after confirming * your observability backend's data-retention and PII policies allow it. * * **Grafana Cloud token scopes**: for all three signals to reach their * respective backends, the service account token used in * `OTEL_EXPORTER_OTLP_HEADERS` must have: * - `Traces Publisher` — writes to Tempo (traces) * - `Metrics Publisher` — writes to Mimir (gen_ai.* histograms) * - `Logs Publisher` — writes to Loki (structured log records) * A token missing any of these scopes will receive `401 Unauthorized: * invalid scope requested` silently from the OTLP gateway. Enable OTel * diagnostics with `OTEL_LOG_LEVEL=error` to surface export failures. * * The OTel SDK runtime is bundled but loaded via dynamic `import()` behind the * env check, so disabling the bridge skips the SDK boot entirely. Library * callers who already have configured providers in their process can inject * their own runtime via `startOtelBridge({ runtime })` so spans and metrics * join the host providers instead of a second `NodeSDK`. */ import type { MeterProvider, TracerProvider } from '@opentelemetry/api'; import type { LoggerProvider } from '@opentelemetry/api-logs'; import type { AgentLike } from './gitlab-review.js'; import { type GeneratedComment } from './types.js'; export interface OtelBridge { shutdown(): Promise; /** * Returns a function that, when called with an agent, subscribes to its live * event stream and emits per-turn and per-tool-call OTel spans/metrics. * Must be called after the `reviewer.run` diagnostic span is open (i.e. from * inside `traceDiagnosticPhase('reviewer.run', ...)`). Returns `undefined` * when the span is not yet open or OTel is disabled. */ createAgentTelemetry(runId: string): ((agent: AgentLike) => () => void) | undefined; /** * Emits one structured OTel log record per generated comment to Loki/the * configured log backend. Each record carries `event.name`, * `code_review.comment.*` attributes, and the comment body as the log * line. Safe to call at any point after the run phase has opened. */ logComments(comments: GeneratedComment[], runId: string): void; } export interface OtelRuntime { tracerProvider: TracerProvider; meterProvider: MeterProvider; loggerProvider: LoggerProvider; shutdown(): Promise; } export interface OtelBridgeOptions { /** * Pre-wired OTel runtime. When provided, the bridge uses the supplied * providers and skips dynamic import of `@opentelemetry/sdk-node`. Library * callers with configured `TracerProvider`/`MeterProvider` should pass their * own providers plus a no-op `shutdown`; tests inject fakes with assertion * hooks. */ runtime?: OtelRuntime; /** * Override the env source used for the opt-in check. Defaults to * `process.env`. */ env?: NodeJS.ProcessEnv; /** * When true, attaches LLM output text and tool call arguments/results to * spans as `gen_ai.output.messages`, `gen_ai.tool.call.arguments`, and * `gen_ai.tool.call.result`. Defaults to `isContentCaptureEnabled(env)`. * * Only enable after confirming your observability backend's data-retention * and PII policies permit storing code review content. */ captureContent?: boolean; } export declare function isOtelEnabled(env?: NodeJS.ProcessEnv): boolean; /** * Returns true when `CODE_REVIEW_OTEL_CAPTURE_CONTENT=1` (or `true`) is set. * * When enabled, per-turn assistant output text is attached to turn spans as * `gen_ai.output.messages`, and tool arguments / results are attached to * `execute_tool` spans as `gen_ai.tool.call.arguments` / `gen_ai.tool.call.result`. * * These fields may contain code diffs and review commentary — only enable after * confirming your observability backend's data-retention and PII policies. */ export declare function isContentCaptureEnabled(env?: NodeJS.ProcessEnv): boolean; export declare function startOtelBridge(options?: OtelBridgeOptions): Promise; /** * Applies our OTLP exporter env defaults, only when the caller hasn't set them * (explicit choices, including `none`, always win). * * Metrics stay on the SDK/backend default **cumulative** temporality. Delta * would be the textbook choice for short-lived CI jobs (cumulative series from * ephemeral jobs start mid-flight, so range aggregation of totals is operator- * dependent), but 0.9.1 defaulted to delta and it was verified to BREAK ingest * on Grafana Cloud — the OTLP endpoint silently dropped every delta-temporality * metric (a review's metrics never landed), so 0.9.2 reverted it. Do not force * delta here unless your backend is confirmed to ingest it (e.g. an OTel * Collector / Alloy running `deltatocumulative` in front of the backend). To * aggregate a range total from these cumulative ephemeral-job metrics, use * per-series `max_over_time`. */ export declare function applyOtelExporterDefaults(env?: NodeJS.ProcessEnv): void; //# sourceMappingURL=otel.d.ts.map