38

そこで、PythonのSysLogHandlerを使用してsyslogにログを記録するようにPythonアプリケーションを構成しましたが、すべて正常に動作します。複数行の処理を除きます。複数行のログレコードをそれほどひどく出力する必要があるわけではありませんが(少しは実行します)、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")
4

3 に答える 3

38

または、構文解析のためにsyslogを1行のままにしておきたい場合は、ログを表示するときに文字を置き換えるだけです。

tail -f /var/log/syslog | sed 's/#012/\n\t/g'
于 2012-04-26T17:50:51.320 に答える
36

OK、ついにそれを理解しました...

rsyslogは、デフォルトですべての奇妙な文字(ASCII <32)をエスケープします。これには、改行(およびタブなど)が含まれます。

$ EscapeControlCharactersOnReceive:

このディレクティブは、メッセージの受信中に制御文字を置き換えるようにrsyslogdに指示します。印刷できないメッセージがsyslogシステム全体に入るのを防ぐ方法を提供することを目的としています。このオプションをオンにすると、すべての制御文字が3桁の8進数に変換され、接頭辞として$ ControlCharacterEscapePrefix文字(デフォルトでは「\」)が付けられます。たとえば、メッセージにベル文字(ctrl-g)が含まれている場合、「\007」に変換されます。

これをrsyslog構成に追加するだけで、オフにできます。

$EscapeControlCharactersOnReceive off

または、「新しい」高度な構文を使用します。

global(parser.escapeControlCharactersOnReceive="off")
于 2011-04-04T20:46:21.257 に答える
3

もう1つのオプションは、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)
于 2016-06-02T08:54:23.170 に答える