ivuorinen / monolog-gdpr-filter
Monolog processor for GDPR masking with regex and dot-notation paths
Requires
- php: ^8.2
- adbario/php-dot-notation: ^3.3
- monolog/monolog: ^3.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.47
- guuzen/psalm-enum-plugin: ^1.1
- orklah/psalm-strict-equality: ^3.1
- phpunit/phpunit: ^11
- psalm/plugin-phpunit: ^0.19.5
- rector/rector: ^2.1
- squizlabs/php_codesniffer: ^3.9
- vimeo/psalm: ^6.13
README
Monolog GDPR Filter is a PHP library that provides a Monolog processor for GDPR compliance. It allows masking, removing, or replacing sensitive data in logs using regex patterns, field-level configuration, and custom callbacks. Designed for easy integration with Monolog and Laravel.
Features
- Regex-based masking for patterns like SSNs, credit cards, emails
- Field-level masking/removal/replacement using dot-notation paths
- Custom callbacks for advanced masking logic per field
- Audit logging for compliance tracking
- Easy integration with Monolog and Laravel
Installation
Install via Composer:
composer require ivuorinen/monolog-gdpr-filter
Usage
Basic Monolog Setup
use Monolog\Logger; use Monolog\Handler\StreamHandler; use Ivuorinen\MonologGdprFilter\GdprProcessor; use Ivuorinen\MonologGdprFilter\FieldMaskConfig; $patterns = GdprProcessor::getDefaultPatterns(); $fieldPaths = [ 'user.ssn' => GdprProcessor::removeField(), 'payment.card' => GdprProcessor::replaceWith('[CC]'), 'contact.email' => GdprProcessor::maskWithRegex(), 'metadata.session' => GdprProcessor::replaceWith('[SESSION]'), ]; // Optional: custom callback for advanced masking $customCallbacks = [ 'user.name' => fn($value) => strtoupper($value), ]; // Optional: audit logger for compliance $auditLogger = function($path, $original, $masked) { error_log("GDPR mask: $path: $original => $masked"); }; $logger = new Logger('app'); $logger->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); $logger->pushProcessor( new GdprProcessor($patterns, $fieldPaths, $customCallbacks, $auditLogger) ); $logger->warning('This is a warning message.', [ 'user' => ['ssn' => '123456-900T'], 'contact' => ['email' => 'user@example.com'], 'payment' => ['card' => '1234567812345678'], ]);
FieldMaskConfig Options
GdprProcessor::maskWithRegex()
— Mask field value using regex patternsGdprProcessor::removeField()
— Remove field from contextGdprProcessor::replaceWith($value)
— Replace field value with static value
Custom Callbacks
Provide custom callbacks for specific fields:
$customCallbacks = [ 'user.name' => fn($value) => strtoupper($value), ];
Audit Logger
Optionally provide an audit logger callback to record masking actions:
$auditLogger = function($path, $original, $masked) { // Log or store audit info };
IMPORTANT: Be mindful what you send to your audit log. Passing the original value might defeat the whole purpose of this project.
Laravel Integration
You can integrate the GDPR processor with Laravel logging in two ways:
1. Service Provider
// app/Providers/AppServiceProvider.php use Illuminate\Support\ServiceProvider; use Ivuorinen\MonologGdprFilter\GdprProcessor; class AppServiceProvider extends ServiceProvider { public function boot() { $patterns = GdprProcessor::getDefaultPatterns(); $fieldPaths = [ 'user.ssn' => '[GDPR]', 'payment.card' => '[CC]', 'contact.email' => '', // empty string = regex mask 'metadata.session' => '[SESSION]', ]; $this->app['log']->getLogger() ->pushProcessor(new GdprProcessor($patterns, $fieldPaths)); } }
2. Tap Class (config/logging.php)
// app/Logging/GdprTap.php namespace App\Logging; use Monolog\Logger; use Ivuorinen\MonologGdprFilter\GdprProcessor; class GdprTap { public function __invoke(Logger $logger) { $patterns = GdprProcessor::getDefaultPatterns(); $fieldPaths = [ 'user.ssn' => '[GDPR]', 'payment.card' => '[CC]', 'contact.email' => '', 'metadata.session' => '[SESSION]', ]; $logger->pushProcessor(new GdprProcessor($patterns, $fieldPaths)); } }
Reference in config/logging.php
:
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['single'], 'tap' => [App\Logging\GdprTap::class], ], // ... ],
Configuration
You can configure the processor to filter out sensitive data by specifying:
- Regex patterns: Used for masking values in messages and context
- Field paths: Dot-notation paths for masking/removal/replacement
- Custom callbacks: For advanced per-field masking
- Audit logger: For compliance tracking
Testing & Quality
This project uses PHPUnit for testing, Psalm and PHPStan for static analysis, and PHP_CodeSniffer for code style checks.
Running Tests
To run the test suite:
composer test
To generate a code coverage report (HTML output in the coverage/
directory):
composer test:coverage
Linting & Static Analysis
To run all linters and static analysis:
composer lint
To automatically fix code style and static analysis issues:
composer lint:fix
Notable Implementation Details
- If a regex replacement in
regExpMessage
results in an empty string or the string "0", the original message is returned. This is covered by dedicated PHPUnit tests. - If a regex pattern is invalid, the audit logger (if set) is called, and the original message is returned.
Directory Structure
src/
— Main library source codetests/
— PHPUnit testscoverage/
— Code coverage reportsvendor/
— Composer dependencies
Legal Disclaimer
CAUTION: This library helps mask/filter sensitive data for GDPR compliance, but it is your responsibility to ensure your application fully complies with all legal requirements. Review your logging and data handling policies regularly.
Contributing
If you would like to contribute to this project, please fork the repository and submit a pull request.
License
This project is licensed under the MIT License. See the LICENSE file for more details.