[issue29372] RotatingFileHandler rotates empty logfile if it emits a large string
Lee Griffiths
report at bugs.python.org
Wed Jan 25 11:03:44 EST 2017
New submission from Lee Griffiths:
If you write a really big string to an empty file, and that string is > maxBytes, then `RotatingFileHandler` (or even `BaseRotatingHandler`) will roll that empty file into the backup queue.
I think it should instead use that empty file for the mega-string. By not doing so it "wastes" a slot in the backup queue.
It's a very minor issue: I doubt it really happens IRL, but I noticed it when extending RotatingFileHandler in py2.7 to add gzip stuff and my test cases used a really small size (16 bytes!)
Here's a test file:
#!/usr/bin/env python3
# coding=utf-8
import logging
import os
import tempfile
from logging.handlers import RotatingFileHandler
class MockRecord(object):
def __init__(self, msg):
self.msg = msg
self.stack_info = None
self.exc_info = None
self.exc_text = None
def getMessage(self):
return self.msg
def test_file_rollover_from_mega_string(temp_dir_path):
# This is a pretty weird test.
# It tests that writing a huge string to a blank file causes the blank
# file to be archived and the huge string written to the next log file.
#
# Normally the log files would have a large max bytes so we'd have to
# be writing a giant string to an empty file for this to happen.
# But, even if it does, it's what BaseRotatingHandler does, so...
log_path = os.path.join(temp_dir_path, "mylog.log")
handler = RotatingFileHandler(log_path, maxBytes=16, backupCount=5)
handler.setFormatter(logging.Formatter())
with open(log_path) as log:
assert log.read() == ""
# ----------------------------------------------
handler.emit(MockRecord("There once was a test from bitbucket"))
with open(log_path) as log:
log_read = log.read()
assert log_read == "There once was a test from bitbucket\n"
with open(log_path + ".1") as log:
log_read = log.read()
assert log_read == ""
# ----------------------------------------------
handler.emit(MockRecord("11 chars"))
with open(log_path) as log:
log_read = log.read()
assert log_read == "11 chars\n"
with open(log_path + ".1") as log:
log_read = log.read()
assert log_read == "There once was a test from bitbucket\n"
with open(log_path + ".2") as log:
log_read = log.read()
assert log_read == ""
handler.close()
test_file_rollover_from_mega_string(tempfile.mkdtemp())
and here's a patch that I think will fix it:
~/src/others/cpython (master *%=)$ cat empty_rollover.patch
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 7d77973..0dabfd7 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -186,7 +186,11 @@ class RotatingFileHandler(BaseRotatingHandler):
if self.maxBytes > 0: # are we rolling over?
msg = "%s\n" % self.format(record)
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
- if self.stream.tell() + len(msg) >= self.maxBytes:
+ size = self.stream.tell()
+ if size == 0:
+ # No point rolling-over an empty file
+ return 0
+ elif size + len(msg) >= self.maxBytes:
return 1
return 0
----------
components: Library (Lib)
messages: 286265
nosy: Poddster, vinay.sajip
priority: normal
severity: normal
status: open
title: RotatingFileHandler rotates empty logfile if it emits a large string
type: resource usage
versions: Python 2.7, Python 3.7
_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue29372>
_______________________________________
More information about the Python-bugs-list
mailing list