2

I'm trying to create a custom logger this way:

File: logger.py

import logging

class Logger(logging.getLoggerClass()):
    def warning(self, msg, *args, **kwargs):
        super(Logger, self).warning(msg, *args, **kwargs)

logging.setLoggerClass(Logger)
log = logging.getLogger('test')
handler = logging.StreamHandler()
formatter = logging.Formatter('%(pathname)s')
handler.setFormatter(formatter)
log.addHandler(handler)

File: test.py

from logger import log

log.warning('')

Output:

$ python test.py
/home/dario/Desktop/logging_test/logger.py

The expected output would be:

/home/dario/Desktop/logging_test/test.py

What's even weirder, if I comment the setLoggerClass line I do get test.py, but without the full path.

What am I doing wrong? Thank you!

Tested with Python 2.7.4 and 3.3.1 on Arch Linux x86_64.

kynikos
  • 1,152
  • 4
  • 14
  • 25
  • Is there any particular reason you need to subclass the logger class? – Aya Apr 20 '13 at 16:56
  • My goal is formatting the log messages in different ways depending on their level; everything works fine except for this thing, but I'm still testing it 'cause I'm pretty sure at some point in the development I was indeed getting the right path – kynikos Apr 20 '13 at 17:21
  • Probably simpler to use [Handlers](http://docs.python.org/2/howto/logging.html#handlers). – Aya Apr 20 '13 at 17:29
  • Is there a way to make a handler handle only one specific log level (e.g. INFO) ignoring all the others? – kynikos Apr 20 '13 at 17:35
  • Yep, using filters, thanks! I'll look into that, but first I want to understand this behaviour fully :) – kynikos Apr 20 '13 at 17:46

1 Answers1

0

From the Python Documentation - Logging - LogRecord attributes:

%(pathname)s - Full pathname of the source file where the logging call was issued (if available).

I.e. where a logging object, (or any subclass, like Logger) was initialized.
In this case logging and your instance of it, log, is both defined and initialized in the same file test.py.

Maybe it's a bit clearer if I split up the files:

logger.py: (the class)

import logging                                           

# This is the path `logging` gets                        
class Logger(logging.getLoggerClass()):                  
    def warning(self, msg, *args, **kwargs):             
        super(Logger, self).warning(msg, *args, **kwargs)

log.py: (a log module which has a log object of the type Logger)

import logging
from logger import Logger

logging.setLoggerClass(Logger)
log = logging.getLogger('test')
handler = logging.StreamHandler()

# Not this file's path, but where class Logger
# creates a logging object with super()
formatter = logging.Formatter('%(pathname)s')
handler.setFormatter(formatter)
log.addHandler(handler)

test.py: (main)

from log import log

log.warning('')    
timss
  • 9,982
  • 4
  • 34
  • 56
  • More correctly, it's where the base logger class's method was called from, not where it was defined, although they happen to be the same file in this example. – Aya Apr 20 '13 at 16:54
  • 1
    Then why if I don't extend Logger, pathname doesn't return `/usr/lib/.../logging/__init__.py` (where the original `Logger` class is defined) but `test.py`? – kynikos Apr 20 '13 at 17:32
  • @kynikos Again, it's where the `warning()` method was called from, not where it was defined. – Aya Apr 20 '13 at 17:56
  • So it's because of the `super` call, sorry I didn't get it. Then I guess there's _no way_ to get the correct pathname when extending the Logger class this way... Thank you again – kynikos Apr 20 '13 at 18:02
  • @kynikos You could use `%(name)` instead. Take a look at [logging configuration](http://docs.python.org/2/howto/logging.html#configuring-logging) to make it easier to use. – timss Apr 20 '13 at 18:08
  • Thanks timss, however I need the path of the file where the call was made, not the logger name, which is what `%(name)` displays; anyway solving this problem with filters, as mentioned in the comments to the question, is a better solution – kynikos Apr 20 '13 at 18:19
  • @kynikos actually, you can get the correct pathname, but it's much more complicated than using handlers. – Aya Apr 20 '13 at 18:23
  • Yeah I've had a look at the source of the logging module to see how it gets pathname, I should probably override more classes/methods, really not worth it ^^' – kynikos Apr 20 '13 at 18:36