そこで、PythonのSysLogHandlerを使用してsyslogにログを記録するようにPythonアプリケーションを構成しました。複数行の処理を除いて、すべてが正常に機能します。複数行のログレコードをそれほどひどく出力する必要があるわけではありません(I少しやります)が、Pythonの例外を読み取ることができる必要があります。rsyslog4.2.0でUbuntuを使用しています。これが私が得ているものです:
Mar 28 20:11:59 telemachos root: ERROR 'EXCEPTION'#012Traceback (most recent call last):#012 File "./test.py", line 22, in <module>#012 foo()#012 File "./test.py", line 13, in foo#012 bar()#012 File "./test.py", line 16, in bar#012 bla()#012 File "./test.py", line 19, in bla#012 raise Exception("EXCEPTION!")#012Exception: EXCEPTION!
必要な場合に備えてコードをテストします。
import logging
from logging.handlers import SysLogHandler
logger = logging.getLogger()
logger.setLevel(logging.INFO)
syslog = SysLogHandler(address='/dev/log', facility='local0')
formatter = logging.Formatter('%(name)s: %(levelname)s %(message)r')
syslog.setFormatter(formatter)
logger.addHandler(syslog)
def foo():
bar()
def bar():
bla()
def bla():
raise Exception("EXCEPTION!")
try:
foo()
except:
logger.exception("EXCEPTION")
わかりました、最終的にそれを理解しました...
rsyslogはデフォルトですべての奇妙な文字(ASCII <32)をエスケープし、これには改行(およびタブなど)が含まれます。これをrsyslog構成に追加して、これをオフにします。
$EscapeControlCharactersOnReceive off
または、構文解析のためにsyslogを1行でそのまま保持する場合は、ログを表示するときに文字を置き換えるだけです。
tail -f /var/log/syslog | sed 's/#012/\n\t/g'
別のオプションは、SysLogHandlerをサブクラス化してemit()
をオーバーライドすることです。送信したテキストの各行に対してスーパークラスemit()
を呼び出すことができます。何かのようなもの:
from logging import LogRecord
from logging.handlers import SysLogHandler
class MultilineSysLogHandler(SysLogHandler):
def emit(self, record):
if '\n' in record.msg:
record_args = [record.args] if isinstance(record.args, dict) else record.args
for single_line in record.msg.split('\n'):
single_line_record = LogRecord(
name=record.name,
level=record.levelno,
pathname=record.pathname,
msg=single_line,
args=record_args,
exc_info=record.exc_info,
func=record.funcName
)
super(MultilineSysLogHandler, self).emit(single_line_record)
else:
super(MultilineSysLogHandler, self).emit(record)