logging-claim-audit
Offline, stdlib-only audit of documented record-keeping promises in a Python project against its Python source. It reads docs and code, runs nothing, uses no network, and never opens the contents of any environment file.
A project can promise three kinds of record-keeping behaviour, and each can drift from the code without any test failing:
- a file-sink promise: records are kept in a file the user can find later;
- a machine-readable record promise: records are emitted in a shape a parser can consume directly;
- an absence-of-records promise: the tool keeps nothing at all.
The first two fail quietly when the code never builds the corresponding
mechanism. The third fails quietly in the other direction: a user who was
told nothing is kept discovers records the docs said would not exist.
This tool checks all three directions statically, from prose in the root
README and docs/**/*.md against imports and calls in production
Python source.
Installation
pip install logging-claim-audit
Or from source:
python3 -m pip install .
Usage
logging-claim-audit /path/to/project
logging-claim-audit /path/to/project --json
logging-claim-audit /path/to/project --fail-on HIGH
logging-claim-audit /path/to/project --ignore "vendor/*"
Exit codes: 0 means pass, 2 means at least one finding at or above
the --fail-on threshold (default MEDIUM), 1 means a usage error.
--verbose prints verified promises. --json prints findings and
verified promises as JSON.
Rules
documented-file-log-claim-false (HIGH)
file-sink promise present, zero file-sink evidence in production
source and zero file-sink evidence under tests/fixtures only.
documented-file-log-claim-false-test-only (MEDIUM)
file-sink promise present, zero production file-sink evidence, but
file-sink evidence under tests/fixtures only.
documented-structured-log-claim-false (HIGH)
machine-readable record promise present, zero machine-readable
evidence in production source and zero under tests/fixtures only.
documented-structured-log-claim-false-test-only (MEDIUM)
machine-readable record promise present, zero production
machine-readable evidence, but such evidence under tests/fixtures only.
documented-no-log-claim-false (HIGH)
absence-of-records promise present, but production source contains
record-keeping evidence (any of the kinds below).
documented-no-log-claim-false-test-only (MEDIUM)
absence-of-records promise present, zero production record-keeping
evidence, but such evidence under tests/fixtures only.
Claim phrases (exact phrases only, matched on normalised prose with word boundaries; fenced code blocks are excluded, inline code counts):
file-sink family:
"logs to a file", "writes logs to a file", "write logs to a file",
"logs are written to a file", "log file", "log files"
machine-readable family:
"structured logging", "structured logs", "json logs",
"logs in json format", "logs as json", "json formatted logs"
absence family:
"no logging", "does not log", "never logs", "no logs",
"without logging", "does not log anything", "never logs anything"
Negation on a sentence suppresses the file-sink and machine-readable families on that sentence, but not the absence family (whose phrases are themselves negative wordings). A denial scoped to a file sink only (for example a sentence saying records are never written to a file) yields no promise of either kind and is not audited. One finding per family at most; a tree with no production Python source at all yields one HIGH finding per promised family; a tree with no promise yields a pass even if record-keeping calls are everywhere.
Evidence (production source only; tests/, fixtures/, docs/,
examples/, and symlinked files are excluded from production evidence):
- File-sink evidence:
FileHandlerfamily calls (FileHandler,RotatingFileHandler,TimedRotatingFileHandler,WatchedFileHandler),basicConfigwith afilenamekeyword whose value is notNone, and logurulogger.addwith a string file sink. - Machine-readable evidence:
structlog/pythonjsonloggerimports,JsonFormattercalls, logurulogger.add(serialize=True), and a record-keeping call whose argument is ajson.dumps(...)call. - Any-record evidence (falsifies an absence promise): all of the above,
plus any record-keeping library import, any record-keeping call on a
receiver whose dotted name contains
log, andgetLoggercalls. - A bare name that is redefined in the same file (a local function, class, or parameter with the same name) suppresses name-based evidence for that name in that file; attribute-based evidence is unaffected.
Differentiation
- silent-claim-audit: output volume (quiet/verbose), never whether records go through a record-keeping framework or to a file sink.
- format-claim-audit: data formats read/written, never the shape or destination of the tool's own operational records.
- privacy-claim-audit: network/telemetry presence, never local record keeping.
- bandit/ruff: code issues, never docs promises.
- logging / structlog / loguru documentation: libraries that provide record keeping, never docs-vs-code truth.
Honest limitations
- Static pattern matching, not semantic judgement: a file-sink call in dead code counts as evidence, and an unused record-keeping import counts as evidence. Both are intentional over-approximations.
- A variable sink value is unknown and skipped; only string-literal sinks count for loguru file sinks.
basicConfig(filename=None)andserialize=Falseare explicitly not evidence.dictConfigcontents are not parsed: a file handler named only inside a configuration dict literal is missed. This is the main recall gap alongside print-based records:print(json.dumps(...))is not a record-keeping call and is not counted.- A plain
Formatterwith a format string is not machine-readable evidence by itself. - A bare
.infoon a receiver whose name contains nologis not a record-keeping call. - This tool checks record-keeping existence, destination, and shape — not whether records are complete, rotated, or actually flushed.
Development
PYTHONPATH=src python3 -m unittest discover -s tests -v
python3 -m build
Requires Python 3.9 or later. Standard library only, no dependencies.
Metadata
Release files for logging-claim-audit 0.1.0
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 |
|---|---|---|---|---|
| logging_claim_audit-0.1.0.tar.gz | 14.9 kB | Without provenance | Details for logging_claim_audit-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| logging_claim_audit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for logging_claim_audit-0.1.0-py3-none-any.whl |
Total release size: 24.4 kB
Release files / logging_claim_audit-0.1.0.tar.gz
| Download URL | logging_claim_audit-0.1.0.tar.gz |
|---|---|
| Size | 14.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd01d56821aaf84a8644278170fa72a6fe736e7b975c25dacc4c67bc55ed946c
|
|
BLAKE2b-256 checksum How to use checksums |
e537df09f6b82fced132164bf6680a958e199c3f24dae8ffceddbea889f5552e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / logging_claim_audit-0.1.0-py3-none-any.whl
| Download URL | logging_claim_audit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0368907e50ed16cda80d519598119df79062fb128558f302f65baac6782d7f49
|
|
BLAKE2b-256 checksum How to use checksums |
f16784df1c5fe1fa7e801c90f4daa770e16fe236cc0a519b9b00f77e87241c6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for logging-claim-audit 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.