Libraries
    Preparing search index...

    Module @cleverbrush/otel

    @cleverbrush/otel

    OpenTelemetry instrumentation for the Cleverbrush framework — traces, logs, and metrics over OTLP for @cleverbrush/server, @cleverbrush/orm, and @cleverbrush/log. Designed to ship straight into SigNoz, Grafana Tempo, Jaeger, or any OTLP-compatible backend.

    npm install @cleverbrush/otel @opentelemetry/api
    # Optional auto-instrumentations (only if you want them):
    npm install @opentelemetry/instrumentation-http \
    @opentelemetry/instrumentation-undici \
    @opentelemetry/instrumentation-runtime-node
    // telemetry.ts — load FIRST
    import { setupOtel } from '@cleverbrush/otel';
    import {
    outboundHttpInstrumentations,
    runtimeMetrics
    } from '@cleverbrush/otel/instrumentations';

    export const otel = setupOtel({
    serviceName: 'todo-backend',
    serviceVersion: '1.0.0',
    environment: process.env.NODE_ENV,
    otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
    instrumentations: [
    ...outboundHttpInstrumentations(),
    ...runtimeMetrics()
    ]
    });

    Run with:

    node --import ./dist/telemetry.js dist/index.js
    

    Don't forget to await otel.shutdown() on SIGTERM / SIGINT so batched data flushes.

    import { tracingMiddleware } from '@cleverbrush/otel';
    import { createServer } from '@cleverbrush/server';

    const server = createServer()
    .use(tracingMiddleware({ excludePaths: ['/health'] })) // first!
    .use(corsMiddleware)
    // ... rest of the chain

    A SpanKind.SERVER span is opened per request, named operationId or METHOD route and tagged with the standard HTTP semantic-convention attributes. W3C traceparent is extracted, so spans link to upstream callers.

    import { createClient } from '@cleverbrush/client';
    import { clientTracingMiddleware } from '@cleverbrush/otel/client';

    const client = createClient(api, {
    baseUrl: 'http://todo-backend:3000',
    middlewares: [clientTracingMiddleware()]
    });

    clientTracingMiddleware() opens a SpanKind.CLIENT span around each typed client call and injects W3C traceparent / tracestate / baggage headers. When the downstream Cleverbrush service uses tracingMiddleware(), SigNoz and other OTel backends show both services under one distributed trace.

    Put the tracing middleware first in the client middleware list so it wraps retries, timeouts, and batching. If you use batching(), keep batching last so each logical subrequest carries its own trace context.

    import { instrumentKnex } from '@cleverbrush/otel';
    import knex from 'knex';

    const db = instrumentKnex(
    knex({ client: 'pg', connection: '...' })
    );

    Every Knex query becomes a SpanKind.CLIENT span with db.system.name, db.namespace, db.operation.name, db.query.text, and parented under the active server span automatically.

    import { createLogger, consoleSink } from '@cleverbrush/log';
    import { otelLogSink, traceEnricher } from '@cleverbrush/otel';

    const logger = createLogger({
    minimumLevel: 'information',
    sinks: [consoleSink({ theme: 'dark' }), otelLogSink()],
    enrichers: [traceEnricher()] // attaches TraceId/SpanId to every event
    });
    Export Purpose
    setupOtel(config) Boot the Node SDK; returns { shutdown(), sdk }
    tracingMiddleware(opts?) @cleverbrush/server middleware; opens SERVER span
    clientTracingMiddleware(opts?) @cleverbrush/client middleware; opens CLIENT span
    instrumentKnex(knex, opts?) Hook a Knex instance; emits CLIENT span per query
    otelLogSink(opts?) @cleverbrush/log sink → OTLP log records
    traceEnricher() @cleverbrush/log enricher → adds TraceId / SpanId
    configureOtel(services, opts?) Register ITracer / IMeter in @cleverbrush/di
    outboundHttpInstrumentations() Lazy-load HTTP / undici client auto-instrumentations
    runtimeMetrics() Lazy-load Node runtime metrics
    OTEL_SPAN_ITEM_KEY ctx.items key under which the request span is stashed

    All optional auto-instrumentations and knex are declared as optional peer dependencies, so the package is usable with only @opentelemetry/api installed.

    tracingMiddleware stores the active server span on ctx.items under OTEL_SPAN_ITEM_KEY. Use this to attach custom attributes or events from inside endpoint handlers:

    import { OTEL_SPAN_ITEM_KEY } from '@cleverbrush/otel';
    import type { Span } from '@opentelemetry/api';

    // Inside a @cleverbrush/server endpoint handler
    const span = ctx.items.get(OTEL_SPAN_ITEM_KEY) as Span | undefined;
    span?.setAttribute('app.user_id', userId);
    span?.addEvent('cache.miss', { key: cacheKey });

    setupOtel reads OTEL_EXPORTER_OTLP_ENDPOINT from the environment by default (recommended). Per-signal endpoints (tracesEndpoint / logsEndpoint / metricsEndpoint) and signal toggles (disableTraces, disableLogs, disableMetrics) let you wire up split collectors. Headers (e.g. for SaaS tokens) are passed via headers: { authorization: 'Bearer …' }.

    tracingMiddleware does not record query strings (recordQuery: false by default) and instrumentKnex lets you redact SQL via sanitizeStatement. otelLogSink accepts a sanitizeAttribute hook to drop sensitive fields per event.

    BSD-3-Clause

    Modules

    client
    instrumentations