@foam-ai/cliengo-kori
v2.0.0
Published
Foam observability toolkit for Cliengo kori (Fastify 5 + Pino + optional New Relic).
Downloads
2,688
Readme
@foam-ai/cliengo-kori
Foam observability for kori — Fastify 5, Pino, and optional New Relic bridge.
Exports traces, logs, and metrics to Foam's OTLP endpoint. Injects trace context into Pino logs, propagates traces across SNS/SQS boundaries, and optionally bridges New Relic so both systems share the same traceId.
Quick start
// src/foam.ts — import before anything else
import { init } from '@foam-ai/cliengo-kori';
init('kori', {});
// Reads FOAM_OTEL_TOKEN from env automatically.
// Or pass it explicitly: init('kori', { token: '...' })// src/server.ts
import { getFoam, createFastifyLoggerConfig } from '@foam-ai/cliengo-kori';
const foam = getFoam()!;
const fastify = Fastify({
logger: createFastifyLoggerConfig({ level: 'info' }),
});
await fastify.register(foam.createFastifyPlugin());// Shutdown — call in your SIGTERM handler
await getFoam()?.shutdown();init(serviceName, options)
Initializes Foam and returns a KoriInstance. Call once at startup, before creating the Fastify server. In non-production environments (without forceExport), returns an inert no-op instance — no providers, no patches, no network calls.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| token | string | process.env.FOAM_OTEL_TOKEN | Foam OTLP bearer token. Falls back to FOAM_OTEL_TOKEN env var. If missing when exporting, logs a warning and returns an inert instance. |
| newrelic | boolean | false | true loads New Relic via require('newrelic'). false or omitted skips the NR bridge — everything works through OTel alone. |
| forceExport | boolean | false | Export telemetry even outside production (NODE_ENV !== 'production'). Useful for staging. |
KoriInstance methods
createFastifyPlugin()
Returns a Fastify plugin that creates one OTel span per HTTP request. Register it on your Fastify instance:
await fastify.register(foam.createFastifyPlugin());The plugin hooks into onRequest, onError, and onResponse to manage span lifecycle, record exceptions, and capture request context (params, query, body, headers — with automatic redaction of sensitive fields).
createFastifyLoggerConfig(opts?)
Returns a Pino configuration object for Fastify's logger constructor option. Includes the trace-context mixin and an OTLP log destination automatically.
Fastify({ logger: createFastifyLoggerConfig({ level: 'info' }) });Pass streams to replace the default stdout output (e.g., pino-pretty in development):
foam.createFastifyLoggerConfig({
level: 'debug',
streams: [{ stream: pinoPretty() }],
});wrapSqsConsumer(spanName, msg, fn)
Wraps an SQS message handler with an OTel span and optional NR background transaction. Extracts the traceparent from the message attributes to continue the upstream trace.
await foam.wrapSqsConsumer('automation-events', msg, async () => {
// process the message
});Supports both RawMessageDelivery=true (traceparent in msg.MessageAttributes) and RawMessageDelivery=false (traceparent inside the SNS envelope in msg.Body).
injectSnsAttributes(attrs)
Adds a traceparent attribute to SNS MessageAttributes so downstream SQS consumers can continue the trace.
const params = {
Message: JSON.stringify(payload),
TopicArn: topicArn,
MessageAttributes: foam.injectSnsAttributes({
triggerType: { DataType: 'String', StringValue: 'chat' },
}),
};
await sns.publish(params);getTraceContext()
Returns the current { traceId, spanId, traceparent } from the active OTel span, NR transaction, or generates fresh IDs. Useful for propagating trace context to outgoing HTTP calls or other systems.
buildTraceparent()
Returns a W3C traceparent string from the active trace context, or generates a fresh one.
shutdown()
Flushes all pending traces, logs, and metrics, then shuts down the OTel providers. Call this in your SIGTERM handler:
process.on('SIGTERM', async () => {
await getFoam()?.shutdown();
await fastify.close();
process.exit(0);
});getFoam(serviceName?)
Retrieves the KoriInstance created by init(). If only one instance exists, serviceName can be omitted.
createFastifyLoggerConfig(opts?)
Standalone version of foam.createFastifyLoggerConfig() — looks up the Foam instance internally via getFoam(). Convenient when you don't want to pass the instance around:
import { createFastifyLoggerConfig } from '@foam-ai/cliengo-kori';
Fastify({ logger: createFastifyLoggerConfig({ level: 'info' }) });Trace propagation
Traces propagate across service boundaries via W3C traceparent:
SNS publish (combee) SQS consumer (kori)
─────────────────── ──────────────────
injectSnsAttributes() ──────> wrapSqsConsumer()
adds traceparent to extracts traceparent,
MessageAttributes creates child spanThe Fastify plugin creates a shadow OTel span per HTTP request, inheriting the traceId from New Relic (if bridged) or generating a fresh one. All Pino logs within the request carry the same traceId for log-to-trace correlation.
Design philosophy
This package is a toolkit, not an agent. It never:
- Registers process handlers (
uncaughtException,unhandledRejection) - Sets global tracer providers
- Monkey-patches runtime modules (
http,mongodb,redis, etc.)
The consumer owns process lifecycle, shutdown, and any additional instrumentation (e.g., @opentelemetry/instrumentation-http).
