pythonでsyslogの受信だったり送信だったりをする


概要

syslogseverとsyslogclient兼用のスクリプトです。
syslogの受信テストや送信テストにご利用ください。
syslogserverとして動作時は受信したsyslogを画面に表示と同時にsyslog.logファイルへ保存します。

実行環境

python3.6.9で動作確認

> python -V
Python 3.6.9 :: Anaconda, Inc.

condaで環境構築する際はこちらの記事へ
python環境構築 Miniconda3ハンズオン 複数バージョンを共存させる

pysyslogclientを追加

> pip install pysyslogclient

ソースコード

サーバ側の処理で以下の記事を参考にさせていただきました。
https://qiita.com/ranmatsu/items/f76fcc607869aeab35e3
https://gist.github.com/marcelom/4218010

syslogtool.py
"""
python3.6
"""
from datetime import datetime, timezone, timedelta
import argparse
import logging
import socketserver
import pysyslogclient #pip install pysyslogclient

#コマンドライン引数
PARSER = argparse.ArgumentParser()
PARSER.add_argument("-mode", "--mode", default="CLI", help="action mode:CLI(default) or SERVER")
PARSER.add_argument("-i", "--ip", default="127.0.0.1", help="IP or hostname(default localhost)")
PARSER.add_argument("-p", "--port", default="514", help="port number(default 514)")
PARSER.add_argument("-pr", "--protocol", default="UDP", help="TCP or UDP(default)")
PARSER.add_argument("-c", "--count", default="1", help="send count(default 1)")
PARSER.add_argument("-m", "--message", default="syslog message!!", help="syslog message")

class SyslogUDPHandler(socketserver.BaseRequestHandler):
    """
    SyslogUDPHandler
    """
    LOG_FILE = 'syslog.log'
    logging.basicConfig(level=logging.INFO, format='%(message)s',
                        datefmt='', filename=LOG_FILE, filemode='a')

    def handle(self):
        data = bytes.decode(self.request[0].strip())

        datalist = str(data).split(" ")
        datalist[1] = applytimezonejst(datalist[1])
        message = " ".join(datalist)

        socket = self.request[1]
        print(f"{self.client_address[0]}: {message}")
        logging.info(message)

def applytimezonejst(utcdate):
    """
    syslogパケット内のUTCの日付をJSTに変換して返す
    """
    _dt = datetime.strptime(utcdate, "%Y-%m-%dT%H:%M:%S.%fZ")
    _dt2 = _dt.replace(tzinfo=timezone.utc)\
            .astimezone(timezone(timedelta(hours=9)))\
            .strftime("%Y/%m/%d %H:%M:%S %Z %z")

    return _dt2


def syslogserver(host, port):
    """
    syslogserver
    """
    try:
        server = socketserver.UDPServer((host, int(port)), SyslogUDPHandler)
        print(f"start syslog server ({host}:{port})")
        server.serve_forever(poll_interval=0.5)

    except KeyboardInterrupt:
        print("Crtl+C Pressed. Shutting down.")

def syslogclient(host, port, prot, count, message):
    """
    syslogclient
    """

    client = pysyslogclient.SyslogClientRFC5424(host, port, proto=prot)

    for i in range(int(count)):
        client.log(message)
        print(f"sendcount:{str(i+1)}")

def main():
    """
    main
    """
    optargs = PARSER.parse_args()
    mode = optargs.mode
    host = optargs.ip
    port = optargs.port
    prot = optargs.protocol
    count = optargs.count
    message = optargs.message

    if mode == "CLI":
        syslogclient(host, port, prot, count, message)
    else:
        syslogserver(host, port)

if __name__ == '__main__':
    main()

使い方

  • サーバモード

下記コマンドでサーバが起動し指定したアドレス、ポートで待ち受けます。

python syslogtool.py --mode SERVER -i <IPアドレス> -p <ポート番号>
  • クライアントモード
python syslogtool.py -i <IPアドレス> -pr <UDP or TCP> -p <ポート番号> -m <syslogメッセージ> -c <送信回数>
  • help
python syslogtool.py -h
usage: syslogtool.py [-h] [-mode MODE] [-i IP] [-p PORT] [-pr PROTOCOL]
                     [-c COUNT] [-m MESSAGE]

optional arguments:
  -h, --help            show this help message and exit
  -mode MODE, --mode MODE
                        action mode:CLI(default) or SERVER
  -i IP, --ip IP        IP or hostname(default localhost)
  -p PORT, --port PORT  port number(default 514)
  -pr PROTOCOL, --protocol PROTOCOL
                        TCP or UDP(default)
  -c COUNT, --count COUNT
                        send count(default 1)
  -m MESSAGE, --message MESSAGE
                        syslog message

exe化

以下を実行するとdistフォルダの中に syslogtool.exeが生成されます。
exeを配布すれば至る所で動かせます

> pip install pyinstaller
> pyinstaller syslogtool.py --onedir --onefile --clean