Summary
opencode run never emits OTel spans to an OTLP collector because process.exit() in the finally block of index.ts kills the process before the BatchSpanProcessor can flush its buffer.
The AppRuntime wraps a ManagedRuntime whose Observability.layer initializes the OTel NodeSdk with a BatchSpanProcessor. Disposing the runtime would trigger the SDK's shutdown() → forceFlush() chain, but AppRuntime.dispose() is never called.
Root cause
In packages/opencode/src/index.ts:
} finally {
process.exit() // kills pending async ops including span export
}
Fix
Call await AppRuntime.dispose() before process.exit():
} finally {
await AppRuntime.dispose().catch(() => {})
process.exit()
}
Reproduction
- Start a local OTLP collector on
localhost:4318
- Run:
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 opencode run --format json "Say hi"
- Observe: 0 spans received by the collector
Related: #13438
Summary
opencode runnever emits OTel spans to an OTLP collector becauseprocess.exit()in thefinallyblock ofindex.tskills the process before theBatchSpanProcessorcan flush its buffer.The
AppRuntimewraps aManagedRuntimewhoseObservability.layerinitializes the OTelNodeSdkwith aBatchSpanProcessor. Disposing the runtime would trigger the SDK'sshutdown()→forceFlush()chain, butAppRuntime.dispose()is never called.Root cause
In
packages/opencode/src/index.ts:Fix
Call
await AppRuntime.dispose()beforeprocess.exit():Reproduction
localhost:4318OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 opencode run --format json "Say hi"Related: #13438