Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with using Azure Applications Insights sdk with NestJS logger

In our nestjs application we are trying to use multiple loggers, one using Logger from nestjs and the other is Azure Application Insight client.trackTrace . When both loggers are called I see the following error 1: 0x10003c597 node::Abort() [/usr/local/bin/node] 2: 0x1000bc617 node::Chdir(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node] 3: 0x10023663f v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo*) [/usr/local/bin/node] 4: 0x100235b81 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node] 5: 0x100235220 v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node] 6: 0x3196422dbe3d Abort trap: 6

If only one logger is used then no issue, both work fine on their own.

If the nestjs Logger is replaced with a logger that either calls console.log, console.error ..etc or process.env.stdout.write(..) then it works fine. So there seems to be something going on between nestjs Logger and the AppicationInsights client.

factory to create logger

import * as appInsights from 'applicationinsights';
import {Logger, LoggerService} from '@nestjs/common';



  appInsights
    .setup()
    .setAutoCollectConsole(true, true)
    .setAutoDependencyCorrelation(true)
    .start();



export const getLogger = (prefix: string): LoggerService => {


    const appInsightLogger: LoggerService = new AppInsightLogger(
      prefix,
      appInsights.defaultClient,



    return new MultiLogger(appInsightLogger, new Logger(prefix));


  }

MultiLogger

import { LoggerService } from '@nestjs/common';

export class MultiLogger implements LoggerService {
  constructor(private readonly logger1: LoggerService, private readonly logger2:LoggerService) {}

  error(message: any, trace?: string, context?: string) {

    this.logger1.error(message, trace, context);
   this.logger2.error(message, trace, context);
  }
  log(message: any, context?: string) {

    this.logger1.log(message, context);
    this.logger2.log(message, context)
  }


  warn(message: any, context?: string) {

    this.logger1.warn(message, context);
    this.logger2.warn(message, context)
  }

  debug?(message: any, context?: string) {

    this.logger1.debug(message, context);
    this.logger2.debug(message, context);
  }
  verbose?(message: any, context?: string) {

    this.logger1.verbose(message, context);
    this.logger2.verbose(message, context)
  }
}

like image 595
Joe Avatar asked Sep 08 '25 10:09

Joe


1 Answers

Rather than creating a new logger to log to default nestJs logger and also app insights, the solution you were after is to extend the default logger and perform the extra logging to app insights in there (this will resolve the issue you're having).

Once extended, you can also then inject the logger

To get access to the app insights client, I created a setClient method on the logger and called it during bootstrap in main.ts:

const app = await NestFactory.create(AppModule);
const logger = await app.resolve(GcsLogger);
logger.setClient(appInsights.defaultClient);
app.useLogger(logger);

custom, extended logger:

@Injectable({ scope: Scope.TRANSIENT })
export class GcsLogger extends Logger {
  private client: TelemetryClient;

  constructor() {
    super();
  }

  setClient(client: TelemetryClient) {
    this.client = client;
  }

  error(message: any, trace?: string, context?: string) {
    this.client.trackException({
      exception: message as Error,
      severity: SeverityLevel.Error,
      properties: [context, super.context, trace],
    } as ExceptionTelemetry);
    this.client.trackTrace({
      message,
      severity: SeverityLevel.Error,
    } as TraceTelemetry);
    super.error(message, trace);
  }

  warn = (message: string) => {
    this.client.trackTrace({
      message,
      severity: SeverityLevel.Warning,
      properties: [super.context],
    } as TraceTelemetry);
    super.warn(message);
  };

  debug(message: any, context?: string): any {
    this.client.trackTrace({
      message,
      severity: SeverityLevel.Information,
      properties: [context, super.context],
    } as TraceTelemetry);
    super.debug(message);
  }

  log(message: any, context?: string): any {
    this.client.trackTrace({
      message,
      severity: SeverityLevel.Information,
      properties: [context, super.context],
    } as TraceTelemetry);
    super.log(message);
  }

  verbose(message: any, context?: string): any {
    this.client.trackTrace({
      message,
      severity: SeverityLevel.Verbose,
      properties: [context, super.context],
    } as TraceTelemetry);
    super.verbose(message);
  }
}
like image 125
Ian Avatar answered Sep 10 '25 06:09

Ian