как выводить логи ошибок PHP в формате JSON

У меня возникла необходимость вывода лога ошибок PHP в формате JSON и дополнительно в лог передать домен и URL запроса для облегчения определения места возникновения ошибки и ее воспроизведения.

Как это сделать ?


Ответы (1 шт):

Автор решения: Aleksey Vaganov

PHP позволяет имплементировать Callback функцию для пользовательской обработки ошибок. Для регистрации обработчика нужно использовать функции:

  1. set_error_handler - для регистрации обработчика ошибок
  2. set_exception_handler - для регистрации обработчика исключений

Я сделал класс Handler для имплементацию обработчиков:

<?php

final class Handler {
    public function handleError(int $errno, string $errstr, string $errfile, int $errline) : bool
    {
        $message = $this->createMessage($errno, $errstr, $errfile, $errline);
        $this->putMessage($message);

        return true;
    }

    public function handleException(Throwable $ex) : void
    {
        $message = $this->createMessage(-1, $ex->getMessage(), $ex->getFile(), $ex->getLine());
        $this->putMessage($message);
    }

    private function createMessage(int $errno, string $errstr, string $errfile, int $errline) : string
    {
        $object = new stdClass();
        $object->host = $_SERVER['HTTP_HOST'] ?? '';
        $object->request_uri = $_SERVER['REQUEST_URI'] ?? '';
        $object->query_string = $_SERVER['QUERY_STRING'] ?? '';
        $object->request_method = $_SERVER['REQUEST_METHOD'] ?? '';
        $object->errno = $errno;
        $object->file = $errfile;
        $object->line = $errline;
        $object->message = $errstr;
        $object->date_time = date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']);

        try {
            $json = json_encode($object, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_THROW_ON_ERROR) . PHP_EOL;
        } catch (JsonException $exception) {
            return '{}' . PHP_EOL;
        }

        return $json;
    }

    private function putMessage(string $message) : void
    {
        file_put_contents('php://stderr', $message);
    }
}

А для того, чтобы зарегистрировать обработчики как можно раньше я написал скрипт register_handlers.php:

<?php

require __DIR__ . /handler.php;
$handler = new Handler();

set_error_handler([$handler, 'handleError']);
set_exception_handler([$handler, 'handleException']);

и подключил его в php.ini через директиву auto_prepend_file.

Лог пишется в stderr и т.к. PHP-FPM у меня в докер-контейнере, то лог ошибок попадает в лог контейнера php и его можно как посмотреть командой docker logs или направить куда угодно нативными средствами докера. Я для своих нужд отправляю лог в GrayLog.

→ Ссылка