たいていのsyslogのデフォルトの設定だと、
- 同じログが結構な量、複数のファイルに記録されて(IO負荷的、ディスクサイズ的に)無駄だなぁ
- 日付のフォーマットが機械処理しづらいなぁ
- ローテートがめんどいなぁ
と思ってたので、今つくってる環境では慣習を気にせずに syslog-ng (v2.0.9) の設定をしてみたのでそのメモです。
不要なログは記録しない
options { ... mark_freq(0); stats_freq(0); ... }
日付の形式を変える
options { ... ts_format(iso); ... }
これで、こんなの
Dec 19 16:44:20 HOST ...
から、こんなの
2008-12-19T14:07:52+09:00 HOST ...
に変わります。
facilityごとにわける
facilityごとのfilterを作る。
desticationは$FACILITYというfacility名に展開されるマクロを使って記述を簡素化。
ただ、authとauthprivはひとつにまとめたいので、例外的に設定してます。
destination df_facility { file("/var/log/archive/${FACILITY}/$YEAR-$MONTH"); }; destination df_auth { file("/var/log/archive/auth/$YEAR-$MONTH"); }; filter f_kern { facility(kern); }; ... filter f_auth { facility(auth, authpriv); }; ... filter f_local7 { facility(local7); }; log { source(s_local) ; filter(f_kern); destination(df_facility); }; ... log { source(s_local) ; filter(f_auth); destination(df_auth); }; ...
levelごとにわける (一部)
debian/syslog-ng.conf からそのまま。
filter f_emerg { level(emerg); }; filter f_debug { level(debug) and not facility(auth,authpriv,news,mail); }; filter f_at_least_crit { level(crit..emerg); }; filter f_at_least_err { level(err..emerg); }; filter f_at_least_warning { level(warning..emerg); }; filter f_at_least_notice { level(notice..emerg); }; filter f_at_least_info { level(info..emerg); };
ログローテート要らず
こんな感じで、さいしょっからログの出力先を、ログ種別と月次でわける。
destination df_facility { file("/var/log/archive/${FACILITY}/$YEAR-$MONTH"); }
んで、月初とか(毎日00:01とかでもOK)にこんなスクリプトを実行してsymlinkする。
#!/bin/sh # Time-stamp: <2008-12-19 16:03:22 JST, hirose31> # /var/log/TYPE (symlink) # /var/log/archive/TYPE/YYYY-MM timestamp=$(date '+%Y-%m') facility="kern user mail daemon auth syslog lpr news uucp cron ftp local0 local1 local2 local3 local4 local5 local6 local7" level="emerg alert crit err warning notice info debug" custom="" for d in $facility $level $custom; do [ -d "/var/log/archive/${d}" ] || continue ln -sf archive/${d}/${timestamp} /var/log/${d} done
今のログを見たいときは /var/log/auth を見る。
過去のを見たいときは /var/log/archive/auth/2008-01 とかを見る。
マクロを使った効率的なログの集約
WEB+DB PRESS Vol.40 にも書いたんですが、複数ある Apache のログを syslog で飛ばしてログサーバに集約する例。
ログはloggerを使ってsyslogに流す。
facility.levelは固定(local6.info)で、
tagにサービス (VirtualHost) の識別子を入れる。
<VirtualHost *> ServerName d.hatena.ne.jp ... CustomLog "|/usr/bin/logger -t diary -p local6.info --" orenolog ... </VirtualHost> <VirtualHost *> ServerName b.hatena.ne.jp ... CustomLog "|/usr/bin/logger -t bookmark -p local6.info --" orenolog ... </VirtualHost>
Apacheが動いているマシンのsyslong-ng.confはこんな感じで、全部ログサーバ(log.example.org)に転送する。
filter f_httpd { facility(local6) and level(info); }; destination df_httpd { udp("log.example.org"); }; log { source(s_local); filter(f_httpd); destination(df_httpd); };
ログサーバのsyslog-ng.confはこんな感じで、loggerのtagで指定した識別子を使って複数のApacheからのログをまとつつディレクトリをわけて整理する。
filter f_httpd { facility(local6) and level(info); }; destination df_httpd_aggregate { file("/var/log/httpd/realtime/${PROGRAM}/acc_$YEAR-$MONTH-$DAY" perm(0644) dir_perm(0750) ); }; log { source(s_remote); filter(f_httpd); destination(df_httpd_aggregate); };
通知
とあるログが出力されたら、メールやIRCやIMやトランスバイブレータなどを使って通知する方法。
ひとつめは、ログをファイルじゃなくて名前付きパイプに書く。
destination dp_notifier { pipe("/dev/notifier"); };
あとはこの名前付きパイプをreadしてログを読んで、然るべき方法で通知を実行するプログラムを走らせておけばOK。
ふたつめは、プログラムに標準入力でログを渡す方法。
destination dx_notifier { program("/path/to/notifier"); };
このプログラムはsyslog-ngから起動されて、ログが出力され次第、標準入力から読めます。なので、exitしないでstdinをreadしてればOK。exitしてもいいけど、そするとログが吐かれる度にプロセス起動となりDoSっぽくのでやめたほうがいいと思います。
filterとlogはこんな感じで。
filter f_auth_fail { ( program("sshd") and (match("Invalid user") or match("Failed password for")) ) or ( program("login") and (match("authentication failure") or match("FAILED LOGIN")) ); }; log { source(s_local); filter(f_auth_fail); destination(dp_notifier); destination(dx_notifier); };
パフォーマンス
syncとかバッファリングとかudpとかtcpとか。このへんは追々。なんか情報あったら教えてください><
options { chain_hostnames(0); time_reopen(10); time_reap(360); sync(0); mark_freq(0); stats_freq(0); log_fifo_size(2048); log_msg_size(2048); create_dirs(yes); ts_format(iso); owner(root); group(root); perm(0640); dir_owner(root); dir_group(root); dir_perm(0755); use_dns(yes); }; ### sources ############################################################## source s_local { internal(); unix-stream("/dev/log"); file("/proc/kmsg" log_prefix("kernel: ")); }; source s_remote { udp(); tcp(); }; ### destinations ######################################################### destination df_facility { file("/var/log/archive/${FACILITY}/$YEAR-$MONTH"); }; destination df_auth { file("/var/log/archive/auth/$YEAR-$MONTH"); }; destination df_level { file("/var/log/archive/${LEVEL}/$YEAR-$MONTH"); }; destination du_all { usertty("*"); }; destination dp_xconsole { pipe("/dev/xconsole"); }; #destination dn_logserver { udp("log.local"); }; destination dp_notifier { pipe("/dev/notifier"); }; #destination dx_notifier { program("/path/to/notifier"); }; ### filters ############################################################## filter f_kern { facility(kern); }; filter f_user { facility(user); }; filter f_mail { facility(mail); }; filter f_daemon { facility(daemon); }; filter f_auth { facility(auth, authpriv); }; filter f_syslog { facility(syslog); }; filter f_lpr { facility(lpr); }; filter f_news { facility(news); }; filter f_uucp { facility(uucp); }; filter f_cron { facility(cron); }; filter f_ftp { facility(ftp); }; filter f_local0 { facility(local0); }; filter f_local1 { facility(local1); }; filter f_local2 { facility(local2); }; filter f_local3 { facility(local3); }; filter f_local4 { facility(local4); }; filter f_local5 { facility(local5); }; filter f_local6 { facility(local6); }; filter f_local7 { facility(local7); }; # emerg alert crit err warning notice info debug filter f_emerg { level(emerg); }; filter f_debug { level(debug) and not facility(auth,authpriv,news,mail); }; filter f_at_least_crit { level(crit..emerg); }; filter f_at_least_err { level(err..emerg); }; filter f_at_least_warning { level(warning..emerg); }; filter f_at_least_notice { level(notice..emerg); }; filter f_at_least_info { level(info..emerg); }; filter f_xconsole { filter(f_at_least_warning); }; filter f_auth_fail { ( program("sshd") and (match("Invalid user") or match("Failed password for")) ) or ( program("login") and (match(" authentication failure") or match("FAILED LOGIN")) ); }; ### logs ################################################################# log { source(s_local) ; filter(f_kern); destination(df_facility); }; log { source(s_local) ; filter(f_user); destination(df_facility); }; log { source(s_local) ; filter(f_mail); destination(df_facility); }; log { source(s_local) ; filter(f_daemon); destination(df_facility); }; log { source(s_local) ; filter(f_auth); destination(df_auth); }; log { source(s_local) ; filter(f_syslog); destination(df_facility); }; log { source(s_local) ; filter(f_lpr); destination(df_facility); }; log { source(s_local) ; filter(f_news); destination(df_facility); }; log { source(s_local) ; filter(f_uucp); destination(df_facility); }; log { source(s_local) ; filter(f_cron); destination(df_facility); }; log { source(s_local) ; filter(f_ftp); destination(df_facility); }; log { source(s_remote) ; filter(f_local1); destination(df_facility); }; log { source(s_local); filter(f_emerg); destination(df_level); destination(du_all); destination(dp_notifier); #destination(dx_notifier); }; log { source(s_local); filter(f_debug); destination(df_level); }; log { source(s_local); filter(f_xconsole); destination(dp_xconsole); }; log { source(s_local); filter(f_auth_fail); destination(dp_notifier); #destination(dx_notifier); };