Corredor

ウェブ、プログラミングの勉強メモ。

例外が発生しても異常終了しない log4js のロガーを作る

Node.js でロギングする際は log4js をよく使っているのだが、以前、ロギング処理自体に問題があってエラーを起こしてしまった。

そのコードは以下のようなコードだった。

let result = null;
try {
  // API をコールしてデータを取得するテイ
  result = await fetchAPI('http://example.com/users/1');
}
catch(error) {
  // エラーオブジェクトを文字列化してログ出力しようとしたら…
  myLog4JsLogger.error('API コールでエラー発生', JSON.stringify(error));
}

変数 myLog4JsLogger でエラーログを出力する際、error オブジェクトを JSON.stringify() で文字列化して出力しようとしていた。しかしこの error オブジェクト、循環参照が含まれており、JSON.stringify() する際に Converting circular structure to JSON というエラーが発生してしまっていた。catch 句の中で例外が発生するので、このエラーは外に漏れ、異常終了に繋がってしまった。

このような話は Murga の以下の記事にも書いた。

neos21.hatenablog.jp

こんなことをやらかしたので、「ロガーでロギングする時に発生したエラーは握り潰せたらいいんじゃね?」と軽い気持ちで作ったのがこのラッパー。

log4js.getLogger() で取得したロガーのインスタンスをラップする。

例えば以下のコードは、JSON.parse() に失敗すると例外が発生してしまう。

myLogger.info( JSON.parse(jsonStr) );

このように、例外が発生しそうで怖い要素は、以下のように関数でラップして渡してやる。

myLogger.info( () => JSON.parse(jsonStr) );

// 以下と同じ
myLogger.info( () => { return JSON.parse(jsonStr); } );
myLogger.info( function() { return JSON.parse(jsonStr); } );

このように関数でラップしてやれば、まだ関数は実行されていないので、この時点での例外は発生しない。

そして、ラッパークラス内は try / catch で全体を囲んだ状態で、引数に関数が渡っていればそれを実行しているので、例外が発生しても呼び出し元に影響しない、というワケ。

async / await を使って、ほとんど同じ作りで、非同期処理に対応した関数も用意してある。「Promise を返す関数」をロガーのラッパーの引数に渡してやれば良い。


以上。ホントはそもそもロギングするモノをよく把握して実装して例外なんか起こすなよって話なんだけども。w

Node.jsデザインパターン 第2版

Node.jsデザインパターン 第2版

  • 作者: Mario Casciaro,Luciano Mammino,武舎広幸,阿部和也
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/05/18
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

Nodeクックブック

Nodeクックブック