python logging file is not working when using logging.basicConfig

PythonLogging

Python Problem Overview


I have the following lines of code that initialize logging. I comment one out and leave the other to be used. The problem that I'm facing is that the one that is meant to log to the file not logging to file. It is instead logging to the console. Please help.

For logging to Console:

logging.basicConfig(level=logging.INFO,
        format='%(asctime)s [%(levelname)s] (%(threadName)-10s) %(message)s',)

for file logging

logging.basicConfig(filename='server-soap.1.log',level=logging.INFO,
        format='%(asctime)s [%(levelname)s] (%(threadName)-10s) %(message)s')

Python Solutions


Solution 1 - Python

I found out what the problem was. It was in the ordering of the imports and the logging definition.

The effect of the poor ordering was that the libraries that I imported before defining the logging using logging.basicConfig() defined the logging. This therefore took precedence to the logging that I was trying to define later using logging.basicConfig()

Below is how I needed to order it:

import logging
## for file logging
logging.basicConfig(filename='server-soap.1.log',
		level=logging.INFO,
		format='%(asctime)s %(levelname)s %(threadName)-10s %(message)s',)
					
from pysimplesoap.server import SoapDispatcher, SOAPHandler
from BaseHTTPServer import HTTPServer
import time,random,datetime,pytz,sys,threading
from datetime import timedelta
#DB
import psycopg2, psycopg2.extras
from psycopg2.pool import ThreadedConnectionPool

#ESB Call
from suds import WebFault
from suds.client import Client

But the faulty ordering that I initially had was:

from pysimplesoap.server import SoapDispatcher, SOAPHandler
from BaseHTTPServer import HTTPServer
import logging
import time,random,datetime,pytz,sys,threading
from datetime import timedelta
#DB
import psycopg2, psycopg2.extras
from psycopg2.pool import ThreadedConnectionPool

#ESB Call
from suds import WebFault
from suds.client import Client

## for file logging

logging.basicConfig(filename='server-soap.1.log',
		level=logging.INFO,
		format='%(asctime)s %(levelname)s %(threadName)-10s %(message)s',)

Solution 2 - Python

"Changed in version 3.8: The force argument was added." I think it's a better choice for new version.

For older Version(< 3.8):

From the source code of logging I found the flows: > This function does nothing if the root logger already has handlers configured. It is a convenience method intended for use by simple scripts to do one-shot configuration of the logging package.

So, if some module we import called the basicConfig() method before us, our call will do nothing.

A solution I found can work is that you can reload logging before your own calling to basicConfig(), such as

def init_logger(*, fn=None):

    # !!! here
    from imp import reload # python 2.x don't need to import reload, use it directly
    reload(logging)

    logging_params = {
        'level': logging.INFO,
        'format': '%(asctime)s__[%(levelname)s, %(module)s.%(funcName)s](%(name)s)__[L%(lineno)d] %(message)s',
    }

    if fn is not None:
        logging_params['filename'] = fn

    logging.basicConfig(**logging_params)
    logging.error('init basic configure of logging success')

Solution 3 - Python

In case basicConfig() does not work:

logger = logging.getLogger('Spam Logger')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)

# 'application' code
logger.debug('debug Spam message')
logging.debug('debug Spam message')
logger.info('info Ham message')
logger.warning('warn Eggs message')
logger.error('error Spam and Ham message')
logger.critical('critical Ham and Eggs message')

which gives me the following output:

2019-06-20 11:33:48,967 - Spam Logger - DEBUG - debug Spam message
2019-06-20 11:33:48,968 - Spam Logger - INFO - info Ham message
2019-06-20 11:33:48,968 - Spam Logger - WARNING - warn Eggs message
2019-06-20 11:33:48,968 - Spam Logger - ERROR - error Spam and Ham message
2019-06-20 11:33:48,968 - Spam Logger - CRITICAL - critical Ham and Eggs message

For the sake of reference, Python Logging Cookbook is readworthy.

Solution 4 - Python

I got the same error, I fixed it by passing the following argument to the basic config.

logging.basicConfig(
    level="WARNING",
    format="%(asctime)s - %(name)s - [ %(message)s ]",
    datefmt='%d-%b-%y %H:%M:%S',
    force=True,
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler()
    ])

Here as you can see passing force=True overrides any other BasicConfigs

Solution 5 - Python

Another solution that worked for me is instead of tracing down which module might be importing logging or even calling basicConfig before me is to just call setLevel after basicConfig again.

import os
import logging

RUNTIME_DEBUG_LEVEL = os.environ.get('RUNTIME_DEBUG_LEVEL').upper()
LOGGING_KWARGS = {
    'level': getattr(logging, RUNTIME_DEBUG_LEVEL)
}

logging.basicConfig(**LOGGING_KWARGS)
logging.setLevel(getattr(logging, RUNTIME_DEBUG_LEVEL))

Sort of crude, seems hacky, fixed my problem, worth a share.

Solution 6 - Python

IF YOU JUST WANT TO SET THE LOG LEVEL OF ALL LOGGERS


instead of ordering your imports after logging config:

just set level on the root level:

# Option 1:
logging.root.setLevel(logging.INFO)

# Option 2 - make it configurable:
# env variable + default value INFO
logging.root.setLevel(os.environ.get('LOG_LEVEL', logging.INFO))

Solution 7 - Python

Like vacing's answer mentioned, basicConfig has no effect if the root logger already has handlers configured.

I was using pytest which seems to set handlers which means the default logging setup with loglevel WARNING is active -- so it appears my app fails to log, but this only happens when executing unit tests with pytest. In a normal app run logs are produced as expected which is enough for my use case.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPhilView Question on Stackoverflow
Solution 1 - PythonPhilView Answer on Stackoverflow
Solution 2 - PythonvacingView Answer on Stackoverflow
Solution 3 - PythonShayan AmaniView Answer on Stackoverflow
Solution 4 - PythonAlen Paul VargheseView Answer on Stackoverflow
Solution 5 - PythonWill CharltonView Answer on Stackoverflow
Solution 6 - PythonYitzchakView Answer on Stackoverflow
Solution 7 - PythonxjclView Answer on Stackoverflow