classification
Title: [logging] template for filename timestamps
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.8
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: steveha, vinay.sajip
Priority: normal Keywords:

Created on 2018-05-14 20:53 by steveha, last changed 2018-05-15 07:49 by vinay.sajip. This issue is now closed.

Messages (5)
msg316573 - (view) Author: Steve R. Hastings (steveha) * Date: 2018-05-14 20:53
When a logged file has a timed rotation, it is renamed with an archival filename that includes a timestamp.  The logging library has a small set of predefined filename templates and no way is provided to override them.

Also, the current rule is that while the file is in active use for logging, it will not have a timestamp in the filename; the filename will be something like: foo.log

Then, at file rotation time, foo.log is closed and then renamed to an archival name that includes a timestamp (something like: foo-2018-05-14.log), and a new active log file is opened with the name foo.log again.

Proposed enhancement: it should be possible to provide template codes that specify the format of the timestamp, and there should be an option that when the file is in active use its filename will include the timestamp.  (Then at rotation time, the file is simply closed, with no need to rename it; and a new file with a new timestamp is opened.)

For example, specifying a log filename of "foo-%Y%m%d-%H%M%S" would specify a filename like: foo-20180514-160000.log

Use case: the company that employs me had a logging system requiring both of the above features.  The timestamp in the filename had to be in a format different than the one format built-in to the logging module, and the timestamp needed to be in the file at all times.  The logging system included a daemon that did the equivalent of tail -f on the logfile and collected log events as they were written.

Note: I have written code that implements the features described above.

Additional note: some template formats could cause a problem with deleting the oldest backup files.

When the option backupCount is set to a number >= 1, then at rotation time the handler will check whether the number of backup files exceeds the specified count, and will delete the oldest files to reduce the number of backup files to exactly the backupCount number.

The oldest files are found by sorting the filenames; the presumption is that the archival filenames will sort with the oldest files first.  All the built-in templates produce filenames where this presumption is correct.  A foolish user could specify a timestamp format where month appears before date, or hour appears before month, or any other template that does not follow this ordering: year/month/date/hour/minutes/seconds

We could also add a feature where, when the template is specified and backupCount is specified, the handler will check that the template follows the ordering so that the oldest files do sort first, and raise an exception if the template doesn't follow the ordering.  Alternatively, we can add a note in the documentation warning of this issue.
msg316600 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2018-05-14 22:28
> The logging library has a small set of predefined filename templates and no way is provided to override them.

What about

https://docs.python.org/3/library/logging.handlers.html#logging.handlers.BaseRotatingHandler.namer

which allows you to specify your own naming scheme?

What prevents you from subclassing one of the existing rotating handlers and implementing the algorithm you want?
msg316608 - (view) Author: Steve R. Hastings (steveha) * Date: 2018-05-15 01:57
> What about [ BaseRotatingHandler.namer ] which allows you to specify your own naming scheme?

I confess that I overlooked that; it was added later than the version of Python in which I wrote my original code.

The current Python code still has a small set of predefined file templates, but now has a way to specify a callable that can completely override the filename.  I agree that this can be used to implement any desired filename system, although it would be more work than simply specifying the desired template codes.

Are you planning to remove the predefined filename templates and produce a more functional version of the code where the .namer() function is always used to produce a filename, with a set of predefined functions that produce equivalent filenames to the built-in templates?
msg316616 - (view) Author: Steve R. Hastings (steveha) * Date: 2018-05-15 03:37
I just reviewed the Python 3.6 logging code.  Unless I am mistaken, it still has the limitation that when a logging file is active for writing log events, that file always has the same filename (self.baseFilename).  Did I overlook anything?

At rotation time, the self.namer() function is called, and it could implement any desired naming scheme.  However, its only argument is the already templated filename.

So if I needed to implement logging with a filename of: foo-YYYYmmdd.log at all times, how would I get the current file (the open file to which log events are being written) to have that pattern of name?

And if I needed to write a self.namer() function to rename to that standard, is this the recommended approach?

# for daily rotations, the built-in template is: "%Y-%m-%d"
def namer(self, filename):
    # filename will look like: foo-YYYY-mm-dd.log
    year = filename[-14:-10]
    month = filename[-9:-7]
    day = filename[-6:-4]
    base = filename[:-14]
    new_filename = base + year + month + day + ".log"
    return new_filename  # will look like: foo-YYYYmmdd.log

The logging event that triggered the rollover is not passed to the namer() function, just the templated default filename.

In my opinion, it is more convenient for the user to simply specify the desired format using template codes, such as:

handler = TimedRotatingFileHandler("foo", suffix="-%Y%m%d", when="D")


Also, unless I have overlooked something, using the self.namer() function to implement a custom naming scheme completely disables the code that automatically deletes the oldest backup files when backupCount is specified.  The getBackupFilesToDelete() function uses the self.extMatch value (a pre-compiled regular expression) to find files to delete; with a custom naming scheme, the files will not match the pattern.  Therefore users with a custom naming scheme would have to implement some external solution to deleting old files after log rotation.

The code I am proposing to donate to Python automatically builds a suitable regular expression for the self.extMatch member variable, based on the user's specified format string.  I believe this is an advantage for the code I propose to donate.
msg316630 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2018-05-15 07:40
> Are you planning to remove the predefined filename templates

No. They work fine as is for most people, from what I can tell.

> it still has the limitation that when a logging file is active for writing log events, that file always has the same filename (self.baseFilename)

That's not a limitation particularly, it's that way by design.

> So if I needed to implement logging with a filename of: foo-YYYYmmdd.log at all times

Implement your own subclass and do whatever you need in there, including deletion of oldest files etc. Publish it on PyPI and see what the uptake is like. I'm not sure a donation of code in this area will be accepted, but there's no need for your bespoke handler subclass to be in the stdlib.
History
Date User Action Args
2018-05-15 07:49:09vinay.sajipsetstatus: open -> closed
resolution: rejected
stage: resolved
2018-05-15 07:40:43vinay.sajipsetmessages: + msg316630
2018-05-15 03:37:05stevehasetmessages: + msg316616
2018-05-15 01:57:40stevehasetmessages: + msg316608
2018-05-14 22:28:45vinay.sajipsetmessages: + msg316600
2018-05-14 20:53:27stevehacreate