views:

72

answers:

3

I am currently writing an API and an application which uses the API. I have gotten suggestions from people stating that I should perform logging using handlers in the application and use a "logger" object for logging from the API.

In light of the advice I received above, is the following implementation correct?

class test:
    def __init__(self, verbose):
        self.logger = logging.getLogger("test")
        self.logger.setLevel(verbose)

    def do_something(self):
        # do something
        self.logger.log("something")
        # by doing this i get the error message "No handlers could be found for logger "test"

The implementation i had in mind was as follows:

 #!/usr/bin/python

 """ 
 ....
 ....
 create a logger with a handler 
 ....
 ....

 """

 myobject = test()
 try:
     myobject.do_something()
 except SomeError:
     logger.log("cant do something")

Id like to get my basics strong, id be grateful for any help and suggestions for code you might recommend I look up.

Thnkx!

+1  A: 

The danger with the pattern that you are thinking about is that you may end up effectively hiding exceptions by putting them in a log. Many exceptions really should crash your program because they represent a problem that needs to be fixed. Generally, it is more useful to be able to step into code with a debugger to find out what caused the exception.

If there are cases that an exception represents an expected condition that does not affect the stability of the app or the correctness of its behavior, doing nothing but writing a notation to the log is OK. But be very, very careful about how you use this.

Adam Crossland
+3  A: 

It's not very clear whether your question is about the specifics of how to use logging or about logging exceptions, but if the latter, I would agree with Adam Crossland that log-and-swallow is a pattern to be avoided.

In terms of the mechanics of logging, I would make the following observations:

  1. You don't need to have a logger as an instance member. It's more natural to declare loggers at module level using logger = logging.getLogger(__name__), and this will also work as expected in sub-packages.
  2. Your call logger.log("message") would likely fail anyway because the log method has a level as the first argument, rather than a message.

You should declare handlers, and if your usage scenario is fairly simple you can do this in your main method or if __name__ == '__main__': clause by adding for example

logging.basicConfig(filename='/tmp/myapp.log', level=logging.DEBUG, 
                    format='%(asctime)s %(levelname)s %(name)s %(message)s')

and then elsewhere in your code, just do for example

import logging
logger = logging.getLogger(__name__)

once at the top of each module where you want to use logging, and then

logger.debug('message with %s', 'arguments') # or .info, .warning, .error etc.

in your code wherever needed.

Vinay Sajip
+1  A: 

I usually do the following:

import logging
import logging.config
logging.config.fileConfig('log.congig')

# for one line log records 
G_LOG = logging.getLogger(__name__)
# for records with stacktraces
ST_LOG = logging.getLogger('stacktrace.' + __name__)


try:
    # some code
    G_LOG.info('some message %s %s', param1, param2)
except (StandardError,):
    message = 'some message'
    G_LOG.error(message)
    # exc_info appends stacktrace to the log message
    ST_LOG.error(message, exc_info=True)

Format of the config file can be seen in the python manual

newtover