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)
}
}
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With