LoginSignup
59
39

More than 3 years have passed since last update.

log4js-node の使い方【v5.2.2】

Posted at

1. はじめに

log4js-nodeは、log4js を javascript 用に移植した log4js を node 用に書き直したものらしい。
Java の log4j とは大きく違うとのこと。
ロガーの使い方がいまいち分かっていなかったので、調査ついでにまとめた。

テスト環境

  • Windows10, MINGW64, VSCode
  • node: 10.14.2
  • babel-node: 7.6.1
  • log4js: 5.2.2
  • ES6 形式で書きたかったので babel-node を使用
  • ログファイルは VSCode + Log File Highlighter で表示 (ちゃんと設定してないです…)
console
$ npm install log4js

参考:

2. 基本的な使い方

ログの出力(logging)

test.js
import log4js from 'log4js'

const logger = log4js.getLogger()
logger.level = 'all'

logger.trace('Some trace messages')
logger.debug('Some debug messages')
logger.info('Some info messages')
logger.warn('Some warn messages')
logger.error('Some error messages')
logger.fatal('Some fatal messages')

log4js.shutdown((err) => {
  if (err) throw err
  process.exit(0)
})

image.png

  • logger.level は ALL (最小) < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < MARK < OFF (最大)
  • default は OFF (console へ出力しない)
  • level は独自のものを設定することも可能だが取り扱わない
  • log4js.shutdown(cb(err)) はログを確実に保存してから終了する際に使用する (flush 処理)
  • 定義されている level は以下を参照

image.png

参考:

ログのカテゴリ (category)

test.js
const logger = log4js.getLogger()
logger.level = 'all'
logger.info('Some info messages', 'append', 'more')

const cheseLogger = log4js.getLogger('cheese')
cheseLogger.level = 'all'
cheseLogger.info('Cheese is Comte.')

image.png

  • ログを category ごとにグループ化して出力することができる
  • category は log4js.getLogger([category])で指定する
  • default は default というグループ
  • category ごとに出力する level を指定できる
  • 前項で触れなかったが、複数の引数を使用するとスペース区切りで出力される

参考:

3. 高度な使い方(Configure)

コンソールとファイルに出力 (stdout / file)

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

image.png
image.png

  • appender は渡されたログを出力する機械と考える
  • default の category を、 stdout に出力する out と file に出力する app という appender を定義した
  • appender の name(key) は自由に指定可能
  • categories で category ごとに使用する appender と level などを定義できる
  • logger.level は この level と同じ意味となる
  • ファイルに出力されるログは末尾に追記される

参考:

ログのローリング (file / fileSync)

test.js
log4js.configure({
  appenders: {
    app: { type: 'file', filename: 'application.log', maxLogSize: 100, backups: 1 }
  },
  categories: {
    default: { appenders: ['app'], level: 'all' }
  }
})

image.png

  • file 系の appender は書き込むファイルをローテートすることが可能
  • 上記は application.log.2 が保持上限を超えて削除されている
  • type: fileSync で同期的に書き込むことも可能 (test などの用途)
  • options
    • type: file / fileSync
    • filename: string - ログファイルの名称 (xxx.ext)
    • maxLogSize: integer - 1ファイルの最大サイズ (byte)、default は上限なし
    • backups: integer - 保持するファイル数、default は 5
    • compress: boolean - true で ローリングしたファイルを圧縮する(.gz)
    • keepFileExt: boolean - true で 拡張子を保持する (xxx.ext.1 を xxx.1.ext にする)
    • encoding: string - default は utf-8

参考:

日付ごとのローリング(dateFile)

test.js
log4js.configure({
  appenders: {
    app: { type: 'dateFile', filename: 'application.log', pattern: '.yyyyMMdd-hhmmss' }
  },
  categories: {
    default: { appenders: ['app'], level: 'all' }
  }
})

