37

I'm writing some code that uses the python logging system. The idea is that if the LOG doesn't already exist create the log but if it does then get the log and resume logging to that file. Here is my code:

import logging
import os

log_filename='Transactions.log')
if os.path.isfile(log_filename)!=True:
    LOG = logging.getLogger('log_filename')
    LOG.setLevel(logging.DEBUG)
    # create file handler which logs even debug messages
    fh = logging.FileHandler('log_filename')
    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')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    # add the handlers to the logger
    LOG.addHandler(fh)
    LOG.addHandler(ch)
else:
    LOG=logging.getLogger()

I suspect the problem is with my else block but I don't know how to fix. Could anybody shed some light on this situation.

1
  • set up your logger once and then import LOG from any place you want, no need to check if the log file exists
    – mic4ael
    Commented Jan 20, 2017 at 13:36

5 Answers 5

45

The logging module's FileHandler takes care of that for you. No need for complexity.

The handler takes an optional mode parameter, to specify whether it starts writing or appending data to it.

From the docs:

class logging.FileHandler(filename, mode='a', encoding=None, delay=False)

The specified file is opened and used as the stream for logging. If mode is not specified, 'a' is used.

4
  • 44
    If the directory does not exist, you will still get an exception. Logging is happy to create a new file for you, but not a whole directory structure.
    – mightypile
    Commented Apr 7, 2018 at 21:03
  • 1
    Which mode should @CiaranWelsh specify in order to create the file if not present?
    – UserK
    Commented Jun 5, 2018 at 12:41
  • 4
    @UserK if file is not present, either of a or w would be fine. a would append to the same file in next run, whereas w mode will delete the old file and create an entirely new one. Also read what @mightypile commented above.
    – hjpotter92
    Commented Jun 5, 2018 at 13:28
  • On Python 2.7, it doesn't seem to work. FileHandler can't find the path and it returns error unless you explicitly make a path using os.makedirs() Commented Jul 30, 2020 at 1:36
39

For anyone who was trying to create a new directory structure like logs/mylogfile.log, as @mightypile mentioned, FileHandler will not create a new directory structure for you. I used os.makedirs to ensure the directory structure.

import os
import logging

log_filename = "logs/output.log"
os.makedirs(os.path.dirname(log_filename), exist_ok=True)
file_handler = logging.FileHandler(log_filename, mode="w", encoding=None, delay=False)
1
  • 1
    Thanks! I believe it's log_filename on the last line Commented Nov 21, 2023 at 3:29
0

When you run

LOG = logging.getLogger('log_filename')

for the first time a global variable is created. Hence, you could also add the following code to the script above:

global LOG
if LOG is not None:
    print("found logger !")
else:
    ("no global variable logger found")
0

You might want to use absolute path.

logging.FileHandler(filename="/home/user/PycharmProjects/project/logs/log_file.log")
0

Based on @KhoPhi and @loop 's answers, when using a logging config dict you might want to use a class as a handler that you can use in the config. For that you can use the following:

from pathlib import Path
from logging.handlers import RotatingFileHandler as _RotatingFileHandler

class RotatingFileHandler(_RotatingFileHandler):
    def __init__(self, filename: str, *args, **kwargs):
        Path(filename).absolute().parent.mkdir(exist_ok=True, parents=True)
        super().__init__(filename, *args, **kwargs)

you can then use all the examples above with your own handler:

RotatingFileHandler("logs/my_file.log")

or use it in the config file as:

...
handlers:
  my_handler:
    class: your_module.your_submodule.RotatingFileHandler
    filename: logs/my_file.log
...

Not the answer you're looking for? Browse other questions tagged or ask your own question.