How to create a log file every day using logging module?
Asked Answered
B

6

41

I'm new to logging module of Python. I want to create a new log file every day while my application is in running condition.

log file name - my_app_20170622.log
log file entries within time - 00:00:01 to 23:59:59

On the next day I want to create a new log file with next day's date:

log file name - my_app_20170623.log
log file entries within time - 00:00:01 to 23:59:59

I'm using logging module of Python.

I'm using like below:

log_level = int(log_level)
logger = logging.getLogger('simple')
logger.setLevel(log_level)
fh = logging.FileHandler(log_file_name)
fh.setLevel(log_level)
formatter = logging.Formatter(log_format)
fh.setFormatter(formatter)
logger.addHandler(fh)

Is their any configurations in logging module of Python to create a log on daily basis?

Blithesome answered 23/6, 2017 at 9:42 Comment(1)
Possible duplicate of Need to do a daily log rotation (0utc) using PythonSulphurbottom
E
63

You have to create a TimedRotatingFileHandler:

from logging.handlers import TimedRotatingFileHandler
logname = "my_app.log"
handler = TimedRotatingFileHandler(logname, when="midnight", backupCount=30)
handler.suffix = "%Y%m%d"
logger.addHandler(handler)

This piece of code will create a my_app.log but the log will be moved to a new log file named my_app.log.20170623 when the current day ends at midnight.

I hope this helps.

Encouragement answered 23/6, 2017 at 9:53 Comment(4)
This "%Y%m%d" format will not create 20170623. It will create file like my_app.log.2017-06-23. why it is like that?Blithesome
You are right @kit, I made a mistake. Please, try the fixed solution. The suffix modification has to be done in the handler and not in the logger.Encouragement
Yes I posted the correct solution as a answer to this question to get the appropriate file name.Blithesome
Hi @kit, why did you post the correct solution as an answer? My answer does what you asked, didn't I?Encouragement
P
14

RotatingFileHandler

class RotatingFileHandler(  filename[, mode[, maxBytes[, backupCount]]])

Returns a new instance of the RotatingFileHandler class. The specified file is opened and used as the stream for logging. If mode is not specified, a is used. By default, the file grows indefinitely.

A RotatingFileHandler allows us to rotate our log statements into a new file every time the current log file reaches a certain size.

In this example we’ll set it up so that when it reaches 500 bytes we’ll rotate into a new file up to a maximum number of 2 backups.

import logging
import logging.handlers as handlers
import time

logger = logging.getLogger('my_app')
logger.setLevel(logging.INFO)

logHandler = handlers.RotatingFileHandler('app.log', maxBytes=500, backupCount=2)
logHandler.setLevel(logging.INFO)
logger.addHandler(logHandler)

def main():
    while True:
        time.sleep(1)
        logger.info("A Sample Log Statement")

main()

Upon execution of this you should notice that every time app.log exceeds 500 bytes, it is then closed and renamed app.log.x where the value of x increments till it reaches whatever we have set backupCount to.

TimedRotatingFileHandler

class TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])

Returns a new instance of the TimedRotatingFileHandler class. The specified file is opened and used as the stream for logging. On rotating it also sets the filename suffix. Rotating happens based on the product of when and interval.

You can use the when to specify the type of interval. The list of possible values is, note that they are not case sensitive:

|   Value  |    Type of interval   |
|:--------:|:---------------------:|
|     S    |        Seconds        |
|     M    |        Minutes        |
|     H    |         Hours         |
|     D    |          Days         |
|     W    |  Week day (0=Monday)  |
| midnight | Roll over at midnight |

TimedRotatingFileHandler allows us to capture log files by a time slice.

import logging
import logging.handlers as handlers
import time

logger = logging.getLogger('my_app')
logger.setLevel(logging.INFO)

logHandler = handlers.TimedRotatingFileHandler('timed_app.log', when='M', interval=1)
logHandler.setLevel(logging.INFO)
logger.addHandler(logHandler)

def main():
    while True:
        time.sleep(1)
        logger.info("A Sample Log Statement")

main()

Running this code will then create new log files every minute indefinitely. We can set the backupCount parameter on our logHandler instance and it will cap the number of log files we create.

Use of Appropriate Log Levels

