Rの便利なlogging package: logger
Rでログを取る場合どうしていますか?インタラクティブなデータ分析ならprint
やcat
でもよいのですが、バッチ処理を行うような場合は、print
文に現在時刻を含んだり、コンソールだけではなくファイルにも出力したりしたいところです。
Pythonなら標準ライブラリのloggingやサードバーティーのloguruなどがありますが、同じようにRでもloggerを使いたいですね。
便利なロガーパッケージのloggerを紹介します。Pythonのloggingに近いインタフェースをしているので1、loggingを使ったことがあればすんなり使えるのではないかと思います。
環境
- R 4.3.1
- logger 0.2.2
インストール
インストールはこちらです。
# CRANからインストールする場合
install.packages("logger")
# GitHubからインストールする場合
remotes::install_github("daroczig/logger")
library(logger)
基本的な使い方
コンソールに表示するだけであれば、以下で使うことができます。最初にlogger::log_threshold
でログを出力する閾値を定めます。
logのlevelは高い順にfatal > error > warn > success > info > debug > trace
です。(参考)
log_threshold(INFO)
log_info("info")
#> INFO [2023-10-04 02:38:37] info
log_warn("warn")
#> WARN [2023-10-04 02:38:37] warn
# DEBUGはINFOより下のlevelなので表示されない
log_debug("debug")
デフォルトではlogger::log_formatter(logger::formatter_glue)
が設定されているため、glue::glue
を使わなくてもglue
の記法で変数を展開したり関数を評価したりできます。
x <- 1
log_info("x is {x}")
#> INFO [2023-10-04 02:38:37] x is 1
log_info("x + 1 is {x + 1}")
#> INFO [2023-10-04 02:38:37] x + 1 is 2
ログの出力先は、logger::log_appender
の引数appender
で設定することができます。デフォルトではlogger::log_appender(appender=logger::appender_console)
が設定されていますので、デフォルト設定のままコンソールに出力するだけであればlogger::log_appender
は不要です。
logger::log_appender
の引数appender
にappender_
で始まる関数を渡すことで、出力先を変えることができます。
以下のようにすれば、コンソールとファイルに同時に出力することもできます2。
file_path <- tempfile()
log_appender(appender_console)
log_appender(appender_file(file=file_path))
log_threshold(INFO)
log_info("info")
appender_
で始まる出力先を設定する関数は他にも色々ありますが、logger::appender_slack
で出力先をSlackにすることができるのが嬉しいポイントですね。内部ではslackr::slackr_msg
を呼んでいるようです。バッチ処理が正常に終了したとき、あるいはエラーが出たときだけSlackに通知したいということがよくあります。
出力先ごとに出し分ける
loggerパッケージにはnamespace
とindex
という概念があります。前者はloggerの名前空間(logger::log_appender
のデフォルト値は"global"
)、後者は同一のnamespaceの中でのloggerのindexです(デフォルト値は1
)。
namespace
は関数内でのログをメイン処理から分けるような場合などに使います。index
を活用すると、以下のようにコンソールとファイルで別々のlog
levelの閾値を設定するようなこともできます。
file_path <- tempfile()
log_appender(appender_console, namespace="global", index=1)
log_appender(appender_file(file=file_path), namespace="global", index=2)
# コンソールにはINFO以上、ファイルにはDEBUG以上でログを出力する
log_threshold(INFO, namespace="global", index=1)
log_threshold(DEBUG, namespace="global", index=2)
log_info("info")
log_debug("debug")
log_trace("trace")
readLines(file_path)
#> [1] "INFO [2023-10-04 02:38:37] info" "DEBUG [2023-10-04 02:38:37] debug"
なお、同一のnamespace
とindex
にlogger::appender_console
のコンソール出力とlogger::appender_file
のファイル出力を行う場合は、logger::appender_tee
というエイリアスが使えます。
log_appender(appender_tee(file=file_path), namespace="global", index=1)
ログフォーマットをカスタマイズする
logのlayoutをlogger::log_layout
の引数layout
に指定すればOKです。
例えば、logger::layout_json
でjsonの形式にできます。
file_path <- tempfile()
log_appender(appender_console)
log_threshold(INFO)
log_layout(layout_json())
log_info("info")
フォーマットをカスタマイズすることもできます。logger::layout_glue_generator
では、glue
の記法でカスタマイズすることができます。ログレベル(level
)や時刻(time
)、メッセージ(msg
)などいくつかの変数が組み込まれています。変数の一覧はこちらにあります。
file_path <- tempfile()
log_appender(appender_file(file=file_path))
log_threshold(INFO)
my_layout <- layout_glue_generator(
format="{level} | {format(time, '%Y-%m-%dT%H:%M:%S+09:00')} | {msg}"
)
log_layout(my_layout)
log_info("info")
readLines(file_path)
#> [1] "INFO | 2023-10-04T02:38:37+09:00 | info"
おわりに
これくらいを抑えておけばひとまず使えるかと思います。vignetteが充実しているので詳細はvignetteをご覧ください。
Reference
パッケージの作者もそのように書いています。(参考)“A lightweight, modern and flexibly logging utility for R – heavily inspired by the futile.logger R package and logging Python module.” ↩︎
なお、RMarkdownやQuartoのコードブロックにログを出力する場合、
logger::appender_console
やlogger::appender_stderr
では出力が表示されないようです。logger::appender_stdout
では出力できます。環境はrmarkdown: 2.25, knitr: 1.44, Quarto (CLI): 1.3.450 (Windows 10, 64bit)です。 ↩︎