syslog-ng
関連記事
概要
syslog-ng は定義済みの 'source' からのメッセージを受け取って、強力な filter ディレクティブに基づいて、適当な destination に転送します。標準的なシンプルな設定だと、syslog-ng は3つの source からメッセージを読み取ります:
- デフォルトの
/dev/log
デバイス (ほとんどのログはここに送られます) - syslog-ng の"内部的な"ログメッセージ
/proc/kmsg
カーネルメッセージ
受信元は "source" ディレクティブを使って定義します。受信されたメッセージは次に定義済みのフィルター ("filter" キーワード) によってフィルタリングされ、送信元のプログラムやログレベルにあわせて、適当な "destination" に送信されます。送信先としてはログファイル (例: /var/log/messages.log
) や、コンソールやリモートサーバーにメッセージを表示するなどが考えられます。中心的な関数は log です。この関数は特定の source に対してどのフィルターを適用し、作成されたメッセージをどこに送信すればいいのか定義します。
syslog-ng.service
サービスファイルを使って syslog-ng を有効化します。systemd 216 から、メッセージはデフォルトでは syslog に転送されなくなりました。syslog-ng 3.6 のリリースまで Syslog-ng は journald に対応していませんでした。systemd 216 以上で syslog-ng を使用するには /etc/systemd/journald.conf
を編集して ForwardToSyslog=yes
オプションを設定する必要があったのです。
最新の syslog-ng を使っている場合は、オプションを変更する必要はありません。syslog-ng が journal からメッセージを引っ張ってきてくれます。ForwardToSyslog=yes
と設定していた場合は ForwardToSyslog=no
に戻してください。ソケットの関連付けによるオーバーヘッドと ログに無駄なエラーメッセージが残る のを防ぐためです。一方で、ログを二度保存したくなく journald を Storage=none
にする場合、ForwardToSyslog=yes
を設定する必要があります。これによって syslog-ng は 'journald' の journal ファイルに従うようになります。
インストール
syslog-ng パッケージをインストール してください。
syslog-ngを使用開始するには、 start/enable syslog-ng@default.service
です。
Source
syslog-ng は source からログメッセージを受信します。source を定義するときは以下の構文に従う必要があります:
source <identifier> { source-driver(params); source-driver(params); ... };
identifier と source-driver については 公式マニュアル で読むことができます。マニュアルにしたがって上記の設定ファイルを説明します。unix-stream() source-driver は指定された AF_UNIX ソケットを開いてメッセージが来るのを待ちます。internal() source-driver は syslog-ng によって生成されたメッセージを取得します。
したがって、以下の設定の意味は: src
は /dev/log
ソケットと syslog-ng からのメッセージを取得する、となります。
source src { unix-stream("/dev/log"); internal(); };
カーネルはログメッセージを /proc/kmsg
に送信して file() ドライバーはファイルからログメッセージを読み取ります。したがって、以下の設定の意味は: kernsrc は /proc/kmsg
ファイルからメッセージを取得する、となります。
source kernsrc { file("/proc/kmsg"); };
デフォルト設定では syslog-ng の後に、以下のように source が定義されています:
source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };
pipe("/proc/kmsg")
によってメッセージを読み込むことでパフォーマンスには良い影響がありますが、読み書きモードで開くのでセキュリティ上問題になります。このことは syslog-ng admin guide のセクション 3.3.3 で触れられています:
"パイプは file() ドライバーとよく似ていますが、多少の違いがあり、例えば pipe() は読み書きモードで開くので、/proc/kmsg
などの特殊なファイルで使用するのは推奨されません" (この議論については ここの投稿 で読むことができます)。
リモートサーバーからデータを読み取るためにポートを開けるには、以下の構文の source を定義します。UDP の場合:
source s_net { udp(); };
もしくは TCP によってログメッセージを受信するには:
source s_net { tcp(); };
どちらも514番ポートを listen します。
syslog-ng と systemd journal
syslog-ng バージョン 3.6.1 から systemd を使用する Linux 環境ではデフォルトの system()
で journald が使われます。
journald と syslog-ng 両方のファイルを使用したい場合、次のように設定を行って下さい。systemd-journald 側は、/etc/systemd/journald.conf
ファイルで、Storage=
を auto
に設定するかオプションの設定を削除してください (デフォルトで auto に設定されます)。また、ForwardToSyslog=
を no
に設定するか設定を削除してください (デフォルトで no に設定されます)。/etc/syslog-ng/syslog-ng.conf
で、以下の source
を使って下さい:
source src { system(); internal(); };
また、syslog-ng のテキストログは維持しつつ journald のログを残したくない場合、/etc/systemd/journald.conf
で Storage=volatile
と ForwardToSyslog=yes
を設定してください。この設定を行うと journald はメモリに保存されます。syslog-ng 3.6.3 現在、syslog-ng は journald を system(); ソースとして使用するため Storage=none
と設定してしまうと、systemd ジャーナルは全てのメッセージを消去してしまい syslog-ng にメッセージが転送されません。
変更を行った後は systemd-journald.service
と syslog-ng.service
デーモンを再起動してください。
Destination
syslog-ng では、ログメッセージはファイルに送信されます。構文は source とよく似ています:
destination <identifier> {destination-driver(params); destination-driver(params); ... };
通常はファイルにログを出力することになりますが、他にも様々な destination-driver にログを書き出すことが可能です: パイプ, Unix ソケット, TCP-UDP ポート,
ターミナルまたは特定のプログラムなど。したがって、以下の設定は authlog メッセージを /var/log/auth.log
に送信します:
destination authlog { file("/var/log/auth.log"); };
(ユーザーがログインしているとき) usertty()
は指定されたユーザーのターミナルにメッセージを送信します。root のターミナルにコンソールメッセージを送りたい場合:
destination console { usertty("root"); };
pipe()
を使えばメッセージをパイプに送信することができます。以下の設定は xconsole メッセージを /dev/xconsole
パイプに送信します。
destination xconsole { pipe("/dev/xconsole"); };
ネットワーク上にメッセージを送信するには、udp()
を使います。以下の destination はログデータを別のサーバーに送信します。
destination remote_server { udp("10.0.0.2" port(514)); };
メッセージのフィルターを作成
filter ステートメントの構文は:
filter <identifier> { expression; };
expression には関数を使うことができます。例えばファシリティコードによってメッセージを選り分ける facility()
関数などです。Linux カーネルには少数ながらログに使うことが出来る facility がいくつかあります。それぞれの facility にはログレベルが存在します。debug は最も情報量が多く、panic は深刻なエラーのみを表示します。facility, ログレベル, プライオリティの名前は /usr/include/sys/syslog.h
で確かめることができます。May 11 23:42:31 mimosinnet su(pam_unix)[18569]: session opened for user root by (uid=1000) のような authorization からのメッセージを取り出すには、以下を使います:
filter f_auth { facility(auth); };
facility には論理演算子 and
, or
, not
を使うことが可能です。例えば以下のフィルターは authorization, network news, mail からではないメッセージを選択します:
filter f_debug { not facility(auth, authpriv, news, mail); };
level()
関数はプライオリティレベルによってメッセージを選択します。informational レベルを選択したい場合は:
filter f_info { level(info); };
関数と論理演算子は組み合わせて複雑な条件を作成することができます。以下のフィルターはプライオリティレベルが informational から warning の間で facility が auth, authpriv, mail, news ではないメッセージを抜き出します:
filter f_messages { level(info..warn) and not facility(auth, authpriv, mail, news); };
match("regex" value("TEMPLATE"))
関数を使って正規表現にメッセージをマッチさせて選択することも可能です。例えば:
filter f_failed { match("failed" value("MESSAGE")); };
以下はテンプレートのリストです:
"AMPM", "BSDTAG", "DATE, C_DATE, R_DATE, S_DATE", "DAY, C_DAY, R_DAY, S_DAY", "FACILITY", "FACILITY_NUM", "FULLDATE, C_FULLDATE, R_FULLDATE, S_FULLDATE", "FULLHOST", "FULLHOST_FROM", "HOUR, C_HOUR, R_HOUR, S_HOUR", "HOUR12, C_HOUR12, R_HOUR12, S_HOUR12", "HOST", "HOST_FROM", "ISODATE, C_ISODATE, R_ISODATE, S_ISODATE", "LEVEL_NUM", "LOGHOST", "MIN, C_MIN, R_MIN, S_MIN", "MONTH, C_MONTH, R_MONTH, S_MONTH", "MONTH_ABBREV, C_MONTH_ABBREV, R_MONTH_ABBREV, S_MONTH_ABBREV", "MONTH_NAME, C_MONTH_NAME, R_MONTH_NAME, S_MONTH_NAME", "MONTH_WEEK, C_MONTH_WEEK, R_MONTH_WEEK, S_MONTH_WEEK", "MSEC, C_MSEC, R_MSEC, S_MSEC", "MSG or MESSAGE", "MSGHDR", "MSGID", "MSGONLY", "PID", "PRI", "PRIORITY or LEVEL", "PROGRAM", "SDATA, .SDATA.SDID.SDNAME", "SEC, C_SEC, R_SEC, S_SEC", "SOURCEIP", "SEQNUM", "STAMP, R_STAMP, S_STAMP", "SYSUPTIME", "TAG", "TAGS", "TZ, C_TZ, R_TZ, S_TZ", "TZOFFSET, C_TZOFFSET, R_TZOFFSET, S_TZOFFSET", "UNIXTIME, C_UNIXTIME, R_UNIXTIME, S_UNIXTIME", "USEC, C_USEC, R_USEC, S_USEC", "YEAR, C_YEAR, R_YEAR, S_YEAR", "WEEK, C_WEEK, R_WEEK, S_WEEK", "WEEK_ABBREV, C_WEEK_ABBREV, R_WEEK_ABBREV, S_WEEK_ABBREV", "WEEK_DAY, C_WEEK_DAY, R_WEEK_DAY, S_WEEK_DAY", "WEEKDAY, C_WEEKDAY, R_WEEKDAY, S_WEEKDAY", "WEEK_DAY_NAME, C_WEEK_DAY_NAME, R_WEEK_DAY_NAME, S_WEEK_DAY_NAME".
特定のリモートホストから受信したメッセージをフィルタリングする場合は、host()
関数を使って下さい:
filter f_host { host( "192.168.1.1" ); };
ログのパス
syslog-ng は source, filter, destination を log ステートメントで接続します。構文は:
log {source(s1); source(s2); ... filter(f1); filter(f2); ... destination(d1); destination(d2); ... flags(flag1[, flag2...]); };
以下は src
source からのメッセージを f_info
filter でフィルターにかけて mailinfo
destination に送信する例です:
log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };
ヒントとテクニック
syslog-ng の背後にあるロジックを理解したら、様々な設定、複雑な設定をすることが可能になります。以下はほんの一例です。
syslog-ng に設定ファイルをリロードさせる
syslog-ng に設定ファイルを再評価させることが可能です。プロセスに SIGHUP
を手動で送信するか、systemctl の reload 関数を呼び出して下さい:
# systemctl reload syslog-ng
ログ出力をリモートホストにフェイルオーバー
以下の設定は標準ポート (514) と代替ポートを使って、TCP と UDP プロトコル両方でデフォルトの暗号化されていない syslog パケットを送信します。同一の出力を同一のマシンに4回試行して、確実にパケットを送信します。再起動できないリモートサーバーをデバッグするときに特に便利です。様々なポートとプロトコルを使うことで、ファイアウォールフィルターなどのネットワークの問題を通過できるようにしています。また、ポートフォワーディングやトンネルを使う場合にも有用です。このような設定は、逆接続で開始される ssh 接続のトンネルにうってつけでしょう。
#sending to a remote syslog server on TCP and UDP ports (not encrypted) destination askapache_failover_loghost { tcp("208.86.158.195" port(25214)); udp("208.86.158.195" port(25214)); udp("mysyslog1.dyndns.org" port(514)); }; log { source(src); destination(askapache_failover_loghost); };
そして loghost 側ではログを受信します:
#a USB redirected console for flexible viewing destination debugging_console { file("/dev/ttyU1"); }; # listens on IP addresses and ports, sets the incoming settings source prone_to_failover_host { tcp(ip(208.86.158.195),port(25214)); udp(ip(208.86.158.195) port(25214)); udp(default-facility(syslog) default-priority(emerg)); tcp(default-facility(syslog) default-priority(emerg)); } # log it log { source(prone_to_failover_host); destination(debugging_console); };
ログを別のファイルに移動
ログを /var/log/messages
から他のファイルに移動するには:
#sshd configuration destination ssh { file("/var/log/ssh.log"); }; filter f_ssh { program("sshd"); }; log { source(src); filter(f_ssh); destination(ssh); };
loghost として設定
システムを loghost として設定することはとても簡単です。設定に以下のように記述を行い、必要なディレクトリを作成してください。このシンプルな設定では、ログのファイル名はリモートホストの FQDN に基づいて名付けられ、/var/log/remote/
にファイルが配置されます。remote ディレクトリを作成した後、syslog-ng の設定をリロードしてください。
source net { udp(); }; destination remote { file("/var/log/remote/${FULLHOST}-log"); }; log { source(net); destination(remote); };
パフォーマンスの向上
いくつかの方法を使って syslog-ng のパフォーマンスを上げることができます:
ときどき書き込ませる
旧 sync(X)
オプションは現在 flush_lines(X)
と呼ばれるようになっており、これによってファイルへの書き込みを X
行にバッファします。デフォルトは0です (バッファしません)。
処理やディスク領域の重複を避ける
一つのログメッセージが別々のログファイルに複数回送信されるということがあります。例えば、初期設定では、以下のような定義があります:
destination cron { file("/var/log/cron.log"); }; destination messages { file("/var/log/messages"); }; filter f_cron { facility(cron); }; filter f_messages { level(info..warn) and not facility(auth, authpriv, mail, news); }; log { source(src); filter(f_cron); destination(cron); }; log { source(src); filter(f_messages); destination(messages); };
The same message from the cron
facility will end up in both the cron.log
and messages
files. To change this behavior we can use the final
flag,
ending up further processing with the message. Therefore, in this example, if we want messages from the cron
facility not ending up in the
messages file, we should change the cron's log sentence by:
log { source(src); filter(f_cron); destination(cron); flags(final); };
f_messages
フィルターから cron
ファシリティを除外する方法もあります:
filter f_messages { level(info..warn) and not facility(cron, auth, authpriv, mail, news); };
PostgreSQL Destination
このセクションでは2つのロールを使います: syslog
と logwriter
です。syslog
は syslog
データベースの管理者であり、logwriter
だけが logs
テーブルにレコードを追加することができることにします。
ログ用にテーブルを作成する必要はありません。syslog-ng が自動的に作成します。
psql -U postgres
postgres=# CREATE ROLE syslog WITH LOGIN; postgres=# \password syslog # Using the \password function is secure because postgres=# CREATE ROLE logwriter WITH LOGIN; postgres=# \password logwriter # the password is not saved in history. postgres=# CREATE DATABASE syslog OWNER syslog; postgres=# \q # You are done here for the moment
pg_hba.conf
を編集して syslog
と logwriter
が PostgreSQL への接続を確立できるようにします。
/var/lib/postgres/data/pg_hba.conf
# TYPE DATABASE USER CIDR-ADDRESS METHOD host syslog logwriter 192.168.0.1/24 md5 host syslog syslog 192.168.0.10/32 md5
PostgreSQL に設定ファイルをリロードさせてください:
# systemctl reload postgresql
/etc/syslog-ng/syslog-ng.conf
を編集して PostgreSQL に書き込む場所と方法を設定します。syslog-ng は logwriter
ロールを利用します。
... # # SQL logging support # destination d_pgsql { sql(type(pgsql) host("127.0.0.1") username("logwriter") password("password") database("syslog") table("logs_${HOST}_${R_YEAR}${R_MONTH}${R_DAY}") #or whatever you want, example ${HOST}" for hosts, ${LEVEL}" for levels.. etc columns("datetime timestamp with time zone", "host varchar(32)", "program varchar(16)", "pid varchar(16)", "message varchar(200)") values("$R_ISODATE", "$HOST", "$PROGRAM", "$PID", "$MSG") indexes("datetime", "host", "program", "pid", "message")); }; log { source(src); destination(d_pgsql); };
最後に、syslog-ng を再起動してください。
# systemctl restart syslog-ng
ちゃんとログが記録されているか確認もしましょう。
psql -U logwriter -d syslog syslog=> SELECT * FROM <your table name> ORDER BY datetime DESC LIMIT 10;
ISO 8601 タイムスタンプ
ビフォー:
#logger These timestamps are not optimal. #tail -n 1 /var/log/messages.log Feb 18 14:25:01 hostname logger: These timestamps are not optimal. #
ts_format(iso);
を /etc/syslog-ng/syslog-ng.conf
の options セクションに追加。例:
options { stats_freq (0); flush_lines (0); time_reopen (10); log_fifo_size (1000); long_hostnames(off); use_dns (no); use_fqdn (no); create_dirs (no); keep_hostname (yes); perm(0640); group("log"); ts_format(iso); #make ISO-8601 timestamps };
そして:
# systemctl reload syslog-ng
アフター:
#logger Now THAT is a timestamp! #tail -n 2 /var/log/messages.log Feb 18 14:25:01 hostname logger: These timestamps are not optimal. 2010-02-18T20:23:58-05:00 electron logger: Now THAT is a timestamp! #
RFC 3339 タイムスタンプ
上記と同じように編集。ただし ts_format
には iso
の代わりに rfc3339
を使用。
ログレベル
Log levels are defined separately for each logged facility in syslog-ng config. Available log levels are listed in /usr/include/sys/syslog.h :
define LOG_EMERG 0 /* system is unusable */ define LOG_ALERT 1 /* action must be taken immediately */ define LOG_CRIT 2 /* critical conditions */ define LOG_ERR 3 /* error conditions */ define LOG_WARNING 4 /* warning conditions */ define LOG_NOTICE 5 /* normal but significant condition */ define LOG_INFO 6 /* informational */ define LOG_DEBUG 7 /* debug-level messages */
マクロと変数
Macros can be used in both templates, and in destination file names. Macros of syslog-ng OSE.
以下のコードは macroname=value@
の形式でログを /var/log/test.log
に書き出します。
template t_test { template("PROGRAM=$PROGRAM@PID=$PID@BSDTAG=$BSDTAG@TAG=$TAG@TAGS=$TAGS@FACILITY=$FACILITY@FACILITY_NUM=$FACILITY_NUM@LEVEL=$LEVEL@LEVEL_NUM=$LEVEL_NUM@PRI=$PRI@PRIORITY=$PRIORITY@FULLHOST=$FULLHOST@FULLHOST_FROM=$FULLHOST_FROM@HOST=$HOST@HOST_FROM=$HOST_FROM@LOGHOST=$LOGHOST@MSGHDR=$MSGHDR@MSGID=$MSGID@MSGONLY=$MSGONLY@MSG=$MSG@MESSAGE=$MESSAGE@SOURCE=$SOURCE@SOURCEIP=$SOURCEIP@SOURCE_IP=$SOURCE_IP@SEQNUM=$SEQNUM@UNIXTIME=$UNIXTIME@FULLDATE=$FULLDATE@ISODATE=$ISODATE@DATE=$DATE@STAMP=$STAMP@TZ=$TZ@TZOFFSET=$TZOFFSET@SEC=$SEC@MIN=$MIN@HOUR=$HOUR@HOUR12=$HOUR12@DAY=$DAY@WEEK=$WEEK@WEEK_DAY=$WEEK_DAY@WEEK_DAY_ABBREV=$WEEK_DAY_ABBREV@WEEK_DAY_NAME=$WEEK_DAY_NAME@MONTH=$MONTH@MONTH_ABBREV=$MONTH_ABBREV@MONTH_NAME=$MONTH_NAME@MONTH_WEEK=$MONTH_WEEK@YEAR=$YEAR@YEAR_DAY=$YEAR_DAY \n"); template_escape(no); }; destination d_test { file("/var/log/test.log" template(t_test)); }; log { source(s_local); destination(d_test); flags(final); };
You can create your own value list as below once syslog-ng is restarted with:
tail /var/log/test.log|tr "@" "\n"
PROGRAM=kernel PID= BSDTAG=4A TAG=04 TAGS=.source.s_local FACILITY=kern FACILITY_NUM=0 LEVEL=warning LEVEL_NUM=4 PRI=4 PRIORITY=warning FULLHOST=www.askapache.com FULLHOST_FROM=www.askapache.com HOST=www.askapache.com HOST_FROM=www.askapache.com LOGHOST= MSGHDR=kernel: MSGID= MSGONLY=Firewall: *INVALID* IN=eth0 OUT= MAC=00:00 SRC=x.x.x.x DST=198.101.159.98 LEN=40 TOS=0x00 PREC=0x00 TTL=113 ID=7730 DF PROTO=TCP SPT=52369 DPT=80 WINDOW=0 RES=0x00 ACK RST URGP=0 MSG=Firewall: *INVALID* IN=eth0 OUT= MAC=00:00 SRC=x.x.x.x DST=198.101.159.98 LEN=40 TOS=0x00 PREC=0x00 TTL=113 ID=7730 DF PROTO=TCP SPT=52369 DPT=80 WINDOW=0 RES=0x00 ACK RST URGP=0 MESSAGE=Firewall: *INVALID* IN=eth0 OUT= MAC=00:00 SRC=x.x.x.x DST=198.101.159.98 LEN=40 TOS=0x00 PREC=0x00 TTL=113 ID=7730 DF PROTO=TCP SPT=52369 DPT=80 WINDOW=0 RES=0x00 ACK RST URGP=0 SOURCE=s_local SOURCEIP=127.0.0.1 SOURCE_IP= UNIXTIME=1369742458 FULLDATE=2013 May 28 08:00:58 ISODATE=2013-05-28T08:00:58-04:00 DATE=May 28 08:00:58 STAMP=2013-05-28T08:00:58-04:00 TZ=-04:00 TZOFFSET=-04:00 SEC=58 MIN=00 HOUR=08 HOUR12= DAY=28 WEEK=21 WEEK_DAY=3 WEEK_DAY_ABBREV=Tue WEEK_DAY_NAME=Tuesday MONTH=05 MONTH_ABBREV=May MONTH_NAME=May MONTH_WEEK=4 YEAR=2013 YEAR_DAY=148
参照
- syslog-ng OSE プロジェクトページ
- syslog-ng ドキュメントポータル
- syslog-ng Project Page on Freshmeat
- Gentoo syslog-ng wiki
- Gentoo Security Handbook on Logging
- What is Syslog? Logging with PostgreSQL HOWTO
- ISO 8601 - ISO 8601 の Wikipedia ページ
- RFC 3164 - BSD syslog プロトコル
- RFC 5424 - Syslog プロトコル
- RFC 3339 - Date and Time on the Internet: Timestamps