python-systemd
特徴
JournalHandlerをつかえば構造化ログをjournaldに送れる
PyPIのリリース版が古く、OSの依存ライブラリが多いため、インストールがちょっと面倒
まとめ
systemd環境でpythonを動作させるなら、 python-systemd を使いたい
ログレベルをjournalctlで認識できるだけでも価値がある
ログ出力側でextraを指定すれば、絞り込みが容易になる(Webアプリのログインユーザーでの絞り込み等)
複数のログファイルに出力を分けたいニーズについては、 SYSLOG_IDENTIFIER の指定で制御可能になる
インストール
code:bash
$ sudo apt install libsystemd-dev gcc python3-dev pkg-config
$ 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': { # 全てキャッチする
'level': 'NOTSET',
},
'loggers': {
'myapp': {
'level': 'NOTSET',
'propagate': False
},
'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)
code:myapp.service
Description=MyApp
Type=oneshot
ExecStart=/home/vagrant/venv/bin/python /home/vagrant/myapp.py
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... 詳細:
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 に出力したログはログレベルが認識されているため、絞り込み可能
https://gyazo.com/a18f52817bb9c67abd9b2db5bbc84b41
1つのUnitで複数の SYSLOG_IDENTIFIER を指定できるため、目的別に指定して絞り込み可能
https://gyazo.com/40b29412ae13ad8e861666cda9f095cd
extraに指定したユーザー名で絞り込み
journalctl USER=user1
https://gyazo.com/631a1b69b3dc23966acce5201df4671b
参考