在zf2中定义特定于控制器的日志

时间:2016-10-19 13:13:18

标签: php zend-framework2 php-7

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

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

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

可以在控制器中使用不同的日志吗?

我可以在 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控制器没有自己的配置,因此,我需要找到另一种方式。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

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

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
    }
}

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

答案 1 :(得分:0)

我们最后做了什么

主模块中的

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'

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

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

它写入控制器定义的文件