npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@apdev/nestjs-otel-observability

v1.0.3

Published

A comprehensive OpenTelemetry observability module for NestJS applications with automatic tracing, structured logging, metrics, and error handling

Readme

@pafrtds/nestjs-otel-observability

A comprehensive OpenTelemetry observability module for NestJS applications. Provides automatic distributed tracing, structured logging, and metrics collection with minimal configuration.

Features

  • Distributed Tracing: Automatic trace propagation across HTTP, RabbitMQ, and WebSocket
  • Structured Logging: JSON logs with automatic trace context enrichment (trace_id, span_id)
  • Metrics Collection: HTTP request duration, error counts, RabbitMQ processing, WebSocket events
  • Global Error Handling: Automatic error classification (Axios, Prisma, generic) with detailed logging
  • RabbitMQ Integration: Transparent trace context injection/extraction for @golevelup/nestjs-rabbitmq
  • WebSocket Support: Full tracing for Socket.IO events
  • OTLP Export: Send telemetry to OpenTelemetry Collector (compatible with Grafana, Jaeger, etc.)
  • Resilience: Graceful degradation if OTLP endpoint is unavailable

Requirements

  • Node.js >= 18.0.0
  • NestJS >= 10.0.0

Installation

npm install @pafrtds/nestjs-otel-observability

Peer Dependencies

The following packages are required as peer dependencies:

npm install @nestjs/common @nestjs/core reflect-metadata rxjs

Optional Dependencies

For RabbitMQ tracing:

npm install @golevelup/nestjs-rabbitmq

For WebSocket tracing:

npm install @nestjs/websockets @nestjs/platform-socket.io socket.io

Quick Start

1. Create the tracing bootstrap file

Create src/tracing.bootstrap.ts:

import { initTracing } from '@pafrtds/nestjs-otel-observability';

initTracing({
  serviceName: process.env.SERVICE_NAME || 'my-service',
  serviceVersion: process.env.SERVICE_VERSION || '1.0.0',
  environment: process.env.NODE_ENV || 'development',
  
  // OTLP endpoints (optional, defaults to localhost:4318)
  otlpTraceEndpoint: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
  otlpMetricsEndpoint: process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
  otlpLogsEndpoint: process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
  
  // Feature toggles
  enableMetrics: true,
  enableOtlpLogs: true,
  enableConsoleLogs: true,
});

2. Import tracing bootstrap FIRST in main.ts

import './tracing.bootstrap'; // MUST be the first import!

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { StructuredLoggerService } from '@pafrtds/nestjs-otel-observability';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // Optionally use the structured logger
  const logger = app.get(StructuredLoggerService);
  app.useLogger(logger);
  
  await app.listen(3000);
}

bootstrap();

3. Import the module in AppModule

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ObservabilityModule } from '@pafrtds/nestjs-otel-observability';

