TypeScriptでロギングするためにwinstonを導入してみる

使用しながらメモを残していきます

ドキュメント: https://github.com/winstonjs/winston#readme

# インストール

```
npm i winston
npm i -D @types/winston
```

# 実装

今回はLambdaからCloudWatchLogに出力させるのが目的のため、transportsは`Console()`を指定している

```typescript:src/logging/logger.ts
import * as winston from "winston";

export class Logger {
  private logger: winston.Logger;
  private stage: string;

  constructor(stage: string) {
    this.stage = stage;
  }

  public async initialize(): Promise<winston.Logger> {
    this.logger = winston.createLogger({
      level: "info",
      format: winston.format.combine(
        winston.format.timestamp({
          format: "YYYY-MM-DD HH:mm:ss"
        }),
        winston.format.errors({ stack: true }),
        winston.format.splat(),
        winston.format.json()
      ),
      defaultMeta: { service: "winston-lambda" },
      transports: new winston.transports.Console()
    });

    // 検証環境の場合、loggingをdebugレベルまで上げる
    if (this.stage !== "prd") {
      // clear()をする事によって、createLoggerの際に指定したtransportsの設定を消せる
      this.logger.clear();
      this.logger.add(
        new winston.transports.Console({
          level: "debug"
        })
      );
    }

    return this.logger;
  }
}
```

コメントにてログに出力される内容を補足しています。
(process.env.STAGEが`string | undefined`なのは見逃してください)


```typescript:src/handler.ts
import { Handler } from "aws-lambda";
import { Logger } from "./logging/logger";

export const handler: Handler = async () => {
  try {
    const logger = await new Logger(process.env.STAGE).initialize();

    // (process.env.STAGE === prd): ログに表示される
    // (process.env.STAGE !== prd): ログに表示される
    logger.log({
      level: "error",
      message: "ERROR message"
    });

    // (process.env.STAGE === prd): ログに表示される
    // (process.env.STAGE !== prd): ログに表示される
    logger.log({
      level: "info",
      message: "INFO message"
    });

    // (process.env.STAGE === prd): ログに表示されない
    // (process.env.STAGE !== prd): ログに表示される
    logger.log({
      level: "debug",
      message: "DEBUG message"
    });

    // (process.env.STAGE === prd): ログに表示されない
    // (process.env.STAGE !== prd): ログに表示されない
    logger.log({
      level: "silly",
      message: "SILLY message"
    });

    return {
      statusCode: 200,
      body: JSON.stringify({
        message: "we are winston"
      })
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({
        message: "error"
      })
    };
  }
};
```

#CloudWatch Logs

`process.env.STAGE = "dev"`でデプロイした結果
`"level": "silly"`は出力されない

```
START RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ Version: $LATEST
{
    "level": "error",
    "message": "ERROR message",
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:18:03"
}
{
    "level": "info",
    "message": "INFO message",
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:18:03"
}
{
    "level": "debug",
    "message": "DEBUG message",
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:18:03"
}
END RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
REPORT RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■	Duration: 24.04 ms	Billed Duration: 100 ms	Memory Size: 1024 MB	Max Memory Used: 81 MB	Init Duration: 227.71 ms	
```

# 補足

### 出力項目を増やす事も出来る
・環境を出力する様に修正した例

```typescript
logger.log({
  level: "info",
  message: "SILLY message",
  stage: process.env.STAGE
});
```

### 出力形式の変更

`json()`から`simple()`に変更する

```typescript/src/handler.ts
// winston.format.json()
winston.format.simple()
```

cloudwatch logs

logで指定した内容が、`{$level}: {$message}`となり
メタ情報がJSONにて出力される


```
START RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ Version: $LATEST
error: ERROR message 
{
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:52:26"
}

info: INFO message 
{
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:52:26"
}

debug: DEBUG message 
{
    "service": "winston-lambda",
    "timestamp": "2019-12-23 06:52:26"
}

END RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
REPORT RequestId: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■	Duration: 17.07 ms	Billed Duration: 100 ms	Memory Size: 1024 MB	Max Memory Used: 81 MB	Init Duration: 216.07 ms
```

# 感想

環境変数を用いて出力先を制御したり、出力内容を変更する設定が簡単に行えるので、今後ロギングにはwinstonを使用していきたい