Handler for logging to a set of files, which switches from one file to the next when the current file reaches a certain size, or at certain timed intervals @filename - log file name @max_bytes - file size in bytes to rotate file @interval - Duration to rotate file @back
| 13 | |
| 14 | |
| 15 | class EnhancedRotatingFileHandler(handlers.TimedRotatingFileHandler, |
| 16 | handlers.RotatingFileHandler): |
| 17 | """ |
| 18 | Handler for logging to a set of files, which switches from one file |
| 19 | to the next when the current file reaches a certain size, or at certain |
| 20 | timed intervals |
| 21 | @filename - log file name |
| 22 | @max_bytes - file size in bytes to rotate file |
| 23 | @interval - Duration to rotate file |
| 24 | @backup_count - Maximum number of files to retain |
| 25 | @encoding - file encoding |
| 26 | @when - 'when' events supported: |
| 27 | # S - Seconds |
| 28 | # M - Minutes |
| 29 | # H - Hours |
| 30 | # D - Days |
| 31 | # midnight - roll over at midnight |
| 32 | # W{0-6} - roll over on a certain day; 0 - Monday |
| 33 | Here we are defaulting rotation with minutes interval |
| 34 | """ |
| 35 | def __init__(self, filename, max_bytes=1, interval=60, backup_count=0, |
| 36 | encoding=None, when='M'): |
| 37 | max_bytes = max_bytes * 1024 * 1024 |
| 38 | handlers.TimedRotatingFileHandler.__init__(self, filename=filename, |
| 39 | when=when, |
| 40 | interval=interval, |
| 41 | backupCount=backup_count, |
| 42 | encoding=encoding) |
| 43 | |
| 44 | handlers.RotatingFileHandler.__init__(self, filename=filename, |
| 45 | mode='a', |
| 46 | maxBytes=max_bytes, |
| 47 | backupCount=backup_count, |
| 48 | encoding=encoding) |
| 49 | |
| 50 | # Create new log files with mode 0o600 so they are not world/group |
| 51 | # readable. Pre-existing files keep their permissions; the parent |
| 52 | # DATA_DIR is already 0o700 on POSIX, so this is defense-in-depth. |
| 53 | # On Windows the mode arg to os.open is ignored — fall back to the |
| 54 | # default behavior there. O_CLOEXEC matches built-in open()'s default |
| 55 | # non-inheritable fd behavior (PEP 446); os.open does not set it |
| 56 | # otherwise. |
| 57 | def _open(self): |
| 58 | if os.name == 'nt': |
| 59 | return super()._open() |
| 60 | flags = os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | ( |
| 61 | os.O_APPEND if self.mode == 'a' else os.O_TRUNC) |
| 62 | fd = os.open(self.baseFilename, flags, 0o600) |
| 63 | try: |
| 64 | return os.fdopen(fd, self.mode, encoding=self.encoding, |
| 65 | errors=getattr(self, 'errors', None)) |
| 66 | except Exception: |
| 67 | os.close(fd) |
| 68 | raise |
| 69 | |
| 70 | # Time & Size combined rollover |
| 71 | def shouldRollover(self, record): |
| 72 | return handlers.TimedRotatingFileHandler.shouldRollover(self, record) \ |