Class MdcProjector
key -> value pairs an alert body may carry — the include-mdc-keys feature.
The allow-list is the whole point. Only keys the operator named are ever read, there is deliberately no wildcard and no "include everything" mode, and an unset allow-list yields an empty map without the MDC ever being consulted. The MDC of a production application routinely holds session tokens, user identifiers, and other data that must never leave the process in a notification, so the selection can only ever widen by an explicit configuration change.
Adapters (logback, JUL, ...) call project(java.util.List<java.lang.String>, java.util.function.Function<java.lang.String, java.lang.String>) with the configured key list and a lookup
function bound to their framework's context, and hand the result to AlertEvent. This class
is public precisely because those adapters live in sibling modules; it is otherwise an internal
utility with no state.
Three properties make the projection safe to append to an alert body:
- Structure-safe. Every control character, Unicode line/paragraph separator
and format (Cf) character is replaced with a single space, so an MDC value can neither forge
body structure (a fake
Caused by:line) nor breakPayloadTruncator's line-by-line splitting, nor smuggle a bidi override past a reader's eyes. - Bounded. At most 16 entries, each value at most 256 characters, and at most 1024 characters overall — so the context block can never crowd the message, cause chain, and stack frames out of ntfy's 4096-byte body budget.
- Cheap. The caps are enforced while iterating, so a pathological 10 000-entry allow-list costs at most 16 context lookups per event, not 10 000.
Every guard here is idempotent: sanitize(java.util.Map<java.lang.String, java.lang.String>) applied to an already-sanitized map returns an
equal map, which is what lets AlertEvent re-run it on construction as belt-and-braces
without mangling a projection this class already produced.
-
Method Summary
-
Method Details
-
project
Reads the allow-listed keys out of a logging context and returns the sanitized, bounded, configured-order map to render into an alert body.Semantics, in order:
- A
null/emptyallowedKeysor anulllookupreturns an empty map without callinglookupeven once — the feature being unset must cost nothing and must not touch the context at all. allowedKeysis walked in order; that order IS the rendering order in the body.null/blank keys and keys already consulted are skipped.- A key whose value is absent, blank, or nothing but control characters produces no entry —
and therefore no line in the body — rather than an empty
"key: "line. - A
lookupthat throws is treated exactly like an absent value: a hostile or simply broken context implementation must never break the logging path it is decorating.
- Parameters:
allowedKeys- the operator-configured MDC key names, in the order they should be renderedlookup- reads one key from the ambient logging context, returningnullwhen absent- Returns:
- an unmodifiable, insertion-ordered map; never
null
- A
-