Files
monolog-gdpr-filter/docs/troubleshooting.md
Ismo Vuorinen 47564c5cd6 feat!: upgrade min. php version to 8.4 (#86)
* feat: upgrade min php to 7.4, upgrade packages

* chore: update ci/cd, docs, supporting config to php 8.4

* chore: update rest of the docs, supporting config to php 8.4
2026-02-01 10:20:40 +02:00

10 KiB

Troubleshooting Guide

This guide helps diagnose and resolve common issues with the Monolog GDPR Filter library.

Table of Contents

Installation Issues

Composer Installation Fails

Symptom: composer require fails with dependency conflicts.

Solution:

# Check PHP version
php -v  # Must be 8.4 or higher

# Clear Composer cache
composer clear-cache

# Update Composer
composer self-update

# Try again with verbose output
composer require ivuorinen/monolog-gdpr-filter -vvv

Class Not Found Errors

Symptom: Class 'Ivuorinen\MonologGdprFilter\GdprProcessor' not found

Solutions:

  1. Regenerate autoloader:
composer dump-autoload
  1. Verify installation:
composer show ivuorinen/monolog-gdpr-filter
  1. Check namespace in your code:
<?php
// Correct
use Ivuorinen\MonologGdprFilter\GdprProcessor;

// Wrong
use MonologGdprFilter\GdprProcessor;

Pattern Matching Problems

Pattern Not Matching Expected Data

Symptom: Sensitive data is not being masked.

Diagnostic steps:

<?php

use Ivuorinen\MonologGdprFilter\PatternValidator;

$validator = new PatternValidator();
$pattern = '/your-pattern-here/';

// Test 1: Validate pattern syntax
$result = $validator->validate($pattern);
if (!$result['valid']) {
    echo "Invalid pattern: " . $result['error'] . "\n";
}

// Test 2: Test pattern directly
$testData = 'your test data with sensitive@email.com';
if (preg_match($pattern, $testData, $matches)) {
    echo "Pattern matches: " . print_r($matches, true);
} else {
    echo "Pattern does not match\n";
}

// Test 3: Test with processor
$processor = new GdprProcessor([$pattern => '[MASKED]']);
$record = [
    'message' => $testData,
    'context' => [],
    'level' => 200,
    'level_name' => 'INFO',
    'channel' => 'app',
    'datetime' => new DateTimeImmutable(),
    'extra' => [],
];

$result = $processor($record);
echo "Result: " . $result['message'] . "\n";

Pattern Matches Too Much

Symptom: Non-sensitive data is being masked.

Solutions:

  1. Add word boundaries:
<?php
// Too broad
$pattern = '/\d{4}/';  // Matches any 4 digits

// Better - with boundaries
$pattern = '/\b\d{4}\b/';  // Matches standalone 4-digit numbers
  1. Use more specific patterns:
<?php
// Too broad for credit cards
$pattern = '/\d{16}/';

// Better - credit card format
$pattern = '/\b(?:\d{4}[-\s]?){3}\d{4}\b/';
  1. Add negative lookahead/lookbehind:
<?php
// Avoid matching dates that look like years
$pattern = '/(?<!\d{2}\/)\b\d{4}\b(?!\/\d{2})/';

Special Characters in Patterns

Symptom: Pattern with special characters fails.

Solution: Escape special regex characters:

<?php
// Wrong - unescaped special chars
$pattern = '/user.name@domain.com/';

// Correct - escaped dots
$pattern = '/user\.name@domain\.com/';

// Using preg_quote for dynamic patterns
$email = 'user.name@domain.com';
$pattern = '/' . preg_quote($email, '/') . '/';

Performance Issues

Slow Processing

Symptom: Log processing is slower than expected.

Diagnostic:

<?php

$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    $processor($record);
}
$elapsed = microtime(true) - $start;
echo "1000 records: {$elapsed}s\n";

Solutions:

  1. Reduce pattern count:
<?php
// Only include patterns you need
$patterns = DefaultPatterns::emails() + DefaultPatterns::creditCards();
  1. Simplify complex patterns:
<?php
// Slow: Complex pattern with many alternatives
$slow = '/(january|february|march|april|may|june|july|august|september|october|november|december)/i';

// Faster: Simpler pattern
$fast = '/\b[A-Z][a-z]{2,8}\b/';
  1. Limit recursion depth:
<?php
$processor = new GdprProcessor($patterns, [], [], null, 5);  // Max depth 5

See Performance Tuning Guide for detailed optimization strategies.

High CPU Usage

Symptom: Processing causes CPU spikes.

Solutions:

  1. Check for catastrophic backtracking:
<?php
// Problematic pattern
$bad = '/.*@.*\..*/';  // Can cause backtracking

// Fixed pattern
$good = '/[^@]+@[^.]+\.[a-z]+/i';
  1. Add pattern timeout (PHP 7.3+):
<?php
// Set PCRE backtrack limit
ini_set('pcre.backtrack_limit', '100000');

Memory Problems

Out of Memory Errors

Symptom: Allowed memory size exhausted

Solutions:

  1. Use streaming for large files:
<?php
use Ivuorinen\MonologGdprFilter\Streaming\StreamingProcessor;
use Ivuorinen\MonologGdprFilter\MaskingOrchestrator;

$orchestrator = new MaskingOrchestrator($patterns);
$streaming = new StreamingProcessor($orchestrator, chunkSize: 100);

