Skip to main content

A module that provides a universal python light on iops way of logging to files your program execution.

Project description

rotary_logger

Rotary Logger logo

PyPI - Python Version PyPI - Implementation PyPI - Wheel PyPI - Version PyPI - Downloads PyPI - License Execution status GitHub Workflow Status (with event) GitHub repo size GitHub Repo stars GitHub commit activity (branch) GitHub last commit (branch)

Static Badge

Table of contents

Features

  • Mirror stdout, stderr, and optionally stdin into rotating log files
  • Optionally merge all streams into a single file or keep them split into separate per-stream subfolders (stdout/, stderr/, stdin/)
  • Configurable log-line prefixes per stream (e.g. [STDOUT], [STDERR], [STDIN]) and optional per-call function tracing (e.g. [WRITE], [READLINE])
  • Low-IO buffered writes using a swap-buffer flush strategy (configurable flush threshold, default 8 KB)
  • Automatic log file rotation when a file exceeds a configurable size (default 2 GB)
  • Log folder organised by date: <root>/logs/<year>/<month>/<day>/[<stream>/]<timestamp>.log
  • Runtime configurable text encoding (default utf-8)
  • Safe concurrent use (per-object RLock; see developer notes on lock ordering)
  • Runtime environment variable overrides for log folder, file toggle, and max size (see Environment variables)

Installation

From PyPI (when published):

pip install rotary_logger

From source (recommended for development):

git clone https://github.com/Hanra-s-work/rotary_logger.git
cd rotary_logger
python -m venv .venv
source .venv/bin/activate
pip install -e .[dev]

If you only need the package without dev dependencies:

pip install -e .

Quickstart

CLI

You can use the package as a CLI similar to tee:

echo "hello" | python -m rotary_logger my_log_folder

You can also use the shortcut: pytee.

It works similarly to python -m rotary_logger.

The positional argument is the base folder where logs will be stored. The package always builds the rest of the path automatically in the following way: path/to/folder/year/month/day/. If you pass -m (--merge), all streams are written to timestamped files directly under the day folder; otherwise two subfolders stdout/ and stderr/ are created, each containing their own timestamped files.

If multiple destination folders are passed, only the first is used and a warning is printed to stderr.

Library usage

Embed RotaryLogger in your application:

from pathlib import Path
from rotary_logger import RotaryLogger, RL_CONST

_path_to_store_the_log: Path = Path('/var/log/myapp')

RL = RotaryLogger(
 log_to_file=True,
 override=False,
 default_max_filesize=(2*RL_CONST.GB1),
 merge_streams=False # Set to True if you want your stdout and stderr to be put into the same file instead of seperate.
)
RL.start_logging(log_folder=_path_to_store_the_log, merged=False)

This replaces sys.stdout and sys.stderr with TeeStream wrappers. To stop logging in-process call RL.stop_logging() — this restores the original streams, flushes any buffered data, and unregisters the atexit flush handlers.

Public API exports

The following symbols are exported from the top-level rotary_logger package:

from rotary_logger import RotaryLogger  # main high-level class
from rotary_logger import Tee           # CLI entrypoint wrapper
from rotary_logger import TeeStream     # low-level stream mirror
from rotary_logger import FileInstance  # buffered file writer / rotator
from rotary_logger import RL_CONST      # package constants (GB1, MB1, StdMode, …)

Documentation

You can find documentation here: docs as well as here: https://hanra-s-work.github.io/rotary_logger/

Logo source

The source of the logo used in the documentation: https://deepai.org, then edited in gimp.

Configuration & options

Common CLI options

Flag Long form Description
(positional) files Base folder for log output (optional; disables file logging when omitted)
-a --append Append to existing log files instead of overwriting
-m --merge Merge stdout and stderr into a single log file
-i --ignore-interrupts Ignore Ctrl+C (SIGINT)
-s N --max-size N Maximum log file size in MB before rotation

Library API (short)

  • RotaryLogger(log_to_file, override, raw_log_folder, default_log_folder, default_max_filesize, merge_streams, *, encoding, merge_stdin, capture_stdin, capture_stdout, capture_stderr, prefix_in_stream, prefix_out_stream, prefix_err_stream, log_function_calls_stdin, log_function_calls_stdout, log_function_calls_stderr) — constructor; does not start logging
  • RotaryLogger.start_logging(*, log_folder=None, max_filesize=None, merged=None, log_to_file=True, merge_stdin=None) — begin capturing and rotating logs

Refer to the module docs (or docstrings) for full API details.

Running tests

The project uses pytest. From the repository root (inside your virtualenv):

pip install -r requirements.txt
pytest -q

To run the CI-like test harness used during development, use action_test.sh (requires Docker):

./action_test.sh

