Wednesday, June 23, 2010

Action Helpers, Part 2: Logger

Now that we've seen how to use one of the existing Action Helpers in Part 1, let's look at building our own. This time, we'll build one for logging page views and the messages from the Flash Messenger.

As before, we'll start in Bootstrap.php by registering the helper:
protected function _initMsgLogger()
{
require_once('My/Action/Helper/MsgLogger.php');
Zend_Controller_Action_HelperBroker::addHelper(new My_Action_Helper_MsgLogger());

// make sure flash messager is also initialized if this is used
$this->_initMessenger();
}
Zend_Application contains a logging plugin that uses Zend_Logger and can be initialized through the application.ini file. If you look at ErrorController.php for the default application, you'll see that it references this Log resource. To initialize this resource for the application, add the following lines to application.ini (note: define BASE_PATH in index.php):
resources.log.stream.writerName = "Stream"
resources.log.stream.writerParams.stream = BASE_PATH "/data/logs/application.log"
resources.log.stream.writerParams.mode = "a"
resources.log.stream.filterName = "Priority"
resources.log.stream.filterParams.priority = 6
Note: Make sure that the application.log file has been created and is writable by the web user.

The priority filter will stop logging for messages above a certain priority. The built-in log priorities for Zend_Framework are DEBUG (7), INFO (6), NOTICE (5), WARN (4), CRIT (2), ALERT (1), and EMERG (0). So setting the priority filter to 6 will stop debug messages and allow everything else.

Now for the meat of the MsgLogger. Action Helpers have a couple of hooks where they can be inserted into the dispatch cycle, preDispatch() and postDispatch(). For our logger, we want to log any messages that were added to the FlashMessenger during the action, so we'll use the postDispatch() hook.
class My_Action_Helper_MsgLogger extends Zend_Controller_Action_Helper_Abstract {

public function getLog()
{
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
if (!$bootstrap->hasPluginResource('Log')) {
return false;
}
$log = $bootstrap->getResource('Log');
return $log;
}

public function postDispatch()
{
if ($log = $this->getLog()) {
$request = $this->getRequest();
$log->debug($request->controller . ', ' . $request->action);

if ($flashMessenger = Zend_Controller_Action_HelperBroker::getExistingHelper('FlashMessenger')) {

$messages = $flashMessenger->getMessages()
+ $flashMessenger->getCurrentMessages();

foreach ($messages as $message) {
$log->info($message);
}
}
}
}
}
Note that even though we are getting our messages from the FlashMessenger here, they are still available in our layout as well. That is because there are no actions or redirects between our Action Helper postDispatch() and constructing the layout, which runs in a Controller Plugin postDispatch(). Here is that handy diagram by Kevin Schroeder again. If we had an Action Helper that was redirecting to another page in its postDispatch() method AFTER the MsgLogger was called, this could clear the messages before the layout can pick them up.

As is, this logger will log all the messages from the Flash Messenger as "info" and will additionally log the calling controller/action as "debug" (which means they will not be logged based on our current priority settings, but could be turned on for debugging). However, if you were using status codes on the FlashMessenger messages, then you could additionally log the message priority to the system log. We are using the INFO priority by calling $logger->info("msg"). However, we could use $logger->log("msg", Zend_Log::INFO) instead. So imagine we were using flashMessenger->addMessage(array(Zend_Log::ERR=>"error message")) when creating our messages. Then we could log something like this:
foreach $messages as $msgtype=>$message {
$info = $request->controller . ', ' . $request->action . ', ' . $message;
$logger->log($info, $msgtype);
}
Hopefully this gives some idea on how to create a custom action helper and some more insight into using the Zend_Logger for capturing application data.

No comments:

Post a Comment