1

I have the following handler:

import logging 
from peewee import * 

db = SqliteDatabase("my_app.db") 

class Log(Model): 
    message = CharField() 
    class Meta: 
        database = db 

Log.create_table(db) 

class DatabaseHandler(logging.Handler): 
    def emit(self, record): 
        try: 
            event = Log( 
                message=record.message 
            ) 
            event.save() 

        except Exception: 
            self.handleError(record)

And when I do:

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(DatabaseHandler)
logger.info("something")   

I get the following error message:

Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
  File "/home/raf/miniconda3/lib/python3.7/logging/__init__.py", line 1383, in info
    self._log(INFO, msg, args, **kwargs)
  File "/home/raf/miniconda3/lib/python3.7/logging/__init__.py", line 1519, in _log
    self.handle(record)
  File "/home/raf/miniconda3/lib/python3.7/logging/__init__.py", line 1529, in handle
    self.callHandlers(record)
  File "/home/raf/miniconda3/lib/python3.7/logging/__init__.py", line 1590, in callHandlers
    if record.levelno >= hdlr.level:
AttributeError: type object 'DatabaseHandler' has no attribute 'level'

I only could find this error in one other place (https://github.com/GNS3/gns3-gui/issues/2109) and it has no solution.

It's probably because I wrote the handler incorrectly, I'd appreciate it if anyone could help!

Greg Sadetsky
  • 4,863
  • 1
  • 38
  • 48
Atonal
  • 520
  • 4
  • 14

2 Answers2

4

As far as I can tell you are trying to inherit in DatabaseHandler the Handler object.

The official documentation states: "Note that Handler is never instantiated directly; this class acts as a base for more useful subclasses. However, the init() method in subclasses needs to call Handler.init()." As far as I can tell you should initialise the the handler in your class.

polar_bear
  • 41
  • 1
  • You mean something like this? ``` class DatabaseHandler(logging.Handler): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) ... ``` I still get the same error message though. – Atonal Feb 22 '20 at 01:05
1

As correctly pointed out by @polar_bear, DatabaseHandler needs to be instantiated before being passed to addHandler. Another problem was accessing record.message when you should be accessing record.msg (someone found this here).

Here's the corrected code:

import logging 
from peewee import * 

db = SqliteDatabase("my_app.db") 

class Log(Model): 
    message = CharField() 
    class Meta: 
        database = db 

Log.create_table(db) 

class DatabaseHandler(logging.Handler): 
    def emit(self, record): 
      try: 
          event = Log( 
              message=record.msg
          ) 
          event.save() 

      except Exception: 
          self.handleError(record)

dh = DatabaseHandler()

logger = logging.getLogger(__name__) 
logger.setLevel(logging.DEBUG) 
logger.addHandler(dh)
logger.info("something")
Greg Sadetsky
  • 4,863
  • 1
  • 38
  • 48
  • Awesome! Thanks! And do you why I have to do `record.msg`? Judging by (https://docs.python.org/3/library/logging.html#logrecord-objects) `message` should be the attribute and `msg` an argument of a LogRecord. Does this mean `record` is not yet instantiated when it's passed to `emit` function? – Atonal Feb 22 '20 at 01:14
  • 1
    Great question! Python source code to the rescue :-) It seems that the `message` attribute gets set on the record in the record's formatter's `format()` method call -- [see here](https://github.com/python/cpython/blob/3.8/Lib/logging/__init__.py#L664). So: `msg` is the "real", initial message, while `message` is the human-readable representation of it which does get set (some point after emit). It also makes sense, as `msg` is formatted using `args` -- `message` is the end result of that formatting -- [see here under `msg`](https://docs.python.org/3/library/logging.html#logrecord-attributes)) – Greg Sadetsky Feb 22 '20 at 01:29
  • 1
    ... which also means that you might want to do `message=record.msg % record.args` :-) – Greg Sadetsky Feb 22 '20 at 01:32