Skip to main content

jacl4py

Just another custom logger for Python.

jacl4py is a standalone package containing the custom Python logger previously used by pookiepy.

Release Status

Releases before 1.0.0 are testing versions and may introduce breaking changes without a major version increment. Semantic versioning will begin with 1.0.0.

Installation

Install from PyPI:

pip install jacl4py

Or install the local package with uv:

uv pip install .

Usage

from jacl4py.logger import INTERNAL_INFO, get_logger

logger = get_logger("service")
logger.iinfo("framework lifecycle event")
logger.log(INTERNAL_INFO, "another internal event")
logger.info("service started")

Only get_logger() is needed to configure a logger. Package loggers use their own registry, so importing the module does not replace Python's global logger class. logging.getLogger("service") and get_logger("service") are separate objects and do not change each other's handlers. The INTERNAL_DEBUG and INTERNAL_INFO level names are registered with logging.

The console handler defaults to INFO; the file handler defaults to INTERNAL_DEBUG. The default log_dir=LogDir.DEFAULT writes log files under the system temporary directory in <safe-name><uuid8>/<safe-name>.log. For example, get_logger("test") might write to test12345678/test.log under the temporary directory. The suffix is the first eight hexadecimal characters of UUID4; existing paths are never reused on a collision. Names are restricted to ASCII letters, digits, dots, underscores, and hyphens for filesystem use, with other characters replaced by underscores and the name component limited to 64 characters. The original logger name is preserved in log records.

Each writer has one stable active filename. Files rotate daily and retain up to 30 backups for that writer, not necessarily 30 calendar days. Reinitialization and new processes receive fresh paths. Old run directories and file families are preserved, not automatically pruned. The custom iinfo() and idebug() methods emit at levels 7 and 5 respectively.

Pass log_dir=None to disable file logging, or a string or Path for a custom directory. An explicit directory is used as given, with a unique filename <safe-name><uuid8>.log inside it. Pass None for console_log_level or file_log_level to disable that handler. Use an application-owned directory when file permissions or durable retention matter.

from jacl4py.logger import LogDir, get_logger

logger = get_logger("service", log_dir=LogDir.DEFAULT)
console_only = get_logger("console", log_dir=None)

JacLogger.setLevel() follows standard logging behavior: it changes only the logger threshold, preserving independent console and file handler levels. Reusing a configured name returns the cached logger, emits a warning, and ignores new configuration arguments. Initialization and deletion are serialized across threads; ordinary log calls do not acquire the package lifecycle lock.

Pass reinit_if_exists=True to replace an existing logger and apply new settings without the cached-logger warning:

from jacl4py.logger import delete_logger, get_logger

log = get_logger("my_test11", reinit_if_exists=True)
delete_logger("my_test11")

delete_logger(name) closes and removes the package logger's handlers and unregisters it without touching standard loggers. It returns True if a package logger was deleted, otherwise False. Existing log files are preserved. Logging through a deleted JacLogger reference raises ResourceNotInitializedError, a subclass of RuntimeError, even for messages below the configured level. Import it from jacl4py.logger or jacl4py.exceptions. Use the new object returned by get_logger() after reinitialization. Package child loggers remain usable and reconnect when the named logger is recreated. Use get_logger() for child names too.

In each worker process, call get_logger() to obtain a separate writer. After fork, inherited package logger references are invalidated automatically; do not continue logging through an inherited reference. No queue or listener is required. Logging is synchronous, including disk writes and rollover, so it can block application threads or an async event loop. Configure or replace loggers before starting work rather than while other threads are emitting records.

The version is available from the imported logger module:

from jacl4py import logger

print(logger.__version__)

For a release, edit only __version__ in jacl4py/__init__.py. PDM reads that constant for wheel and source-distribution metadata; jacl4py.__version__ and jacl4py.logger.__version__ expose the same value.

Development

This standalone repository targets Python 3.10 or newer. It is authored by Fabian Krumm and distributed under the BSD 3-Clause License from the original project.

Run the unit tests with uv:

uv pip install -r requirements.txt
uv run --with-requirements requirements.txt python -m unittest discover -s tests -p "test_*.py"

Install development tools, including Pylint and coverage:

uv pip install -r requirements-dev.txt

Run the same Pylint check as the push and pull request workflow:

uv run --with-requirements requirements-dev.txt python -m pylint --jobs=1 jacl4py tests

Check test coverage, including branches and missing lines:

uv run --with-requirements requirements-dev.txt python -m coverage run --branch --source=jacl4py -m unittest discover -s tests -p "test_*.py"
uv run --with-requirements requirements-dev.txt python -m coverage report -m

Build with:

uv build

