Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python logging from library module

Tags:

python

logging

I am trying to setup generic logging in my Python library modules so that they use the logger configured in the calling module without having to hard code a logger name. I've seen plenty of examples using logging.basicConfig() in the calling module and calling logging.debug() in the library module, but it doesn't work when I configure my own StreamHandler. What am I doing wrong?

This is my calling module:

import logging, logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
consolehandler = logging.StreamHandler()
consoleformatter = logging.Formatter('[%(name)s] %(levelname)s %(message)s')
consolehandler.setFormatter(consoleformatter)
logger.addHandler(consolehandler)
import libmodule

def run():
    logger.info("message from calling module")
    libmodule.say("message from library module")

I've tried this in libmodule.py:

import logging

def say(msg):
    logging.info(msg)

and this:

import logging
logger = logging.getLogger()

def say(msg):
    logger.info(msg)

But in both cases when I call run(), I get this output:

[callingmodule] INFO message from calling module

but was expecting this:

[callingmodule] INFO message from calling module
[callingmodule] INFO message from library module
like image 686
Bruce Alport Avatar asked Oct 16 '14 13:10

Bruce Alport


People also ask

Is logging a module in Python?

Python comes with a logging module in the standard library that provides a flexible framework for emitting log messages from Python programs. This module is widely used by libraries and is the first go-to point for most developers when it comes to logging.

Is logging part of Python standard library?

Python provides a logging system as a part of its standard library, so you can quickly add logging to your application.

What is logging getLogger (__ Name __?

logger = logging.getLogger(__name__) This means that logger names track the package/module hierarchy, and it's intuitively obvious where events are logged just from the logger name. Sounds like good advice.


1 Answers

That's because in the first instance, you get a logger by name, and in the second, you just use getLogger(), which returns the root logger. Which is not the same one, and doesn't have your custom stream handler installed.

The easier way to do this is to follow the guidance in the docs here:

'Multiple calls to getLogger() with the same name will always return a reference to the same Logger object.'

In other words, if you just use getLogger('my_common_name') in both places, then both of them will automatically point to the same logger, even if you've customized it in one place.

Added: If you want to capture the logger from a parent, then you would do something like this in your library:

# In libmodule

_log = None

def initLogger(logger=None):
    global _log
    if logger != None:
        _log = logger
    else:
        import logging
        _log = logging.getLogger()

# Later in the module
def say(message):
    _log.info(message)

then in your parent module:

# In the parent module
mylog = a logger i set up

import libmodule
libmodule.initLogger(mylog)

That should make them both point to the same logger.

like image 157
Corley Brigman Avatar answered Oct 17 '22 08:10

Corley Brigman