Как включить подробное логгирование на Symfony 4 в prod окружении
Симфония 4.4.51 , приложение реализующее api не работает при включенном prod окружении (APP_ENV=prod) и работает при переключении на dev окружение (меняю строку в .env.local) В prod окружении в ответ на http запросы возвращает 500 internal server error, при этом в лог var/log/prod.log ничего не кладет - уровень логирования на prod очень скудный.
Как включить на prod более подробный уровень логирования?
Скопировал config/packages/dev/monolog.yaml
в config/packages/prod/monolog.yaml сбросил кеш bin/console cache:clear но это не помогло.
Ну и в дополнение - может быть кто то сталкивался в чем может быть причина, что приложение обрабатывающее http запросы может работать на dev и не работать при переключении на prod?
Ответы (1 шт):
Я так понимаю, проблема у вас локально воспроизводится, т.е. возможность дебага есть.
В таком случае, самый простой способ будет определить свой ExceptionEventListener и поймать в нем вашу ошибку.
Это обычный класс вида:
class ExceptionListener
{
public function __construct(private readonly LoggerInterface $appLogger)
{}
public function onKernelException(ExceptionEvent $event): void
{
$this->appLogger->error($event->getThrowable()->getMessage());
}
}
И далее, подключить его в services.yaml:
published_message.listener:
class: App\Shared\Infrastructure\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
Таким образом будете ловить все исключения и логгировать их.
Если же именно интересует конфигурация monolog-а, которую к сожалению вы не привели, то такая должна работать корректно:
monolog:
channels: [ 'app' ]
handlers:
app:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: [ '!event', '!doctrine', '!request', '!security', '!messenger' ]
Если же вам не помогла ни одна из рекомендаций, то приложите пожалуйста больше контекста, расскажите, что вы уже пытались сделать и каков был результат + немного контекста о вашей инфраструктуре (используете ли обычный подход с php-fpm или же что-то иное).
Но как еще один вариант, оберните в index.php вызов вашего приложения в try-catch и ловите \Throwable интерфейс.
Так же, у вас может быть не исключение, а error, в таком случае, можете добавить кастомный error-handler следующий образом в index.php и dump-ить ошибку:
set_error_handler(
function ($errno, $errstr, $errfile, $errline) use ($logger): bool {
$logger
->error(
message: $errstr,
context: [
'$stacktrace' => traceToString(debug_backtrace())
]
);
return true;
},
);
function traceToString($trace): array {
foreach ($trace as $i => $call) {
if (array_key_exists('object', $call) && is_object($call['object'])) {
$call['object'] = get_class($call['object']);
}
if (array_key_exists('args', $call) && is_array($call['args'])) {
foreach ($call['args'] as &$arg) {
if (is_object($arg)) {
$arg = get_class($arg);
}
}
}
$file = $call['file'] ?? '__UNDEFINED FILE__';
$line = $call['line'] ?? '__UNDEFINED LINE__';
$type = (
!empty($call['object'])
? ($call['object'].($call['type'] ?? '__UNDEFINED TYPE__'))
: ''
);
if (!array_key_exists('function', $call)) {
$func = '__UNDEFINED FUNC__';
} else {
if (is_array($call['function'])) {
$func = implode(', ', $call['function']);
} elseif (is_string($call['function'])) {
$func = $call['function'];
} else {
$func = '__UNDEFINED FUNC__';
}
}
if (!array_key_exists('args', $call)) {
$args = '__UNDEFINED ARGS__';
} else {
if (is_array($call['args'])) {
$args = $this->convertArgsToString($call['args']);
} elseif (is_string($call['args'])) {
$args = $call['args'];
} else {
$args = '__UNDEFINED ARGS__';
}
}
$traceText[$i] = '#'.$i.' '.$file.'('.$line.') ';
$traceText[$i] .= $type;
$traceText[$i] .= $func.'('.$args.')';
}
return $traceText ?? [];
}
function convertArgsToString($args): string
{
if (is_object($args)) {
return get_class($args);
} elseif (is_array($args)) {
$result = [];
foreach ($args as $key => $value) {
$result[] = $key.' => '.$this->convertArgsToString($value);
}
return implode(', ', $result);
} elseif (is_string($args)) {
return '"'.$args.'"';
} elseif (is_bool($args)) {
return $args ? 'true' : 'false';
} elseif (is_null($args)) {
return 'null';
} else {
return (string) $args;
}
}