🐯
NestJS+Winstonでカスタムロガーを作る
概要
NestJSとWinstonを組み合わせて、ロガーをカスタマイズします。
Winstonをカスタマイズすることで、ログファイルやコンソールログだけでなく、New RelicやDATADOGなどにも柔軟に連携できます。
セットアップ
NestJSのプロジェクトを作成する
NestJSのプロジェクトを作成します。 (Setup参照)
$ npm i -g @nestjs/cli
$ nest new project-name
作成したプロジェクトに移動して、コマンドを実行します。
$ cd project-name
$ npm run start
ブラウザでhttp://localhost:3000
にアクセスします。
"Hello World!"と表示されたら、セットアップは完了です。
Winstonをインストールする
プロジェクト内にWinstonをインストールします。
$ npm i winston
カスタムロガーを設定する
NestJSのカスタムロガーについては、Custom implementationを参照
カスタムロガーを実装する
カスタムロガーのファイルを作成する
NestJS CLIでModule
とService
を作ります。
$ nest g s myLogger
$ nest g mo myLogger
下のように、Module
とService
が作成されます。
project-name
|-- src
|-- my-logger
|-- my-logger.module.ts
|-- my-logger.service.spec.ts (使いません; Serviceのテストコード)
|-- my-logger.service.ts
カスタムロガーのソースコードを書く
my-logger.service.ts
にコードを実装します。
今回はWinstonのUsageのソースコードをベースに、タイムスタンプを追加しました。
LoggerService
をimplementsして、log()
error()
warn()
debug()
verbose()
を実装します。
それぞれのメソッドの中身は、Winstonのロガーを設定しています。
my-logger.service.ts
import {LoggerService} from '@nestjs/common';
import {createLogger, format, Logger, transports} from 'winston';
export class MyLoggerService implements LoggerService {
logger: Logger;
constructor() {
this.logger = createLogger({
level: 'info',
format: format.combine(format.timestamp(), format.json()),
defaultMeta: {service: 'user-service'},
transports: [
//
// - Write all logs with level `error` and below to `error.log`
// - Write all logs with level `info` and below to `combined.log`
//
new transports.File({filename: 'error.log', level: 'error'}),
new transports.File({filename: 'combined.log'}),
],
});
}
log(message: string) {
this.logger.info(message);
}
error(message: string, trace: string) {
this.logger.error(message, trace)
}
warn(message: string) {
this.logger.warn(message);
}
debug(message: string) {
this.logger.debug(message);
}
verbose(message: string) {
this.logger.verbose(message)
}
}
Moduleを設定する
src/my-logger/my-logger.module.ts
にカスタムロガーを設定します。
my-logger.module.ts
import { Module } from '@nestjs/common';
import {MyLoggerService} from "./my-logger.service";
@Module({
providers: [MyLoggerService],
exports: [MyLoggerService]
})
export class MyLoggerModule {}
カスタムロガーをデフォルトに設定する
src/main.ts
を下記に書き換えます。
これでNestJS標準のロガーは使われず、カスタマイズしたロガーがデフォルトになります。
main.ts
import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {MyLoggerService} from "./my-logger/my-logger.service";
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: false,
});
app.useLogger(app.get(MyLoggerService))
await app.listen(3000);
}
bootstrap();
ログを出力する
app.service.ts
にロガーを設定します。
app.service.ts
import {Injectable, Logger} from '@nestjs/common';
@Injectable()
export class AppService {
private readonly logger = new Logger();
getHello(): string {
this.logger.log('Hello World!');
return 'Hello World!';
}
}
http://localhost:3000
にアクセスすると、combined.log
にログが出力されます。
{"message":"Hello World!","level":"info","service":"user-service","timestamp":"2021-05-18T17:01:21.506Z"}
Discussion