Package detail

nestjs-ddtrace

codebrick-corp438.1kMIT6.0.0

NestJS Datadog Trace Library

nestjs, datadog, ddtrace, dd-trace

readme

NestJS Datadog Trace

Install

npm i nestjs-ddtrace --save

Setup

  1. Create tracing file (tracing.ts):

     import tracer from 'dd-trace';
    
     // initialized in a different file to avoid hoisting.
     tracer.init({
       // https://docs.datadoghq.com/tracing/connect_logs_and_traces/nodejs/
       logInjection: true
     });
     export default tracer;
  2. Import the tracing file:

     import './tracing';
     import { NestFactory } from '@nestjs/core';
     import { AppModule } from './app.module';
     import { Logger as PinoLogger } from 'nestjs-pino';
     import { Logger } from '@nestjs/common';
    
     async function bootstrap() {
       const app = await NestFactory.create(AppModule, { bufferLogs: true });
       app.useLogger(app.get(PinoLogger));
    
       const logger = new Logger('main');
       const port = process.env.PORT || 3000;
       await app.listen(3000).then(() => {
         logger.log(`Listening on port: ${port}`);
       });
     }
     bootstrap();
  3. Add LoggerModule and DatadogModule to AppModule:

     import { Module } from '@nestjs/common';
     import { LoggerModule } from 'nestjs-pino';
     import { DatadogTraceModule } from 'nestjs-ddtrace';
    
     @Module({
       imports: [LoggerModule.forRoot({
         pinoHttp: {
           level: process.env.ENV !== 'prod' ? 'trace' : 'info'
         }
       }), DatadogTraceModule.forRoot()],
     })
     export class AppModule {}

Span Decorator

If you need, you can define a custom Tracing Span for a method or class. 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 { DatadogTraceModule } from 'nestjs-ddtrace';

@Module({
  imports: [DatadogTraceModule.forRoot()],
})

export class AppModule {}

Tracing Service

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

import { Span, TraceService } from 'nestjs-ddtrace';

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

  @Span()
  async getBooks() {
    const currentSpan = this.traceService.getActiveSpan(); // --> retrives current span, comes from http or @Span
    await this.doSomething();
    currentSpan.addTags({
      'getBooks': 'true'
    });

    const childSpan = this.traceService.getTracer().startSpan('ms', {childOf: currentSpan});
    childSpan.setTag('userId', 1);
    await this.doSomethingElse();
    childSpan.finish(); // new span ends

    try {
      doSomething();
    } catch (e) {
      currentSpan.setTag('error', e);
      throw e;
    }
    return [`Harry Potter and the Philosopher's Stone`];
  }
}
import { Span } from 'nestjs-ddtrace';

@Injectable()
@Span()
export class BookService {
  async getBooks() { ... }
  async deleteBook(id: string) { ... }
}

@Controller()
@Span()
export class HelloController {
  @Get('/books')
  getBooks() { ... }

  @Delete('/books/:id')
  deleteBooks() { ... }
}

No Span Decorator

If you need to explicitly exclude a method or class from having a custom tracing Span then you can explicitly exclude it.

import { NoSpan, Span } from 'nestjs-ddtrace';

@Injectable()
@Span()
export class BookService {
  async getBooks() { ... }
  @NoSpan()
  async deleteBook(id: string) { ... }
}

@Controller()
@NoSpan()
export class HelloController {
  @Get('/books')
  getBooks() { ... }

  @Delete('/books/:id')
  deleteBooks() { ... }
}

Custom tracing spans for all controllers and providers

Custom tracing spans can be enabled for all controllers and providers using the controllers and providers options.

import { DatadogTraceModule } from 'nestjs-ddtrace';

@Module({
  imports: [DatadogTraceModule.forRoot({
      controllers: true,
      providers: true,
    })],
})

export class AppModule {}

Controllers and providers can be excluded by including their name in either the excludeControllers or excludeProviders options.

This may be useful for:

  • having a single place to specify what should be excluded
  • excluding controllers and providers you do not own so using the @NoSpan decorator is not an option.
import { DatadogTraceModule } from 'nestjs-ddtrace';

@Module({
  imports: [DatadogTraceModule.forRoot({
      controllers: true,
      providers: true,
      excludeProviders: ['TraceService'],
    })],
})

export class AppModule {}

Miscellaneous

Inspired by the nestjs-otel and nestjs-opentelemetry repository.