image.png

  • pattern で指定した日付の粒度でローテートすることが可能
  • 上記は1秒ごとに切り替える設定で二回実行した結果
  • file 系と違って保持数は指定できない?(要検証)
  • 保持日数は daysToKepp で指定できる
  • option
    • type: dateFile
    • filename: string - ログファイルの名称 (xxx.ext)
    • pattern: string - ローテートするタイミング、default は .YYYY-MM-dd、参照:date-format
    • daysToKeep: integer - 保持する日数、 default は上限なし
    • alwaysIncludePattern: boolean - true で現在のログファイル名にも日付を付与する
    • compress: boolean - true で ローリングしたファイルを圧縮する(.gz)
    • keepFileExt: boolean - true で 拡張子を保持する (xxx.ext.date を xxx.date.ext にする)
    • encoding: string - default は utf-8

参考:

appendars のレベルフィルター (logLevelFilter)

test.js
log4js.configure({
  appenders: {
    out: { type: 'stdout' },
    app: { type: 'file', filename: 'application.log' },
    wrapErr: { type: 'logLevelFilter', appender: 'app', level: 'warn' }
  },
  categories: {
    default: { appenders: ['out', 'wrapErr'], level: 'all' }
  }
})

image.png
image.png

  • logLevelFilter を用いると appender ごとに出力する level を指定可能
  • 出力する appender にラップするように使用する
  • これによりエラーログだけを別途で処理することも可能
  • ※ appender は上から処理されるので logLevelFilter は最後に配置する必要がある
  • options
    • type: logLevelFilter
    • level: string - 出力する最小の level
    • maxLevel: string - 出力する最大の level 、default は FATAL

参考:

その他

4. 出力ログのレイアウト

標準レイアウト(Built-in Layout)

test.js
log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: { type: 'basic' } }
  },
  categories: {
    default: { appenders: ['out'], level: 'all' }
  }
})
  • 各種 appender に layout を指定することができる
  • 必須ではないので必要に応じて…
  • ※ file 系の appenders に colores を指定しないこと! (色付けは制御文字を使用しているため)

type: basic
image.png

type: coloured / colores
image.png

type: messagePassThrough
image.png

参考:

出力パターン (Pattern format)

test.js
log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: { type: 'pattern', pattern: '%d %[%5p%] %c %m' } }
  },
  categories: {
    default: { appenders: ['out'], level: 'all' }
  }
})

image.png

  • 出力する文字列のパターンを独自に設定できる
  • field は %[padding].[truncation][field]{[format]} で定義されている
    • padding: integer - 空白埋め文字数、右詰め
    • truncation: integer - 最大文字数、切り捨て
    • field: string - フィールド名
    • format: string(option) - フィールドのオプション (任意)
  • 上記の場合、「日付 level(5文字埋め)を色付きで カテゴリ 本文」となる
  • ※ file 系の appenders に %[ %] を指定しないこと! (色付けは制御文字を使用しているため)
  • pattern field (サンプル)
    • %r: ローカル時刻 (02:19:11)
    • %p: ログ level (INFO)
    • %c: ログ category (default)
    • %h: ホスト名 (PCの名前等)
    • %m: メッセージ
    • %d: 日時、{ISO8601 | yyyy-MM-ddThh:mm:ss.SSS} (2019-10-23T02:13:53.028)、参照:date-format
    • %%: %のエスケープ
    • %n: 改行
    • %z: プロセスID、process.pid (28076)
    • %[: 色付け開始
    • %]: 色付け終了
    • enableCallStack: true 時の field (後述)
      • %f: ログ出力元のファイル名、{depth | 0} (C:\xxx\test.js)
      • %l: ログ出力元の行番号 (13)
      • %o: ログ出力元の列位置 (8)
      • %s: スタックトレース ( at Object.info (C:\xxx/test.js:13:8) \n ...)
  • トークンは取り扱わない

参考:

enableCallStack

test.js
log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: { type: 'pattern', pattern: '%[[%d] %p %c -%] %m%n%f %l %o%n%s' } }
  },
  categories: {
    default: { appenders: ['out'], level: 'all', enableCallStack: true }
  }
})

const logger = log4js.getLogger()
logger.info('Some info messages')

image.png

  • category で enableCallStack: true を設定すると出力箇所のスタックトレースが取得できる
  • %s の前に %n で改行を入れないと出力が崩れるので注意
  • enableCallStack: false の際、だった各種 field は出力されないが %n は出力される点も注意
  • (スルーできる field があれば便利だったかも)
  • error 出力などの場面で使用するのが良い?

参考:

