winstonでのエラーログにエラーメッセージを含める

winstonでエラーをロギングするときに発生する問題

以下のようにwinstonのloggerを用意したとします。

const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.Console(),
  ],
});

そして以下のような文を実行します。

logger.info('something has happened');

結果は想像の通り、以下のようになります。

{"message":"something has happened","level":"info"}

しかし、以下の場合はどうでしょう。

logger.error(new Error('something has happened'));

このような出力になり、スタックの内容やエラーメッセージは表示されません。

{"level":"error"}

解決策

そこで、loggerの定義を拡張して以下のようにします。

loggerに渡されたオブジェクト(iとしています)がErrorオブジェクトのインスタンスだった場合に、i.messageの内容をログ出力のmessageとして設定するようにしています。

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format((i) => {
      if (i instanceof Error) {
        return Object.assign({}, i, {
          message: i.message,
        });
      }

      return i;
    })(),
    winston.format.json(),
  ),
  transports: [
    new winston.transports.Console(),
  ]
});

さきほどと同じ文を実行すると以下のような出力となり、うまくいっていることがわかります。

{"level":"error","message":"something has happened"}

stackなど、Errorオブジェクトの他のプロパティに関しても、同じようにして追加することができるはずです。

おまけ

winstonのloggerは、オブジェクトを渡されたとき、列挙可能なプロパティ(とそれに対応する値)のみをログに含めるようです。Errorオブジェクトのmessageプロパティややstackプロパティは列挙可能ではないので、このようなことになっているみたいです。

※ 執筆時のwinstonのバージョンは3.2.1です。