#Should we use a custom logger or stick to native logger?

1 messages · Page 1 of 1 (latest)

last rock
#

My custom logger implementation

import {
  CloudWatchLogsClient,
  CreateLogGroupCommand,
  CreateLogStreamCommand,
  DescribeLogGroupsCommand,
  DescribeLogStreamsCommand,
  PutLogEventsCommand,
  PutRetentionPolicyCommand,
} from '@aws-sdk/client-cloudwatch-logs'
import { ConsoleLogger, Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { EnvironmentVariables } from 'apps/env.validation'

@Injectable()
export class CustomLoggerService extends ConsoleLogger {
  private cloudWatchClient: CloudWatchLogsClient
  private logGroupName: string
  private logStreamName: string
  private retentionInDays: number
  private sequenceToken: string | undefined

  constructor(private configService: ConfigService<EnvironmentVariables>) {
    super()

    const env = configService.get<string>('NODE_ENV')
    this.logGroupName = `/my-app-name/${configService.get<string>('NODE_ENV')}`
    this.logStreamName = env
    this.retentionInDays = env === 'production' ? -1 : 7

    if (env === 'production') {
      this.cloudWatchClient = new CloudWatchLogsClient({
        region: configService.get<string>('AWS_DEFAULT_REGION'),
      })
      this.setupLogGroup()
      this.setupLogStream()
    }
  }

  private async setupLogStream() {
    // setting up the log stream
  }

  private async setupLogGroup() {
    // setting up the log group
  }
#
  private async logToCloudWatch(
    level: string,
    message: string,
    context?: string,
    stack?: string,
  ) {
    if (this.configService.get<string>('NODE_ENV') !== 'production') return

    try {
      const logEvents = [
        {
          message: JSON.stringify({
            level,
            message,
            context,
            stack,
            timestamp: new Date().toISOString(),
          }),
          timestamp: Date.now(),
        },
      ]

      const command = new PutLogEventsCommand({
        logGroupName: this.logGroupName,
        logStreamName: this.logStreamName,
        logEvents,
        sequenceToken: this.sequenceToken,
      })

      const response = await this.cloudWatchClient.send(command)
      this.sequenceToken = response.nextSequenceToken
    } catch (error) {
      console.error('Failed to send logs to CloudWatch:', error)
    }
  }

  log(message: string, context?: string) {
    super.log(message, context)
    this.logToCloudWatch('info', message, context)
  }

  error(message: any, trace?: string, context?: string) {
    super.error(message, trace, context)
    if (message instanceof Error) {
      this.logToCloudWatch(
        'error',
        JSON.stringify(message),
        context,
        message.stack,
      )
    } else {
      this.logToCloudWatch('error', message, context)
    }
  }

  warn(message: string, context?: string) {
    super.warn(message, context)
    this.logToCloudWatch('warn', message, context)
  }

  debug(message: string, context?: string) {
    super.debug(message, context)
    this.logToCloudWatch('debug', message, context)
  }

  verbose(message: string, context?: string) {
    super.verbose(message, context)
    this.logToCloudWatch('verbose', message, context)
  }
}