ログ

システム汎用ログ(syslog)設定

システム汎用のログ設定は/etc/syslog.confにある。以下の記述ルールがある。

【書式】
ファシリティ.優先度 出力先
ファシリティ
以下のいずれかの値でどのグループ(ファシリティ)の情報に対する指定であるのかを記述する。また、アスタリスク(*)を記して、全てのファシリティを対象とすることもできる。
  • auth
  • authpriv
  • cron
  • daemon
  • kern
  • lpr
  • mail
  • mark(内部用途に用意されたものなのでアプリケーションは利用すべきではない)
  • news
  • syslog
  • user
  • uucp
  • local0
  • local1
  • local2
  • local3
  • local4
  • local5
  • local6
  • local7
ファシリティはコンマ(,)区切りで複数列挙可能(優先度ではコンマ区切りによる複数列挙はできない)。
優先度
下記値(優先度の低い順に列挙)のいずれかが指定でき、そのまま記すと指定した優先度以上のものが出力対象となる。直前に等号(=)を記せばその優先度だけが対象になり、感嘆符(!)を記せばその優先度以上が除外され、!= を記せばその優先度だけが除外される。また、アスタリスク(*)を記して、全ての優先度を対象としたり、「none」を記して全ての優先度を除外する(=全く何も出力しない)こともできる。
  • debug
  • info
  • notice
  • warning
  • err
  • crit
  • alert
  • emerg
出力先
出力先を記す。以下の種類がある。
ローカルファイル
出力先となるログファイル名をシステムルートからの絶対パスで記す。
名前付きパイプ
ファイル名の先頭にパイプ記号(|)を記すと、メッセージが指定した先に渡される? 渡すには mkfifo コマンドでパイプを作る必要があるよう。
ターミナル・コンソール
「tty」を指定すると標準出力に出力が行われる。ローカルファイルとして /dev/console を指定しても同じ。
リモートシステム
「@ホスト名」の書式で指定する。指定したホスト上で syslogd が動作している必要がある。
ユーザリスト
通常、メッセージはシステムのrootに宛てて送られるが、ログイン中にメッセージを受け取るべきユーザを列挙することができる。ユーザ名はコンマ(,)区切りで列挙する。あるいはアスタリスク(*)を記すことでログイン中の全ユーザに対して通知するよう設定することもできる。
【記述例】
# カーネルメッセージ(kern)を除く、優先度がcrit以上のメッセージを全て /var/adm/critical に出力
*.=crit;kern.none  /var/adm/critical
# カーネルメッセージ(kern)は全て /var/adm/kernel に出力
kern.*             /var/adm/kernel
# カーネルメッセージ(kern)で優先度crit以上は @hogesv にも送る
kern.crit             @hogesv
# カーネルメッセージ(kern)で優先度crit以上はコンソールにも送る(画面に表示する)
kern.crit             /dev/console
# カーネルメッセージ(kern)で優先度info, notice, warningのものを /var/adm/kernel-info に出力
# (優先度err以上は除外)
kern.info;kern.!err   /var/adm/kernel-info
# mail, news, authpriv, cronを除く全ファシリティについて優先度info以上を /var/log/messages に出力
*.info;mail.none;news.none;authpriv.none;cron.none   /var/log/messages

ローテーション設定

CentOSやRHELで、ログのローテーションはcronによって毎日logrotateを実行して行われる。設定内容は/etc/logrotate.confおよび/etc/logrotate.d/配下の各ファイルでに記述される。

# ローテーション頻度
weekly
# 保存世代数
rotate 12
# バックアップ後新たな空ログを作るかどうか
create
# 圧縮の有無
compress
# このフォルダ内の設定をインポートする
include /etc/logrotate.d

logrotate.confには共通の基本設定を、/etc/logrotate.d/以下に各デーモン個別の設定を書くといった使い分けができる。

各設定変更後、特にデーモン類の再起動は必要ないらしい(cronでlogrotateが呼び出される際に各設定が適用されるため3)。

