python日志:自定义python日志记录引发错误

python日志:自定义python日志记录引发错误,python,logging,Python,Logging,我试图使用python日志模块创建一个自定义日志文件,该文件记录主机名等其他信息,并将其添加到我的数据库中。下面是我为此创建的类,处理程序部分工作得很好,但是现在我添加了一个自定义的LogRecord类,它抛出了以下错误: /src/lib/__init__.py", line 31, in __init__ logging.LogRecord.__init__(self, *args, **kwargs) exceptions.TypeError: __init__() takes at mo

我试图使用python日志模块创建一个自定义日志文件,该文件记录主机名等其他信息,并将其添加到我的数据库中。下面是我为此创建的类,处理程序部分工作得很好,但是现在我添加了一个自定义的
LogRecord
类,它抛出了以下错误:

/src/lib/__init__.py", line 31, in __init__
logging.LogRecord.__init__(self, *args, **kwargs)
exceptions.TypeError: __init__() takes at most 9 arguments (10 given)
下面是我如何执行它的

logging.setLoggerClass(MyLogger)

log = logging.getLogger('testing')
log.addHandler(MyLogHandler())
d = {'host': '192.168.0.1'}
log.warn('Hi', d)    
这是课程。它显然与*args、**kwargs有关,但是当我看它时,*args是空的,**kwargs只包含上面指定的
d
变量。我不明白这个问题

class MyLogRecord(logging.LogRecord):
    def __init__(self, *args, **kwargs):
        logging.LogRecord.__init__(self, *args, **kwargs) //THIS IS THE LINE IT DIES ON
        self.host = 'localhost'

class MyLogFormatter(logging.Formatter):

    def __init__(self, fmt, datefmt=None, host=None):
        logging.Formatter.__init__(self, fmt, datefmt)
        self.host = host

    def format(self, record):
        return logging.Formatter.format(record)

class MyLogger(logging.getLoggerClass()):
    def makeRecord(self, *args, **kwargs):
        return MyLogRecord(*args, **kwargs)

class MyLogHandler(logging.Handler): # Inherit from logging.Handler
    def __init__(self):
        # run the regular Handler __init__
        logging.Handler.__init__(self)
        # Our custom argument
        self.mongo = MongoLogger()

    def setupCustomLogger(self, name, this_host):
        formatter = MyLogFormatter(fmt='%(asctime)s - %(levelname)s - %(module)s - %(message)s - %(host)s')

        handler = logging.StreamHandler()
        handler.setFormatter(formatter)

        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        logger.addHandler(handler)
        return logger

    def emit(self, record):
        # record.message is the log message
        self.mongo.log(record)


class MongoLogger(object):

'''Logs messages to a MongoDB fh_admin log collection.'''
def log(self, message):
    #@todo write log to DB
    print message

错误是告诉你到底出了什么问题;您正在使用太多参数调用构造函数。要了解我的意思,请看一下在
makeRecord
的默认实现中通常是如何构造日志记录的:

def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
    """
    A factory method which can be overridden in subclasses to create
    specialized LogRecords.
    """
    rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
    if extra is not None:
        for key in extra:
            if (key in ["message", "asctime"]) or (key in rv.__dict__):
                raise KeyError("Attempt to overwrite %r in LogRecord" % key)
            rv.__dict__[key] = extra[key]
    return rv
注意makeRecord如何获取一个不直接传递给
LogRecord
额外的
参数?另一方面,您正在将其直接传递给
LogRecord.\uuuu init\uuuu
,这导致了错误

从这里开始,你有两个选择;您可以提供一个更完整的
makeRecord
实现,也可以尝试使用
LoggerAdapter
类,该类可以帮助您以更少的代码实现相同的目标

下面是一个例子:

# Common log info to be added to all logs reported with `log_adapter`
context = {'host': 'localhost'}

log = logging.getLogger('testing')
log.addHandler(logging.StreamHandler())
d = {'host': '192.168.0.1'}

log_adapter = logging.LoggerAdapter(log, context)
log_adapter.warning('Hi', d)
如果每次记录某个内容时都需要计算“host”(例如)的值,则可以将
context
设置为类的实例,该类看起来像字典。像这样:

class LogContext(object):

    def __getitem__(self, key):
        if key == 'host':
            return 'localhost'
        raise KeyError(key)

    def __iter__(self):
        return iter(['host'])

log_adapter = logging.LoggerAdapter(log, LogContext())
log_adapter.warning('Hi', d)
关于
LoggingAdapter
需要注意的一点是,它显然没有将所有方便的快捷方式函数定义为普通的Logger类。这就是为什么我调用了
warning
方法,而不是像上面那样调用
warn

有关
LoggingAdapter
和向日志添加上下文的更多信息,请参阅


注意-我没有在示例中包括
MyLogHandler
MyLogFormatter
MongoLogger
,因为它们与问题/错误无关。

您没有提供足够的代码来重现问题。即使删除了对未包含的类(FirehoseLogRecord、MongoLogger)的引用,我也无法重现您描述的此错误抱歉,我已更新了问题。它不应该是FirehoseLogRecord,它应该是MyLogRecord,这就是导致问题的原因。普通的
logging.LogRecord.\uuuuu init\uuuuu
是否在同一个参数列表中消亡?这更有意义,我注意到,在我回到我获取信息的地方为自己重新构建它之后,代码是在5年前发布的。从那以后可能有一点变化。:)我想我应该能够将所有这些拼凑起来,将我的自定义日志写入数据库。非常感谢您的详细解释!LoggingAdapter看起来是一个不错的选择,加上我花了太多时间在日志上乱搞,我想它都模糊在一起了,现在清晰多了!我猜LoggerAdapter没有logging.getLogger('testing')以便在整个应用程序中轻松找到它?@Hallik我不知道,但是您可以创建一个简单的函数来执行类似的操作,例如:
def getLogAdapter(name):context={};logging.LoggerAdapter(logging.getLogger(名称)、上下文)
。或者你只需在某个模块中实例化此适配器,然后在需要使用它的任何地方导入它,或者(根据你的应用程序的构造时间,只需将其传递给他人即可。非常好。我将使用
过滤器
。谢谢!