I tried to use the internal Logger
of nestjs (described on https://docs.nestjs.com/techniques/logger -> but with no description of how to use it)
But I had problems (tried to inject LoggerService
and so on)
Can anybody explain how to do this?
I tried to use the internal Logger
of nestjs (described on https://docs.nestjs.com/techniques/logger -> but with no description of how to use it)
But I had problems (tried to inject LoggerService
and so on)
Can anybody explain how to do this?
Better than accessing the Logger
statically is to create an instance for your class:
@Controller()
export class AppController {
private readonly logger = new Logger(AppController.name);
@Get()
async get() {
this.logger.log('Getting stuff');
}
}
You can provide a context in the constructor like new Logger(AppController.name)
so that the class name (or anything else) will be part of all log messages in this class.
If you at some point want to extend or replace the default LoggerService
, you do not need to change any of your application code besides setting the new logger. Your new logger will automatically be used. If you access it statically it will continue to take the default implementation.
const app = await NestFactory.create(AppModule, {logger: new MyLogger()});
Logger
in your tests:module.useLogger(new NoOpLogger());
AppController.name
come through? –
Butene Logger
implementation: context || this.context
. MyLogger
's method is hence called with the instance variable this.context
of Logger
if it is not explicitly called with a context
. See here: github.com/nestjs/nest/blob/… –
Fairbanks new Logger
in the code make the code not testable, right? –
Hokeypokey module.useLogger(new NoOpLogger());
–
Fairbanks new Logger
pick up new logger implementation? Is it not the default implementation explicitly called? Does this Logger
gte injected logger from app under the hood? –
Osteal new Logger
holds a Logger instance as member variable. All methods internally call the method of instance
. When you override the Logger
it just sets that instance
field. Have a look at the source code: github.com/nestjs/nest/blob/master/packages/common/services/… –
Fairbanks this.logger.log({message: 'error', params})
. This will work as long as the object is stringifyable; has no circular structure. –
Fairbanks Logger
writes to stdout
, see source code. If you want to change that, you can overwrite this behavior with a custom logger, see answer above under point 2). –
Fairbanks @Injectable
in the constructor, just like angular does it. That would make more sense, wouldn't it ? –
Kathiekathleen You need to import first into your class:
import { Logger } from '@nestjs/common';
and then you can begin with logging:
Logger.log('info')
Logger.warn('warning')
Logger.error('something went wrong! ', error)
new
. –
Osteal Logger.log('my message', MyServiceClass.name)
–
Compendium Best practice is to inject the existing logger.
app.module.ts
import { Logger, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, Logger],
})
export class AppModule {}
And in the app.service.ts
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class AppService {
constructor(private readonly logger: Logger) {}
sayHello() {
this.logger.log('Hello world!')
}
}
Injecting a custom logger
section here –
Catawba logger.setContext(...)
from? That method does not exist for me. How can I use an injected logger AND set the context to the current class name? –
Trudy This answer might be useful for others who are trying with CustomLogger Implementation. I am trying to show a sample custom logger implementation and how it can be injected to the Nestjs framework.
I understand that Nestjs inherently uses pino logger. This is just a custom implementation of logger service (which you can replace with bunyan, winston, etc..) This is the folder structure I use:
> src /
> modules /
> database /
> ...
> database.module.ts
> api /
> services /
> controllers /
> interceptors /
> middlewares /
> models /
> schemas /
> shared /
> services /
> app.util.service.ts
> pino.logger.service.ts
> utils /
> interceptors /
> filters /
> main.ts
> app.controller.ts
> app.service.ts
> server.util.service.ts
This is the main gist of it. So the logger service is implemented as follows
import {Injectable, LoggerService, Scope} from "@nestjs/common";
import * as pino from 'pino';
import {AppUtilService} from "./app.util.service";
import * as os from "os";
import {APP_LOG_REDACT, APP_MESSAGE_KEY} from "../utils/app.constants";
@Injectable({
scope: Scope.DEFAULT
})
export class PinoLoggerService implements LoggerService{
constructor(private appUtilService: AppUtilService) {
}
logService = (fileNameString): pino.Logger => {
return pino({
useLevelLabels: true,
prettyPrint: this.appUtilService.isDevEnv(),
// tslint:disable-next-line: object-literal-sort-keys
messageKey: APP_MESSAGE_KEY,
level: this.appUtilService.getLogLevel(),
redact: {
paths: APP_LOG_REDACT,
censor: '**SECRET-INFO**'
},
base: {
hostName: os.hostname(),
platform: os.platform(),
processId: process.pid,
timestamp: this.appUtilService.getCurrentLocaleTimeZone(),
// tslint:disable-next-line: object-literal-sort-keys
fileName: this.appUtilService.getFileName(fileNameString),
},
});
}
debug(message: any, context?: string): any {
}
error(message: any, trace?: string, context?: string): any {
}
log(message: any, context?: string): any {
}
warn(message: any, context?: string): any {
}
}
The custom implementation is implemented with the my specific options in pinojs github I am using fastifyjs instead of express (again to match my prject needs). So I've added the logger in fastify js server options. If you are using express, its better to specify the new custom implementation in the Nest application Adapter as stated above.
My util service that takes care of implementing the fastify server
import * as fastify from "fastify";
import {Http2Server, Http2ServerRequest, Http2ServerResponse} from "http2";
import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger";
import * as fs from "fs";
import * as path from "path";
import * as uuid from "uuid";
import * as qs from "query-string";
import {PinoLoggerService} from "./modules/shared/services/pino.logger.service";
import {AppUtilService} from "./modules/shared/services/app.util.service";
import {AppConstantsService} from "./modules/shared/services/app.constants.service";
import {AppModel} from "./modules/shared/model/app.model";
import {Reflector} from "@nestjs/core";
export class ServerUtilService {
private logService;
private appConstantsService;
private appUtilServiceInstance: AppUtilService;
private fastifyInstance: fastify.FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse>;
constructor() {
this.appUtilServiceInstance = new AppUtilService();
this.logService = new PinoLoggerService(this.appUtilServiceInstance);
this.appConstantsService = new AppConstantsService(this.appUtilServiceInstance);
}
retrieveAppConstants(): AppModel {
return this.appConstantsService.getServerConstants();
}
retrieveAppUtilService(): AppUtilService {
return this.appConstantsService;
}
createFastifyServerInstance = (): fastify.FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse> => {
const serverConstants = this.appConstantsService.getServerConstants();
const httpsOptions = {
cert: fs.readFileSync(path.join(process.cwd() + '/https-keys/cert.pem')),
key: fs.readFileSync(path.join(process.cwd() + '/https-keys/key.pem')),
allowHTTP1: true,
rejectUnauthorized: true,
};
this.fastifyInstance = fastify({
http2: true,
https: httpsOptions,
bodyLimit: 26214400,
pluginTimeout: 20000,
genReqId: () => {
return uuid.v4().toString();
},
requestIdHeader: serverConstants.requestIdHeader,
modifyCoreObjects: true,
trustProxy: serverConstants.trustProxy,
ignoreTrailingSlash: true,
logger: this.logService,
querystringParser: (str) => {
return qs.parse(str);
},
});
this.addContentTypeParser();
return this.fastifyInstance;
};
private addContentTypeParser() {
this.fastifyInstance.addContentTypeParser('*', (req, done) => {
let data = '';
req.on('data', chunk => {
console.log('inside data listener event');
return data += chunk; });
req.on('end', () => {
done(null,data);
})
});
}
}
export const ServerUtilServiceInstance = new ServerUtilService();
And in my main.ts
async function bootstrap() {
const fastifyServerInstance =
ServerUtilServiceInstance.createFastifyServerInstance();
const serverConstants = ServerUtilServiceInstance.retrieveAppConstants();
const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(fastifyServerInstance)
);
....
... // global filters, interceptors, pipes
....
await app.listen(serverConstants.port, '0.0.0.0');
}
The answer is simple. There are static methods on the Logger class.
e.g.
static log(message: string, context = '', isTimeDiffEnabled = true)
Usage:
Logger.log('Only a test');
Simply you can use logger for your requirement(for error, for warn).This is the sample code for it.
import {Logger, Injectable} from '@nestjs/common';
@Injectable()
export class EmployersService {
private readonly logger = new Logger(EmployersService.name);
findAll() {
this.logger.log('info message'); //for info
this.logger.warn('warn message'); //for warn
this.logger.error('error message'); //for error
}
}
My approach to this is to use an AppLogger
service via the NestJS DI, which wraps the NestJS logger. This means:
private readonly logger = new Logger(AppController.name);
approach)It looks like:
@Injectable()
export class MyService {
constructor(private readonly logger: AppLogger) {}
doSomething() {
this.logger.log('Did something.', MyService.name);
}
}
@Global()
@Module({
imports: [],
controllers: [],
providers: [
AppLogger,
Logger,
],
exports: [AppLogger],
})
export class ConfigModule {}
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class AppLogger {
constructor(private readonly logger: Logger) {}
error(message: any, context: string) {
this.logger.error(message, context);
}
warn(message: any, context: string) {
this.logger.warn(message, context);
}
log(message: any, context: string) {
this.logger.log(message, context);
}
debug(message: any, context: string) {
this.logger.debug(message, context);
}
verbose(message: any, context: string) {
this.logger.verbose(message, context);
}
}
here is a simple usage of nestJs internal Logger:
import { Logger } from '@nestjs/common';
export abstract class TestLogger {
protected abstract readonly logger: Logger;
async testLogger(){
this.logger.warn(
'Document was not found with filterQuery: '
);
}
}
for more complex usage and setup guide you can visit this article:
© 2022 - 2024 — McMap. All rights reserved.