Zero-config PII redaction for Python logging
Project description
HushLog
Zero-config PII redaction for Python logging.
Features
- Zero-config -- one call to
hushlog.patch()and you're done - Non-invasive -- wraps existing formatters, no logger rewrites needed
- Performant -- pre-compiled regex with heuristic early-exit checks
- Type-safe -- fully typed with PEP 561
py.typedmarker - Python 3.10+ -- supports Python 3.10 through 3.13
Installation
pip install hushlog
Or with uv:
uv add hushlog
Quick Start
import logging
import hushlog
# Configure logging FIRST, then patch
logging.basicConfig(level=logging.INFO)
hushlog.patch()
logger = logging.getLogger(__name__)
logger.info("User email: john@example.com")
# Output: User email: [EMAIL REDACTED]
logger.info("Card: 4111-1111-1111-1111")
# Output: Card: [CREDIT_CARD REDACTED]
logger.info("SSN: 123-45-6789")
# Output: SSN: [SSN REDACTED]
How It Works
HushLog wraps your existing logging formatters with a RedactingFormatter that scans the final formatted string for PII patterns. It never replaces loggers or handlers -- your existing logger.info() calls remain unchanged. All regex patterns are pre-compiled at import time with lightweight heuristic pre-checks to minimize overhead on the hot logging path.
What Gets Redacted
| Pattern | Example | Output | Notes |
|---|---|---|---|
john@example.com |
[EMAIL REDACTED] |
RFC 5322 subset, @ heuristic pre-check |
|
| Credit Card | 4111-1111-1111-1111 |
[CREDIT_CARD REDACTED] |
Luhn validated, supports spaces/dashes |
| SSN | 123-45-6789 |
[SSN REDACTED] |
Dashed format only, invalid ranges excluded |
| Phone | (555) 123-4567 |
[PHONE REDACTED] |
US NANP, multiple formats |
| JWT | eyJhbGci... |
[JWT REDACTED] |
3-5 segment base64url tokens |
| AWS Access Key | AKIAIOSFODNN7EXAMPLE |
[AWS_ACCESS_KEY REDACTED] |
AKIA/ASIA prefixed |
| AWS Secret Key | aws_secret_access_key=... |
[AWS_SECRET_KEY REDACTED] |
Context-dependent (requires label) |
| Stripe Key | sk_live_abc123... |
[STRIPE_KEY REDACTED] |
sk/pk/rk live/test keys |
| GitHub Token | ghp_xxxx... |
[GITHUB_TOKEN REDACTED] |
Classic + fine-grained (github_pat_) |
| GCP API Key | AIzaSyA... |
[GCP_KEY REDACTED] |
AIza-prefixed keys |
| Generic Secret | password=MyS3cret |
[SECRET REDACTED] |
Label-based (password, secret, api_key, etc.) |
| IPv4 | 192.168.1.1 |
[IPV4 REDACTED] |
Octet-validated, rejects version strings |
| IPv6 | 2001:db8::8a2e:370:7334 |
[IPV6 REDACTED] |
Full, compressed, and mixed forms |
Configuration
Disable specific built-in patterns or add custom ones:
from hushlog import Config
hushlog.patch(Config(
disable_patterns=frozenset({"phone"}),
custom_patterns={"internal_id": r"ID-[A-Z]{3}-[0-9]{6}"},
))
Partial Masking
Show partial values instead of full redaction:
hushlog.patch(Config(mask_style="partial"))
# john@example.com → j***@e***.com
# 4111111111111111 → ****-****-****-1111
# 078-05-1120 → ***-**-1120
# (555) 234-5678 → (***) ***-5678
Use a custom mask character:
hushlog.patch(Config(mask_style="partial", mask_character="#"))
# john@example.com → j###@e###.com
Note: Partial masking reveals partial information (first/last characters). In small organizations, this may be identifying. Use
mask_style="full"(default) for maximum privacy.
Teardown
Call unpatch() to remove HushLog's formatter wrappers and restore the original formatters. This is useful for testing or runtime toggling:
hushlog.unpatch()
Calling unpatch() without a prior patch() is safe (no-op). Calling patch() multiple times is also safe (idempotent).
Limitations
- Only handlers present on the root logger at
patch()time are wrapped. Handlers added later will not be redacted. - Named loggers with
propagate=Falseand their own handlers bypass root-level redaction. - No structured log support yet (structlog/loguru integrations planned for v0.3.0).
- Phone detection is US NANP only.
Planned
Structlog/loguru integrations, pattern validation, and more. See the roadmap for details.
Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
License
MIT -- see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hushlog-0.2.0a4.tar.gz.
File metadata
- Download URL: hushlog-0.2.0a4.tar.gz
- Upload date:
- Size: 71.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aacecceadbff90a5c227065b3cbf12d4a340f93c30a8a4fd3028407476388896
|
|
| MD5 |
af64e6bf2f4eb60e611042e317b34937
|
|
| BLAKE2b-256 |
be2c10500ca63e729f443ec8c3c4dc093da13365917d4d1be5d43229ba053591
|
Provenance
The following attestation bundles were made for hushlog-0.2.0a4.tar.gz:
Publisher:
release.yml on FelipeMorandini/hushlog
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hushlog-0.2.0a4.tar.gz -
Subject digest:
aacecceadbff90a5c227065b3cbf12d4a340f93c30a8a4fd3028407476388896 - Sigstore transparency entry: 1135425978
- Sigstore integration time:
-
Permalink:
FelipeMorandini/hushlog@9091e8fdb3d220fdc6a47ae665e3628da6a210e6 -
Branch / Tag:
refs/tags/v0.2.0a4 - Owner: https://github.com/FelipeMorandini
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9091e8fdb3d220fdc6a47ae665e3628da6a210e6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hushlog-0.2.0a4-py3-none-any.whl.
File metadata
- Download URL: hushlog-0.2.0a4-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fc0ea3b196f3f8d4d60d1cc5f8bc9872bd3dc74161aaf352d2f93766b31fbb3
|
|
| MD5 |
7351905476b0ddf6dc95cc74919804f3
|
|
| BLAKE2b-256 |
c8b511ed77d2ac7cb2c46eee68476ebe0513909f7be36f82d7d40645e5c13649
|
Provenance
The following attestation bundles were made for hushlog-0.2.0a4-py3-none-any.whl:
Publisher:
release.yml on FelipeMorandini/hushlog
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hushlog-0.2.0a4-py3-none-any.whl -
Subject digest:
1fc0ea3b196f3f8d4d60d1cc5f8bc9872bd3dc74161aaf352d2f93766b31fbb3 - Sigstore transparency entry: 1135426010
- Sigstore integration time:
-
Permalink:
FelipeMorandini/hushlog@9091e8fdb3d220fdc6a47ae665e3628da6a210e6 -
Branch / Tag:
refs/tags/v0.2.0a4 - Owner: https://github.com/FelipeMorandini
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9091e8fdb3d220fdc6a47ae665e3628da6a210e6 -
Trigger Event:
push
-
Statement type: