Objective for this procedure check: enable database profiling for the Orinoco Zend Framework 2 project. Write to a logfile. Make sure the profiler works across all modules.

Step 1: in the config/autoload/database.local configuration file set  the profiler to true

return array(
    'db' => array(
        'username' => 'user',
        'password' => 'xxxxxxxx',
	'profiler' => true

Step 2: enable logging to a file, to the application Module.php add a logger service via a factory

public function getServiceConfig()
	return array(
	    'factories' => array(
		'logger' => function($sm) {
	    $logger = new \Zend\Log\Logger;
	    $config = $sm->get('Config');
	    $logFile = $config['logDir'] . '/' . date("Y-m-d") . '.txt';
	    $writer = new \Zend\Log\Writer\Stream($logFile);
	    return $logger;

In the same file add:

 public function onBootstrap($e)

	$eventManager = $e->getApplication()->getEventManager();
	$eventManager->attach(MvcEvent::EVENT_FINISH, function($e) {

	    $app = $e->getApplication();
	    $sm = $app->getServiceManager();
             // requires > 5.4.0 
             // else make it static with Module::setDatabaseLogging($sm)

protected function setDatabaseLogging($sm)
	$config = $sm->get('Config');
	if (!$config['db']['profiler']) {
	    return false;
	$dbAdapter = $sm->get('dbAdapter');
	$profiler = $dbAdapter
	$logger = $sm->get('Logger');
	$queryProfiles = $profiler->getProfiles();
	foreach ($queryProfiles as $profile) {
	    $str = $this->formatString($profile);

    protected function formatString($profile)
	$sql = $profile['sql'];
	if ($profile['parameters'] 
instanceof \Zend\Db\Adapter\ParameterContainer) {   
	    $parameters = $profile['parameters'];
	    foreach ($parameters as $k => $v) {
		$sql = str_replace(":" . $k, $v, $sql);

	return sprintf("%s; (in %s seconds)", $sql, $profile['elapse']);

The onBootstrap() method runs every time a script is called and only after all modules are initialised and able to listen to events. The eventManager is an implementation of the observer design pattern. In this code example an anonymous function is attached to the event MvcEvent::EVENT_FINISH. This event is triggered after everything is done in the code. Database profiling was already set in motion, therefore all that is left to do is collecting all the profiling results and write them to a file.

Writing to a file on the server is preferred over outputting the profiler content to the browser. With redirects and forwards queries my get overlooked.

Also see part 2 in a series of ZF2 database model procedure checks. For the code changes in the Orinoco project see here