With the TimedRotatingFileHandler and the RotatingFileHandler it is possible to do the following things such as log all error messages to a rotating file, but all normal log files to a TimedRotatingFileHandler as we hope that we can expect far more of them than error messages.

Two levels of records are split out two different log levels: INFO and ERROR to two distinct places.

import logging
import logging.handlers as handlers
import time

logger = logging.getLogger('my_app')
logger.setLevel(logging.INFO)

## Here we define our formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logHandler = handlers.TimedRotatingFileHandler('normal.log', when='M', interval=1, backupCount=0)
logHandler.setLevel(logging.INFO)
logHandler.setFormatter(formatter)

errorLogHandler = handlers.RotatingFileHandler('error.log', maxBytes=5000, backupCount=0)
errorLogHandler.setLevel(logging.ERROR)
errorLogHandler.setFormatter(formatter)

logger.addHandler(logHandler)
logger.addHandler(errorLogHandler)

def main():
    while True:
        time.sleep(1)
        logger.info("A Sample Log Statement")
        logger.error("An error log statement")

main()

You should notice that 3 log files are created when you run this. The error.log will contain only logs that are of level ERROR or higher. The normal.log will contain a combination of all log messages logged out of our application.

These are just a few things I feel are important when implementing your own logging system.

Postorbital answered 17/1, 2021 at 0:9 Comment(0)
B
7

Finally, I got the correct answer and I want to share this answer.

Basically, need to create a TimedRotatingFileHandler like below -

log_format = "%(asctime)s - %(levelname)s - %(message)s"
log_level = 10
handler = TimedRotatingFileHandler("my_app.log", when="midnight", interval=1)
handler.setLevel(log_level)
formatter = logging.Formatter(log_format)
handler.setFormatter(formatter)

# add a suffix which you want
handler.suffix = "%Y%m%d"

#need to change the extMatch variable to match the suffix for it
handler.extMatch = re.compile(r"^\d{8}$") 

# finally add handler to logger    
logger.addHandler(handler)

This above code will generate file like my_app.log for current day and my_app.log.20170704 for previous day.

Hope it helps.

Blithesome answered 4/7, 2017 at 7:17 Comment(7)
Why do you need the handler.extMatch line?Encouragement
we need to change this variable as per our requirement like If I want 20170704 i.e. it's regex should be ^\d{8}$.Blithesome
Have you tried without that line? In the response I wrote it works without it.Encouragement
Yes I tried and it is not working without that line.Blithesome
The source code for TimedRotatingFileHandler in python 3.7 shows that extMatch is only used to find old log files to delete. Old files are only deleted if you set backupCount to a positive value. It is zero by default.Wildawildcat
the line handler.setLevel(log_level) confused me some hours, change it to logger.setLevel(log_level)Cutlery
Careful with handler.suffix as it changes the default naming of file and will cause infinite backup files created even if you set backupCount in TimedRotatingFileHandler's arguments.Polity
F
3

TimedRotatingFileHandler can be used for this purpose. Please refer the below code.

from logging.config import dictConfig
import logging

dictConfig({
    'version': 1,
    'formatters': {
        'standard': {
            'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
        }
    },
    'handlers': {
        'myapp_handler': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'filename': './my_app.log',
            'when': 'd',
            'interval': 1,
            'backupCount': 30,
            'level': 'DEBUG',
            "encoding": "utf8",
            'formatter': 'standard'
        },
    },
    'loggers': {
        'simple': {
            'level': 'DEBUG',
            'handlers': ['myapp_handler']
        }
    },
})


logger = logging.getLogger("simple")

logger.error("This is a test error")

In the above example, I have used dictConfig to configure the logger. Please refer the link: https://docs.python.org/3/library/logging.config.html to know the other ways of configuration.

Once the day change, the logger module creates a new file by suffixing the current file with the date.

Foliation answered 26/4, 2021 at 6:46 Comment(0)
D
1

I suggest you take a look at logging.handlers.TimedRotatingFileHandler. I think it's what you're looking for.

Dale answered 23/6, 2017 at 9:48 Comment(0)
A
0

If you just use the default append option when creating the log file, use today's date YYYYMMDD somewhere in the file name. It will simply append to that log file it has been created otherwise it will create that file. This works if you want the logs to begin and end at midnight of course, if you want a specific time during the day for the logs to switch this method will not work.

Acea answered 25/5, 2023 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.