This allows to support rotation based on the file birth time on Linux.
rollover interval.
When computing the next rollover time for the first time (when the handler
- is created), the last modification time of an existing log file, or else
+ is created), the creation time (if supported by the OS and file system)
+ or the last modification of an existing log file, or else
the current time, is used to compute when the next rotation will occur.
If the *utc* argument is true, times in UTC will be used; otherwise
.. versionchanged:: 3.9
The *errors* parameter was added.
+ .. versionchanged:: next
+ Use the creation time instead of the last modification time, if supported by the OS and file system.
+
+
.. method:: doRollover()
Does a rollover, as described above.
requires ``lzma`` 5.4.0 or newer while RISC-V requires 5.6.0 or newer.
(Contributed by Chien Wong in :gh:`115988`.)
+logging
+-------
+
+* :class:`~logging.handlers.TimedRotatingFileHandler` now uses the creation
+ time instead of the last modification time of an existing log file as
+ the basis for the first rotation after handler creation, if supported by
+ the OS and file system.
+ This allows it to be used in short-running programs that start and end
+ before the rotation interval expires.
+ (Contributed by Iván Márton and Serhiy Storchaka in :gh:`84649`.)
+
os
--
if os.path.exists(filename):
# Use the minimum of file creation and modification time as
# the base of the rollover calculation
- stat_result = os.stat(filename)
- # Use st_birthtime whenever it is available or use st_ctime
- # instead otherwise
- try:
- creation_time = stat_result.st_birthtime
- except AttributeError:
- creation_time = stat_result.st_ctime
- t = int(min(creation_time, stat_result.st_mtime))
+ creation_time = modification_time = None
+ if hasattr(os, 'statx'):
+ statx_result = os.statx(filename,
+ os.STATX_BTIME|os.STATX_CTIME|os.STATX_MTIME)
+ # Use stx_btime whenever it is available or use stx_ctime
+ # instead otherwise
+ creation_time = statx_result.stx_btime
+ if creation_time is None:
+ creation_time = statx_result.stx_ctime
+ modification_time = statx_result.stx_mtime
+ if creation_time is None or modification_time is None:
+ stat_result = os.stat(filename)
+ # Use st_birthtime whenever it is available or use st_ctime
+ # instead otherwise
+ if creation_time is None:
+ try:
+ creation_time = stat_result.st_birthtime
+ except AttributeError:
+ creation_time = stat_result.st_ctime
+ if modification_time is None:
+ modification_time = stat_result.st_mtime
+ t = int(min(creation_time, modification_time))
else:
t = int(time.time())
self.rolloverAt = self.computeRollover(t)
"has_fork_support", "requires_fork",
"has_subprocess_support", "requires_subprocess",
"has_socket_support", "requires_working_socket",
- "has_st_birthtime",
"has_remote_subprocess_debugging", "requires_remote_subprocess_debugging",
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
"check__all__", "skip_if_buggy_ucrt_strfptime",
or is_android
)
-# At the moment, st_birthtime attribute is only supported on Windows,
-# MacOS and FreeBSD.
-has_st_birthtime = sys.platform.startswith(("win", "freebsd", "darwin"))
-
def requires_fork():
return unittest.skipUnless(has_fork_support, "requires working os.fork()")
print(tf.read())
self.assertTrue(found, msg=msg)
- @unittest.skipUnless(support.has_st_birthtime,
- "st_birthtime not available or supported by Python on this OS")
+ @unittest.skipUnless(hasattr(os.stat_result, 'st_birthtime') or hasattr(os, 'statx'),
+ "st_birthtime and statx() not available or supported by Python on this OS")
@support.requires_resource('walltime')
def test_rollover_based_on_st_birthtime_only(self):
def add_record(message: str) -> None:
-A bug has been fixed that made the ``TimedRotatingFileHandler`` use the
-MTIME attribute of the configured log file to to detect whether it has to be
-rotated yet or not. In cases when the file was changed within the rotation
-period the value of the MTIME was also updated to the current time and as a
-result the rotation never happened. The file creation time (CTIME) is used
-instead that makes the rotation file modification independent.
+:class:`~logging.handlers.TimedRotatingFileHandler` now uses the creation time
+instead of the last modification time of an existing log file as the basis
+for the first rotation after handler creation, if supported by the OS and file system.
+This allows it to be used in short-running programs that start and end before
+the rotation interval expires.