Ecodev /
felix
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Ecodev\Felix\Log; |
||
| 6 | |||
| 7 | use Ecodev\Felix\Model\CurrentUser; |
||
| 8 | use Laminas\Log\Processor\ProcessorInterface; |
||
| 9 | |||
| 10 | class EventCompleter implements ProcessorInterface |
||
| 11 | { |
||
| 12 | 5 | public function __construct(private readonly string $baseUrl) |
|
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 13 | { |
||
| 14 | 5 | } |
|
| 15 | |||
| 16 | /** |
||
| 17 | * Complete a log event with extra data, including stacktrace and any global stuff relevant to the app. |
||
| 18 | */ |
||
| 19 | 4 | public function process(array $event): array |
|
| 20 | { |
||
| 21 | 4 | $envData = $this->getEnvData(); |
|
| 22 | 4 | $event = array_merge($event, $envData); |
|
| 23 | |||
| 24 | // If we are logging PHP errors, then we include all known information in message |
||
| 25 | 4 | if ($event['extra']['errno'] ?? false) { |
|
| 26 | 1 | $event['message'] .= "\nStacktrace:\n" . $this->getStacktrace(); |
|
| 27 | } |
||
| 28 | |||
| 29 | // Security hide clear text password |
||
| 30 | 4 | unset($event['extra']['password']); |
|
| 31 | |||
| 32 | 4 | return $event; |
|
| 33 | } |
||
| 34 | |||
| 35 | /** |
||
| 36 | * Retrieve dynamic information from environment to be logged. |
||
| 37 | */ |
||
| 38 | 4 | private function getEnvData(): array |
|
| 39 | { |
||
| 40 | 4 | $user = CurrentUser::get(); |
|
| 41 | |||
| 42 | 4 | if (PHP_SAPI === 'cli') { |
|
| 43 | global $argv; |
||
| 44 | 4 | $request = $argv; |
|
| 45 | 4 | $ip = !empty(getenv('REMOTE_ADDR')) ? getenv('REMOTE_ADDR') : 'script'; |
|
| 46 | 4 | $url = implode(' ', $argv); |
|
| 47 | 4 | $referer = ''; |
|
| 48 | } else { |
||
| 49 | $request = $_REQUEST; |
||
| 50 | $ip = $_SERVER['REMOTE_ADDR'] ?? ''; |
||
| 51 | $url = $this->baseUrl . $_SERVER['REQUEST_URI']; |
||
| 52 | $referer = $_SERVER['HTTP_REFERER'] ?? ''; |
||
| 53 | } |
||
| 54 | |||
| 55 | 4 | $request = $this->removeSensitiveData($request); |
|
| 56 | |||
| 57 | 4 | $envData = [ |
|
| 58 | 4 | 'creator_id' => $user ? $user->getId() : null, |
|
| 59 | 4 | 'login' => $user ? $user->getLogin() : null, |
|
| 60 | 4 | 'url' => $url, |
|
| 61 | 4 | 'referer' => $referer, |
|
| 62 | 4 | 'request' => json_encode($request, JSON_PRETTY_PRINT), |
|
| 63 | 4 | 'ip' => $ip, |
|
| 64 | ]; |
||
| 65 | |||
| 66 | 4 | return $envData; |
|
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Remove password value from GraphQL variables well-known structure. |
||
| 71 | */ |
||
| 72 | 4 | protected function removeSensitiveData(array $request): array |
|
| 73 | { |
||
| 74 | 4 | foreach ($request as &$r) { |
|
| 75 | 4 | if (is_array($r)) { |
|
| 76 | unset($r['variables']['password']); |
||
| 77 | } |
||
| 78 | } |
||
| 79 | |||
| 80 | 4 | return $request; |
|
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Returns the backtrace excluding the most recent calls to this function so we only get the interesting parts. |
||
| 85 | */ |
||
| 86 | 1 | private function getStacktrace(): string |
|
| 87 | { |
||
| 88 | 1 | ob_start(); |
|
| 89 | 1 | @debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); |
|
| 90 | 1 | $trace = ob_get_contents(); |
|
| 91 | 1 | ob_end_clean(); |
|
| 92 | |||
| 93 | 1 | if ($trace === false) { |
|
| 94 | return 'Could not get stacktrace'; |
||
| 95 | } |
||
| 96 | |||
| 97 | // Remove first items from backtrace as it's this function and previous logging functions which is not interesting |
||
| 98 | 1 | $shortenTrace = preg_replace('/^#[0-4]\s+[^\n]*\n/m', '', $trace); |
|
| 99 | |||
| 100 | 1 | if ($shortenTrace === null) { |
|
| 101 | return $trace; |
||
| 102 | } |
||
| 103 | |||
| 104 | // Renumber backtrace items. |
||
| 105 | 1 | $renumberedTrace = preg_replace_callback('/^#(\d+)/m', fn ($matches) => '#' . ((int) $matches[1] - 5), $shortenTrace); |
|
| 106 | |||
| 107 | 1 | if ($renumberedTrace === null) { |
|
| 108 | return $shortenTrace; |
||
| 109 | } |
||
| 110 | |||
| 111 | 1 | return $renumberedTrace; |
|
| 112 | } |
||
| 113 | } |
||
| 114 |