diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c6d252d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Peter J. Holzer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a988607..7e3d9b0 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,27 @@ -TimeoutSwitchingFileHandler -=========================== +switchinglogfilehandlers +======================== -This is a logging file handler for the Python logging system. -It automatically closes the log file after a period of inactivity -(or after the file has been open for some time whichever comes first) -and then opens a new file at the next emit. +A collection of switching log file handlers for the Python logging system. +Unlike the *rotating* log file handlers in the Python core which always +write to a file with a fixed name and peridically rename that, these +handlers always open a new file with a unique name - old files will +never be renamed. + +TimedSwitchingFileHandler +------------------------- + +This file handler starts a new file at regular intervals, comparable to +the TimedRotatingFileHandler. + +TimeoutSwitchingFileHandler +--------------------------- + +This file handler automatically closes the log file after a period of +inactivity (or after the file has been open for some time whichever +comes first) and then opens a new file at the next emit. This is useful for long-running processes where short periods of -activity alternate with periods of inactivity. Log switchs will +activity alternate with periods of inactivity. Log switchse will typically occur during inactivity, so each log file will include one complete active period. Also, since the log files are closed, they can be safely compressed or removed. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..88c09de --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "switchinglogfilehandlers" +version = "0.0.3" +authors = [ + { name="Peter J. Holzer", email="hjp@hjp.at" }, +] +description = "A collection of switching log file handlers" +readme = "README.md" +requires-python = ">=3.7" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", +] + +[project.urls] +"Homepage" = "https://git.hjp.at:3000/hjp/switchinglogfilehandlers" +"Bug Tracker" = "https://git.hjp.at:3000/hjp/switchinglogfilehandlers/issues" + diff --git a/timeoutswitchingfilehandler.py b/src/switchinglogfilehandlers/__init__.py similarity index 51% rename from timeoutswitchingfilehandler.py rename to src/switchinglogfilehandlers/__init__.py index 03cee4c..cc0fcfa 100644 --- a/timeoutswitchingfilehandler.py +++ b/src/switchinglogfilehandlers/__init__.py @@ -40,3 +40,42 @@ class TimeoutSwitchingFileHandler(logging.Handler): self.fh.close() self.fh = None self.release() + +class TimedSwitchingFileHandler(logging.Handler): + def __init__(self, filename, when='h', utc=False): + super().__init__() + self.basename = filename + when = when.lower() + if when == 's': + self.timestamp_format = "%Y-%m-%d-%H-%M-%S" + elif when == 'm': + self.timestamp_format = "%Y-%m-%d-%H-%M" + elif when == 'h': + self.timestamp_format = "%Y-%m-%d-%H" + elif when == 'd': + self.timestamp_format = "%Y-%m-%d" + elif when == 'w': + self.timestamp_format = "%Gw%V" + else: + raise ValueError(f"Unknown value “{when}” for when") + self.utc = utc + self.current_filename = None + self.fh = None + + def emit(self, record): + msg = self.format(record) + now = time.time() + if self.utc: + now_tm = time.gmtime(now) + else: + now_tm = time.localtime(now) + new_filename = self.basename + time.strftime(self.timestamp_format, now_tm) + ".log" + if new_filename != self.current_filename: + if self.fh: + self.fh.close() + self.fh = open(new_filename, "a") + self.current_filename = new_filename + self.fh.write(msg) + self.fh.write("\n") + self.fh.flush() +