5

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...

c089
  • 4,951
  • 2
  • 25
  • 37
  • See this question: http://stackoverflow.com/questions/401277/naming-python-loggers. The answer is "yes". – S.Lott Aug 17 '10 at 12:56

3 Answers3

9

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
  • 112,946
  • 110
  • 377
  • 526
  • 1
    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 Aug 17 '10 at 13:01
  • 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? – c089 Aug 17 '10 at 13:12
  • @Matt: How do you "keep the module hidden away"? – c089 Aug 17 '10 at 13:13
  • 1
    @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... – c089 Aug 17 '10 at 13:23
  • Sounds good chris. `_logger` is better than accidentally importing it. – Matt Joiner Aug 17 '10 at 14:01
  • Just for the record, I ended up using `_log` because it's shorter to type and had no problems with that. It's short, simple, looks ok and does not introduce any unwanted effects for me :) – c089 Jan 10 '11 at 10:11
  • @c089: Just realised the confusing description I gave. I mean that you can keep the `logging` module hidden from the module, so that you don't accidentally use a Logger other than the one you've designated for the module. By hidden I mean removing it from from the global namespace in the module. – Matt Joiner Jan 11 '14 at 16:43
1

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.

c089
  • 4,951
  • 2
  • 25
  • 37
0

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
  • 90,183
  • 16
  • 117
  • 101
  • 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. – c089 Aug 17 '10 at 13:10