import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import axios from 'axios'; @Injectable() export class LoggingService { private readonly logger = new Logger(LoggingService.name); private readonly graylogUrl: string; private readonly environment: string; constructor(private readonly configService: ConfigService) { this.graylogUrl = this.configService.get('GRAYLOG_URL') || 'http://localhost:12201/gelf'; this.environment = this.configService.get('PROFILE') || 'dev'; } async log( level: string, serviceName: string, methodName: string, message: string, parameters?: unknown[], debugInfo?: unknown[], ) { const logLevel = level.toLowerCase().trim(); const logMessage = `${serviceName}.${methodName}: ${message} | Params: ${JSON.stringify( parameters, )} | Debug: ${JSON.stringify(debugInfo)}`; // Console output via NestJS Logger switch (logLevel) { case 'debug': case 'info': this.logger.debug(logMessage); break; case 'warn': this.logger.warn(logMessage); break; case 'error': this.logger.error(logMessage); break; default: this.logger.log(logMessage); } // Send to Graylog asynchronously this.sendToGraylog({ version: '1.1', host: serviceName || 'nestjs-app', short_message: message, full_message: logMessage, level: this.mapLogLevel(logLevel), _service: serviceName, _method: methodName, _parameters: parameters, _debug: debugInfo, _environment: this.environment, timestamp: Date.now() / 1000, }); } private async sendToGraylog(payload: Record) { try { await axios.post(this.graylogUrl, payload, { headers: { 'Content-Type': 'application/json' }, timeout: 2000, // short timeout }); } catch (err) { this.logger.warn(`Graylog send failed: ${err.message}`); } } private mapLogLevel(level: string): number { // Graylog levels: 0 (emerg) → 7 (debug) const mapping: Record = { emerg: 0, alert: 1, crit: 2, error: 3, warn: 4, notice: 5, info: 6, debug: 7, }; return mapping[level] ?? 6; } }