想象一下情况: 我有服务(在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控制器没有自己的配置,因此,我需要找到另一种方式。
有什么想法吗?
答案 0 :(得分:0)
所以你需要以某种方式告诉记录器哪个控制器正在调用。 我建议你将事件从控制器传递给记录器服务。如果您有权访问所需的所有信息:
您可以使用控制器插件管理器:
<?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();
}
}
注意:为了使事情更加清洁,您仍然可以创建一个单独的记录器服务,通过工厂注入控制器插件。然后你的控制器插件只是你的控制器和记录器服务之间的粘合剂。
您还可以创建一个基于事件的记录器。在这种情况下,您只需记录每个调度事件。像这样你的控制器甚至不知道记录(更清洁,因为控制器内根本没有任何记录器代码)。听众会是这样的:
<?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)
它写入控制器定义的文件