59

I'm trying to write a server that logs exceptions both to the console and to a file. I pulled some code off the cookbook. Here it is:

logger = logging.getLogger('server_logger')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('server.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)

This code logs perfectly fine to the console, but nothing is logged to the file. The file is created, but nothing is ever written to it. I've tried closing the handler, but that doesn't do anything. Neither does flushing it. I searched the Internet, but apparently I'm the only one with this problem. Does anybody have any idea what the problem is? Thanks for your answers.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
thePurpleMonkey
  • 778
  • 2
  • 13
  • 16

6 Answers6

47

Try calling

logger.error('This should go to both console and file')

instead of

logging.error('this will go to the default logger which you have not changed the config of')
Leopd
  • 41,333
  • 31
  • 129
  • 167
  • 1
    Oh hey! This totally made it work! You're a genius! Although I don't totally understand _why_ that made it work... – thePurpleMonkey Apr 09 '13 at 04:37
  • 8
    Calling `logging.error` uses the default logger, which you have not configured. The variable `logger` is the one you defined in the first line, which has all the properties you configured. – Leopd Apr 09 '13 at 04:59
  • still empty wth, i did this already – greendino Oct 17 '22 at 02:06
30

Try to put the import and the basicConfig at the very beggining of the script. Something like this:

import logging
logging.basicConfig(filename='log.log', level=logging.INFO)
.
.
import ...
import ...
Fernando Benito
  • 301
  • 3
  • 2
  • 1
    Thanks for this! I know it's not the answer to this question (OP's problem was using logging.debug/info/error() instead of logger.debug/info/error() ), but this fixed a problem I was having. Using "import h2o" made my logging.basicConfig() call down below it ineffective. I'm guessing something in the h2o module initializes the logging module... genius move by whoever decided to do that. – Brent212 Nov 06 '18 at 02:30
  • Fixed mine as well - I was trying to log something within a unittest. It worked fine then I must have broken something. Bringing the config up fixed it. – LogicOnAbstractions Feb 01 '19 at 17:08
  • This solved my problem as well ; I was importing gensim which has its own logger. Thanks! – CharlesG Jan 05 '21 at 12:44
  • Solved for me as well! – JoAnn Alvarez Feb 04 '22 at 17:20
  • This was the reason my logging was not working - thanks! – TCSGrad Feb 16 '22 at 14:58
12

Put this

for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

in front of the

logging.basicConfig(...)

see also Logging module not writing to file

P Moran
  • 1,624
  • 3
  • 18
  • 32
  • This is perfect! Keeps from having to initialize log before other imports and handles extraneous handlers created in other imported modules (way to handle things!) – Chris Collett Mar 16 '21 at 20:24
5

I know that this question might be a bit too old but I found the above method a bit of an overkill. I ran into a similar issue, I was able to solve it by:

import logging

logging.basicConfig(format = '%(asctime)s %(message)s',
                    datefmt = '%m/%d/%Y %I:%M:%S %p',
                    filename = 'example.log',
                    level=logging.DEBUG)

This will write to example.log all logs that are of level debug or higher.

logging.debug("This is a debug message") will write This is a debug message to example.log. Level is important for this to work.

Abass Sesay
  • 833
  • 10
  • 18
  • 2
    I also thought the OP was a bit overkill for what I wanted to do. I'm trying to make the code you have working, but it doesn't create any file for me, let alone write in it. – Mymozaaa Jun 29 '17 at 18:55
  • @Mymozaaa - https://docs.python.org/2/howto/logging.html#logging-to-a-file. I hope this helps you out. – Abass Sesay Jun 29 '17 at 22:05
  • @AbassSesay - Thank you, I didn't specify the level and it was failing. – pnv May 12 '21 at 10:13
  • the file doesnt even created with this approach, im confused – greendino Oct 17 '22 at 02:07
5

In order to both write to terminal and file you can do like below:

import logging.config

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("log_file.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

usage in the code:

logger.info('message')
logger.error('message')
Amirkhm
  • 948
  • 11
  • 13
3

If root.handlers is not empty, log file will not be created. We should empty root.handlers before calling basicConfig() method. source

Snippet:

for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)

The full code is below:

import logging
##loging
for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename= 'log.txt',
                    filemode='w')

console = logging.StreamHandler()
console.setLevel(logging.INFO)
# add the handler to the root logger
logging.getLogger().addHandler(console)
logging.info("\nParameters:")

for i in range(10):
    logging.info(i)

logging.info("end!")
Umair Qadir
  • 384
  • 3
  • 7