Mask sensitive data
Secrets slip into logs easily — a request body with a password, a header with an
authorization token. SensitiveMaskingProcessor redacts them before they reach any
handler, so they never hit disk or your aggregator.
Add the processor to a channel
The processor is optional — add it after building the manager. Push it onto the channel’s underlying Monolog instance:
use Flytachi\Winter\Logger\Processor\SensitiveMaskingProcessor;
$manager->channel('http')->monolog()->pushProcessor(new SensitiveMaskingProcessor());Now any matching key is replaced with *** in both context and extra:
LoggerFactory::getLogger(self::class)->info('login attempt', [
'username' => 'alice',
'password' => 'hunter2', // ← masked
'metadata' => [
'token' => 'secret-jwt', // ← nested, also masked
],
]);[2024-01-01 12:00:00] [INFO ] -http- [4821] (AuthService): login attempt {"username":"alice","password":"***","metadata":{"token":"***"}}What it matches
- Case-insensitive on keys —
Password,PASSWORD, andpasswordall match. - Recursive — nested arrays are traversed to any depth.
- Applies to both the per-call
contextand the injectedextra.
The default masked keys (all replaced with ***):
password passwd secret token access_token refresh_token
api_key apikey authorization auth cookie set-cookie
credit_card card_number cvv ssn pinThe authoritative list lives in Log format reference.
Add your own keys
Pass extra keys to the constructor — they’re merged with the defaults:
$processor = new SensitiveMaskingProcessor(['patient_id', 'insurance_number']);
$manager->channel('http')->monolog()->pushProcessor($processor);Apply it to every channel
There’s no global switch — add the processor to each channel you want masked. A small loop at bootstrap covers them all:
foreach (['http', 'cli', 'sys'] as $name) {
if ($manager->hasChannel($name)) {
$manager->channel($name)->monolog()->pushProcessor(new SensitiveMaskingProcessor());
}
}Values are matched by key, not by content
The processor redacts based on the field name, not the value. A secret logged under an
unlisted key (e.g. data) or interpolated into the message string won’t be caught — keep
secrets in well-named context keys, and never put them in the message text.
Related
- Log format → Masked keys — the full default list
- API reference → Processors — constructor signature
- Request context — where
extrafields come from