2011-03-28 143 views
34

因此,我配置了我的Python應用程序以使用Python的SysLogHandler登錄到系統日誌,並且一切正常。除了多線處理。不是我需要如此糟糕地發出多行日誌記錄(我做了一點),但我需要能夠讀取Python的異常。我使用rsyslog 4.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") 

回答

30

OK,理解了它最後...

rsyslog現在默認情況下,所有的轉義字符怪異(ASCII < 32),這包括換行符(以及製表符和其他)。另外

$EscapeControlCharactersOnReceive off 
+8

這可能會爲你的情況下工作,但如果你正在寫一個高容量的併發應用,@尼克的回答會讓你更容易找到與您的堆棧跟蹤全力以赴線。您的解決方案將會在第一行之後丟失所有行的應用程序名稱和級別名稱,從而使搜索變得困難。 – mattbornski 2012-04-26 17:59:02

+0

@mattbornski你不會失去任何信息,它只是不會在同一行。 – 2013-06-20 11:23:34

+13

「失去」我的意思是,在這種情況下,「無法重建」。在高容量的應用程序中,將日誌的含義分成多行,通常會導致不可能在多個請求中的行交錯時重新組合。 – mattbornski 2013-06-20 16:50:37

34

,如果你想保持你的系統日誌完整的一條線用於解析,您可以查看日誌時,只需更換字符:只需添加到您的rsyslog現在config來關閉這個功能。

tail -f /var/log/syslog | sed 's/#012/\n\t/g' 
+1

sed不工作,得到「等等線1 ** nt **等等線2」。但是perl的確有效:'tail -f/var/log/syslog | perl -pe's /#012/\ n \ t/g;' – user9645 2014-05-20 17:01:11

+3

sed對我很好 – spikyjt 2016-02-24 15:19:36

3

另一種選擇是子類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) 
+0

level =應該是levelno =和lineno = record.lineno丟失。但是,如果消息在\ n之後包含%s等,參數替換將無法正常工作。此代碼需要在分割之前完全參數化消息,但只有在record.levelno通過過濾器時才需要。 – Terris 2017-07-29 22:38:43