【例】/etc/logrotate.d/httpd
/var/log/httpd/*log {
    missingok
    notifempty
    sharedscripts # 以下の処理はワイルドカードの指定に関わらず1回だけ実行
    postrotate # 処理内容開始
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript # 処理内容終了
}

なお、ログファイル名の指定にワイルドカード(*→任意の0文字以上の文字(列)、?→任意の1文字)を使えるが、特に末尾に*を使う場合は要注意。過去ログまで対象に含まれ、二重にローテーションされてしまう(例:hoge.loghoge.log.1.gzhoge.log.1.gz.1.gz)。意図しないものがローテーション対象に含まれていないかはlogrotateのステータスファイル(/var/lib/logrotate.status)で確認できる。

項目 内容
ローテーション頻度 daily 日次(日が変わるとログを回す)
weekly 週次(週が変わると=日曜日になるとログを回す)
monthly 月次(月が変わると=毎月1日になるとログを回す)
yearly 年次(年が変わると=毎月1月1日になるとログを回す)
size ログファイルのサイズが指定値を越えていたらローテーションを行う。無単位の数値→kB、最後にk→kB、最後にM→MBとして処理。
ログを残す世代数 rotate 数値 指定世代のログを残す
【例】
weekly, rotate 3, compress の設定の場合
[root@server ~]# cd /var/log
[root@server log]# ls -l cron*
-rw------- 1 root root  12345  5月 10 10:00 cron
  -rw------- 1 root root  32244  5月  9 00:00 cron.1.gz[root@server log]# ls -l cron*
-rw------- 1 root root  23456  5月 17 10:00 cron
  -rw------- 1 root root  33150  5月 16 00:00 cron.1.gz
  -rw------- 1 root root  32244  5月  9 00:00 cron.2.gz # 番号を1つ増やした名前に変更[root@server log]# ls -l cron*
-rw------- 1 root root   2432  5月 24 10:00 cron
  -rw------- 1 root root  60618  5月 23 00:00 cron.1.gz
  -rw------- 1 root root  33150  5月 16 00:00 cron.2.gz
  -rw------- 1 root root  32244  5月  9 00:00 cron.3.gz[root@server log]# ls -l cron*
-rw------- 1 root root 294122  6月  1 10:00 cron
  -rw------- 1 root root   4939  5月 30 00:00 cron.1.gz
  -rw------- 1 root root  60618  5月 23 00:00 cron.2.gz
  -rw------- 1 root root  33150  5月 16 00:00 cron.3.gz
# 5/9のログは4世代前になるので消去(3世代まで残す設定の場合)
圧縮 compress 過去のログファイルには圧縮をかける。特に指定しない場合はgzipを使って圧縮される(→compresscmd参照)。
compresscmd 過去のログファイルを圧縮する時に使うプログラムを指定する。指定がない場合の初期値はgzip。
uncompresscmd ログファイルを解凍する時に使うプログラムを指定する。指定がない場合の初期値はgunzip。
nocompress 過去のログは圧縮しない
ローテーションの後処理 postrotate...endscript postrotate と endscript に挟まれた行に記述された内容がシェルによって実行される 通常、ログファイルの絶対パスがスクリプトの第1引数として渡される。sharedscriptsを指定した場合、全てのファイルパターンが引数として渡される。
共通処理の扱い sharedscripts 通常、prerotateとpostrotateで指定されたスクリプトは各ログファイルのローテーション処理が行われた後毎回実行さ、スクリプトの第1引数としてログファイルの絶対パスが渡される。sharedscriptsを指定するとスクリプトは全てのローテーション処理の後に1回だけ実行され、スクリプトには全てのパターンが引数として渡される。ローテーション対象となるファイルが一つもなかった場合、スクリプトは全く実行されない。スクリプトがエラーを出し途中で終了した場合、残りのスクリプト処理は実行されない。このオプションはnosharedscriptsの指定により上書きされ、このオプションの指定によりcreateオプションも自動的に指定されたものとして処理される。
元のログファイルの扱い create モード ユーザ グループ ローテーション処理の直後(postrotateの実行前)にローテーション対象ファイルと同名の空ファイルを作成する。ファイルのアクセスモード、所有者も指定可能。
copy 元のログはそのままにする
nocreate 新たなログファイルは作らない(この設定はcreateオプションを上書きする)。
拡張子 dateext ローテーションを行った日付から生成された値(.YYYYMMDD)が拡張子として用いられる。
  • 現行:dammy.log
  • 第1世代:dammy.log-20100401
  • 第2世代:dammy.log-20100301-20100401
  • 第3世代:dammy.log-20100201-20100301
  • 第4世代:dammy.log-20100101-20100201
2つも日付がつくのがいやなら、以下の指定[7]
【例】圧縮なし
/var/log/dammy.log {
  monthly
  postrotate
  EXT=`date +%Y%m%d`
  for f in $1;
  do mv $f.1 $f-$EXT;
  done
  endscript
}
【例】圧縮あり
/var/log/dammy.log {
  compress
  monthly
  postrotate
  EXT=`date +%Y%m%d`
  for f in $1;
  do mv $f.1.gz $f-$EXT.gz;
  done
  endscript
}
でも、ファイル名を変えてしまったりすると世代管理がちゃんとできるんだろうか?
→そもそもrotateがうまく動作せず(最新の過去ログファイル名は「ログファイル名.1(.gz)」のまま)。
start 数値 拡張子として用いる数値の初期値(最も最近のバックアップの拡張子)を指定する(指定がない場合の既定値は1)
ログが空の時の扱い notifempty ログが空であればローテーションは行わない(この設定はifemptyの設定を上書きする)。
ifempty ログが空であってもローテーションを行う(この設定はnotifemptyの設定を上書きする)。こちらが既定値。
ログファイルがない時の扱い missingok ログファイルがなくてもエラーを生成することなく処理を続行する。

複数のログファイルを指定する場合、1つ目のログファイルはダブルクォートで囲む必要がある。またファイル間は空白で区切る[6]

【例】
"/var/log/httpd/access.log" /var/log/httpd/error.log {
  rotate 5
  mail www@my.org
  size 100k
  sharedscripts
  postrotate
    /sbin/killall -HUP httpd
  endscript
}

ローテーションコマンド

logrotateコマンドは多数のログファイルを生成するシステムでの管理者業務を簡素化するよう設計されています。これによって、自動ローテーション、圧縮、削除、ログファイルのメール送信などを行うことができます。各ログファイルは、日ごと、週ごと、月ごと、あるいはあるサイズを越えた場合などにローテーションされます。

通常、logrotateはcronによって毎日実行されます。但し、ローテーションの基準がログファイルのサイズに設定した上でlogrotateを1日複数回実行するよう変更したか、あるいは -f または --force オプションを指定した場合は1日複数回ローテーションされる可能性があります。

設定ファイルはいくつでも指定することができますが、前に指定した設定ファイルの内容は後に指定した設定ファイルの内容で上書きされます。そのため設定ファイルの指定順所は重要になります。通常は、必要な他の設定ファイルの内容を含むよう記述された単一の設定ファイルを利用するようにするのがいいでしょう。他の設定ファイルの内容を含める方法について詳しくは後述します。そこでファイルではなくディレクトリを指定した場合、そのディレクトリ配下にある全てのファイルが設定ファイルとして用いられます。

コマンドライン引数が何も指定されなかった場合、logrotateはバージョン情報、著作権情報と合わせて簡単な利用方法の説明を表示します。ログのローテーションを行った際何らかのエラーがあると、logrotateは0以外のステータスを返して終了します。

logrotate オプション 設定ファイル 設定ファイル...
-v
より多くの情報を表示します(バーボーズモード)。
-d
デバッグモードで実行します。このオプションを指定すると、自動的に-vも指定したことになります。デバッグモードでは、ログファイルやlogrotateの状態ファイル(既定では/var/lib/logrotate.status)の変更は行われません。
-f--force
logrotateの設定に関わらず、強制的にローテーションを実行します。これはローテーション対象を新たにlogrotateの設定に追加した場合や、個別に古いログファイルを削除した場合に有用なことがあります。これにより新たなログファイルが生成され、ログ記録を正しく続行することができます。

ログ監視(logwatch)

logwatchはシステムログを分析して通知してくれるツール。RedHat系の場合、yum install logwatchでインストール。設定ファイル(/etc/logwatch/conf/logwatch.conf)の書式は以下の通り。

ログ通知(swatch)

ログ転送(netconsole)

netconsoleサービスを使うとシステムログを他のサーバにも転送することができる。ディスク障害が発生してディスクに書き込めない場合など、システムログが残らない場合でもネットワークサービスが生きていればシステムログを残すことができる。実施手順は以下の通り。例はserver1(192.168.0.1)のログをserver2(192.168.0.2)に転送する場合(OSはRHEL5/CentOS5)。

1. [転送元]netconsoleの設定
/etc/sysconfig/netconsoleに以下の行を追記(あるいはコメントアウトされている既存行を修正してコメントアウト解除)。
LOCALPORT=6666                  # 送信元ポート番号
DEV=eth0                        # 送信元ネットワークインタフェース名
SYSLOGADDR=192.168.0.2          # 送信先IPアドレス
SYSLOGPORT=514                  # 送信先ポート番号
SYSLOGMACADDR=00:22:11:33:44:55 # 送信先ネットワークインタフェースのMACアドレス
2. [転送元]netconsoleの自動起動設定

netconsoleがOS起動時に自動起動するよう設定する。

[root@server1 ~]# chkconfig netconsole on
3. [転送元]netconsole起動

netconsoleを手動起動。

[root@server1 ~]# /etc/init.d/netconsole start
Starting netconsole...             [ OK ]
4. [転送先]リモートログを受け付けるようsyslogの設定を変更

/etc/sysconfig/syslogを編集し、"-r" オプションを追加。

SYSLOGD_OPTIONS="-m 0"
↓↓↓
SYSLOGD_OPTIONS="-m 0 -r"
5. [転送元/先]iptablesで必要ポートの通信を通すよう設定を変更(iptablesを使っている場合)

項目1の設定内容であった場合で、iptablesでのチェイン名が「RH-Firewall-1-INPUT」である場合。

[転送元]
[root@server1 ~]# iptables -A RH-Firewall-1-INPUT -p udp -d 192.168.0.2 --sport 6666 --dport 514 -j ACCEPT

[転送先]
[root@server2 ~]# iptables -A RH-Firewall-1-INPUT -p udp -s 192.168.0.1 --sport 6666 --dport 514 -j ACCEPT

チェインの最後に全て拒否する記述があった場合、それより前(上)にルールを追加する必要がある。その場合は -A ではなく-I で追加位置を指定。

[転送元]
[root@server1 ~]# /etc/init.d/iptables status
...
10   REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

テーブル: nat
...
[root@server1 ~]# iptables -I RH-Firewall-1-INPUT 10 -p udp -d 192.168.0.2 --sport 6666 --dport 514 -j ACCEPT
[root@server1 ~]# /etc/init.d/iptables status
...
10   ACCEPT     udp  --  0.0.0.0/0            192.168.0.2         udp spt:6666 dpt:514
11   REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

テーブル: nat
...

[転送先]
[root@server2 ~]# /etc/init.d/iptables status
...
10   REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

テーブル: nat
...
[root@server2 ~]# iptables -I RH-Firewall-1-INPUT 10-p udp -s 192.168.0.1 --sport 6666 --dport 514 -j ACCEPT
[root@server2 ~]# /etc/init.d/iptables status
...
10   ACCEPT     udp  --  192.168.0.1          0.0.0.0/0           udp spt:6666 dpt:514
11   REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

テーブル: nat
...

iptablesの設定変更内容はサービスを再起動すると失われるので、iptables-save >/etc/sysconfig/iptablesで設定を保存しておく。iptablesコマンド/サービスについてはこちらも参照のこと。

6. [転送先]syslogd再起動
[root@server2 ~]# /etc/init.d/syslog restart
7. [転送元/先]ログ転送動作確認

SysRq[14]を用いてkernelメッセージを生成し、転送動作を確認することができる[15]

[root@server1 ~]# echo s > /proc/sysrq-trigger
[root@server1 ~]# dmesg | tail -n 1
SysRq : Show Regs
[root@server2 ~]# tail -n 2 /var/log/messages
Aug 22 09:46:50 server1 SysRq : 
Aug 22 09:46:50 server1 Show Regs

Apacheアクセスログ集計(Webalizer)

ログの解析 - Apache関係 - メモ参照。

アクセスログ集計(AWStats)

AWStatsはWeb、ftp、mailなどのアクセス統計情報を集計してくれるツール[16]、[17]

AWStats Online Document(英語)を私が翻訳したものはこちら。他にも翻訳物あり(鈴木朝子と高橋誠の部屋)。

AWStatsは古いログを後から処理してデータを追加することはできない。それをしたい場合は、処理したいログの対象期間よりも新しい期間のAWStatsデータファイルを削除(移動)して、取り込み処理をやり直すといいらしい[22][23]