🦔

C#プログラムからsyslog(rsyslog)サーバーにログを送る

2024/01/09に公開

ログを記録するプログラムとして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パッケージが用意されているので、下記のものをインストールします。

なおリポジトリはこちらです。
https://github.com/IonxSolutions/serilog-sinks-syslog

ログを送るコード

以下のような 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 を送信します」紹介します。

https://zenn.dev/microsoft/articles/25e9bf687aff6f

$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