慣習を気にせずsyslog-ngの設定をしてみた

たいていの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);
};