@foam-ai/otel-core
Foam's shared server-side OpenTelemetry package for Node.js. One core, adapters as subpath exports, per-customer behavior via configuration — if a bug would ever need a fleet-wide fix, it lives here; if it's customer-specific, it's config in the customer's repo.
Replaces the per-customer packages @foam-ai/cliengo-kori
(/fastify + /pino) and @foam-ai/cliengo-combee
(/express + /winston + /sqs + /sns + /outbound), and the earlier
@foam-ai/node / @foam-ai/node-opentelemetry cores.
Quick start
import { init } from '@foam-ai/otel-core';
init({
serviceName: 'my-service',
// token: defaults to the FOAM_OTEL_TOKEN env var
// endpoint: defaults to OTEL_EXPORTER_OTLP_ENDPOINT env var, then foam prod
});
init() only exports in production (NODE_ENV=production) or with
forceExport: true. It registers global OTel providers, so after init the
standard OTel API works and exports to foam — spans
(tracer.startActiveSpan), exceptions (span.recordException), counters,
histograms, up-down counters, and log records (logger.emit). Convenience
accessors: getTracer(), getMeter(), getLogger().
Adapters
| Subpath | What it gives you |
|---|---|
@foam-ai/otel-core/express |
expressMiddleware(), expressErrorHandler() |
@foam-ai/otel-core/fastify |
fastifyPlugin(), getRequestTraceContext() |
@foam-ai/otel-core/winston |
createWinstonTransport(), createWinstonFormat(), opt-in patchWinston() |
@foam-ai/otel-core/pino |
createPinoDestination(), createPinoMixin(), createPinoLoggerConfig() |
@foam-ai/otel-core/sqs |
wrapSqsConsumer(), wrapSqsBody(), extractSqsTraceparent() |
@foam-ai/otel-core/sns |
injectSnsAttributes(), opt-in patchSns() |
@foam-ai/otel-core/outbound |
opt-in patchOutboundHttp() (shadow spans for egress) |
@foam-ai/otel-core/newrelic |
NR coexistence bridge (resolveNewRelic, getNr, …) |
Host libraries (express, fastify, winston, pino, newrelic,
@aws-sdk/client-sns) are optional peer dependencies — install only what you
use. Nothing is monkey-patched unless you call a patch*() function.
Configuration
| Option | Default | Notes |
|---|---|---|
token |
FOAM_OTEL_TOKEN env |
required to export |
endpoint |
OTEL_EXPORTER_OTLP_ENDPOINT env, then https://otel.api.foam.ai |
|
forceExport |
false |
export outside production |
newrelic |
off | true to auto-detect, or pass the agent |
redactContactInfo |
false |
adds email/phone/telefono/celular to redaction |
redactKeys |
[] |
extra keys to redact |
healthRoutes |
[] |
routes exempted from request-context capture (none by default — health checks are captured) |
ignoredOutboundHosts |
[] |
extra hosts skipped for outbound shadow spans |
captureConsole |
false |
mirror console.* as OTel logs |
captureProcessErrors |
true |
crash capture via uncaughtExceptionMonitor (includes rejections Node escalates; NOT rejections handled by your own listener or under --unhandled-rejections=warn/none) |
Batch cadence honors OTEL_BSP_SCHEDULE_DELAY, OTEL_BLRP_SCHEDULE_DELAY,
and OTEL_METRIC_EXPORT_INTERVAL.
The wire contract (stamps, foam.rid baggage, redaction defaults,
anti-fabrication rules) is specified in contract/SPEC.md
and enforced by the conformance apps under test-apps/.