2011-01-20 57 views
4

我有一個具有多個處理程序的記錄程序,它們有自己的格式化程序。現在我想添加一個縮進功能,並在運行時控制縮進級別。我想要所有處理程序的消息來獲取這個縮進。我試圖將其創建爲過濾器,但發現我似乎無法更改郵件內容。然後我嘗試了它作爲格式化程序,但每個處理程序只能有一個。如何在不明確更改每個處理程序的格式化程序的情況下添加此縮進?
我應該提到,我有一個格式化程序是爲輸出添加顏色的類。它不是一個簡單的格式字符串。使用python日誌包,如何將附加格式插入到具有自己的格式化程序的多個日誌程序處理程序中?


另外,我正在使用一個配置文件。理想情況下,我希望能夠從那裏開車。但是,我需要修改縮進格式化程序的狀態(例如設置縮進級別),但我不知道如何轉到該格式化程序,因爲沒有logger.getFormatter("by_name")方法。
爲了澄清,我需要訪問特定的格式化程序實例,主要是爲了即時調整格式。該實例已由文件的logging.config創建。我沒有找到任何訪問器方法,可以讓我得到特定格式化程序的名稱。

回答

0

這裏的另一個哈克,但簡單的一個我的所有處理器的消息總是與消息級別的字符串開始就修改這些混賬?。每個縮進變化字符串:

# (make a LEVELS dict out of all the logging levels first)  
def indent(self, step = 1): 
     "Change the current indent level by the step (use negative to decrease)" 
     self._indent_level += step 
     if self._indent_level < 0: 
      self._indent_level = 0 
     self._indent_str = self._indent_str_base * self._indent_level 
     for lvl in LEVELS: 
      level_name = self._indent_str + LEVELS[lvl] 
      logging.addLevelName(lvl, level_name) 

(見我其他的答案圍繞縮進功能的東西)
現在壓頭可以是一個獨立的階級,而不與記錄過程的細節搞亂只要。該消息包含級別字符串,縮進將在那裏,即使有些東西在它之前。一般來說不理想,但可能適合我。
任何人有更多的想法,適用於任何味精格式?

4
#!/usr/bin/env python 

import logging 
from random import randint 

log = logging.getLogger("mylog") 
log.setLevel(logging.DEBUG) 

class MyFormatter(logging.Formatter): 
    def __init__(self, fmt): 
     logging.Formatter.__init__(self, fmt) 

    def format(self, record): 
     indent = " " * randint(0, 10) # To show that it works 
     msg = logging.Formatter.format(self, record) 
     return "\n".join([indent + x for x in msg.split("\n")]) 

# Log to file 
filehandler = logging.FileHandler("indent.txt", "w") 
filehandler.setLevel(logging.DEBUG) 
filehandler.setFormatter(MyFormatter("%(levelname)-10s %(message)s")) 
log.addHandler(filehandler) 

# Log to stdout too 
streamhandler = logging.StreamHandler() 
streamhandler.setLevel(logging.INFO) 
streamhandler.setFormatter(MyFormatter("%(message)s")) 
log.addHandler(streamhandler) 

# Test it 
log.debug("Can you show me the dog-kennels, please") 
log.info("They could grip it by the husk") 
log.warning("That's no ordinary rabbit!") 
log.error("Nobody expects the spanish inquisition") 
try: 
    crunchy_frog() 
except: 
    log.exception("It's a real frog") 

結果:

 
    They could grip it by the husk 
    That's no ordinary rabbit! 
      Nobody expects the spanish inquisition 
     It's a real frog 
     Traceback (most recent call last): 
      File "./logtest2.py", line 36, in 
      crunchy_frog() 
     NameError: name 'crunchy_frog' is not defined 

我不知道我理解你的第二個問題。

+0

這對我不起作用:我有一個格式化程序是爲輸出添加顏色的類。它不是一個簡單的格式字符串。另外,在配置文件中,如果我還指定格式化程序,則無法在處理程序部分中指定格式字符串。格式字符串被忽略。看起來像它希望總是看到它與格式化部分。我也澄清了問題的後半部分。 – Evgen 2011-01-20 19:42:48

0

好的,這裏有一種方法可以讓我幾乎所需。子類中的LogRecord覆蓋的getMessage插入縮進和子記錄器makeRecord它:

import logging 
import logging.config 

################################################################################ 
class IndentingLogger(logging.Logger): 
    """A Logger subclass to add indent on top of any logger output 
    """ 
    ############################################################################ 
    def __init__(self, name = 'root', logging_level = logging.NOTSET): 
     "Constructor to keep indent persistent" 
     logging.Logger.__init__(self, name, logging_level) 
     self.indenter = IndentedRecord("", logging.NOTSET, "", 0, None, None, None, None, None) 

    ############################################################################ 
    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None): 
     return self.indenter.set_record(name, level, fn, lno, msg, args, exc_info, func, extra) 


################################################################################ 
class IndentedRecord(logging.LogRecord): 
    """A LogRecord subclass to add indent on top of any logger output 
    """ 
    ######## Class data ######### 
    DEFAULT_INDENT_STR = ' ' 

    ############################################################################ 
    def __init__(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None): 
     "Constructor" 
     logging.LogRecord.__init__(self, name, level, fn, lno, msg, args, exc_info, func) 
     self._indent_level = 0 
     self._indent_str_base = IndentedRecord.DEFAULT_INDENT_STR 
     self._indent_str = "" # cache it 

    ############################################################################ 
    def set_record(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None): 
     "Constructs the base record" 
     logging.LogRecord.__init__(self, name, level, fn, lno, msg, args, exc_info, func) 
     return self 

    ################################################################################ 
    def getMessage(self): 
     "Adds indent on top of the normal getMessage result" 

     # Call base class to get the formatted message 
     message = logging.LogRecord.getMessage(self) 

     # Now insert the indent 
     return self._indent_str + message 

    ################################################################################ 
    def indent(self, step = 1): 
     "Change the current indent level by the step (use negative to decrease)" 
     self._indent_level += step 
     if self._indent_level < 0: 
      self._indent_level = 0 
     self._indent_str = self._indent_str_base * self._indent_level 

    ################################################################################ 
    def set_indent_str(self, chars): 
     "Change the current indent string" 
     if not isinstance(chars, str): 
      raise ValueError("Argument must be a string. Got %s" % chars) 
     self._indent_str_base = chars 

logging.config.fileConfig("reporter.conf") 
logging.setLoggerClass(IndentingLogger) 
logger = logging.getLogger('root') # will be wrong logger, if without argument 

logger.debug("debug message") 
logger.info("info message") 
logger.indenter.indent(+1) 
logger.warn("Indented? warn message") 
logger.indenter.set_indent_str("***") 
logger.error("Indented? error message: %s", "Oops, I did it again!") 
logger.indenter.indent(+1) 
logger.error("Indented? error message: %s", "Oops, I did it again!") 
logger.indenter.indent(-1) 
logger.critical("No indent; critical message") 

結果(實際上有色):

Debug: debug message 
Info: info message 
Warning:  Indented? warn message 
Error:  Indented? error message: Oops, I did it again! 
Error: ******Indented? error message: Oops, I did it again! 
Internal Error: ***No indent; critical message 

莫名其妙的日誌級別字符串也偷偷向前方,所以它不是我想要的。另外,這是尷尬 - 太多這樣一個簡單的功能:(
更好的想法

相關問題