【问题标题】:Define controller-specific logs in zf2在 zf2 中定义特定于控制器的日志
【发布时间】:2016-10-19 13:13:18
【问题描述】:

想象一下情况: 我有服务(在 serviceManager 中定义),由 OneController、TwoController 使用。 我想在从 OneController 调用服务时将服务操作记录到“one.log”,在其他情况下记录到“two.log”。如果服务有很多方法 - 每个方法中的注入记录器都很丑。

控制器中的服务构造函数不可用(从serviceManager获得的服务)

在 serviceManager 中创建多个记录器是不好的选择,因为我想限制在某些控制器中使用所有记录器(或日志文件),除了一个特定的控制器。我想,我需要某种“依赖注入”日志文件来从控制器记录。我无法在模块配置控制器特定的日志文件中定义,因为在配置合并时控制器未定义。

可以在Controllers中使用不同的日志吗?

我可以在module.config.php中定义日志文件

 'logs' => [
    'error' => APP_PATH . '/../var/logs/error.log'
],

...并强制服务管理器工厂使用它

 //closure
 'logger' => function (ServiceManager $sm) {
     $log = new Logger();
     $logSettings =  $sm->get('config')['logs'];

     //use log
     $errorWriter = new LogWriterStream($logSettings['error']);
     $log->addWriter($errorWriter);

     return $log;
 }

然后,在控制器中,我们可以在服务中,在控制器中获取它。

...
$logger = $serviceManager->get('logger');
...

因此,我强制特定的模块使用特定的日志文件。

zf2 控制器没有自己的配置,因此,我需要找到另一种方法。

有什么想法吗?

【问题讨论】:

    标签: php zend-framework2 php-7


    【解决方案1】:

    因此,您需要以某种方式告诉记录器正在调用哪个控制器。 我建议您将事件从控制器传递到记录器服务。如果您可以访问所需的所有信息:

    1) 控制器插件:

    您可以为此使用控制器插件管理器:

    <?php
    namespace Application\Controller\Plugin;
    
    use Zend\Mvc\Controller\Plugin\AbstractPlugin;
    use Zend\Mvc\MvcEvent;
    
    class ControllerEventLogger extends AbstractPlugin{
    
        protected $map = [
            'Application\Controller\OneController' => 'one.log',
            'Application\Controller\TwoController' => 'two.log'
        ];
    
        /**
         * @param  MvcEvent $event
         */
        public function __invoke(MvcEvent $event){
            $routeMatch = $event->getRouteMatch();
            $action = $routeMatch->getParam('action');
            $controller = $routeMatch->getParam('controller');
    
            // map your controller to a log file name here
            $logFileName = $this->map[ $controller ];
    
            // do your logging
        }
    }
    

    在你的module.config.php

    <?php
    return array(
        // ... 
    
        'controller_plugins' => array(
            'invokables' => array(
                'ControllerEventLogger' => 'Application\Controller\Plugin\ControllerEventLogger',
            )
        ),
    
        // ...
    );
    

    在你的控制器类中:

    <?php
    namespace Application\Controller;
    
    use Zend\Mvc\Controller\AbstractActionController;
    use Zend\View\Model\ViewModel;
    
    class OneController extends AbstractActionController{
        public function indexAction(){
            $this->ControllerEventLogger(event);
            return new ViewModel();
        }
    }
    

    注意:为了让事情更整洁,您仍然可以创建一个单独的记录器服务,通过工厂将其注入到控制器插件中。那么你的控制器插件就是你的控制器和记录器服务之间的粘合剂。

    2) 基于监听器的事件:

    您还可以制作一个基于事件的记录器。在这种情况下,您可以简单地记录每个调度事件。像这样,您的控制器甚至不会意识到日志记录(更清洁,因为控制器内部根本没有任何记录器代码)。侦听器类似于:

    <?php
    
    namespace Application\Listener;
    
    use Zend\EventManager\AbstractListenerAggregate;
    use Zend\EventManager\EventManagerInterface;
    use Zend\Mvc\MvcEvent;
    
    class ControllerLoggerListener extends AbstractListenerAggregate
    {
        protected $map = [
            'Application\Controller\OneController' => 'one.log',
            'Application\Controller\TwoController' => 'two.log'
        ];
    
        /**
         * @param  EventManagerInterface $events
         */
        public function attach(EventManagerInterface $events)
        {
            $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, array($this, 'onDispatch'));
        }
    
        /**
         * @param  MvcEvent $event
         */
        public function onDispatch(MvcEvent $event)
        {    
            $routeMatch = $event->getRouteMatch();
            $action = $routeMatch->getParam('action');
            $controller = $routeMatch->getParam('controller');
    
            // map your controller to a log file name here
            $logFileName = $this->map[ $controller ];
    
            // do your logging
        }
    }
    

    有一百种方法可以做到这一点,这完全取决于您的具体需求。

    【讨论】:

    • 谢谢,我想我明白了。在第一种情况下,您调用插件而不是记录器来记录事件。这个插件就像一个日志管理器。在服务中使用 $this->contoller->controllerEventLogger($event)。如何在里面传递字符串消息?也许接口应该提供(事件、消息、级别)?或者这个插件必须只设置记录器?然后基于事件更可取,我认为。
    • 是的,我还要说基于事件是更好的解决方案。在您自己的答案的最终解决方案中,您最终会在构造函数中为记录器提供大量代码,这在 IMO 中是不可取的。关于消息,这有点取决于消息内容来自哪里?起初我以为你只想记录控制器名称和操作。
    【解决方案2】:

    我们终于做了什么

    在主模块中

    class AbstractController extends AbstractActionController {
    
    /**
     * error log name
     * can override 
     * null - use module default
     */
    const ERROR_LOG_FILE_NAME = null;
    
    /**
     * info log name
     * can override 
     * null - use module default
     */
    const INFO_LOG_FILE_NAME = null;
    
    public function __construct()
    {
        /**
         * switch log files if const defined
         */
        if (static::ERROR_LOG_FILE_NAME || static::INFO_LOG_FILE_NAME) {
    
            /** @var Logger $logger */
            $logger = self::$sm->get(Factory::LOGGER);
            $logConfig = self::$sm->get(Factory::CONFIG)['logs'];
    
            //remove writers
            $logger->setWriters(new SplPriorityQueue());
    
            if (static::ERROR_LOG_FILE_NAME) {
                $errorLogPath =  LOG_PATH . '/' .static::ERROR_LOG_FILE_NAME;
            } else {
                //use default
                $errorLogPath = $logConfig['error'];
            }
    
            if (static::INFO_LOG_FILE_NAME) {
                $infoLogPath = LOG_PATH . '/' . static::INFO_LOG_FILE_NAME;
            } else {
                //use module default
                $infoLogPath = $logConfig['info'];
            }
    
            $logger->addWriter(Factory::getErrorLogWriter($errorLogPath));
            $logger->addWriter(Factory::getInfoLogWriter($infoLogPath));
        }
    }
    

    }

    在子控制器中

    const ERROR_LOG_FILE_NAME = 'path/to/file.log'
    

    所以,如果我们在服务中使用记录器,由子控制器调用

    $this->sm->get('logger')->log($message)
    

    它写入控制器定义的文件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多