Distributed tracing decorator for NestJS (HTTP + Microservices) powered by OpenTelemetry — brought to you by Hell Factory 🔥
- ✅
@Span()
decorator to auto-create spans for methods - ✅ Supports both HTTP and NestJS microservice handlers
- ✅ Automatically extracts trace context from incoming headers or payload
- ✅ Integrates seamlessly with OpenTelemetry SDK
- ✅ Minimal + Flexible — zero business logic coupling
npm install @hell-factory/trace-reaper
// Register instead of Client Proxy
// attach headers in payload automation
import { Module } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { ReaperClientProxy } from '@hell-factory/trace-reaper';
import { AppController } from './app.controller';
@Module({
controllers: [AppController],
providers: [
{
provide: 'TODO_SERVICE',
useFactory: () => {
return new ReaperClientProxy({
transport: Transport.RMQ,
options: {
urls: ['amqp://@localhost:5672'],
queue: 'todo_queue',
},
});
},
},
],
})
export class AppModule {}
// Nestjs Http
import { Span } from '@hell-factory/trace-reaper';
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller()
export class HelloController {
@Get('/hello')
@Span() // ⬅️ Automatically creates a span named 'getHello'
getHello(@Req() req: Request) {
return 'Hello World!';
}
}
// NestJS Microservice (e.g. Kafka / Redis / TCP)
import { Span } from '@hell-factory/trace-reaper';
import { Controller } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';
@Controller()
export class UserEvents {
@MessagePattern('user.created')
@Span() // ⬅️ Span created using payload.headers as parent context
handleEvent(@Payload() payload: any) {
// Payload expected to contain headers:
// payload.headers['traceparent']
return 'OK';
}
}
// Register as global interceptor
import { TraceInterceptor } from '@hell-factory/trace-reaper';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new TraceInterceptor());
await app.listen(3000);
}
// Use Controller
@UseInterceptors(TraceInterceptor)
@Controller('user')
export class UserController {
@Get(':id')
getUser(@Param('id') id: string) {
return { id };
}
}