C#プログラムからsyslog(rsyslog)サーバーにログを送る
ログを記録するプログラムとしてsyslogは有名かと思います。
このsyslogサーバーはローカルで動作するアプリケーションのログだけでなく、他のPCからのログも受付け、保存ができることはご存じでしょうか。
本記事では他PCからログを記録するrsyslogサーバーをDockerコンテナで起動し、ログの送信はC#アプリケーションから、というものを紹介します。
どちらも単独機能でみると需要が少ないように感じますが、このいずれか、もしくは両方を求めていた人には刺さる記事になっていることと思います。
Docker で rsyslog を起動
Dockerコンテナでrsyslogを起動します。
このとき、既に用意されているrsyslogコンテナを使うのもよいでしょうが、ここでは以下のようにしてコンテナで手動で起動させてみます。
ポートは514番で、TCP/UDPどちらも接続を受け付けるものとして、このようなポート指定が必要です。プロトコルの指定を除外すると 手元ではUDPでのデータ受信が動作しないようでした。
$ docker run -it -p 514:514/tcp -p 514:514/udp ubuntu:22.04 bash
rsyslog のインストールと設定
コンテナでUbuntuが起動した後は、以下のコマンドを実行して rsyslog をインストールします。
# apt update
# apt install -y rsyslog nano
設定ファイルは /etc/rsyslog.conf
ファイルです。このファイルを編集して、TCPとUDPのログデータを受け付けるようにコメントアウトを外します。
module(load="imudp")
input(type="imudp" port="514")
module(load="imtcp")
input(type="imtcp" port="514")
ちゃんとするならば、ここで受け付けるIPアドレスの範囲などを設定し、むやみに情報を受け取らないようにします。これは $AllowedSender TCP, 127.0.0.1
などのように設定をします。
今回は実験の意味合いが強いのでこのまま無制限にします。
起動
基本的に systemd がコンテナの中では起動しないので、以下のコマンドを実行して単独での実行とします。このコマンドを Windows のシェル(PowerShell)で実行すると CTRL+C も受け付けないようなので注意してください。
$ rsyslogd -n
これでログ情報はrsyslogサーバーに送られれば、/var/log/syslog
ファイルに記録される状態となります。
C#からsyslogへログを送信する
ログ出力用のモジュールとしてSerilogを使います。そしてこのSerilogのサブのモジュールとしてSerilog.Sinks.SyslogMessagesを使います。
NuGetパッケージが用意されているので、下記のものをインストールします。
なおリポジトリはこちらです。
ログを送るコード
以下のような C# 実装をして、ログを送ります。とてもシンプルですね。
using Serilog;
using Serilog.Sinks.Syslog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.TcpSyslog(host: "xxx.yyy.zzz.1", port: 514, format: SyslogFormat.RFC3164)
.CreateLogger();
Log.Error("Hello, syslog message!!");
Log.CloseAndFlush();
なお、UDPで送りたい場合には、.WriteTo.UdpSyslog( ... )
にします。
ログを送信後、syslogサーバー側で /var/log/syslog
ファイルを確認すると、以下のようなメッセージが出力されていることが確認できます。
Jan 6 17:44:03 TECHMADEVPC ConsoleApp1[167636]: Hello, syslog message!!
もし、このようなログが記録されない場合には、受け取り側のファイアウォールの設定の見直しや、rsyslogサーバーが起動して待ち受け状態になっているか、TDP/UDPどちらかは受け取れるのか?あたりから調べてみるとよいでしょう。
ログの形式について
Serlogでログを出力する際に、TCPとUDPを切り替えると出力されるメッセージが変わる、という状況に遭遇しました。具体的には以下のように、メッセージ本文の前に ":" が含まれるかどうか、という点で変わりました。
Jan 6 17:44:03 TECHMADEVPC ConsoleApp1[167636]: Hello, syslog message!!
Jan 6 17:44:03 TECHMADEVPC ConsoleApp1[167636] Hello, syslog message!!
これについては、formatの指定を明示的に設定することで解決します。 SyslogFormat.RFC3164
を使うと、TCP/UDPどちらでも":"ありの出力結果です。
おまけ: PowerShell からsyslogサーバーへログ送信
PowerShell からsyslogサーバーへ向けてログを送信することができるようです。
以下のZennページで紹介されている「syslog を送信します」紹介します。
$syslogServer = "127.0.0.1"
$syslogPort = 514
$udpClient = New-Object System.Net.Sockets.UdpClient
$udpClient.Connect($syslogServer, $syslogPort)
$bytes = [Text.Encoding]::ASCII.GetBytes("<134>Oct 29 23:59:59 MyHost MyApp: Test message")
$udpClient.Send($bytes, $bytes.Length)
$udpClient.Close()
C#のプログラムを作らなくても、PowerShellでこのコマンド列を実行すればメッセージを送れるので、調査の際には有用だと思います。
Discussion