Minimal Python logging I tend to include something like the following in small and medium-sized Python projects, either at the top of the executable or as logger.py:

import logging
import sys

logger = logging.getLogger(__name__)
stoh = logging.StreamHandler(sys.stderr)
fmth = logging.Formatter("[%(levelname)s] %(asctime)s %(message)s")
stoh.setFormatter(fmth)
logger.addHandler(stoh)
logger.setLevel(logging.DEBUG)


Then import logger from logger (as needed), and proceed to make calls throughout the project like logger.level('message').

Are there any obvious (or non-obvious) red flags or anti-patterns with this approach?
Setting up logging

You might be interested in logging.basicConfig, which can setup everything you setup there as well. It's not sufficient if you want for example both a file and a stream logger, but for a small, static configuration like this it's perfectly suitable. Your code up there becomes a simple:

logging.basicConfig(format="[%(levelname)s] %(asctime)s %(message)s", level=logging.DEBUG)
logger = logging.getLogger(__name__)


And you're done. (The default stream is sys.stderr.)

Do note that in no way, shape or form is the long form wrong - it's easier extendable, for one. However, for a quick script it might be easier to use basicConfig.

Module-level logging

I'd recommend you use a different logger for every different file, and have all of them be named the way you did that one. However, if you then also include the %(name) parameter in your format string, your logging messages will each contain the filename of the file they're logging from. This will help in debugging if you don't know exactly where the problems come from. I personally also include %(lineno) for the line number. Personally, I always use the .format method for my logging strings, which makes it look like this:

logging.basicConfig(format="{levelname: &lt;8}:{asctime}:{name: &lt;30}:{lineno: &lt;4}:{message}", level=logging.DEBUG, style="{")
# Or with % formatting:
logging.basicConfig(format="%(levelname)-8s:%(asctime)s:%(name)-30s:%(lineno)-4s:%(message)s", level=logging.DEBUG)


Which tells me exactly where a logging statement was made as well. You won't have to search for your own exact wording anymore when you resume debugging your code for that one weird issue 3 months from now. You can just grab filename and linenumber and you're at the right location.