views:

68

answers:

3

When coding python, I use the logging module a lot.

After some bad experiences and reading articles like this one, I try to prevent import-time executed code wherever possible.

However, for the sake of simplicity, I tend to get my logging object right at the beginning of the module file:

# -*- coding: utf-8 -*-
import logging
logger = logging.getLogger('product.plugin.foo.bar')

This way, my logger is globally accessible and I can just write "logger.error()" anywhere. The alternative is to create it class-wide:

class Bar(object):
    logger = logging.getLogger('product.plugin.foo.bar')

However, now I have to type the Class name everytime. To prevent typing the class name, I am tempted to use "self" instead, which will fail in static methods.

    def my_method(self):
        Bar.logger.error('foo')

    def my_method_2(self):
        self.logger.error('foo') # ok...

    @staticmethod
    def my_method_2():
        self.logger.error('foo') # boom!

So, at first, it looks like creating the logger object module-wide seems like the right thing to do - still it feels like I could end up in import-related trouble when doing it like this...

A: 

Damn - I realized it the second after I posted that question, that my "alternative" actually is not any different: the logger is created at import-time as well ;)

Still, I'm interested in your opinions on the best way to handle this issue. Another advantage of the first solution: We have some situations where we have to check on the availability of modules using import statements in try/except blocks. By creating the logger right at the beginning of the file, you can already use it to log this kind of events.

Chris089
+2  A: 

It's fine. I even use the same variable name logger. Any logging is better than no logging, but I find it's nice practise to only expose the logger variable, keep the module hidden away so your code only references the logger, and hence the namespace you've designated for the module.

If you later need to refine the namespaces for code within the module, you can use self.logger within those classes, or shadow the global logger where necessary.

Update0

__all__ = [anything but logger]
import logging
logger = logging.getLogger("why.is.this.method.still.java.camel.case")
del logging

Taking note of S.Lott's contribution below. Also note that generally you don't want from x import * anyway.

Matt Joiner
It's fine as long as you avoid `from my_module import *` which introduces `logger` into a local namespace in a potentially confusing way.
S.Lott
Exactly - now if two modules use the logger variable and one imports the other, then its own logger will be overwritten, right? So, we could use the module-wide logger, but rename it to _logger and everything should be fine, no?
Chris089
@Matt: How do you "keep the module hidden away"?
Chris089
@S.Lott: Thinking about it further, while using a wildcard import is a sign of bad design anyway (IMHO), I now prefer using the leading _ variable name...
Chris089
Sounds good chris. `_logger` is better than accidentally importing it.
Matt Joiner
A: 

I would create the logger object at the beginning of the module and I would probably even use it in submodules if appropriate.

Anyway, I might still create an additional logging object inside a big class which uses logging a lot if I think it's a good idea - for example when i think it might be useful to configure the logging verbosity or the logging handlers separately for this important class (e.g. an class for ordering processes or for database queries might be such a case).

And you shouldn't worry about that your logging object is accessible outside the module. In fact, Python doesn't support private members at all. I think Guido van Rossum once wrote something like "We are all adults, aren't we?".

tux21b
The configuration of the verbosity and handlers is done at application startup for a logger named 'product', so my logger inherits the configuration from there.
Chris089