簡體   English   中英

Python:跨所有模塊的自定義日志記錄

[英]Python: custom logging across all modules

任務

我有一組腳本,我希望它們能夠生成統一的日志消息,並對記錄實際消息的模塊進行最少的改動。

我已經編寫了一個小模塊“custom_logger”,我計划從主應用程序調用一次,讓它返回一個記錄器,然后我會繼續使用它。

我要導入應用程序的子模塊應該只(或者我希望它們)

  • 應該只“將日志記錄導入為日志” - 這樣如果其他人發現它們有用,就不需要任何特定於我的站點的東西來使它們運行。
  • 應該只用 log.info/error('message') 記錄消息而不添加任何特定於它們的站點
  • 應該使用已配置的“root”記錄器及其所有格式和處理程序,而不影響根記錄器的配置

*custom_logger.py*

import logging
import logging.handlers
import os
import sys


def getLogger(name='root', loglevel='INFO'):
  logger = logging.getLogger(name)

  # if logger 'name' already exists, return it to avoid logging duplicate
  # messages by attaching multiple handlers of the same type
  if logger.handlers:
    return logger
  # if logger 'name' does not already exist, create it and attach handlers
  else:
    # set logLevel to loglevel or to INFO if requested level is incorrect
    loglevel = getattr(logging, loglevel.upper(), logging.INFO)
    logger.setLevel(loglevel)
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
    fmt_date = '%Y-%m-%dT%T%Z'
    formatter = logging.Formatter(fmt, fmt_date)
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    if logger.name == 'root':
      logger.warning('Running: %s %s',
                     os.path.basename(sys.argv[0]),
                     ' '.join(sys.argv[1:]))
    return logger

然后是子模塊,它有一些測試消息,其中包含有效和無效的示例。

子模塊.py

import sys
import custom_logger
import logging


class SubClass(object):

  def __init__(self):
    # NOK (no idea why since by default (no name parameter), it should return the root logger)
    #log = logging.getLogger()
    #log.info('message from SubClass / __init__')

    # OK (works as expected)
    #log = logging.getLogger('root')
    #log.info('message from SubClass / __init__')

    # OK (works as expected)
    log = custom_logger.getLogger('root')
    log.info('message from SubClass / __init__')


  def SomeMethod(self):
    # OK but I'd have to define `log` for every method, which is unacceptable
    # Please see question below all code snippets
    log = custom_logger.getLogger('root')
    log.info('message from SubClass / SomeMethod')

和主應用程序: app.py這里沒什么特別的:

#!/usr/bin/python

import custom_logger
import submodule

log = custom_logger.getLogger('root', loglevel='DEBUG')

log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')

a = submodule.SubClass() # this should produce a log message
a.SomeMethod()           # so should this

我追求的和我得到的輸出,只是以一種非常丑陋的方式:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py   WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py             DEBUG   : debug message
2013-04-08T03:07:46BST app.py             INFO    : info message
2013-04-08T03:07:46BST app.py             WARNING : warning message
2013-04-08T03:07:46BST app.py             ERROR   : error message
2013-04-08T03:07:46BST submodule.py       INFO    : message from SubClass / __init__
2013-04-08T03:07:46BST submodule.py       INFO    : message from SubClass / SomeMethod

我希望能夠在 app.py 中定義一個記錄器,然后在子模塊中僅使用標准 Python 日志記錄庫來使用 app.py 中已配置的記錄器。

另外,一個丑陋的解決方法:如果我將下面的代碼放在 submodule.py 中的導入之后:

log = custom_logger.getLogger('root')

它將在 app.py 中配置我的記錄器之前執行,從而有效地創建子模塊,而不是我的應用程序配置日志記錄。

我考慮的另一種解決方法:在 SubClass 類的構造函數中,我可以定義

self.log = custom_logger.getLogger('root')

然后使用 self.log.error('some error')。 一定有更好的方法 - 如果您能提出有用的建議或指出我誤解文檔的地方,我將不勝感激!

附注。 我花了很多時間閱讀 Python logging howto(基本和高級)和食譜,所以如果我錯過了一些有用的東西,請指出。

謝謝!

如果你想改變根記錄器,你可以在任何地方使用getLogger() ,不帶參數。

關於僅在主模塊中設置的實例,您可以實例化您的記錄器,添加您自己的處理程序,並在所有其他子模塊中使用它(就像我在下面所做的那樣)。

我在custom_logger.py創建了一個繼承 StreamHandler 的custom_logger.py

class MyHandler(logging.StreamHandler):

    def __init__(self):
        logging.StreamHandler.__init__(self)
        fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
        fmt_date = '%Y-%m-%dT%T%Z'
        formatter = logging.Formatter(fmt, fmt_date)
        self.setFormatter(formatter)

然后,在submodule.py ,我將 getLogger 放在導入之后並在方法中對其進行注釋:

import sys
import logging

log = logging.getLogger('root')

class SubClass(object):

    def __init__(self):
         log.info('message from SubClass / __init__')

    def SomeMethod(self):
        log.info('message from SubClass / SomeMethod')

然后,在 app.py 中,我創建了一個 Logger 實例(在所有模塊中都相同)並添加了我的處理程序,用於格式化輸出:

#!/usr/bin/python

import logging
import custom_logger
import submodule

log = logging.getLogger('root')
log.setLevel('DEBUG')
log.addHandler(custom_logger.MyHandler())

log.debug('debug message') 
log.info('info message')
log.warning('warning message')
log.error('error message')

a = submodule.SubClass() # this should produce a log message
a.SomeMethod()           # so should this

輸出:

./app.py 
2013-04-08T15:20:05EEST app.py             DEBUG   : debug message
2013-04-08T15:20:05EEST app.py             INFO    : info message
2013-04-08T15:20:05EEST app.py             WARNING : warning message
2013-04-08T15:20:05EEST app.py             ERROR   : error message
2013-04-08T15:20:05EEST submodule.py       INFO    : message from SubClass / __init__
2013-04-08T15:20:05EEST submodule.py       INFO    : message from SubClass / SomeMethod

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM