NestJS Microservice OpenTelemetry
This library provides a smimple way to automatically for collecting traces from NestJS applications with Microservice architecture. This library integrated NestJS Microservice, OpenTelemetry-js and Nodejs instrumentations
Description
Nestjs is a protocol-agnostic framework. That's why this library can able to work with different protocols like TCP,RabbitMQ, GRPC and HTTP. Also you can observe and trace Nestjs specific layers like Pipe, Guard, Controller and Provider.
-
Distributed Tracing
Installation
npm install @/cherie-xf/nestjs-microservice-otel --save
Introduce
This is a basic configuration without any trace exporter, but includes default injectors
import { OpenTelemetryModule } from '@cherie-xf/nestjs-microservice-otel';
@Module({
imports: [OpenTelemetryModule.forRoot()]
})
export class AppModule {}
Default Parameters
key | value | description |
---|---|---|
spanProcessor | NoopSpanProcessor | default spanProcessor inherited from NodeSDKConfiguration |
serviceName | String | set to resource attribute : SemanticResourceAttributes.SERVICE_NAME |
textMapPropagator | JaegerPropagator, B3Propagator | default textMapPropagator inherited from NodeSDKConfiguration |
OpenTelemetryModule.forRoot()
takes OpenTelemetryModuleConfig as a parameter, this type is inherited by NodeSDKConfiguration so you can use same OpenTelemetry SDK parameter.
Distributed Tracing Setup
Simple setup with Jaeger exporter, including with default trace instrumentations.
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OpenTelemetryModule } from '@cherie-xf/nestjs-microservice-otel';
@Module({
imports: [
OpenTelemetryModule.forRoot({
spanProcessor: new BatchSpanProcessor(
new JaegerExporter({
endpoint: `http://${jaeger.host}:14268/api/traces`,
}),
),
serviceName: `${myServiceName}`,
}),
],
})
export class AppModule {}
After setup, your application will be instrumented, so that you can see almost every layer of application in JeagerUI, including Guards, Pipes, Controllers even global layers like this
List of supported official exporters here.
Trace Interceptor
This library supports: rename trace span name to meaningful name for both http and rpc; propagation extract parent spanContext of RPC type context
main.ts
import { TraceInterceptor } from '@cherie-xf/nestjs-microservice-otel';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// set up global interceptor
app.useGlobalInterceptors(new TraceInterceptor());
await app.listen(port);
}
bootstrap();
api.controller.ts
import {
TraceInterceptor,
} from '@cherie-xf/nestjs-microservice-otel';
@Controller('api')
@UseInterceptors(TraceInterceptor)
export class ApiController {
constructor(
private readonly apiService: ApiService,
) {}
@Get('get-hello')
getHello(@Res() res): string {
return res.status(200).send('Hello World!');
}
}
Microserve RPC Customized ClientProxy: TraceClientProxy
This libary provide customized TraceClientProxy to automatically propagation.inject while making RPC microservice request
import { Inject, Injectable, Logger } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { TraceClientProxy } from '@cherie-xf/nestjs-microservice-otel';
@Injectable()
export class ApiService {
private readonly _logger = new Logger(ApiService.name);
constructor(
@Inject('USER_CLIENT')
private readonly user_client: ClientProxy,
private traceClient: TraceClientProxy,
) {}
async createUser(data: any) {
const pattern = { name: 'user', cmd: 'create.user' };
const payload = {
user_name: data.user_name,
user_email: data.user_email,
};
return await this.traceClient.send(this.user_client, pattern, payload);
}
Trace Decorators
This library supports auto instrumentations for Nestjs layers, but sometimes you need to define custom span for specific method blocks like providers methods. In this case @Span
decorator will help you.
import { Injectable } from '@nestjs/common';
import { Span } from '@metinseylan/nestjs-opentelemetry';
@Injectable()
export class AppService {
@Span()
getHello(): string {
return 'Hello World!';
}
}
Also @Span
decorator takes name
field as a parameter
@Span('hello')
Trace Providers
You can use Decorators to trace Services, or you can access the native OpenTelemetry Trace api to manually handle span.
import { Injectable } from '@nestjs/common';
import { Tracer } from '@opentelemetry/sdk-trace-base';
@Injectable()
export class AppService {
constructor(private readonly tracer: Tracer) {}
getHello(): string {
const span = this.tracer.startSpan('important_section_start');
// do something important
span.setAttributes({ userId: 1150 });
span.end();
return 'Hello World!';
}
}
TraceService
can access directly current span context and start new span.
import { Injectable } from '@nestjs/common';
import { TraceService } from '@metinseylan/nestjs-opentelemetry';
@Injectable()
export class AppService {
constructor(private readonly traceService: TraceService) {}
getHello(): string {
const span = this.traceService.startSpan('hello');
// do something
span.end();
return 'Hello World!';
}
}