Development notes

  • Locking: the code uses per-object threading.RLock instances. The recommended pattern is to snapshot minimal state while holding the lock, release the lock to perform blocking I/O, then re-acquire to commit state. This avoids holding locks during filesystem operations.
  • By default, logs are written under the logs/ folder inside the package directory unless a log_folder is supplied.

Control functions (library API)

RotaryLogger exposes a small set of control functions to manage in-process log capturing. These are safe to call from multiple threads, but there are a few rules and guarantees to understand:

  • start_logging(*, log_folder=None, max_filesize=None, merged=None, log_to_file=True, merge_stdin=None) -> None

    • Start redirecting sys.stdout and sys.stderr to TeeStream wrappers and begin writing to rotating files.
    • Parameters: log_folder — optional base folder to write logs; max_filesize — override rotation size in MB; merged — whether to merge stdout/stderr into a single file; log_to_file — whether to enable file writes; merge_stdin — whether stdin is merged into the shared file.
    • Thread-safety: the function snapshots configuration under an internal lock and performs filesystem checks outside the lock; assignment of sys.stdout/sys.stderr is performed atomically while holding the lock.
  • stop_logging() -> None

    • Stop capturing and restore the original sys.stdout/sys.stderr/sys.stdin objects.
    • This function flushes buffers and also attempts to unregister any atexit flush handlers that were registered by start_logging.
    • Thread-safety: restores streams while holding the internal lock and flushes outside the lock to avoid blocking critical sections.
  • pause_logging(*, toggle: bool = True) -> bool

    • Toggle the pause state. When toggle=True and logging is active, pause it (uninstall TeeStreams, restore originals); when toggle=True and already paused, resume it. When toggle=False, always pause regardless of current state.
    • Returns the new paused state (True when paused).
    • Thread-safety: updates and stream replacements are done while holding the internal lock; expensive flushes are executed outside the lock.
  • resume_logging(*, toggle: bool = False) -> bool

    • Explicitly resume logging. When toggle=False (default), always resume. When toggle=True and logging is already active, pauses instead.
    • Returns the paused state after the call (False when logging was resumed).
    • Thread-safety: same guarantees as pause_logging.
  • is_logging() -> bool

    • Returns True when logging is active (a TeeStream is installed and the logger is not paused).
    • Safe to call concurrently.
  • is_redirected(stream: StdMode) -> bool

    • Query whether the given stream (StdMode.STDOUT, STDIN, STDERR) is currently redirected to a TeeStream.

Notes

  • atexit handlers: RotaryLogger registers flush handlers via atexit.register to attempt a final flush at process exit; those handlers are unregistered when stop_logging() is called. The implementation stores the exact bound-methods used to guarantee atexit.unregister works reliably.
  • Concurrency testing: basic concurrent toggling of pause/resume is covered by the project's tests. Calling start_logging/stop_logging concurrently from multiple threads is heavier and may involve filesystem operations — avoid such patterns in production unless you synchronize externally.
  • stdin capture: stdin is not captured by default. Pass capture_stdin=True to the RotaryLogger constructor to wrap sys.stdin.

Environment variables

The following environment variables are read at import time and can override default configuration:

Variable Type Default Description
LOG_TO_FILE bool (1/true/yes) true Whether file logging is enabled
LOG_FOLDER_NAME str (path) <package_dir>/logs Base folder for log output
LOG_MAX_SIZE int (bytes) 2 GB Maximum log file size before rotation

Documentation (Doxygen)

The project uses generated Doxygen in different formats:

  • HTML
  • LaTeX (every time a version is released)
  • RTF (every time a version is released)

You can view the documentation online, by going here: https://hanra-s-work.github.io/rotary_logger/

Contributing

Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md before opening issues or PRs.

License

See the LICENSE file in the repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rotary_logger-1.0.2.tar.gz (47.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rotary_logger-1.0.2-py3-none-any.whl (40.8 kB view details)

Uploaded Python 3

File details

Details for the file rotary_logger-1.0.2.tar.gz.

File metadata

  • Download URL: rotary_logger-1.0.2.tar.gz
  • Upload date:
  • Size: 47.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for rotary_logger-1.0.2.tar.gz
Algorithm Hash digest
SHA256 43ec77d3b2566f62bb69f4cebb240e4c46d0936a861eb982a3615f8359162d36
MD5 3403908715bae90b1f0f7bb0adcda33a
BLAKE2b-256 85de61e15060d3d732fe418283f6792a25edccb485be7c2b354a168d82f408d6

See more details on using hashes here.

File details

Details for the file rotary_logger-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: rotary_logger-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 40.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for rotary_logger-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e2ad39d5f82ef1a83725bc4a596c9e94f5d09ce4babeab45e3c3292dfbc27b0c
MD5 a94c452c8ebd8bd102ceb257fe1ce467
BLAKE2b-256 2ee936dc5c6c3a1ac1c9fec38d7fdb1164b7067e21a473a6eb727b84d423c5b1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page