requirements.txt contains runtime-only dependencies and mirrors pyproject.toml project dependencies. The workflows use it before tests, build, and publication preflight; the requirements guard test detects drift, so update both files together. PDM's declared build backend supplies uv build build dependencies, while the generated wheel and source-distribution metadata causes pip installs to resolve runtime dependencies automatically. The requirements files are included in source distributions. requirements-dev.txt includes the runtime requirements and adds development-only tools. PDM includes the package source and test/workflow sources directly, so a MANIFEST.in file is unnecessary.

Publishing

GitHub Actions discovers workflows only from the repository root's .github/workflows directory; workflows nested under logger-package are not run automatically in this monorepo. When this package is published from its own repository, keep these workflow files at that repository root.

pypi_publish.yml runs on pushes to master, not GitHub Release publication. A read-only build job runs preflight unit tests, builds wheel and sdist, checks them with Twine, smoke-tests each installed artifact, and uploads the validated distributions. Only then does the pypi-release environment job publish those artifacts through PyPI Trusted Publishing (OIDC, no stored API token), with skip-existing: true, print-hash: false, and attestations: true.

After successful publication, it creates an annotated v<version> tag from jacl4py/__init__.py. An existing tag on the same commit is an idempotent no-op; a tag on another commit is never moved and causes failure. Edit the local version constant manually before a new release: neither tags nor commit messages infer or automatically bump the version. PDM reads that constant for metadata.

Configure the PyPI trusted publisher for project jacl4py, your GitHub owner/repository, workflow filename pypi_publish.yml, and environment pypi-release. Keep that filename to preserve the trusted publisher identity and retain the environment URL https://pypi.org/project/jacl4py/. Confirm project availability and choose an unpublished version before pushing. Skipping existing files allows retries; it does not permit replacing a published version.

Publication depends on its own build job, not a mandatory CI needs barrier. Protect master with required supported-version tests, lint, build and workflow audit checks; protect the environment with reviewers and branch restrictions. Floating 3.x probes are nonblocking, not support guarantees. CI runs Python 3.10-3.14 on five runners, reports coverage without a minimum, and uses Pylint 3.2.6 with the default fail-under of 10 and no disabled messages or custom threshold. See .github/CI.md for the matrix, weekly checks, reference differences, and repository settings.

todos

ai findings

  • Medium (#6): Benchmark synchronous logging under representative load. Document an optional bounded queue/listener recipe only if needed, including overflow behavior and flushing at shutdown. UUID paths isolate writers but do not remove I/O latency.
  • Medium (#7): Make intentionally disabled outputs silent with a NullHandler; track configuration independently of handler presence so Python's lastResort handler cannot unexpectedly emit to stderr.
  • Medium (#8): Validate replacement settings and build handlers before invalidating the working logger. Finish cleanup if one handler fails to close, and consider an opt-in strict policy for required file logging.
  • Medium (#9): Increment stacklevel in iinfo() and idebug() so caller metadata identifies application code rather than the wrapper.
  • Medium (#10): Extend regression coverage for output silence, caller attribution, custom global logger factories, and file open/write/close failures; add branch coverage reporting in CI. High-severity regression tests have been added but still need execution.
  • Medium (#11): Pin the PyPI publishing action to a reviewed commit; lock release tooling, automate dependency updates and vulnerability audits, and verify the release tag against built metadata. Keep consumer dependency ranges separate from release-tool reproducibility.
  • Low (#12): Add real project/support URLs, tested Python classifiers, contribution and private security-reporting guidance, and a compatibility and deprecation policy. Expand privacy, permissions, and application integration guidance as the public API settles.
  • Retention follow-up: Define opt-in cleanup of completed runs if total disk usage must be bounded. Per-writer rotation does not delete older UUID directories or file families; do not delete other writers' files implicitly.

Metadata

Release files for jacl4py 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jacl4py 0.0.1
File Size Uploaded Provenance Actions
jacl4py-0.0.1.tar.gz 30.1 kB With provenance Details for jacl4py-0.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for jacl4py 0.0.1
File Interpreter ABI Platform Actions
jacl4py-0.0.1-py3-none-any.whl Python 3 none any Details for jacl4py-0.0.1-py3-none-any.whl

Total release size: 40.3 kB

Release files / jacl4py-0.0.1.tar.gz

Download URL jacl4py-0.0.1.tar.gz
Size 30.1 kB
Tags Source
SHA-256 checksum
How to use checksums
5174807bc2d478d24256061604defbfcfc7ce096b99610eb08c449066fecab3c
BLAKE2b-256 checksum
How to use checksums
1939d1a395d28fb65c52d0690a7e295a7b2b8d902a652af53fe6a7d175a79f45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / jacl4py-0.0.1-py3-none-any.whl

Download URL jacl4py-0.0.1-py3-none-any.whl
Size 10.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4c0ab85166c70cf14646fcceb01e31538ce418dc2f05bb165cde507c0fe064f
BLAKE2b-256 checksum
How to use checksums
7a36581e71162d65e7457fced43750f28287cf1cd0c594462a0c06cfaca55cf8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for jacl4py 0.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for jacl4py-0.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page