How to structure the Logging in this case (python)
Question: I was wondering what would be the best way for me to structure my logs in a
special situation.

I have a series of python services that use the same python files for
communicating (ex. com.py) with the HW. I have logging implemented in this
modules and i would like for it to be dependent(associated) with the main
service that is calling the modules.

How should i structure the logger logic so that if i have:

  * main_service_1->module_for_comunication

The logging goes to file **main_serv_1.log**

  * main_service_2->module_for_comunication

The logging goes to file **main_serv_2.log**

What would be the best practice in this case without harcoding anything?

Is there a way to know the file which is importing the com.py, so that i am
able inside of the com.py, to use this information to adapt the logging to the
caller?


Answer: In my experience, for a situation like this, the cleanest and easiest to
implement strategy is to **pass the logger to the code that does the
logging**.

So, create a logger for each service you want to have log to a different file,
and pass that logger in to the code from your communications module. You can
use `__name__` to get the name of the current module (the actual module name,
without the `.py` extension).

In the example below I implemented a fallback for the case when no logger is
passed in as well.

**`com.py`**

    
    
    from log import setup_logger
    
    
    class Communicator(object):
    
        def __init__(self, logger=None):
            if logger is None:
                logger = setup_logger(__name__)
    
            self.log = logger
    
        def send(self, data):
            self.log.info('Sending %s bytes of data' % len(data))
    

* * *

**`svc_foo.py`**

    
    
    from com import Communicator
    from log import setup_logger
    
    
    logger = setup_logger(__name__)
    
    
    def foo():
        c = Communicator(logger)
        c.send('foo')
    

* * *

**`svc_bar.py`**

    
    
    from com import Communicator
    from log import setup_logger
    
    
    logger = setup_logger(__name__)
    
    
    def bar():
        c = Communicator(logger)
        c.send('bar')
    

* * *

**`log.py`**

    
    
    from logging import FileHandler
    import logging
    
    
    def setup_logger(name):
        logger = logging.getLogger(name)
        handler = FileHandler('%s.log' % name)
        logger.addHandler(handler)
        return logger
    

* * *

**`main.py`**

    
    
    from svc_bar import bar
    from svc_foo import foo
    import logging
    
    
    # Add a StreamHandler for the root logger, so we get some console output in
    # addition to file logging (for easy of testing). Also set the level for
    # the root level to INFO so our messages don't get filtered.
    logging.basicConfig(level=logging.INFO)
    
    
    foo()
    bar()
    

* * *

So, when you execute `python main.py`, this is what you'll get:

On the console:

    
    
    INFO:svc_foo:Sending 3 bytes of data
    INFO:svc_bar:Sending 3 bytes of data
    

And `svc_foo.log` and `svc_bar.log` each will have one line

    
    
    Sending 3 bytes of data
    

If a client of the `Communicator` class uses it without passing in a logger,
the log output will end up in `com.log` (fallback).

