如果指定的日志文件出现问题,Monolog的StreamHandler会抛出\UnexpectedValueException
。
在我的代码中,我试图抓住\UnexpectedValueException
,但我一直无法抓住。
我的代码是:
<?php
namespace myNamespace;
use Monolog\Logger as Monolog;
use Monolog\Handler\StreamHandler;
class Logger {
private static $instance;
private static function init()
{
if (!self::$instance)
{
$logger = new Monolog(MY_LOG_CHANNEL);
try
{
$logger->pushHandler(new StreamHandler(MY_LOG_PATH . "/" .
MY_LOG_NAME, Monolog::NOTICE));
}
catch (\UnexpectedValueException $e)
{
writeln("Error starting logger" . $e->getMessage());
die;
}
// and so on
它不起作用,我明白了:
Fatal error: Uncaught exception 'UnexpectedValueException' with message 'The stream or
file [somefile.log] could not be opened: failed to open stream: No such file or
directory' in [path to src/Monolog/Handler/StreamHandler.php ]
据我了解,他们已经转移到全局命名空间,所以我应该能够在那里找到它。为什么我不能?我已经尝试了名称空间\myNamesace\UnexpectedValueException
甚至Monolog\UnexpectedValueException
全局或本地的所有组合,但无济于事。
显然我错过了什么,请问是什么?
修改
在另一堂课中,我正在做if (file_exists($fileName)) /** do file_get_contents() etc */ else Logger::error($filename . "does not exist")
当我致电Logger::error()
self::init()
内会触发错误
导致错误是因为我(故意)对日志文件路径进行了操作,如果它是有效的日志文件路径,那么代码运行正常。显然,我想捕捉到这个错误,因此是try / catch。
跟踪中的下一行是上面代码中的行:$logger->pushHandler(new StreamHandler(MY_LOG_PATH . "/" . MY_LOG_NAME, Monolog::NOTICE));
有趣的是,如果我故意错误拼写文件名var,那么我正在捕捉异常的唯一其他地方(目前这只是脚手架代码,还没有业务逻辑)在/** do file_get_contents() etc */
位内。 {1}} barfs和标准
file_get_contents
正如我期望的那样catch (Exception $e)
答案 0 :(得分:2)
这是一个很老的问题,可能在此期间得到解决。但是,为了将来的访问者,我想指出,当日志条目写入给定文件时,抛出异常,而不是在构造时。
try { } catch () {}
设置的方式,创建StreamHandler
时会出现异常。但是,只要您尝试通过$logger->error("Error message")
之类的调用发送到日志就会发生真正的异常,因此您应该在那里捕获异常。
另一方面,我认为从日志库中抛出异常是人们可以做的最愚蠢的事情之一。记录应该是幂等的,不会影响正在运行的应用程序的状态。
答案 1 :(得分:0)
在旧的silex应用程序中,我也遇到了这个问题。我想登录到logstash实例,但是如果logstash不可用,它也不会中断。
幸运的是,我的应用程序只使用了针对Psr\Log\LoggerInterface
键入的记录器,因此我可以编写一个装饰器来防止异常在一个地方中断应用程序,而不必在代码库。
它看起来像这样:
<?php
namespace Dreamlines\DirectBookingForm\ServiceProvider;
use Psr\Log\LoggerInterface;
/**
* DontThrowLoggerDecorator
*
* Monolog will break on info, error, etc. calls
* This decorator wrap the LoggerInterface and ensures that failure to log won't break the app
**/
class DontThrowLoggerDecorator implements LoggerInterface
{
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @inheritDoc
*/
public function emergency($message, array $context = array())
{
try {
$this->logger->emergency($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function alert($message, array $context = array())
{
try {
$this->logger->alert($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function critical($message, array $context = array())
{
try {
$this->logger->critical($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function error($message, array $context = array())
{
try {
$this->logger->error($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function warning($message, array $context = array())
{
try {
$this->logger->warning($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function notice($message, array $context = array())
{
try {
$this->logger->notice($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function info($message, array $context = array())
{
try {
$this->logger->info($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function debug($message, array $context = array())
{
try {
$this->logger->debug($message, $context);
} catch (\Exception $e) {
}
}
/**
* @inheritDoc
*/
public function log($level, $message, array $context = array())
{
try {
$this->logger->log($level, $message, $context);
} catch (\Exception $e) {
}
}
}
然后我将记录器实例包装一次,在我的silex应用程序中,我这样做是这样的:
$app['NOT_BREAKING_LOGGER'] = $app->share(
function () use ($app) {
return new DontThrowLoggerDecorator($app['monolog']);
}
);
我将在每个服务中注入NOT_BREAKING_LOGGER
,而不是独白。