HPCメモ

HPC(High Performance Computing)に関連したりしなかったりすることのメモ書き

log4jsの使い方

この記事は Calendar for UdonTech Advent Calendar 2021 | Advent Calendar 2021 - Qiita の14日目の記事です。

最近log4jが大騒ぎになってますが、今日の記事ではlog4jのnode.js移植版である、log4jsについて解説します。

log4js-node.github.io

インストール方法

npm install log4js

使用方法と解説

公式サイトに載っている一番シンプルな使用例は次のとおり

var log4js = require("log4js");
var logger = log4js.getLogger();
logger.level = "debug"; // default level is OFF - which means no logs at all.
logger.debug("Some debug messages");

このうち、実際にログを行なっているのは4行目のlogger.debug()の呼出し部分です。

一応順番に解説しておくと、各行で行なっている処理は次のとおりです。

  • 1行目: log4jsのモジュール読み込み
  • 2行目: loggerオブジェクトの取得(シングルトンになってる)
  • 3行目: ログレベルをdebug以上に設定

3行目でログレベルを設定している部分にコメントが書かれていますが、デフォルトだとログレベルはOFF(何も出力しない)になっているので、この点だけは注意が必要です。

簡単な中身の解説

ログレベルという設定があることからも想像できるかもしれませんが、log4jsのログ出力はsyslog的にカテゴリー(syslogだとファシリティー)とレベルの2種類の分類が行なわれます。

この例の場合、デフォルトカテゴリーに対して、debugレベルでの出力を行なっています。

カテゴリーを指定するには、getLoggerの引数としてカテゴリ名を渡し、レベルを指定する時はログ関数の名前(ここではdebug)を使います。*1 *2

ログ関数が呼ばれると、loggingEventというオブジェクトが生成されて、Appenderに送られます。

AppenderはさらにLayoutを呼出して、loggingEventを整形し、最終的な出力処理を行ないます。

適当に図解してまとめるとこんな感じになってます。

f:id:n_so5:20211213224322p:plain

appender の設定

デフォルトではappenderとしてconsole出力を行なう stdout が指定されています。 これ以外にも複数のbuild-in appenderが用意されていて、ファイル出力を行なったりslackに投げたりとかできます。

https://log4js-node.github.io/log4js-node/appenders.html

appenderを設定するには、log4js.configure()を使います。公式サイトにあるfile出力を追加する例だと次のような形になってます。

const log4js = require('log4js');
log4js.configure({
  appenders: {
    out: { type: 'stdout' },
    app: { type: 'file', filename: 'application.log' }
  },
  categories: {
    default: { appenders: [ 'out', 'app' ], level: 'debug' }
  }
});

デフォルト設定と同じものですが、outの方で説明します。

appendersの中に {out : {type: 'stdout'}}という項目がありますが、これでoutという名前のstdout appenderを定義しています。

さらに、categoriesの中にあるdefault: appenders: ['out']の部分でdefaultカテゴリのログをoutに渡すという指定をしています。

この例でもやっていますが、1つのカテゴリに対して複数のappenderを指定することができます。また、category毎に異なる設定を渡すこともできるので、一般的な出力を画面に出して、セキュリティログはファイルだけに出力というような設定もappendersの指定だけでできます。

さらに loglevel filterというappenderを使うと、info以上はコンソールに出して、debug以上をファイルに記録というような切り分けもできます。

https://log4js-node.github.io/log4js-node/logLevelFilter.html

layoutの設定

デフォルトのレイアウトは [時刻] [ログレベル] カテゴリ - ログ出力 というような整形を行ないます。

こちらもいくつかbuilt-in設定がありますが、appender毎にデフォルトのlayoutが指定されているので、built-in appenderを使うのであれば、pattern layout以外は使う機会は無いと思います。

https://log4js-node.github.io/log4js-node/layouts.html

一応layoutの指定方法を公式のドキュメントからもってくると次のような形でappenderの設定時に指定しています。

log4js.configure({
  appenders: { out: { type: 'stdout', layout: { type: 'basic' } } },
  categories: { default: { appenders: ['out'], level: 'info' } }
});

この例では、outという名前のstdout appenderに対してbasic layoutを使うことを指定しています。

要するに、コンソール出力をカラーから白黒に変えてるわけですね。

カスタムappender

さらに、独自のappenderを作成することもできます。

公式ドキュメントのappenderとlayoutの説明の一番下に一応説明があるので、まずはこれに目を通しましょう。

https://log4js-node.github.io/log4js-node/appenders.html https://log4js-node.github.io/log4js-node/layouts.html

ちょっと分かり難いですが、カスタムappenderに関するドキュメントは別にこちらに用意されてます。

https://log4js-node.github.io/log4js-node/writing-appenders.html

appenderの実体は、次のような引数を持つ関数です。

(config, layouts, findAppender, levels)=>{}

それぞれの引数の意味は次のとおり

  • config log4js.configure()で渡されてきた設定のうち、そのappenderに関するもの
  • layouts 有効なlayoutの一覧
  • findAppender 名前から他のappenderを取り出す関数(loglevelFilterのように最終的な出力を他のappenderに依存している時に使う)
  • levels 有効なレベル定義の一覧

また、この関数はloggingEventを第一引数とする関数を返す必要があります。

実際に自分でappenderを書く時には、こちらにあるbuilt-in appenderの実装を見ながら書きましょう。

log4js-node/lib/appenders at master · log4js-node/log4js-node · GitHub

通常のappenderを作るならstdout、別のappenderを呼び出すフィルタ的なものを作る時はloglevel filterあたりを参考にするのが読みやすいのでお勧めです。

実際にこのように定義したカスタムappenderを使うためには、公式ドキュメントにあるように次のような設定をします。

const myAppenderModule = {
  configure: (config, layouts, findAppender, levels) => { /* ...your appender config... */ }
};
log4js.configure({
  appenders: { custom: { type: myAppenderModule } },
  categories: { default: { appenders: ['custom'], level: 'debug' } }
});

ここでは、myAppenderModuleという名前でカスタムappenderを定義し、custom という名前でこのappenderを登録して、defaultカテゴリのdebug以上のレベルで使うように指定しています。

カスタムlayout

さらにさらに、独自のレイアウトも追加することができます。

こちらはAPIが用意されていて、log4js.addLayout()という関数で定義します。

addLayoutは第一引数にレイアウトの名前、第二引数にレイアウト関数を返す関数を指定します。レイアウト関数は第一引数にlogEventオブジェクトを受け取って、整形した文字列を返す関数です。こちらはappenderと違って公式ドキュメントの"Custom Layout Example"という項目にコードの例まで載っているので、こちらを見てください。

実際に使う時は、appenderと同様にlog4js.configureの中で指定する必要があります。

まとめ

log4jsはnodejs用の二大ロギングモジュールの片割れです*3

built-inのappenderとlayoutの使い方については解説記事も多いのですが、以前独自のappenderとlayoutを作った時に公式のドキュメントを探し出すのにも苦労したので、この機に解説してみました。

公式のslackで数ヶ月前に「ちょっとサポートする時間がとれんから誰か手伝ってー」みたいな話が作者さんから流れてたので、我こそはと思う方はちょっとお手伝いしてみてはいかがでしょうか?

*1:実際は、logger.log() という関数があって、その第一引数にレベルを指定するのですが、logger.{レベル名}という名前で、logger.log.bind(logger, レベル名) を呼び出せるようになっています。

*2:この説明かえって分かり難い気がしてきた・・・

*3:もう一方はdebug、異論は認める :p