tags:

views:

67

answers:

3

My python application consists of main program and several modules. Each module contains

import logging
log = logging.getLogger('myapp.mymodule')

on global level. Handlers and other stuff initialized in main program, and typically all messages forwarded to syslog.

Now I want to launch multiple instances of application (configuration file with instance name can be specified as command line parameter). The question is: how to pass instance name to each imported module? I want logger name to look like 'myappinstance.mymodule' or 'myapp.instance.module'. And I do not want to mess with configuration file parsing in each module, because this will require hardcoded config path.

+1  A: 

Here is a solution I can think of:

In the main program, set the formatter of logger named myapp

import logging
logger = logging.getLogger("myapp")
formatter = logging.Formatter("%(asctime)s - instance_name - %(levelname)s - %(message)s")
ch = logging.SysLogHandler()
ch.setFormatter(formatter)
logger.addHandler(ch)

Then all imported module using logger myapp.* will contain instance_name in the logging message.

Iamamac
A: 

Well, describing the problem really helps in solving it :) Just had an idea of using environment variables to pass parameters across all modules:

main.py:

import os
os.environ['instance'] = 'blah'
import a

a.py:

import os
import b
print 'a:', os.environ['instance']

b.py:

import os
print 'b:', os.environ['instance']

$ python main.py

b: blah
a: blah

Any other ideas or critics for this one?

Max
I don't think it will solve your problem. There is racing-condition for passing instance name to modules by setting environment variables. What if multiple instances start at the same time?
Iamamac
Environment variables are not global (os-wide), they are inherited down the process tree. I can simultaneously launch two main.py instances and if each one sets specific evnironment variable, it will be propagated only to child processes.
Max
A: 

Simply write your own logging wrapper which will give you the correct name (tweak as needed to get the instance name that you want):

def get_logger(obj=None):
    if isinstance(obj, str):
        return logging.getLogger(obj) 
    elif obj is not None:
        logger_name ="%s.%s" % (obj.__class__.__module__, obj.__class__.__name__)
        return logging.getLogger(logger_name)
    else:
        return logging.getLogger()

class Foo(object):

    def __init__(self):
        self._log = get_logger(self)

Or, if the process id is good enough for you, simply use that in your formatter:

http://www.python.org/doc/2.5.4/lib/node421.html

formatter = logging.Formatter("%(process)d - %(asctime)s - %(levelname)s - %(message)s")

Obviously, that will uniquely identify each process, but won't give you anything related to the instance.

brianz