Tokens

  • key - value の値を埋め込める仕組み
  • token はハードコートせざるを得ないので、どの key を使用しているか定義しておく必要がある
  • これを使うなら message に変数を結合させるのがベストのような?
  • 発行ユーザーなどの用途なら悪くはなさそう
  • ここでは取り扱わない

参考:

カスタムレイアウト (Custom Layout)

test.js
log4js.addLayout('json', function(config) {
  return function(logEvent) {
    return JSON.stringify(logEvent, null, 2) + config.separator
  }
})

log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: { type: 'json', separator: ',' } }
  },
  categories: {
    default: { appenders: ['out'], level: 'all', enableCallStack: true }
  }
})

const logger = log4js.getLogger()
logger.info('Some info messages')

image.png

  • 独自のレイアウトを定義することも可能
  • appender で指定した設定が config から取得できる
  • functionName 以下は enableCallStack: true が必要
  • callback の引数は logEvent の Object なので、これを加工して return に返す

参考:

5. サンプル

test.js
import os from 'os'
import log4js from 'log4js'
import dateFormat from 'date-format'
import chalk from 'chalk'

const LOG_LEVEL = 'ALL' // DEBUG: TRACE or DEBUG, PRODUCTION: INFO or OFF

const levelColors = {
  TRACE: { meta: 'grey', body: 'grey', trace: null },
  DEBUG: { meta: 'green', body: 'grey', trace: null },
  INFO: { meta: 'cyan', body: 'white', trace: null },
  WARN: { meta: 'yellow', body: 'yellow', trace: null },
  ERROR: { meta: 'red', body: 'red', trace: 'white' },
  FATAL: { meta: 'magenta', body: 'magenta', trace: 'white' }
}

const coloring = function(color, text) {
  if (color) {
    return chalk[color](text)
  }
  return text
}

log4js.addLayout('origin', function({ addColor }) {
  return function(e) {
    const date = new Date(e.startTime)
    const level = e.level.levelStr.toUpperCase() // 大文字
    const hasCallStack = e.hasOwnProperty('callStack') // callStack を持っているか

    const dateStr = dateFormat('yyyy-MM-dd hh:mm:ss.SSS', date)
    const message = e.data.join(' ') // データはスペース区切り
    const levelStr = level.padEnd(5).slice(0, 5) // 5文字
    const color = levelColors[level]

    // メタ情報
    const meta = `${levelStr} ${dateStr} [${e.categoryName}]`
    const prefix = addColor ? coloring(color.meta, meta) : meta

    // ログ本体
    const body = addColor ? coloring(color.body, message) : message

    // スタックトレース
    let suffix = ''
    if (hasCallStack && color.trace) {
      const callStack = e.callStack
      suffix += os.EOL
      suffix += addColor ? coloring(color.trace, callStack) : callStack
    }

    return `${prefix} ${body}${suffix}`
  }
})

log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: { type: 'origin', addColor: true } },
    logFile: { type: 'file', filename: 'logs/application.log', layout: { type: 'origin', addColor: false } },
    errFile: { type: 'file', filename: 'logs/error.log', layout: { type: 'origin', addColor: false } },
    log: { type: 'logLevelFilter', appender: 'logFile', level: 'info' },
    err: { type: 'logLevelFilter', appender: 'errFile', level: 'warn' },
  },
  categories: {
    default: { appenders: ['out', 'log', 'err'], level: LOG_LEVEL, enableCallStack: true }
  }
})

const logger = log4js.getLogger()
logger.trace('Some trace messages')
logger.debug('Some debug messages')
logger.info('Some info messages')
logger.warn('Some warn messages')
logger.error('Some error messages')
logger.fatal('Some fatal messages')

log4js.shutdown(() => {})

image.png
image.png

  • console のカラーリングと、2つのファイルに書き出す形式
    • console への出力は LOG_LEVEL で制御する
  • ファイルは INFO 以上と WARN 以上の二種類を用意 (error を把握しやすくする)
    • これにローリングを加えれば完成となる (見やすさのため省略)
    • terminal が 256色 をサポートしていない場合、通常色出力となる
  • 独自の level を定義することは可能だが、カラーリングはサポートしないらしい?

参考:

以上

59
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
39