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
<http://bugs.python.org/issue29372>
___
___
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com