ROS2 loggingメモ

2023/09/25に公開

ROS2のloggingについて

調査distro: iron

内部実装を調査したときのメモ

  • ログ情報はターミナルとファイル2つのどちらかまたは両方へ出力される。
  • loggingの実装方法は複数存在する。(通常はspdlog)
  • rcl_logging_interfaceが異なる実装のlogging方法の仲立ちを行っており、各言語はこのパッケージの関数を内部で呼び出す。

Logger Level

全てのログはLogger Levelを持っている。Logger Levelは次の通りである。便宜上UNKNOWNが設定されているが普通は使わない。
(rcl_interfaces/msg/LoggerLevel.msg 参照)

name value
UNKNOWN 0
DEBUG 10
INFO 20
WARN 30
ERROR 40
FATAL 50

Logger Levelは設定されている値以上のログをロギングの対象とし、それ未満は無視する。例えば現在のLogger LevelがWARN = 30に設定されていた場合、実際のログはWARN,ERROR,FATALの3種類のみ出力される。

Logger name (ロガー名)

Loggerを複数用意し、それぞれに異なるロガー名を設定することで各Loggerのレベルを個別に設定することができる。特にデバッグ用途のログは大量に出力される傾向があるので、名前を分けたLoggerを個別に設定することでコードの変更を行うことなく見やすいログを出力することができるであろう。
ROS2のノードではデフォルトでnode名がロガー名として設定されるが、nodeの中で作成した別のnodeにはそのnode名のloggerは設定されないので注意されたし。 その場合、親のnodeからloggerを取得し、子nodeのloggerと親nodeのloggerを共有するなどの工夫を行わないと子nodeのログがどこにも出力されないといった現象が発生する。logは必ず誰のloggerで出力しているかの意識を行うことが大切である。

実際に出力されるファイルには同じ名前でlaunchされたnodeを区別するためにロガー名のほかにプロセスID(PID)が付与される。

非同期での扱い

基本的にstdoutはスレッドセーフなので非同期スレッドから呼び出しても問題なく動作する(内部でmutexにより管理されている)。

Launch時のオプション

参照

  • pkg://launch/launch/logging/__init__.py
  • pkg://rcl/rcl/include/rcl/arguments.h

output

若干怪しい

ログの出力先を決める。出力先はscreen,log,own_logの3種類存在するが、その組み合わせにより設定方法が異なる。
output="screen"ならばターミナルにのみ出力される。
output="log"ならばファイルに全てのlogが出力されるが、stderrへの出力はターミナルにも出力される。
output="both"はターミナルとファイルの両方へ全て出力される。
output="own_log"はlaunch時に作成されたログファイルとは別のファイルへ出力する。

Launch時のログレベル設定

ros2コマンドにおける--ros-args --log-level <logger_name>:=<log_level>に相当するものを渡せばよい。python版のlaunchだと次のようになる(<logger_name><log_level>には適切な値を設定すること)。
また、<log_level>に大文字小文字の区別はないが、統一しておいたほうが精神衛生上良い。

Node(
  ...,
  ros_arguments=['--log-level', '<logger_name>:=<log_level>'],
  ...
)

logger_levelをconfigなどで設定したい場合次のようにlist in listの構造にすればparseの際に子リストの中身を空白無しで結合してくれる(よく使うros2 launch technique)。

log_level = LaunchConfiguration('log_level')
Node(
  ...,
  ros_arguments=['--log-level', ['<logger_name>', ':=', log_level]],
  ...
)

Discussion