Redact sume_live_ API keys from Python logs with a handler filter
A logging.Filter on a logger skips records from child loggers. Put the redaction filter on the handler so a sume_live_ key never reaches the log file.

Sume API keys start with sume_live_. The authentication docs say keys belong on trusted servers and that a key which shows in logs or chat history should be rotated. A redaction filter is a seatbelt, not a cure: it stops the next leak, and it does not make an already logged key safe.
In Python the usual mistake is attaching the filter to a logger. A filter on a logger runs only for records logged directly on that logger, not for records from its child loggers that propagate up. Attach it to the handler and every record that reaches the handler is cleaned.
The filter
It formats the message first, so keys inside %s arguments are caught, then clears args so the message is not formatted twice.
import logging, re
KEY = re.compile(r"sume_live_[\w-]+")
class RedactSumeKeys(logging.Filter):
def filter(self, record):
record.msg = KEY.sub("sume_live_[redacted]", record.getMessage())
record.args = ()
return True
handler = logging.StreamHandler()
handler.addFilter(RedactSumeKeys()) # on the handler, not a logger
logging.basicConfig(level=logging.INFO, handlers=[handler])
http_log = logging.getLogger("myapp.http.sume") # a child logger still passes the handler
http_log.info("POST /v1/images headers=%s", {"x-api-key": "sume_live_abc123-XYZ"})
http_log.info("rotated to sume_live_new_key_789")What the output looks like
Both log lines print sume_live_[redacted], including the one from myapp.http.sume, a child logger the filter was never attached to. If you attach the same filter to the root logger instead, the child record sails through unredacted.
Limits to keep in mind
- The pattern matches the
sume_live_prefix followed by word characters and hyphens. If you log a header dict, make sure the value is a string the regex can see; a key split across fields is not matched. - Other handlers you add later, such as a Sentry or file handler, need the filter too.
- Rotate the key if the raw value was ever written: create the new key, check it with
GET /v1/me, deploy it, then revoke the old one. - A pre-commit secret scan catches keys in source; this filter catches keys at runtime.
Sources
Related posts
More in Developers
- Redis sorted set scheduler for AI video job polling in Python
Keep video job ids in a Redis ZSET scored by next-poll time, claim due ids with ZREM so no two workers poll one job, reschedule by next_poll_after_seconds.
- Refuse an empty Sume API key or webhook secret: a fail-fast loader
An empty SUME_API_KEY or webhook secret fails late and confusingly. Load both at boot, reject empty or whitespace values, and never print them. Python, tested.
- Save a Sume artifact atomically: write a .part file, then rename
A half-written MP4 that looks finished is worse than none. Download a Sume artifact to a .part file, check the length, rename once. Tested in Python.
- Schedule the next Ideogram 4.5 batch wave from ratelimit-reset
Size each wave from ratelimit-remaining and wave_size_hint, and when the write bucket is empty sleep ratelimit-reset seconds. A pure function you can test.
Written by Sume