Linux Kernel: prink(print kernel)によるメッセージ出力

printk()とは

printk(print kernel)は、ユーザ空間のprintf( print formatted )に相当します。注意すべき点として、printf()と以下の点が異なります。本記事では、この差異を説明します。

printf()との差異
  • フォーマット
  • ログレベルの存在
  • printk()のラッパーマクロの存在
  • ログの出力先がメッセージ用リングバッファ
  • メッセージ表示に使用するコマンド(dmesg等)の存在

                 

printk()フォーマット

pritnk()フォーマットは、printfとほぼ同様です。差異は、ログレベル(0〜7, d, c)が指定できる点、実数型(double/float)をサポートしない点です。ログレベルは後ほど解説します。

文字列の書式は、「printf(3)を参考にする事(“$ man 3 printf”)」とソースコード中に記載されている。下表に、代表的な指定文字を示す。型に応じて、どの変換指定文字を使用すべきか迷った場合は、公式ドキュメントに逆引きが存在します。

変換指定文字 意味
%c 1文字として出力
%d 10進数で出力
%x 16進数で出力
%o 8進数で出力
%f 使用不可。浮動小数点(実数)をKernelはサポートしない
%d 使用不可。浮動小数点(実数)をKernelはサポートしない
%s 文字列として出力
%p ポインタ情報を出力(ポインタ関連は変換指定文字が多数存在

なお、ログレベルと書式文字列の間には、”,”がありません。

KERN_WARNINGは、defineマクロで定義された”4″を意味します。C言語では自動的にログレベルと書式文字列(“Test〜”の部分)は、 文字列として結合されます。ログレベルを指定しなかった場合は、自動的にデフォルト値(KERN_WARNING)となります。

        

ログレベル一覧

文字列

defineマクロ

意味・用途
0 KERN_EMERG  システム停止前の緊急メッセージ
1 KERN_ALERT  早急な対応が必要なエラー
2 KERN_CRIT  HWもしくはSWの致命的なエラー
3 KERN_ERR  ドライバ共通のエラー
4 KERN_WARNING  警告(エラーとなる可能性がある)
5 KERN_NOTICE  注意(エラーではない)
6 KERN_INFO  情報通知
7 KERN_DEBUG  デバッグメッセージ専用
d KERN_DEFAULT デフォルトのログレベル
c KERN_CONT ログの継続(タイムスタンプの更新を回避。ブート中専用)

            

printk()のラッパーマクロ

Kernel開発者は、printk()を高頻度で使用します。利便性を高めるために、printkに関するラッパーマクロが存在します。マクロは、”<Linux>/include/linux/printk.h“に定義されています。

良く使用するマクロは、ログレベルを省略できるマクロです。マクロは、以下のように定義されています。全てのログレベルに対して、マクロが用意されています(下表)。

文字列

ログレベル

ラッパーマクロ
0 KERN_EMERG pr_emerg
1 KERN_ALERT pr_alert
2 KERN_CRIT pr_crit
3 KERN_ERR pr_err
4 KERN_WARNING pr_warningもしくはpr_warn
5 KERN_NOTICE pr_notice
6 KERN_INFO pr_info
7 KERN_DEBUG pr_devel(#ifdefによって、”DEBUG”が0の場合はprintk()しない仕様)
c KERN_CONT pr_cont

上記の他にも、一度しかprintkを表示しないマクロや遅延表示するマクロが存在します。

                 

          

printk()出力先のメッセージリングバッファ

printk()は、ログレベルに関わらず、Kernel内部ログバッファにメッセージを保存しています。このログバッファは循環式であり、バッファ上限値を超えた場合は古いメッセージをに上書きする形で新しいメッセージを保存します。なお、ログバッファにメッセージを書き込む前に、タイムスタンプが付与されます。

ログバッファのサイズ変更は、Linux Kernelビルド前設定(“make menuconfig”)で行います。変更対象は”CONFIG_LOG_BUF_SHIFT”で、Bitシフトでしか設定できません(下図)。

      

メッセージ表示に利用するdmesgコマンド

printk()で用いるログバッファは、dmesgコマンド で内容を表示できます。dmesgは、klogctl(システムコール)を使用して、ログバッファを読み取り、標準出力 に表示します(以下の例を参考)。出力行数が多いため、head/tail/less/grepなどのコマンドで、メッセージを取捨選択したほうが良いです。

ログ出力の程度を抑えるために、ユーザ設定のログレベルのメッセージだけを表示する仕組みがあります。その設定値は、”/proc/sys/kernel/printk”に記載されています。以下にprintkファイルに記載された設定値を示し、その設定値の意味を下表に示します。

設定

意味
console_loglevel ログレベルが設定値より小さい場合のみ、コンソール出力可能。
default_message_level 明示的にログレベルが設定されていないpritnk()メッセージのログレベル
minimum_console_loglevel console_loglevelに設定できる最小値
default_console_loglevel console_loglevelのデフォルト値

“/proc/sys/kernel/printk”は書き込み可能なファイルであるため、以下のように設定値を変更できます。ただし、管理者権限が必要です。

最後に余談ですが、Linuxは、dmesgとは別の仕組みでログが管理されています。システム内部では、klogd が周期的にログ内容を収集し、 /var/log/syslog に書き出しています。こちらに関しては、インフラ系の勉強時に記事を作成します。

        

参考

Linux Kernel公式ドキュメント

カーネル・ロギング: API と実装(IBM)

<Linux>kernel/printk/printk.c

         

おすすめ