@Module({
  imports: [
    ConfigModule.forRoot(),
    
    ObservabilityModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        serviceName: configService.get('SERVICE_NAME', 'my-service'),
        environment: configService.get('NODE_ENV', 'development'),
        enableHttp: true,
        enableRabbit: true,
        enableWebSocket: true,
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | serviceName | string | required | Name of the service | | serviceVersion | string | '1.0.0' | Version of the service | | environment | string | 'development' | Deployment environment | | otlpTraceEndpoint | string | http://localhost:4318/v1/traces | OTLP traces endpoint | | otlpMetricsEndpoint | string | http://localhost:4318/v1/metrics | OTLP metrics endpoint | | otlpLogsEndpoint | string | http://localhost:4318/v1/logs | OTLP logs endpoint | | enableHttp | boolean | true | Enable HTTP instrumentation | | enableRabbit | boolean | true | Enable RabbitMQ instrumentation | | enableWebSocket | boolean | true | Enable WebSocket instrumentation | | enableMetrics | boolean | true | Enable metrics collection | | enableOtlpLogs | boolean | true | Send logs to OTLP endpoint | | enableConsoleLogs | boolean | true | Output logs to console | | logLevel | 'debug' \| 'info' \| 'warn' \| 'error' | 'info' | Minimum log level | | sensitiveFields | string[] | ['password', 'token', ...] | Fields to mask in logs | | maxBodyLogSize | number | 10000 | Maximum body size to log (bytes) | | metricsExportIntervalMs | number | 15000 | Metrics export interval | | debug | boolean | false | Enable verbose OTel logging |

Environment Variables

| Variable | Description | |----------|-------------| | SERVICE_NAME | Service name for telemetry | | SERVICE_VERSION | Service version | | NODE_ENV | Environment (development/production) | | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | OTLP traces endpoint | | OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | OTLP metrics endpoint | | OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | OTLP logs endpoint | | OTEL_LOGS_ENABLED | Enable OTLP logs ('true'/'false') | | OTEL_CONSOLE_LOGS_ENABLED | Enable console logs ('true'/'false') | | OTEL_METRICS_ENABLED | Enable metrics ('true'/'false') | | OTEL_METRICS_EXPORT_INTERVAL_MS | Metrics export interval | | OTEL_DEBUG | Enable debug mode ('true'/'false') |

Usage

Using the Structured Logger

import { Injectable } from '@nestjs/common';
import { StructuredLoggerService } from '@pafrtds/nestjs-otel-observability';

@Injectable()
export class MyService {
  constructor(private readonly logger: StructuredLoggerService) {
    this.logger.setContext('MyService');
  }

  doSomething() {
    // Basic logging
    this.logger.log('Operation started');
    this.logger.debug('Debug information', { userId: 123 });
    this.logger.warn('Warning message');
    this.logger.error('Error occurred', errorStack);

    // With metadata
    this.logger.log('User action', {
      action: 'purchase',
      amount: 99.99,
      productId: 'ABC123',
    });
  }
}

Using Metrics

import { Injectable } from '@nestjs/common';
import { MetricsService } from '@pafrtds/nestjs-otel-observability';

@Injectable()
export class MyService {
  constructor(private readonly metrics: MetricsService) {}

  // Create custom metrics
  private orderCounter = this.metrics.createCounter(
    'orders_total',
    'Total number of orders processed',
  );

  processOrder(order: Order) {
    // Record custom metric
    this.orderCounter.add(1, {
      status: order.status,
      payment_method: order.paymentMethod,
    });
  }
}

Getting Trace Context

import {
  getCurrentTraceId,
  getCurrentSpanId,
  getTraceContextInfo,
} from '@pafrtds/nestjs-otel-observability';

// Get current trace ID (useful for logging or correlation)
const traceId = getCurrentTraceId();

// Get all trace context info
const { traceId, spanId, traceFlags } = getTraceContextInfo();

WebSocket Trace Context Injection

import { SubscribeMessage, MessageBody } from '@nestjs/websockets';
import { injectTraceContext } from '@pafrtds/nestjs-otel-observability';

@SubscribeMessage('getData')
async handleGetData(@MessageBody() data: any) {
  const result = await this.service.getData(data);
  
  // Include trace context in response for client-side correlation
  return injectTraceContext(result);
}

OpenTelemetry Collector Configuration

Example otel-collector-config.yaml:

receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 5s
    send_batch_size: 1000

exporters:
  otlp/tempo:
    endpoint: tempo:4317
    tls:
      insecure: true

  prometheusremotewrite:
    endpoint: http://prometheus:9090/api/v1/write
    resource_to_telemetry_conversion:
      enabled: true

  loki:
    endpoint: http://loki:3100/loki/api/v1/push
    labels:
      resource:
        service.name: "service_name"
        deployment.environment: "environment"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/tempo]
    
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheusremotewrite]
    
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [loki]

Collected Metrics

HTTP Metrics

| Metric | Type | Description | Labels | |--------|------|-------------|--------| | http_requests_total | Counter | Total HTTP requests | method, route, status_code | | http_errors_total | Counter | Total HTTP errors (4xx/5xx) | method, route, status_code | | http_request_duration_seconds | Histogram | Request duration | method, route, status_code |

RabbitMQ Metrics

| Metric | Type | Description | Labels | |--------|------|-------------|--------| | rabbitmq_messages_total | Counter | Total messages processed | exchange, routing_key, operation | | rabbitmq_errors_total | Counter | Total processing errors | exchange, routing_key, operation | | rabbitmq_processing_duration_seconds | Histogram | Processing duration | exchange, routing_key, operation |

WebSocket Metrics

| Metric | Type | Description | Labels | |--------|------|-------------|--------| | websocket_events_total | Counter | Total events processed | event | | websocket_errors_total | Counter | Total event errors | event | | websocket_event_duration_seconds | Histogram | Event processing duration | event |

Error Metrics

| Metric | Type | Description | Labels | |--------|------|-------------|--------| | errors_total | Counter | Total errors by type | error_type, context, error_code |

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     NestJS Application                          │
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │    HTTP     │  │  RabbitMQ   │  │      WebSocket          │  │
│  │  Requests   │  │  Messages   │  │       Events            │  │
│  └──────┬──────┘  └──────┬──────┘  └───────────┬─────────────┘  │
│         │                │                      │                │
│         ▼                ▼                      ▼                │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              ObservabilityModule                          │   │
│  │  ┌────────────────────────────────────────────────────┐  │   │
│  │  │                 Interceptors                        │  │   │
│  │  │  • HttpMetricsInterceptor                          │  │   │
│  │  │  • RabbitMQTraceInterceptor                        │  │   │
│  │  │  • RabbitMQPublishInterceptor (monkey-patch)       │  │   │
│  │  │  • WebSocketTraceInterceptor                       │  │   │
│  │  │  • ObservabilityErrorInterceptor                   │  │   │
│  │  └────────────────────────────────────────────────────┘  │   │
│  │  ┌────────────────────────────────────────────────────┐  │   │
│  │  │                   Services                          │  │   │
│  │  │  • StructuredLoggerService                         │  │   │
│  │  │  • MetricsService                                  │  │   │
│  │  └────────────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
└──────────────────────────────┼───────────────────────────────────┘
                               │
                               ▼
                ┌──────────────────────────┐
                │   OpenTelemetry Collector │
                │   (OTLP HTTP :4318)       │
                └────────────┬─────────────┘
                             │
          ┌──────────────────┼──────────────────┐
          │                  │                  │
          ▼                  ▼                  ▼
     ┌─────────┐       ┌─────────┐       ┌─────────┐
     │  Tempo  │       │Prometheus│       │  Loki   │
     │ Traces  │       │ Metrics │       │  Logs   │
     └─────────┘       └─────────┘       └─────────┘
          │                  │                  │
          └──────────────────┼──────────────────┘
                             │
                             ▼
                      ┌─────────────┐
                      │   Grafana   │
                      └─────────────┘

Error Classification

The module automatically classifies errors into the following types:

| Type | Description | Additional Info | |------|-------------|-----------------| | AxiosError | HTTP client errors | URL, status code, method, headers | | PrismaClientKnownRequestError | Prisma constraint violations | Error code, model, field | | PrismaClientUnknownRequestError | Prisma unknown errors | Sanitized message | | PrismaClientValidationError | Prisma validation errors | Sanitized message | | Error | Generic JavaScript errors | Name, message, stack trace |

Security

The module includes built-in security features:

  • Sensitive field masking: Passwords, tokens, and other sensitive fields are automatically redacted in logs
  • Body truncation: Large request/response bodies are truncated to prevent excessive logging
  • Prisma message sanitization: Values in Prisma error messages are sanitized to prevent data leakage

Default sensitive fields:

  • password, token, authorization, secret, key, apikey
  • api_key, api-key, bearer, credential, private
  • cpf, cnpj, ssn, credit_card, card_number

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.