首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法捕获全局异常

无法捕获全局异常
EN

Stack Overflow用户
提问于 2013-11-21 19:40:32
回答 2查看 1.1K关注 0票数 1

如果指定的日志文件有问题,Monolog的StreamHandler将抛出一个\UnexpectedValueException

在我的代码中,我试图捕获\UnexpectedValueException,但我一直无法捕获。

我的代码是:

代码语言:javascript
复制
<?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

不管用,我明白了:

代码语言:javascript
复制
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()中触发错误

导致此错误的原因是我(有意)咀嚼了日志文件路径,如果它是有效的日志文件路径,则代码运行良好。显然,我想要捕获该错误,因此尝试/捕获。

跟踪的下一行是上面代码中的一行:$logger->pushHandler(new StreamHandler(MY_LOG_PATH . "/" . MY_LOG_NAME, Monolog::NOTICE));

有趣的是,如果我故意拼写文件名var、file_get_contents barfs和标准的catch (Exception $e),那么唯一能捕捉到异常的地方(目前这只是脚手架代码,还没有业务逻辑)就在file_get_contents()位中。

EN

回答 2

Stack Overflow用户

发布于 2015-01-28 20:25:54

这是一个很老的问题,很可能在这段时间内得到了解决。但是,为了将来的访问者,我想指出,当日志条目将被写入给定的文件时,而不是在构建时,就会抛出异常。

按照try { } catch () {}设置的方式,在创建StreamHandler时预期会出现异常。然而,当您试图通过$logger->error("Error message")这样的调用发送到日志时,真正的异常就会发生,因此您应该在那里捕获异常。

另一方面,我认为从日志库中抛出异常是最愚蠢的事情之一。日志记录应该是幂等的,不影响正在运行的应用程序的状态。

票数 3
EN

Stack Overflow用户

发布于 2019-12-11 11:13:50

在一个旧的silex应用程序中,我也遇到了这个问题。我想登录到logstash实例,但是如果logstash不可用,它不应该中断。

幸运的是,我的应用程序只使用针对Psr\Log\LoggerInterface输入的记录器,因此我可以编写一个装饰器,防止异常在一个地方中断应用程序,而不是在代码库中的每个调用上添加一个尝试和捕捉调用。

看起来是这样的:

代码语言:javascript
复制
<?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应用程序中,我只是将我的记录器实例包装了一次,如下所示:

代码语言:javascript
复制
$app['NOT_BREAKING_LOGGER'] = $app->share(
    function () use ($app) {
        return new DontThrowLoggerDecorator($app['monolog']);
    }
);

我将NOT_BREAKING_LOGGER注入到我的每个服务中,而不是单一的服务。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20130380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档