2012-06-29 6 views
3

Я пытаюсь использовать модуль регистрации python для создания пользовательского файла журнала, который записывает другую информацию, такую ​​как имя хоста, и добавляет ее в мою БД. Ниже приведены классы я создал, чтобы сделать это, и Handler часть работала просто отлично, но теперь, когда я добавил пользовательский класс LogRecord, он выдает эту ошибку:python logging: Custom Python LogRecord Throwing error

/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 
+1

Вы не предоставили достаточно кода для воспроизведения проблемы. Даже после удаления ссылок на классы, которые вы не включили (FirehoseLogRecord, MongoLogger), я не могу воспроизвести эту ошибку, которую вы описываете. –

+0

Извините, что обновил вопрос. Это не должно быть FirehoseLogRecord, это должен был быть MyLogRecord, что и вызывает проблему. – Nathan

+0

Смотрите, он умирает от суперкласса init. Является ли простой 'logging.LogRecord .__ init__' умирать в _same аргументе list_? – 9000

ответ

10

Ошибка говорит вам точно, что не так; вы вызываете конструктор со слишком большим количеством аргументов. Для того, чтобы увидеть, что я имею в виду, посмотрите на то, как лог-записи обычно построены в реализации по умолчанию 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 принимает extra параметров, что он не проходит непосредственно LogRecord? С другой стороны, вы передаете это прямо на LogRecord.__init__, что вызывает ошибку.

Здесь у вас есть два варианта; вы можете предоставить более полную реализацию 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) 

Если вам нужно вычислить значение «хозяина» (к примеру) каждый раз, когда что-то вошедший, вы могли бы сделать 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 и добавление контекста к вашим журналам можно найти в python docs.

ПРИМЕЧАНИЕ. Я не включил MyLogHandler, MyLogFormatter или MongoLogger в мои примеры, поскольку они не имели отношения к проблеме/ошибке.

+0

Это имеет гораздо больший смысл, я заметил, что после того, как вернулся к тому, где я получил информацию, чтобы восстановить это для себя, код был опубликован 5 лет назад. С тех пор немного изменилось. :) http: //code.activestate.com/recipes/474089-extend-the-logging-module/Я думаю, что я должен собрать все это вместе, чтобы написать свои собственные журналы в БД. Большое вам спасибо за подробное объяснение! – Nathan

+0

LoggingAdapter выглядит как путь, плюс я потратил столько времени на общение с журналами, я думаю, что все это размыто вместе, гораздо яснее! – Nathan

+0

Я предполагаю, что у LoggerAdapter нет logging.getLogger ('testing'), чтобы было легко найти это во всем приложении? – Nathan