目的
Nest.js に log4js を使う方法をまとめました。
次の内容を実装します。
- 標準Loggerをlog4jsで実装 (今回)
- ミドルウェアでリクエスト情報をログに追加 (次回)
- ログ出力時にスタック情報を追加 (次次回)
事前準備
プロジェクトは Nest.js のCLIコマンドで生成します。
npm i -g @nestjs/cli
nest new logger-sample
以後、 標準テンプレートのプロジェクト をカスタマイズして実装していきます。
log4js をインストール
npm i --save log4js
標準 Logger を log4js で実装
公式ドキュメントにやり方は書いてあります。 Nest.js-TECHNIQUES-Logger
LoggerServiceを実装
標準 Logger を書き換えるために LoggerService を実装します。
logger-sample/src/logger/logger.service.ts
import { LoggerService, Injectable, Scope } from '@nestjs/common';
import { Logger } from 'log4js';
@Injectable({ scope: Scope.TRANSIENT })
export class CustomLogger implements LoggerService{
constructor(private readonly logger: Logger) {}
log(message: any, context?: string) {
this.logger.log(message,context? context : '');
}
error(message: any, trace?: string, context?: string) {
this.logger.error(message,trace? trace : '',context? context : '');
}
warn(message: any, context?: string) {
this.logger.warn(message,context? context : '');
}
debug?(message: any, context?: string) {
this.logger.debug(message,context? context : '');
}
}
- リクエスト毎に出力情報は変わるため、スコープは
TRANSIENTにしています。 -
log4jsのLoggerはコンストラクタから渡すようにしました。 -
verbose()は使わないため実装していません。
LoggerModule を実装
CustomLogger を公開するために LoggerModule を実装します。
logger-sample/logger/logger.module.ts
import { Module } from "@nestjs/common";
import { CustomLogger } from './logger.service';
import {configure,getLogger} from 'log4js';
const config = {
"appenders":{
"access":{
"type": "file",
"filename": "log/trace.log",
"maxLogSize": 10485760,
"category": "access",
"layout": {
"type": "pattern",
"pattern": "[%d{yyyy/MM/dd hh.mm.ss.SSS}],[%p],[%X{ip}],[%X{method} %X{uri}],[%X{file} %X{line}:%X{column} %X{function}],%m"
}
},
"console":{
"type": "stdout",
"layout": {
"type": "pattern",
"pattern": "[%d{yyyy/MM/dd hh.mm.ss.SSS}],[%p],[%X{ip}],[%X{method} %X{uri}],[%X{file} %X{line}:%X{column} %X{function}],%m"
}
}
},
"categories": {
"default":{
"appenders": ["access","console"],
"level": "INFO"
}
}
}
const loggerFactory = {
provide:CustomLogger,
useFactory:()=>{
configure(config);
return new CustomLogger(getLogger("default"));
}
}
@Module({
providers:[loggerFactory],
exports:[loggerFactory]
})
export class LoggerModule {}
-
configはlog4jsの設定情報です。次の設定をしています。- ファイル(logger-sample/log/trace.log)と標準出力にログを出力する。
- リクエスト、スタック情報を追加したログフォーマットに変更
-
loggerFactoryはカスタムインスタンスを作成する方法です。 詳しくは 公式 を参照してください。
LoggerModule を AppModule にインポートする。
imports に LoggerModule を追加するだけです。
logger-sample/src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerModule } from './logger/logger.module';
@Module({
imports: [LoggerModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Nest の標準 Logger を無効化して log4js を設定
main.ts を変更して、標準 Logger の無効化と CustomLogger を設定します。
logger-sample/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { CustomLogger } from './logger/logger.service';
async function bootstrap() {
const app = await NestFactory.create(AppModule,{logger:false});
app.useLogger(app.get(CustomLogger));
await app.listen(3000);
}
bootstrap();
app.service.ts で実際に log4js でログ出力を記述します。
logger-sample/src/app.service.ts
import { Injectable } from '@nestjs/common';
import { CustomLogger } from './logger/logger.service';
@Injectable()
export class AppService {
constructor(private logger: CustomLogger){}
getHello(): string {
this.logger.error('Hello World!!');
return 'Hello World!';
}
}
-
constructorでCustomLoggerを注入します。 -
getHello()のthis.logger.error('Hello World!!');でログ出力しています。
実際に動かした結果
13:28:05 - Found 0 errors. Watching for file changes.
[2020/04/07 13.28.06.101],[INFO],[null],[null null],[null null:null null],RoutesResolver
[2020/04/07 13.28.06.106],[INFO],[null],[null null],[null null:null null],RouterExplorer
[2020/04/07 13.28.06.108],[INFO],[null],[null null],[null null:null null],NestApplication
[2020/04/07 13.28.09.370],[ERROR],[null],[null null],[null null:null null],Hello World!!
null が多いですが、後の実装で設定しておくのでひとまずOK
これで標準 Logger を log4js に置き換えることができました。