// Process file without loading entirely into memory
$lineParser = fn(string $line): array => ['message' => $line, 'context' => []];
foreach ($streaming->processFile($largefile, $lineParser) as $record) {
    // Process one record at a time
}
  1. Reduce recursion depth:
<?php
$processor = new GdprProcessor($patterns, [], [], null, 3);
  1. Disable audit logging:
<?php
$processor = new GdprProcessor($patterns, [], [], null);  // No audit logger

Memory Leaks

Symptom: Memory usage grows over time in long-running processes.

Solutions:

  1. Clear caches periodically:
<?php
// In long-running workers
if ($processedCount % 10000 === 0) {
    gc_collect_cycles();
}
  1. Use fresh processor instances for batch jobs:
<?php
foreach ($batches as $batch) {
    $processor = new GdprProcessor($patterns);  // Fresh instance
    foreach ($batch as $record) {
        $processor($record);
    }
    unset($processor);  // Release memory
}

Integration Issues

Laravel Integration

Symptom: Processor not being applied to logs.

Solutions:

  1. Verify service provider registration:
<?php
// config/app.php
'providers' => [
    Ivuorinen\MonologGdprFilter\Laravel\GdprServiceProvider::class,
],
  1. Check logging configuration:
<?php
// config/logging.php
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['gdpr'],
    ],
    'gdpr' => [
        'driver' => 'single',
        'path' => storage_path('logs/laravel.log'),
        'tap' => [GdprLogTap::class],
    ],
],
  1. Clear config cache:
php artisan config:clear
php artisan cache:clear

Monolog Integration

Symptom: Processor not working with Monolog logger.

Solution: Ensure processor is pushed to logger:

<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Ivuorinen\MonologGdprFilter\GdprProcessor;

$logger = new Logger('app');
$logger->pushHandler(new StreamHandler('app.log'));
$logger->pushProcessor(new GdprProcessor(DefaultPatterns::all()));

// Test it
$logger->info('User email: test@example.com');

Symfony Integration

See Symfony Integration Guide for detailed setup.

Audit Logging Issues

Audit Logger Not Receiving Events

Symptom: Audit callback never called.

Solutions:

  1. Verify audit logger is set:
<?php
$auditLogs = [];
$auditLogger = function (string $path, mixed $original, mixed $masked) use (&$auditLogs): void {
    $auditLogs[] = compact('path', 'original', 'masked');
};

$processor = new GdprProcessor(
    patterns: $patterns,
    auditLogger: $auditLogger
);
  1. Verify masking is actually occurring:
<?php
// Audit is only called when data is actually masked
$record = ['message' => 'No sensitive data here', 'context' => []];
// This won't trigger audit because nothing is masked

Rate-Limited Audit Missing Events

Symptom: Some audit events are being dropped.

Solution: Adjust rate limit settings:

<?php
use Ivuorinen\MonologGdprFilter\RateLimiter;
use Ivuorinen\MonologGdprFilter\RateLimitedAuditLogger;

$rateLimiter = new RateLimiter(
    maxEvents: 1000,     // Increase limit
    windowSeconds: 60,
    burstLimit: 100      // Increase burst
);

$rateLimitedLogger = new RateLimitedAuditLogger($baseLogger, $rateLimiter);

Error Messages Reference

InvalidRegexPatternException

Message: Invalid regex pattern: [pattern]

Cause: The pattern has invalid regex syntax.

Solution:

<?php
// Test pattern before using
$pattern = '/[invalid/';
if (@preg_match($pattern, '') === false) {
    echo "Invalid pattern: " . preg_last_error_msg();
}

RecursionDepthExceededException

Message: Maximum recursion depth exceeded

Cause: Nested data structure exceeds max depth.

Solutions:

<?php
// Increase max depth
$processor = new GdprProcessor($patterns, [], [], null, 20);

// Or flatten your data before processing
$flatContext = iterator_to_array(
    new RecursiveIteratorIterator(
        new RecursiveArrayIterator($context)
    ),
    false
);

MaskingOperationFailedException

Message: Masking operation failed: [details]

Cause: An error occurred during masking.

Solution: Enable recovery mode:

<?php
use Ivuorinen\MonologGdprFilter\Recovery\FallbackMaskStrategy;
use Ivuorinen\MonologGdprFilter\Recovery\FailureMode;

$fallback = new FallbackMaskStrategy(FailureMode::FAIL_SAFE);
// Use with your processor

InvalidConfigurationException

Message: Invalid configuration: [details]

Cause: Invalid processor configuration.

Solution: Validate configuration:

<?php
use Ivuorinen\MonologGdprFilter\Builder\GdprProcessorBuilder;

try {
    $processor = (new GdprProcessorBuilder())
        ->addPattern('/valid-pattern/', '[MASKED]')
        ->build();
} catch (InvalidConfigurationException $e) {
    echo "Configuration error: " . $e->getMessage();
}

Getting Help

If you're still experiencing issues:

  1. Check the tests: The test suite contains many usage examples:

    ls tests/
    
  2. Enable debug mode: Add verbose logging:

    <?php
    $auditLogger = function ($path, $original, $masked): void {
        error_log("GDPR Mask: $path | $original -> $masked");
    };
    
  3. Report issues: Open an issue on GitHub with:

    • PHP version (php -v)
    • Library version (composer show ivuorinen/monolog-gdpr-filter)
    • Minimal reproduction code
    • Expected vs actual behavior