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'slastResorthandler 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
stackleveliniinfo()andidebug()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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.