All Projects → pragmaticivan → nestjs-otel

pragmaticivan / nestjs-otel

Licence: Apache-2.0 license
OpenTelemetry (Tracing + Metrics) module for Nest framework (node.js) 🔭

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to nestjs-otel

typegraphql-nestjs
TypeGraphQL integration with NestJS
Stars: ✭ 117 (-57.14%)
Mutual labels:  nest, nestjs
angular-chat
Angular v.9, Node.js, Nest.js v.6, Mongoose, Socket.io, Passport, Angular Universal SSR (in progress...)
Stars: ✭ 35 (-87.18%)
Mutual labels:  nest, nestjs
nestjs-session
Idiomatic Session Module for NestJS. Built on top of `express-session` 😎
Stars: ✭ 150 (-45.05%)
Mutual labels:  nest, nestjs
nestjs-starter
🚀 Nest framework starter
Stars: ✭ 30 (-89.01%)
Mutual labels:  nest, nestjs
unnue-nuxt
开媛笔记,基于nuxt ssr首屏服务器端渲染 ⚡。用于分享、记录、交流和学习,希望可以帮助到小伙伴们。同时网站在永久更新,备好鸡血,一起来战 Ooh aah!
Stars: ✭ 98 (-64.1%)
Mutual labels:  nest, nestjs
ogma
A monorepo for the ogma logger and related packages
Stars: ✭ 201 (-26.37%)
Mutual labels:  nest, nestjs
uptrace
Open source APM: OpenTelemetry traces, metrics, and logs
Stars: ✭ 1,187 (+334.8%)
Mutual labels:  observability, opentelemetry
prime-nestjs
A production-ready NestJS boilerplate using Typescript, Postgres, TypeORM, and Docker.
Stars: ✭ 140 (-48.72%)
Mutual labels:  nest, nestjs
nest-xray
Distributed tracing for Nestjs with AWS X-Ray as the backend. Instrument incoming and outgoing HTTP requests
Stars: ✭ 50 (-81.68%)
Mutual labels:  nest, nestjs
azure-serverless-deprecated
[Deprecated] Azure Serverless module for Nest framework (node.js) 🌩
Stars: ✭ 44 (-83.88%)
Mutual labels:  nest, nestjs
bundled-nest
💥 Nest 🔰 Webpack 🔰 Docker 💥 --- 🏯 Now archived for historical reference ⛩
Stars: ✭ 59 (-78.39%)
Mutual labels:  nest, nestjs
azure-func-http
Azure Functions HTTP adapter for Nest framework (node.js) 🌥
Stars: ✭ 121 (-55.68%)
Mutual labels:  nest, nestjs
nestjs-asyncapi
NestJS AsyncAPI module - generate the documentation of your event-based services using decorators
Stars: ✭ 88 (-67.77%)
Mutual labels:  nest, nestjs
nestjs-dynamoose
Dynamoose module for Nest
Stars: ✭ 84 (-69.23%)
Mutual labels:  nest, nestjs
aws-otel-java-instrumentation
AWS Distro for OpenTelemetry Java Instrumentation Library
Stars: ✭ 41 (-84.98%)
Mutual labels:  observability, opentelemetry
discord-nestjs
👾 NestJS package for discord.js
Stars: ✭ 173 (-36.63%)
Mutual labels:  nest, nestjs
nestjs-objection
Objection module for NestJS
Stars: ✭ 24 (-91.21%)
Mutual labels:  nest, nestjs
nestjs-telegraf
🤖 Powerful Nest module for easy and fast creation Telegram bots
Stars: ✭ 300 (+9.89%)
Mutual labels:  nest, nestjs
nestjs-ioredis
IORedis module for Nest
Stars: ✭ 21 (-92.31%)
Mutual labels:  nest, nestjs
nestjs-extensions
[WIP] A bunch of useful and opinionated filters, modules, pipes... to use with Nest framework. 😻
Stars: ✭ 43 (-84.25%)
Mutual labels:  nest, nestjs

Nest Logo

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

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({
  metricExporter: new PrometheusExporter({
    port: 8081,
  }),
  metricInterval: 1000,
  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
    defaultMetrics: true, // Includes Default Metrics
    apiMetrics: {
      enable: true, // Includes api metrics
      timeBuckets: [], // You can change the default time buckets
      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
    },
  },
});

@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-metrics';

@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-metrics';

@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 Metric Description Labels Metric Type
http_request_total Total number of HTTP requests. method, path Counter
http_response_total Total number of HTTP responses. method, status, path Counter
http_response_success_total Total number of all successful responses. - Counter
http_response_error_total Total number of all response errors. - Counter
http_request_duration_seconds HTTP latency value recorder in seconds. method, status, path Histogram
http_client_error_total Total number of client error requests. - Counter
http_server_error_total Total number of server error requests. - Counter
http_server_aborts_total Total number of data transfers aborted. - Counter
http_request_size_bytes Current total of incoming bytes. - Histogram
http_response_size_bytes Current total of outgoing bytes. - Histogram

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);

Examples

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

Stargazers over time

Stargazers over time

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].