How to get a Logger that Prints to Console and to File in fewest lines
<p>This is how I obtain a logger that prints to both console and a file:</p>

<pre><code>import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
handler2 = logging.FileHandler(os.path.join(os.path.split(os.path.abspath(__file__))[0], 'my.log'), mode='w')
handler2.setFormatter(formatter)
logger.addHandler(handler)
logger.addHandler(handler2)
</code></pre>

<p>Is there a way to accomplish something similar to this in fewer operations? I don't particularly care about the mode of the file or the filename.</p>

<p>Edit: The use case for this is when I'm prototyping a new script and do not wish to spend the time writing a configuration file until later.</p>

<p>My opinion: when you are prototyping, you want a log file for each module.</p>

<h2>A contextual handler</h2>

<p>To do that, you can process as follow:</p>

<ul>
<li>Create a <code>LogNameFileHandler</code>: this is a subclass of <code>logging.StreamHandler</code> which behave like <code>logging.FileHandler</code>, but which create a log file for each logger (based on their name).</li>
<li>Create a singleton <code>LOGGER</code> which set up a (the) root logger with this handler and the classic console logger (the way you suggest).</li>
<li>Use you logger in different module the simplest way: <code>logger = LOGGER.getChild(__name__)</code>.</li>
</ul>

<h2>Details implementation</h2>

<p>In <code>log_handler.py</code>:</p>

<pre><code>import io
import logging
import os


class LogNameFileHandler(logging.StreamHandler):
    def __init__(self, root_dir, mode='a', encoding=None):
        super(LogNameFileHandler, self).__init__(stream=None)
        self.root_dir = os.path.abspath(root_dir)
        self.mode = mode
        self.encoding = encoding
        # Set stream to None, because StreamHandler set it to sys.stderr
        self.stream = None
        #: :type log_path: str
        self.log_path = None

    def _open(self):
        log_dir = os.path.dirname(self.log_path)
        if not os.path.isdir(log_dir):
            os.makedirs(log_dir)
        return io.open(self.log_path, mode=self.mode, encoding=self.encoding)

    def close(self):
        self.acquire()
        try:
            try:
                if self.stream:
                    try:
                        self.flush()
                    finally:
                        stream = self.stream
                        self.stream = None
                        if hasattr(stream, "close"):
                            stream.close()
            finally:
                super(LogNameFileHandler, self).close()
        finally:
            self.release()

    def emit(self, record):
        name = record.name.replace(".", os.sep)
        log_name = name + ".log"
        self.log_path = os.path.join(self.root_dir, log_name)
        self.stream = self._open()
        super(LogNameFileHandler, self).emit(record)
</code></pre>

<p>This handler opens a new file for each <code>emit</code>, of course, it's up to you to handle a cacheâ¦ For prototyping, it should be OK. You can use a mapping <code>record.name</code> => <code>stream</code>.</p>

<p>In <code>log_setup.py</code>:</p>

<pre><code>import logging
import os

from log_handler import LogNameFileHandler


def _init_logger(log_dir, name=None):
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    formatter = logging.Formatter(u'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
    handler1 = logging.StreamHandler()
    handler1.setFormatter(formatter)
    handler2 = LogNameFileHandler(log_dir, mode="a+", encoding="utf8")
    handler2.setFormatter(formatter)
    logger.addHandler(handler1)
    logger.addHandler(handler2)
    return logger


LOGGER = _init_logger(os.path.dirname(__file__))
</code></pre>

<p>This module defines the <code>LOGGER</code> singleton, which you canuse in all yours Python modulesâ¦</p>

<h2>Usage</h2>

<p>In your <code>package/module.py</code>:</p>

<pre><code>from log_setup import LOGGER

logger = LOGGER.getChild(__name__)
logger.info("hello solution3")
</code></pre>

<p>Thatâs all (all the dust is under the rug).</p>

<p>If you set up the <code>root</code> logger, you can aslo write:</p>

<pre><code>import logging

logger = logging.getLogger(__name__)
...
</code></pre>

python logging