Files
open-multi-agent/scripts/observability-example-smoke.mjs
Jack Chen 6eece1d5ee feat(examples): add a real OTLP/HTTP export example (#562)
Every observability example used an in-process exporter, which proves the
adapter's semantics but never serializes a span or opens a socket. Nothing in
the repository showed the path an OpenTelemetry user actually takes, so the
exporter choice, Resource, auth headers, and shutdown order were left for each
reader to reconstruct.

`otlp-backend.ts` runs OTel SDK to OTLP/HTTP exporter to HTTP to a backend, and
prints what crossed the wire. The backend is a loopback listener the example
starts itself, so it still needs no API key, no external collector, and no
internet access; `OTLP_URL` and `OTLP_HEADERS` redirect the same payload to a
hosted vendor.

It also demonstrates two things that are easy to get wrong. `service.name`
belongs to the provider's Resource, and a provider built without one files
every span under `unknown_service:node`. Tool input and output require both
halves of the capture opt-in, so the example sets the core policy and the
adapter mode together and states what the run exports without them.

`runToolDemo` joins the shared demo runtime so the example can show a real
`execute_tool` span; the existing `runDemo` export is unchanged. The example is
registered in the catalog and in the smoke script, which now runs eight
examples.
2026-09-01 01:47:34 +08:00

38 lines
1.2 KiB
JavaScript

import { spawn } from 'node:child_process'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'
import { join } from 'node:path'
const root = fileURLToPath(new URL('..', import.meta.url))
// Resolved rather than joined onto `root`: a git worktree has no local
// `node_modules` and resolves upwards to the main checkout.
const tsx = createRequire(import.meta.url).resolve('tsx/cli')
const directory = join(root, 'packages', 'core', 'examples', 'integrations', 'observability-v2')
const examples = [
'batching-exporter.ts',
'in-memory-store.ts',
'file-trace-store.ts',
'otel-provider.ts',
'otlp-backend.ts',
'cli-lifecycle.ts',
'server-lifecycle.ts',
'serverless-lifecycle.ts',
]
for (const example of examples) {
await new Promise((resolve, reject) => {
const child = spawn(process.execPath, [tsx, join(directory, example)], {
cwd: root,
stdio: 'inherit',
env: { ...process.env, NO_COLOR: '1' },
})
child.once('error', reject)
child.once('exit', (code, signal) => {
if (code === 0) resolve()
else reject(new Error(`${example} failed with code ${code ?? 'null'} signal ${signal ?? 'none'}`))
})
})
}
console.log(`observability example smoke: ${examples.length} passed`)