Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

nestjs-otel

pragmaticivan210kApache-2.06.2.0TypeScript support: included

NestJS OpenTelemetry Library

nestjs, opentelemetry, otel, tracing, observability, prometheus

readme

nestjs-otel

NestJS OpenTelemetry (OTEL)

Build Status NPM

Description

OpenTelemetry module for Nest.

Questions

For questions and support please use the official Discord channel.

Why

Setting up observability metrics with nestjs requires multiple libraries and patterns. OpenTelemetry has support for multiple exporters and types of metrics such as Prometheus Metrics.

Observability

Please read this comprehensive whitepaper if that's your first time working with metrics, tracing, and logs.

observability-signals

Examples

A full working examples are available. This includes a nestjs application fully integrated with prometheus, grafana, loki and tempo:

Installation

npm i nestjs-otel @opentelemetry/sdk-node --save

Setup

Some peers dependencies are required when some configurations are enabled.

@opentelemetry/exporter-prometheus
  1. Create tracing file (tracing.ts):
import {
  CompositePropagator,
  W3CTraceContextPropagator,
  W3CBaggagePropagator,
} from '@opentelemetry/core';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
import * as process from 'process';

const otelSDK = new NodeSDK({
  metricReader: new PrometheusExporter({
    port: 8081,
  }),
  spanProcessor: new BatchSpanProcessor(new JaegerExporter()),
  contextManager: new AsyncLocalStorageContextManager(),
  textMapPropagator: new CompositePropagator({
    propagators: [
      new JaegerPropagator(),
      new W3CTraceContextPropagator(),
      new W3CBaggagePropagator(),
      new B3Propagator(),
      new B3Propagator({
        injectEncoding: B3InjectEncoding.MULTI_HEADER,
      }),
    ],
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

export default otelSDK;

// You can also use the shutdown method to gracefully shut down the SDK before process shutdown
// or on some operating system signal.
process.on('SIGTERM', () => {
  otelSDK
    .shutdown()
    .then(
      () => console.log('SDK shut down successfully'),
      err => console.log('Error shutting down SDK', err)
    )
    .finally(() => process.exit(0));
});
  1. Import the metric file and start otel node SDK:
import otelSDK from './tracing';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Logger } from 'nestjs-pino';

async function bootstrap() {
  // Start SDK before nestjs factory create
  await otelSDK.start();

  const app = await NestFactory.create(AppModule);
  app.useLogger(app.get(Logger));
  await app.listen(3000);
}
bootstrap();
  1. Configure nest-otel:
const OpenTelemetryModuleConfig = OpenTelemetryModule.forRoot({
  metrics: {
    hostMetrics: true, // Includes Host Metrics
    apiMetrics: {
      enable: true, // Includes api metrics
      defaultAttributes: {
        // You can set default labels for api metrics
        custom: 'label',
      },
      ignoreRoutes: ['/favicon.ico'], // You can ignore specific routes (See https://docs.nestjs.com/middleware#excluding-routes for options)
      ignoreUndefinedRoutes: false, //Records metrics for all URLs, even undefined ones
      prefix: 'my_prefix', // Add a custom prefix to all API metrics
    },
  },
});

@Module({
  imports: [OpenTelemetryModuleConfig],
})
export class AppModule {}

Span Decorator

If you need, you can define a custom Tracing Span for a method. It works async or sync. Span takes its name from the parameter; but by default, it is the same as the method's name

import { Span } from 'nestjs-otel';

@Span('CRITICAL_SECTION')
async getBooks() {
    return [`Harry Potter and the Philosopher's Stone`];
}

Tracing Service

In case you need to access native span methods for special logics in the method block:

import { TraceService } from 'nestjs-otel';

@Injectable()
export class BookService {
  constructor(private readonly traceService: TraceService) {}

  @Span()
  async getBooks() {
    const currentSpan = this.traceService.getSpan(); // --> retrives current span, comes from http or @Span
    await this.doSomething();
    currentSpan.addEvent('event 1');
    currentSpan.end(); // current span end

    const span = this.traceService.startSpan('sub_span'); // start new span
    span.setAttributes({ userId: 1 });
    await this.doSomethingElse();
    span.end(); // new span ends
    return [`Harry Potter and the Philosopher's Stone`];
  }
}

Metric Service

OpenTelemetry Metrics allow a user to collect data and export it to metrics backend like Prometheus.

import { MetricService } from 'nestjs-otel';
import { Counter } from '@opentelemetry/api';

@Injectable()
export class BookService {
  private customMetricCounter: Counter;

  constructor(private readonly metricService: MetricService) {
    this.customMetricCounter = this.metricService.getCounter('custom_counter', {
      description: 'Description for counter',
    });
  }

  async getBooks() {
    this.customMetricCounter.add(1);
    return [`Harry Potter and the Philosopher's Stone`];
  }
}

Metric Decorators

Metric Class Instances

If you want to count how many instance of a specific class has been created:

@OtelInstanceCounter() // It will generate a counter called: app_MyClass_instances_total.
export class MyClass {}

Metric Class Method

If you want to increment a counter on each call of a specific method:

@Injectable()
export class MyService {
  @OtelMethodCounter()
  doSomething() {}
}
@Controller()
export class AppController {
  @Get()
  @OtelMethodCounter() // It will generate `app_AppController_doSomething_calls_total` counter.
  doSomething() {
    // do your stuff
  }
}

Metric Param Decorator

You have the following decorators:

  • @OtelCounter()
  • @OtelUpDownCounter()
  • @OtelHistogram()
  • @OtelObservableGauge()
  • @OtelObservableCounter()
  • @OtelObservableUpDownCounter()

Example of usage:

import { OtelCounter } from 'nestjs-otel';
import { Counter } from '@opentelemetry/api';

@Controller()
export class AppController {
  @Get('/home')
  home(
    @OtelCounter('app_counter_1_inc', { description: 'counter 1 description' }) counter1: Counter
  ) {
    counter1.add(1);
  }
}

API Metrics with Middleware

Impl Otel Metric Prometheus Metric Description Metric Type
http.server.request.count http_server_request_count_total Total number of HTTP requests. Counter
http.server.response.count http_server_response_count_total Total number of HTTP responses. Counter
http.server.abort.count http_server_abort_count_total Total number of data transfers aborted. Counter
http.server.duration http_server_duration The duration of the inbound HTTP request. Histogram
http.server.request.size http_server_request_size Size of incoming bytes. Histogram
http.server.response.size http_server_response_size Size of outgoing bytes. Histogram
http.server.response.success.count http_server_response_success_count_total Total number of all successful responses. Counter
http.server.response.error.count http_server_response_error_count_total Total number of server error responses. Counter
http.client.request.error.count http_client_request_error_count_total Total number of client error requests. Counter

Prometheus Metrics

When metricExporter is defined in otel SDK with a PrometheusExporterit will start a new process on port 8081 (default port) and metrics will be available at http://localhost:8081/metrics.

Using with a logger

Pino with instrumentation

This approach uses otel instrumentation to automatically inject spanId and traceId.

import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';

const otelSDK = new NodeSDK({
  instrumentations: [new PinoInstrumentation()],
});

Pino with custom formatter

This approach uses the global trace context for injecting SpanId and traceId as a property of your structured log.

import Pino, { Logger } from 'pino';
import { LoggerOptions } from 'pino';
import { trace, context } from '@opentelemetry/api';

export const loggerOptions: LoggerOptions = {
  formatters: {
    log(object) {
      const span = trace.getSpan(context.active());
      if (!span) return { ...object };
      const { spanId, traceId } = trace.getSpan(context.active())?.spanContext();
      return { ...object, spanId, traceId };
    },
  },
};

export const logger: Logger = Pino(loggerOptions);

Stargazers over time

Stargazers over time

changelog

Changelog

6.2.0 (2025-03-02)

Features

  • middleware: backward compatibility for nestjs v10 and proper support for v11 middleware (f22d1e5)

6.1.2 (2025-01-17)

Bug Fixes

6.1.1 (2024-05-26)

Bug Fixes

  • removed MeterProvider.addMetricReader deprecation (17d348d)
  • rework param decorators to get correct type (3ba9fe9)

6.1.0 (2024-05-09)

Features

6.0.0 (2024-05-08)

⚠ BREAKING CHANGES

  • Too many changes since I last commited to this project.

Features

Bug Fixes

  • Span being incompatible with MethodDecorator type (75dbf0e)

5.1.5 (2023-09-04)

Bug Fixes

  • latency buckets are not matching the expected time unit in milliseconds (c269bac)

5.1.4 (2023-06-28)

Bug Fixes

  • should support both 9 and 10 versions (50f2273)

5.1.3 (2023-06-21)

Bug Fixes

  • #231 Remove unnecessary files from package bundle (faa521b)

5.1.2 (2023-05-05)

Bug Fixes

  • invalid values for error count metrics (7b13c0b)

5.1.1 (2023-04-21)

Bug Fixes

  • update packages and remove outdated examples (7150dcf)
  • update release please permissions (8db8736)

5.1.0 (2023-04-05)

Features

  • update to stable packages (76b577c)

5.0.0 (2022-11-27)

⚠ BREAKING CHANGES

  • updates to latest metric sdk and drop node-sdk dependency

Features

  • update packages (163ba38)
  • update packages (d0f92fb)
  • update packages (28fdc69)
  • updates to latest metric sdk and drop node-sdk dependency (46c2df3)

Bug Fixes

  • getSpan returning undefined, enable strict null checks (#361) (b7f7cbd)

4.0.1 (2022-08-29)

Bug Fixes

  • bump nestjs requirement to 9.x (24cde7c)

4.0.0 (2022-08-29)

⚠ BREAKING CHANGES

  • support latest metric sdk

Features

  • build: update dependencies (c2f8b7b)
  • support latest metric sdk (e8d2e96)
  • tracing: pass options with span decorator (3424b88)
  • update remaining counters (d11f6d9)

Bug Fixes

  • forRootAsync uses the wrong module and empty options breaks the configure method (c2dc102)

3.0.4 (2022-03-29)

Bug Fixes

  • metrics: make sure metadata is kept (de7ca0f)
  • tracing: make sure metadata is kept (c34ae56)

3.0.3 (2022-03-25)

Bug Fixes

  • tracing: record exception and set correct span status (616c12b)

3.0.2 (2022-03-24)

Bug Fixes

  • tracing: use startActiveSpan to ensure span in correct context (d608b84)

3.0.1 (2022-01-03)

Bug Fixes

  • #171: fixes missing observation callback for observable metrics (7d89c1f), closes #171

3.0.0 (2021-12-30)

⚠ BREAKING CHANGES

  • Anything related to metrics sdk has changed. OTEL now has a stable spec and all the projects are moving towards new interfaces.

Features

  • ename value recorder on decorators and update readme (646e2ea)
  • support all metric types from otel spec (36a7c5f)
  • update metric spec to the latest otel lib (6ed63ae)
  • update packages to compply with latest otel metric spec (943ca06)

2.6.1 (2021-10-13)

Reverts

  • replace arrow function back with unnamed function (3e7ac1f)

2.6.0 (2021-10-12)

Features

  • metrics: option for ignoring undefined routes (15577e8)
  • metrics: option to ignore specific routes (b8a05f1)

Bug Fixes

  • eslint setup (14d9870)
  • linting (1961f18)
  • linting: replace unnamed function with arrow function (12fa02c)
  • metrics: add missing commas in example config in README.md (7b159c6)

2.5.2 (2021-10-07)

Bug Fixes

  • enable nestjs 7.x as peer dependency (e6c6a1e)

2.5.1 (2021-10-06)

Bug Fixes

  • metrics for fastify platform (4b61e70)

2.5.0 (2021-09-26)

Features

  • add defaultLabels support (6efb0a5)

2.4.0 (2021-08-24)

Features

  • add http size and server abort metrics (ba64308)

2.3.0 (2021-08-13)

Features

  • update peer dependency to allow support for both v7 and v8 of NestJs (647eb89)

Bug Fixes

  • error nodeMetrics is not a function (cf7d0fc)
  • removed .npmrc file, as it only had default values (c27a8af)
  • updates package-lock.json with default node 14 np version (3301753)

2.2.0 (2021-08-02)

Features

  • update dependencies to latest (385e3db)

2.1.0 (2021-07-28)

Features

2.0.0 (2021-07-28)

⚠ BREAKING CHANGES

  • removes nodeSDKConfiguration option

Features

  • node-sdk to be defined by the user instead of through the lib (5156324)

1.8.2 (2021-07-25)

Bug Fixes

  • metric: fixes metric service not properly reusing existing metrics (9f24fd8)

1.8.1 (2021-07-25)

Bug Fixes

  • middleware: fixes api middleware when no requesting invalid route (2a008d9)

1.8.0 (2021-07-24)

Features

  • update api metrics to use route match path instead of full route (ad51bac), closes #48

Bug Fixes

  • fixes forRootAsync usage (a390f0e)

1.7.0 (2021-07-14)

Features

  • remove unused constant and reorganize pkgs (d37fc28)

1.6.0 (2021-06-30)

Features

  • changes license to Apache2 (5129fdb)

1.5.0 (2021-06-30)

Features

1.4.0 (2021-06-29)

Features

  • removes prometheus Interface and use metrics instead (f3fd29e)
  • sets meter provider globally on sdk (4be57ef)

1.3.0 (2021-06-28)

Features

  • improves api metrics middleware (df50305)

1.2.3 (2021-06-27)

Bug Fixes

  • properly ignore /metrics path on middleware (45973a4)

1.2.2 (2021-06-27)

Bug Fixes

  • resolve problems with conditional dependency and default configs and add jest config (1f1fb12)

1.2.1 (2021-06-25)

Bug Fixes

  • exports MetricService on core module (e8096a6)

1.2.0 (2021-06-25)

Features

1.1.0 (2021-06-25)

Features

  • use lts npm match for 14.x (9088eac)

Bug Fixes

  • removes latest npm requirement (9dd42f8)

1.0.0 (2021-06-25)

Features