python-systemd
Pythonのloggingをsystemd/journaldと接続して構造化情報を送信するライブラリ。
https://github.com/systemd/python-systemd
特徴
JournalHandlerをつかえば構造化ログをjournaldに送れる
PyPIのリリース版が古く、OSの依存ライブラリが多いため、インストールがちょっと面倒
まとめ
systemd環境でpythonを動作させるなら、 python-systemd を使いたい
systemd+gunicorn設定と併存可能
ログレベルをjournalctlで認識できるだけでも価値がある
ログ出力側でextraを指定すれば、絞り込みが容易になる(Webアプリのログインユーザーでの絞り込み等)
複数のログファイルに出力を分けたいニーズについては、 SYSLOG_IDENTIFIER の指定で制御可能になる
インストール
code:bash
$ sudo apt install libsystemd-dev gcc python3-dev pkg-config
$ pip install git+https://github.com/systemd/python-systemd.git#egg=systemd
$ pip freeze
pkg-resources==0.0.0
systemd-python==235
(おまけ)同じOSの他マシンで使う用にwheelを用意しておくと便利
上記手順のapt install はsystemd-pythonのビルドに必要だったけど、実行用としては不要
ビルド結果をwhlファイルにまとめて、これを別環境にもっていってインストールすればよい
code:bash
$ pip install wheel
$ pip wheel systemd-python
$ ls
systemd_python-235-cp36-cp36m-linux_x86_64.whl
構造化ログの送信実験
実行コード
code:myapp.py
import logging
from logging.config import dictConfig
config = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(levelname)s %(asctime)s %(name)s %(process)d %(message)s'
},
},
'handlers': {
'stream': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard'
},
'journald-myapp': {
'level': 'DEBUG',
'class': 'systemd.journal.JournalHandler',
'formatter': 'standard',
'SYSLOG_IDENTIFIER': 'myapp',
},
'journald-payment': {
'level': 'DEBUG',
'class': 'systemd.journal.JournalHandler',
'formatter': 'standard',
'SYSLOG_IDENTIFIER': 'myapp-payment',
},
},
'root': { # 全てキャッチする
'handlers': 'stream', 'journald-myapp',
'level': 'NOTSET',
},
'loggers': {
'myapp': {
'handlers': 'stream', 'journald-myapp',
'level': 'NOTSET',
'propagate': False
},
'payment': {
'handlers': 'stream', 'journald-payment',
'level': 'NOTSET',
'propagate': False
},
},
}
dictConfig(config)
logger_myapp = logging.getLogger('myapp')
logger_payment = logging.getLogger('payment')
for user in ('user1', 'user2', 'user3'):
extra = {'USER': user}
logger_myapp.debug( "Some %s message: %s", 'debug', 'detail', extra=extra)
logger_myapp.info( "Some %s message: %s", 'info', 'detail', extra=extra)
logger_myapp.warning("Some %s message: %s", 'warning', 'detail', extra=extra)
logger_myapp.error( "Some %s message: %s", 'error', 'detail', extra=extra)
logger_payment.debug( "Some %s message: %s", 'debug', 'detail', extra=extra)
logger_payment.info( "Some %s message: %s", 'info', 'detail', extra=extra)
logger_payment.warning("Some %s message: %s", 'warning', 'detail', extra=extra)
logger_payment.error( "Some %s message: %s", 'error', 'detail', extra=extra)
systemd設定 (document)
code:myapp.service
Unit
Description=MyApp
Service
Type=oneshot
ExecStart=/home/vagrant/venv/bin/python /home/vagrant/myapp.py
Install
WantedBy=multi-user.target
インストール
code:bash
$ sudo ln -s /etc/systemd/system/myapp.servicde ./myapp.service
$ systemctl daemon-reload
$ sudo systemctl enable myapp
Created symlink /etc/systemd/system/multi-user.target.wants/myapp.service → /home/xxx/myapp.service.
実行
code:bash
$ sudo systemctl start myapp
ログ確認
code:bash
$ (venv) vagrant@ubuntu-bionic:~$ sudo journalctl -u myapp
-- Logs begin at Fri 2019-09-06 03:20:19 UTC, end at Mon 2019-09-09 10:16:43 UTC. --
Sep 09 10:08:45 ubuntu-bionic systemd1: Starting MyApp...
Sep 09 10:08:45 ubuntu-bionic python8935: DEBUG 2019-09-09 10:08:45,417 myapp 8935 Some debug message: detail
Sep 09 10:08:45 ubuntu-bionic myapp8935: DEBUG 2019-09-09 10:08:45,417 myapp 8935 Some debug message: detail
詳細:
https://gyazo.com/e2962505ad987098e2b24d5516fdadff
journalctlのフォーマット:
<日時> <HOST> <SYSLOG_IDENTIFIER>[<PROCESS_ID>]: <log-message>
python loggerのフォーマット(上記の<log-message>部分):
<LOG_LEVEL> [<DATETIME>] <LOGGER_NAME> <PROCESS_ID> <message>
loggerのformatterで指定した内容
log出力時に指定したextraの内容はformatterに指定すれば表示される
StreamHandler に出力したログは SYSLOG_IDENTIFIER=python で出力される
JournalHandler に出力したログは指定した SYSLOG_IDENTIFIER (myapp, myapp-payment) で出力される
JournalHandler に出力したログはログレベルが認識されているため、絞り込み可能
journalctl -p warning (-pのdocument)
https://gyazo.com/a18f52817bb9c67abd9b2db5bbc84b41
1つのUnitで複数の SYSLOG_IDENTIFIER を指定できるため、目的別に指定して絞り込み可能
journalctl -t myapp (-tのdocument)
https://gyazo.com/40b29412ae13ad8e861666cda9f095cd
extraに指定したユーザー名で絞り込み
journalctl USER=user1
https://gyazo.com/631a1b69b3dc23966acce5201df4671b
参考
How To Use Journalctl to View and Manipulate Systemd Logs | DigitalOcean
Logging to systemd in Python - Thomas Stringer - Medium
systemd.journal module — python-systemd 234 documentation
https://www.freedesktop.org/software/systemd/man/journalctl.html
Python Logging 入門