Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/devops-use-logging.md
1---2title: Use Structured Logging3impact: MEDIUM-HIGH4impactDescription: Structured logging enables effective debugging and monitoring5tags: devops, logging, structured-logs, pino6---78## Use Structured Logging910Use NestJS Logger with structured JSON output in production. Include contextual information (request ID, user ID, operation) to trace requests across services. Avoid console.log and implement proper log levels.1112**Incorrect (using console.log in production):**1314```typescript15// Use console.log in production16@Injectable()17export class UsersService {18async createUser(dto: CreateUserDto): Promise<User> {19console.log('Creating user:', dto);20// Not structured, no levels, lost in production logs2122try {23const user = await this.repo.save(dto);24console.log('User created:', user.id);25return user;26} catch (error) {27console.log('Error:', error); // Using log for errors28throw error;29}30}31}3233// Log sensitive data34console.log('Login attempt:', { email, password }); // SECURITY RISK!3536// Inconsistent log format37logger.log('User ' + userId + ' created at ' + new Date());38// Hard to parse, no structure39```4041**Correct (use structured logging with context):**4243```typescript44// Configure logger in main.ts45async function bootstrap() {46const app = await NestFactory.create(AppModule, {47logger:48process.env.NODE_ENV === 'production'49? ['error', 'warn', 'log']50: ['error', 'warn', 'log', 'debug', 'verbose'],51});52}5354// Use NestJS Logger with context55@Injectable()56export class UsersService {57private readonly logger = new Logger(UsersService.name);5859async createUser(dto: CreateUserDto): Promise<User> {60this.logger.log('Creating user', { email: dto.email });6162try {63const user = await this.repo.save(dto);64this.logger.log('User created', { userId: user.id });65return user;66} catch (error) {67this.logger.error('Failed to create user', error.stack, {68email: dto.email,69});70throw error;71}72}73}7475// Custom logger for JSON output76@Injectable()77export class JsonLogger implements LoggerService {78log(message: string, context?: object): void {79console.log(80JSON.stringify({81level: 'info',82timestamp: new Date().toISOString(),83message,84...context,85}),86);87}8889error(message: string, trace?: string, context?: object): void {90console.error(91JSON.stringify({92level: 'error',93timestamp: new Date().toISOString(),94message,95trace,96...context,97}),98);99}100101warn(message: string, context?: object): void {102console.warn(103JSON.stringify({104level: 'warn',105timestamp: new Date().toISOString(),106message,107...context,108}),109);110}111112debug(message: string, context?: object): void {113console.debug(114JSON.stringify({115level: 'debug',116timestamp: new Date().toISOString(),117message,118...context,119}),120);121}122}123124// Request context logging with ClsModule125import { ClsModule, ClsService } from 'nestjs-cls';126127@Module({128imports: [129ClsModule.forRoot({130global: true,131middleware: {132mount: true,133generateId: true,134},135}),136],137})138export class AppModule {}139140// Middleware to set request context141@Injectable()142export class RequestContextMiddleware implements NestMiddleware {143constructor(private cls: ClsService) {}144145use(req: Request, res: Response, next: NextFunction): void {146const requestId = req.headers['x-request-id'] || randomUUID();147this.cls.set('requestId', requestId);148this.cls.set('userId', req.user?.id);149150res.setHeader('x-request-id', requestId);151next();152}153}154155// Logger that includes request context156@Injectable()157export class ContextLogger {158constructor(private cls: ClsService) {}159160log(message: string, data?: object): void {161console.log(162JSON.stringify({163level: 'info',164timestamp: new Date().toISOString(),165requestId: this.cls.get('requestId'),166userId: this.cls.get('userId'),167message,168...data,169}),170);171}172173error(message: string, error: Error, data?: object): void {174console.error(175JSON.stringify({176level: 'error',177timestamp: new Date().toISOString(),178requestId: this.cls.get('requestId'),179userId: this.cls.get('userId'),180message,181error: error.message,182stack: error.stack,183...data,184}),185);186}187}188189// Pino integration for high-performance logging190import { LoggerModule } from 'nestjs-pino';191192@Module({193imports: [194LoggerModule.forRoot({195pinoHttp: {196level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',197transport:198process.env.NODE_ENV !== 'production'199? { target: 'pino-pretty' }200: undefined,201redact: ['req.headers.authorization', 'req.body.password'],202serializers: {203req: (req) => ({204method: req.method,205url: req.url,206query: req.query,207}),208res: (res) => ({209statusCode: res.statusCode,210}),211},212},213}),214],215})216export class AppModule {}217218// Usage with Pino219@Injectable()220export class UsersService {221constructor(private logger: PinoLogger) {222this.logger.setContext(UsersService.name);223}224225async findOne(id: string): Promise<User> {226this.logger.info({ userId: id }, 'Finding user');227// Pino uses first arg for data, second for message228}229}230```231232Reference: [NestJS Logger](https://docs.nestjs.com/techniques/logger)233