[ProfilerBundle] refactored the profiler bundle
This commit is contained in:
parent
fad8bd768c
commit
b9ae18db39
@ -22,16 +22,24 @@ use Symfony\Framework\ProfilerBundle\DataCollector\DataCollector;
|
|||||||
*/
|
*/
|
||||||
class DoctrineDataCollector extends DataCollector
|
class DoctrineDataCollector extends DataCollector
|
||||||
{
|
{
|
||||||
protected function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$data = array();
|
$this->data = array();
|
||||||
if ($this->container->hasService('doctrine.dbal.logger')) {
|
if ($this->container->hasService('doctrine.dbal.logger')) {
|
||||||
$data = array(
|
$this->data = array(
|
||||||
'queries' => $this->container->getDoctrine_Dbal_LoggerService()->queries,
|
'queries' => $this->container->getDoctrine_Dbal_LoggerService()->queries,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
public function getQueryCount()
|
||||||
|
{
|
||||||
|
return count($this->data['queries']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueries()
|
||||||
|
{
|
||||||
|
return $this->data['queries'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
|
@ -20,18 +20,28 @@ namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
|||||||
*/
|
*/
|
||||||
class AppDataCollector extends DataCollector
|
class AppDataCollector extends DataCollector
|
||||||
{
|
{
|
||||||
protected function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$request = $this->container->getRequestService();
|
$request = $this->container->getRequestService();
|
||||||
|
|
||||||
return array(
|
$this->data = array(
|
||||||
'route' => $request->path->get('_route') ? $request->path->get('_route') : '<span style="color: #a33">NONE</span>',
|
'route' => $request->path->get('_route') ? $request->path->get('_route') : '<span style="color: #a33">NONE</span>',
|
||||||
'format' => $request->getRequestFormat(),
|
'format' => $request->getRequestFormat(),
|
||||||
'content_type' => $this->manager->getResponse()->headers->get('Content-Type') ? $this->manager->getResponse()->headers->get('Content-Type') : 'text/html',
|
'content_type' => $this->profiler->getResponse()->headers->get('Content-Type') ? $this->profiler->getResponse()->headers->get('Content-Type') : 'text/html',
|
||||||
'code' => $this->manager->getResponse()->getStatusCode(),
|
'code' => $this->profiler->getResponse()->getStatusCode(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRoute()
|
||||||
|
{
|
||||||
|
return $this->data['route'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormat()
|
||||||
|
{
|
||||||
|
return $this->data['format'];
|
||||||
|
}
|
||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
{
|
{
|
||||||
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABKElEQVR42sSTPa6CQBSFv3lRrCRYACvQxMLCBhsTK5fAGtiAPaGfDbgGNmBCS0PFAqhsoSGSWE1yrTDvxd+E4t1qkrnn3HPPnFEiwpD6YWCNPjUcj0fquhYAz/MUQBRFzwniOH6cMBrJfD4HoKoq6UleKkiS5H7WWstut+N0OmHbNrZt92rURw+01rJerzmfzyyXSy6XC77vf2ei1lpWqxVN02CMwRhDEARUVcXHFfrJbdsyHo8BcByHsiwxxqjfBj4omE6nstlsuF6vWJaFZVl4nkdZlhwOB/U2B1mWSRiGFEWB67pMJhNc16Uoipfgpx6EYUie58xmM/I8fwsGUH2UsywTgMViAUCapnRdp9498x+COI5lu93eL/b7vfomyurfP9NggtsAfaVzbTWryOIAAAAASUVORK5CYII=" />
|
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABKElEQVR42sSTPa6CQBSFv3lRrCRYACvQxMLCBhsTK5fAGtiAPaGfDbgGNmBCS0PFAqhsoSGSWE1yrTDvxd+E4t1qkrnn3HPPnFEiwpD6YWCNPjUcj0fquhYAz/MUQBRFzwniOH6cMBrJfD4HoKoq6UleKkiS5H7WWstut+N0OmHbNrZt92rURw+01rJerzmfzyyXSy6XC77vf2ei1lpWqxVN02CMwRhDEARUVcXHFfrJbdsyHo8BcByHsiwxxqjfBj4omE6nstlsuF6vWJaFZVl4nkdZlhwOB/U2B1mWSRiGFEWB67pMJhNc16Uoipfgpx6EYUie58xmM/I8fwsGUH2UsywTgMViAUCapnRdp9498x+COI5lu93eL/b7vfomyurfP9NggtsAfaVzbTWryOIAAAAASUVORK5CYII=" />
|
||||||
|
@ -22,12 +22,12 @@ use Symfony\Foundation\Kernel;
|
|||||||
*/
|
*/
|
||||||
class ConfigDataCollector extends DataCollector
|
class ConfigDataCollector extends DataCollector
|
||||||
{
|
{
|
||||||
protected function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$kernel = $this->container->getKernelService();
|
$kernel = $this->container->getKernelService();
|
||||||
|
|
||||||
return array(
|
$this->data = array(
|
||||||
'token' => $this->manager->getProfilerStorage()->getToken(),
|
'token' => $this->profiler->getProfilerStorage()->getToken(),
|
||||||
'symfony_version' => Kernel::VERSION,
|
'symfony_version' => Kernel::VERSION,
|
||||||
'name' => $kernel->getName(),
|
'name' => $kernel->getName(),
|
||||||
'env' => $kernel->getEnvironment(),
|
'env' => $kernel->getEnvironment(),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
||||||
|
|
||||||
use Symfony\Components\DependencyInjection\ContainerInterface;
|
use Symfony\Components\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Framework\ProfilerBundle\Profiler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Symfony framework.
|
* This file is part of the Symfony framework.
|
||||||
@ -22,7 +23,7 @@ use Symfony\Components\DependencyInjection\ContainerInterface;
|
|||||||
*/
|
*/
|
||||||
abstract class DataCollector implements DataCollectorInterface
|
abstract class DataCollector implements DataCollectorInterface
|
||||||
{
|
{
|
||||||
protected $manager;
|
protected $profiler;
|
||||||
protected $container;
|
protected $container;
|
||||||
protected $data;
|
protected $data;
|
||||||
|
|
||||||
@ -33,17 +34,18 @@ abstract class DataCollector implements DataCollectorInterface
|
|||||||
|
|
||||||
public function getData()
|
public function getData()
|
||||||
{
|
{
|
||||||
if (null === $this->data) {
|
|
||||||
$this->data = $this->collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract protected function collect();
|
public function setData($data)
|
||||||
|
|
||||||
public function setCollectorManager(DataCollectorManager $manager)
|
|
||||||
{
|
{
|
||||||
$this->manager = $manager;
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function collect();
|
||||||
|
|
||||||
|
public function setProfiler(Profiler $profiler)
|
||||||
|
{
|
||||||
|
$this->profiler = $profiler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Framework\ProfilerBundle\Profiler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Symfony framework.
|
* This file is part of the Symfony framework.
|
||||||
*
|
*
|
||||||
@ -20,7 +22,7 @@ namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
|||||||
*/
|
*/
|
||||||
interface DataCollectorInterface
|
interface DataCollectorInterface
|
||||||
{
|
{
|
||||||
public function setCollectorManager(DataCollectorManager $manager);
|
public function setProfiler(Profiler $profiler);
|
||||||
|
|
||||||
public function getData();
|
public function getData();
|
||||||
|
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
|
||||||
|
|
||||||
use Symfony\Components\DependencyInjection\ContainerInterface;
|
|
||||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
|
||||||
use Symfony\Components\EventDispatcher\Event;
|
|
||||||
use Symfony\Components\HttpKernel\Response;
|
|
||||||
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
|
||||||
use Symfony\Framework\ProfilerBundle\ProfilerStorage;
|
|
||||||
use Symfony\Foundation\LoggerInterface;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the Symfony framework.
|
|
||||||
*
|
|
||||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
*
|
|
||||||
* This source file is subject to the MIT license that is bundled
|
|
||||||
* with this source code in the file LICENSE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DataCollectorManager.
|
|
||||||
*
|
|
||||||
* @package Symfony
|
|
||||||
* @subpackage Framework_ProfilerBundle
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
*/
|
|
||||||
class DataCollectorManager
|
|
||||||
{
|
|
||||||
protected $container;
|
|
||||||
protected $profilerStorage;
|
|
||||||
protected $collectors;
|
|
||||||
protected $response;
|
|
||||||
protected $lifetime;
|
|
||||||
protected $logger;
|
|
||||||
|
|
||||||
public function __construct(ContainerInterface $container, LoggerInterface $logger, ProfilerStorage $profilerStorage, $lifetime = 86400)
|
|
||||||
{
|
|
||||||
$this->container = $container;
|
|
||||||
$this->logger = $logger;
|
|
||||||
$this->lifetime = $lifetime;
|
|
||||||
$this->profilerStorage = $profilerStorage;
|
|
||||||
$this->collectors = $this->initCollectors();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a core.response listener.
|
|
||||||
*
|
|
||||||
* @param Symfony\Components\EventDispatcher\EventDispatcher $dispatcher An EventDispatcher instance
|
|
||||||
*/
|
|
||||||
public function register(EventDispatcher $dispatcher)
|
|
||||||
{
|
|
||||||
$dispatcher->connect('core.response', array($this, 'handle'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(Event $event, Response $response)
|
|
||||||
{
|
|
||||||
if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->response = $response;
|
|
||||||
$this->response->headers->set('X-Debug-Token', $this->profilerStorage->getToken());
|
|
||||||
|
|
||||||
$data = array();
|
|
||||||
foreach ($this->collectors as $name => $collector) {
|
|
||||||
$data[$name] = $collector->getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->profilerStorage->write($data);
|
|
||||||
$this->profilerStorage->purge($this->lifetime);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->logger->err('Unable to store the profiler information.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getProfilerStorage()
|
|
||||||
{
|
|
||||||
return $this->profilerStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCollectors()
|
|
||||||
{
|
|
||||||
return $this->collectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initCollectors()
|
|
||||||
{
|
|
||||||
$config = $this->container->findAnnotatedServiceIds('data_collector');
|
|
||||||
$ids = array();
|
|
||||||
$coreCollectors = array();
|
|
||||||
$userCollectors = array();
|
|
||||||
foreach ($config as $id => $attributes) {
|
|
||||||
$collector = $this->container->getService($id);
|
|
||||||
$collector->setCollectorManager($this);
|
|
||||||
|
|
||||||
if (isset($attributes[0]['core']) && $attributes[0]['core']) {
|
|
||||||
$coreCollectors[$collector->getName()] = $collector;
|
|
||||||
} else {
|
|
||||||
$userCollectors[$collector->getName()] = $collector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->collectors = array_merge($coreCollectors, $userCollectors);
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,13 +20,18 @@ namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
|||||||
*/
|
*/
|
||||||
class MemoryDataCollector extends DataCollector
|
class MemoryDataCollector extends DataCollector
|
||||||
{
|
{
|
||||||
protected function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
return array(
|
$this->data = array(
|
||||||
'memory' => memory_get_peak_usage(true),
|
'memory' => memory_get_peak_usage(true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMemory()
|
||||||
|
{
|
||||||
|
return $this->data['memory'];
|
||||||
|
}
|
||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
{
|
{
|
||||||
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAmElEQVR42sSTuwoEIQxFr7JtOgf0n+z9Rhsr/0nB0jKiW00xs7Myj4VNFQj3cAKJGGPgSUk8rNfaeO8vqTjnxAYAAMuynAqXUj4NAKDWen8FKSWstadCIYRjg9YaUkrTsDHm2GAFtNamgP18A2BmKKWmAGaeG+ScpwCt9XdA7x299ylgP//dJQIAEYGI7gNijJcNxN+/8T0A1+E5NmcLfJkAAAAASUVORK5CYII=" />
|
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAmElEQVR42sSTuwoEIQxFr7JtOgf0n+z9Rhsr/0nB0jKiW00xs7Myj4VNFQj3cAKJGGPgSUk8rNfaeO8vqTjnxAYAAMuynAqXUj4NAKDWen8FKSWstadCIYRjg9YaUkrTsDHm2GAFtNamgP18A2BmKKWmAGaeG+ScpwCt9XdA7x299ylgP//dJQIAEYGI7gNijJcNxN+/8T0A1+E5NmcLfJkAAAAASUVORK5CYII=" />
|
||||||
|
@ -20,13 +20,18 @@ namespace Symfony\Framework\ProfilerBundle\DataCollector;
|
|||||||
*/
|
*/
|
||||||
class TimerDataCollector extends DataCollector
|
class TimerDataCollector extends DataCollector
|
||||||
{
|
{
|
||||||
protected function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
return array(
|
$this->data = array(
|
||||||
'time' => microtime(true) - $this->container->getKernelService()->getStartTime(),
|
'time' => microtime(true) - $this->container->getKernelService()->getStartTime(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTime()
|
||||||
|
{
|
||||||
|
return $this->data['time'];
|
||||||
|
}
|
||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
{
|
{
|
||||||
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABSElEQVR42pyTwZHCMAxFXxxKUAXuIA3gFnJxERxohAt9QAM5EhpwB6rAJdjJXmKThIWdWc1oJvbo/y8p383tdmMfMcYEtKurLCKHfZ33nsMOmAFjraXrunofQmhVdQYmEVkTvwhijPMaOI5jLXLO0XUdIQSjqrOINBuCGGMu4AL03leC+/1eiQBUNZdOzFJjCth7X8GXy6WSee8Zx7F0WHCYGGOy1la1aZpqrs/zPNcaa21ZNAZoi3rf9+ScawL1O6VE3/frLtrNEgFSSm+/9Hq9AnA+n/ktvhKcTqev5GWEHELAOccwDKSUPuYwDDjnCCEAZAAjIgdV3Sh9yhKqSnFmGWEKIRjnHI/HA4Dj8VgBz+ez+mBRnzY7EJFi1WqWvRMXSxf19m2JItKoalZVY62toDXw61sonSwzJlX98zUCNGuH/Sd+BgBGROvHb4RJ6gAAAABJRU5ErkJggg==" />
|
return sprintf('<img style="margin-left: 10px; vertical-align: middle" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABSElEQVR42pyTwZHCMAxFXxxKUAXuIA3gFnJxERxohAt9QAM5EhpwB6rAJdjJXmKThIWdWc1oJvbo/y8p383tdmMfMcYEtKurLCKHfZ33nsMOmAFjraXrunofQmhVdQYmEVkTvwhijPMaOI5jLXLO0XUdIQSjqrOINBuCGGMu4AL03leC+/1eiQBUNZdOzFJjCth7X8GXy6WSee8Zx7F0WHCYGGOy1la1aZpqrs/zPNcaa21ZNAZoi3rf9+ScawL1O6VE3/frLtrNEgFSSm+/9Hq9AnA+n/ktvhKcTqev5GWEHELAOccwDKSUPuYwDDjnCCEAZAAjIgdV3Sh9yhKqSnFmGWEKIRjnHI/HA4Dj8VgBz+ez+mBRnzY7EJFi1WqWvRMXSxf19m2JItKoalZVY62toDXw61sonSwzJlX98zUCNGuH/Sd+BgBGROvHb4RJ6gAAAABJRU5ErkJggg==" />
|
||||||
|
@ -26,7 +26,7 @@ class ProfilerExtension extends LoaderExtension
|
|||||||
{
|
{
|
||||||
public function configLoad($config, BuilderConfiguration $configuration)
|
public function configLoad($config, BuilderConfiguration $configuration)
|
||||||
{
|
{
|
||||||
if (!$configuration->hasDefinition('data_collector_manager')) {
|
if (!$configuration->hasDefinition('profiler')) {
|
||||||
$loader = new XmlFileLoader(__DIR__.'/../Resources/config');
|
$loader = new XmlFileLoader(__DIR__.'/../Resources/config');
|
||||||
$configuration->merge($loader->load('collectors.xml'));
|
$configuration->merge($loader->load('collectors.xml'));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Framework\ProfilerBundle\Listener;
|
||||||
|
|
||||||
|
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||||
|
use Symfony\Components\EventDispatcher\Event;
|
||||||
|
use Symfony\Components\HttpKernel\Response;
|
||||||
|
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
||||||
|
use Symfony\Framework\ProfilerBundle\Profiler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony framework.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||||
|
*
|
||||||
|
* This source file is subject to the MIT license that is bundled
|
||||||
|
* with this source code in the file LICENSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataCollector collects data for the current request by listening to the core.response event.
|
||||||
|
*
|
||||||
|
* @package Symfony
|
||||||
|
* @subpackage Framework_ProfilerBundle
|
||||||
|
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||||
|
*/
|
||||||
|
class DataCollector
|
||||||
|
{
|
||||||
|
protected $profiler;
|
||||||
|
|
||||||
|
public function __construct(Profiler $profiler)
|
||||||
|
{
|
||||||
|
$this->profiler = $profiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a core.response listener.
|
||||||
|
*
|
||||||
|
* @param Symfony\Components\EventDispatcher\EventDispatcher $dispatcher An EventDispatcher instance
|
||||||
|
*/
|
||||||
|
public function register(EventDispatcher $dispatcher)
|
||||||
|
{
|
||||||
|
$dispatcher->connect('core.response', array($this, 'handle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Event $event, Response $response)
|
||||||
|
{
|
||||||
|
if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->profiler->collect($response);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ use Symfony\Components\EventDispatcher\EventDispatcher;
|
|||||||
use Symfony\Components\EventDispatcher\Event;
|
use Symfony\Components\EventDispatcher\Event;
|
||||||
use Symfony\Components\HttpKernel\Response;
|
use Symfony\Components\HttpKernel\Response;
|
||||||
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
||||||
use Symfony\Framework\ProfilerBundle\DataCollector\DataCollectorManager;
|
use Symfony\Framework\ProfilerBundle\Profiler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Symfony framework.
|
* This file is part of the Symfony framework.
|
||||||
@ -28,12 +28,12 @@ use Symfony\Framework\ProfilerBundle\DataCollector\DataCollectorManager;
|
|||||||
class WebDebugToolbar
|
class WebDebugToolbar
|
||||||
{
|
{
|
||||||
protected $container;
|
protected $container;
|
||||||
protected $collectorManager;
|
protected $profiler;
|
||||||
|
|
||||||
public function __construct(ContainerInterface $container, DataCollectorManager $collectorManager)
|
public function __construct(ContainerInterface $container, Profiler $profiler)
|
||||||
{
|
{
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
$this->collectorManager = $collectorManager;
|
$this->profiler = $profiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +77,7 @@ class WebDebugToolbar
|
|||||||
protected function injectToolbar(Response $response)
|
protected function injectToolbar(Response $response)
|
||||||
{
|
{
|
||||||
$data = '';
|
$data = '';
|
||||||
foreach ($this->collectorManager->getCollectors() as $name => $collector) {
|
foreach ($this->profiler->getCollectors() as $name => $collector) {
|
||||||
$data .= $collector->getSummary();
|
$data .= $collector->getSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
192
src/Symfony/Framework/ProfilerBundle/Profiler.php
Normal file
192
src/Symfony/Framework/ProfilerBundle/Profiler.php
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Framework\ProfilerBundle;
|
||||||
|
|
||||||
|
use Symfony\Components\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Components\HttpKernel\Response;
|
||||||
|
use Symfony\Framework\ProfilerBundle\ProfilerStorage;
|
||||||
|
use Symfony\Foundation\LoggerInterface;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony framework.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||||
|
*
|
||||||
|
* This source file is subject to the MIT license that is bundled
|
||||||
|
* with this source code in the file LICENSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profiler.
|
||||||
|
*
|
||||||
|
* @package Symfony
|
||||||
|
* @subpackage Framework_ProfilerBundle
|
||||||
|
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||||
|
*/
|
||||||
|
class Profiler implements \ArrayAccess
|
||||||
|
{
|
||||||
|
protected $container;
|
||||||
|
protected $profilerStorage;
|
||||||
|
protected $collectors;
|
||||||
|
protected $response;
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container, ProfilerStorage $profilerStorage, LoggerInterface $logger = null)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
$this->profilerStorage = $profilerStorage;
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->initCollectors();
|
||||||
|
$this->loadCollectorData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
$this->profilerStorage = clone $this->profilerStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(Response $response)
|
||||||
|
{
|
||||||
|
return $this->getProfilerForToken($response->headers->get('X-Debug-Token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfilerForToken($token)
|
||||||
|
{
|
||||||
|
$profiler = clone $this;
|
||||||
|
$profiler->profilerStorage->setToken($token);
|
||||||
|
$profiler->loadCollectorData();
|
||||||
|
|
||||||
|
return $profiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collect(Response $response)
|
||||||
|
{
|
||||||
|
$this->response = $response;
|
||||||
|
$this->response->headers->set('X-Debug-Token', $this->profilerStorage->getToken());
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach ($this->collectors as $name => $collector) {
|
||||||
|
$collector->collect();
|
||||||
|
|
||||||
|
$data[$name] = $collector->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->profilerStorage->write($data);
|
||||||
|
$this->profilerStorage->purge();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (null !== $this->logger) {
|
||||||
|
$this->logger->err('Unable to store the profiler information.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfilerStorage()
|
||||||
|
{
|
||||||
|
return $this->profilerStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadCollectorData()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
foreach ($this->collectors as $name => $collector) {
|
||||||
|
$collector->setData($this->profilerStorage->getData($name));
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (null !== $this->logger) {
|
||||||
|
$this->logger->err('Unable to read the profiler information.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCollectors()
|
||||||
|
{
|
||||||
|
return $this->collectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasCollector($name)
|
||||||
|
{
|
||||||
|
return isset($this->collectors[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCollector($name)
|
||||||
|
{
|
||||||
|
if (!isset($this->collectors[$name])) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->collectors[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the named field exists.
|
||||||
|
*
|
||||||
|
* @param string $name The field name
|
||||||
|
*
|
||||||
|
* @param Boolean true if the field exists, false otherwise
|
||||||
|
*/
|
||||||
|
public function offsetExists($name)
|
||||||
|
{
|
||||||
|
return $this->hasCollector($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a field.
|
||||||
|
*
|
||||||
|
* @param string $name The field name
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException if the field does not exist
|
||||||
|
*/
|
||||||
|
public function offsetGet($name)
|
||||||
|
{
|
||||||
|
return $this->getCollector($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a field.
|
||||||
|
*
|
||||||
|
* @param string $name The field name
|
||||||
|
* @param string|array $value The value of the field
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException if the field does not exist
|
||||||
|
*/
|
||||||
|
public function offsetSet($name, $value)
|
||||||
|
{
|
||||||
|
throw new \LogicException('The Collectors cannot be set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unimplemented.
|
||||||
|
*
|
||||||
|
* @param string $name The field name
|
||||||
|
*/
|
||||||
|
public function offsetUnset($name)
|
||||||
|
{
|
||||||
|
throw new \LogicException('The Collectors cannot be removed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function initCollectors()
|
||||||
|
{
|
||||||
|
$config = $this->container->findAnnotatedServiceIds('data_collector');
|
||||||
|
$ids = array();
|
||||||
|
$coreCollectors = array();
|
||||||
|
$userCollectors = array();
|
||||||
|
foreach ($config as $id => $attributes) {
|
||||||
|
$collector = $this->container->getService($id);
|
||||||
|
$collector->setProfiler($this);
|
||||||
|
|
||||||
|
if (isset($attributes[0]['core']) && $attributes[0]['core']) {
|
||||||
|
$coreCollectors[$collector->getName()] = $collector;
|
||||||
|
} else {
|
||||||
|
$userCollectors[$collector->getName()] = $collector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->collectors = array_merge($coreCollectors, $userCollectors);
|
||||||
|
}
|
||||||
|
}
|
@ -23,12 +23,14 @@ class ProfilerStorage
|
|||||||
protected $token;
|
protected $token;
|
||||||
protected $data;
|
protected $data;
|
||||||
protected $store;
|
protected $store;
|
||||||
|
protected $lifetime;
|
||||||
|
|
||||||
public function __construct($store, $token = null)
|
public function __construct($store, $token = null, $lifetime = 86400)
|
||||||
{
|
{
|
||||||
$this->store = $store;
|
$this->store = $store;
|
||||||
$this->token = null === $token ? uniqid() : $token;
|
$this->token = null === $token ? uniqid() : $token;
|
||||||
$this->data = null;
|
$this->data = null;
|
||||||
|
$this->lifetime = (int) $lifetime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasData()
|
public function hasData()
|
||||||
@ -46,7 +48,13 @@ class ProfilerStorage
|
|||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset($this->data[$name]) ? $this->data[$name] : null;
|
return isset($this->data[$name]) ? $this->data[$name] : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToken($token)
|
||||||
|
{
|
||||||
|
$this->token = $token;
|
||||||
|
$this->data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToken()
|
public function getToken()
|
||||||
@ -134,10 +142,10 @@ class ProfilerStorage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function purge($lifetime)
|
public function purge()
|
||||||
{
|
{
|
||||||
$db = $this->initDb(false);
|
$db = $this->initDb(false);
|
||||||
$args = array(':time' => time() - (int) $lifetime);
|
$args = array(':time' => time() - $this->lifetime);
|
||||||
$this->exec($db, 'DELETE FROM data WHERE created_at < :time', $args);
|
$this->exec($db, 'DELETE FROM data WHERE created_at < :time', $args);
|
||||||
$this->close($db);
|
$this->close($db);
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
|
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
<parameters>
|
<parameters>
|
||||||
<parameter key="data_collector_manager.class">Symfony\Framework\ProfilerBundle\DataCollector\DataCollectorManager</parameter>
|
<parameter key="profiler.class">Symfony\Framework\ProfilerBundle\Profiler</parameter>
|
||||||
<parameter key="data_collector_manager.storage.class">Symfony\Framework\ProfilerBundle\ProfilerStorage</parameter>
|
<parameter key="profiler.storage.class">Symfony\Framework\ProfilerBundle\ProfilerStorage</parameter>
|
||||||
<parameter key="data_collector_manager.storage.file">%kernel.cache_dir%/profiler.db</parameter>
|
<parameter key="profiler.storage.file">%kernel.cache_dir%/profiler.db</parameter>
|
||||||
<parameter key="data_collector_manager.lifetime">86400</parameter>
|
<parameter key="profiler.storage.lifetime">86400</parameter>
|
||||||
|
<parameter key="data_collector.class">Symfony\Framework\ProfilerBundle\Listener\DataCollector</parameter>
|
||||||
<parameter key="data_collector.config.class">Symfony\Framework\ProfilerBundle\DataCollector\ConfigDataCollector</parameter>
|
<parameter key="data_collector.config.class">Symfony\Framework\ProfilerBundle\DataCollector\ConfigDataCollector</parameter>
|
||||||
<parameter key="data_collector.app.class">Symfony\Framework\ProfilerBundle\DataCollector\AppDataCollector</parameter>
|
<parameter key="data_collector.app.class">Symfony\Framework\ProfilerBundle\DataCollector\AppDataCollector</parameter>
|
||||||
<parameter key="data_collector.timer.class">Symfony\Framework\ProfilerBundle\DataCollector\TimerDataCollector</parameter>
|
<parameter key="data_collector.timer.class">Symfony\Framework\ProfilerBundle\DataCollector\TimerDataCollector</parameter>
|
||||||
@ -16,16 +17,21 @@
|
|||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
<service id="data_collector_manager" class="%data_collector_manager.class%">
|
<service id="profiler" class="%profiler.class%">
|
||||||
<annotation name="kernel.listener" />
|
|
||||||
<argument type="service" id="service_container" />
|
<argument type="service" id="service_container" />
|
||||||
<argument type="service" id="logger" />
|
<argument type="service" id="profiler.storage" />
|
||||||
<argument type="service" id="data_collector_manager.storage" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
<argument>%data_collector_manager.lifetime%</argument>
|
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="data_collector_manager.storage" class="%data_collector_manager.storage.class%">
|
<service id="profiler.storage" class="%profiler.storage.class%">
|
||||||
<argument>%data_collector_manager.storage.file%</argument>
|
<argument>%profiler.storage.file%</argument>
|
||||||
|
<argument>null</argument>
|
||||||
|
<argument>%profiler.storage.lifetime%</argument>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="data_collector" class="%data_collector.class%">
|
||||||
|
<annotation name="kernel.listener" />
|
||||||
|
<argument type="service" id="profiler" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="data_collector.config" class="%data_collector.config.class%">
|
<service id="data_collector.config" class="%data_collector.config.class%">
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<service id="debug.toolbar" class="%debug.toolbar.class%">
|
<service id="debug.toolbar" class="%debug.toolbar.class%">
|
||||||
<annotation name="kernel.listener" />
|
<annotation name="kernel.listener" />
|
||||||
<argument type="service" id="service_container" />
|
<argument type="service" id="service_container" />
|
||||||
<argument type="service" id="data_collector_manager" />
|
<argument type="service" id="profiler" />
|
||||||
</service>
|
</service>
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
@ -23,7 +23,7 @@ class ProfilerExtensionTest extends TestCase
|
|||||||
$loader = new ProfilerExtension();
|
$loader = new ProfilerExtension();
|
||||||
|
|
||||||
$configuration = $loader->configLoad(array(), $configuration);
|
$configuration = $loader->configLoad(array(), $configuration);
|
||||||
$this->assertEquals('Symfony\\Framework\\ProfilerBundle\\DataCollector\\DataCollectorManager', $configuration->getParameter('data_collector_manager.class'), '->configLoad() loads the collectors.xml file if not already loaded');
|
$this->assertEquals('Symfony\\Framework\\ProfilerBundle\\Profiler', $configuration->getParameter('profiler.class'), '->configLoad() loads the collectors.xml file if not already loaded');
|
||||||
$this->assertFalse($configuration->hasParameter('debug.toolbar.class'), '->configLoad() does not load the toolbar.xml file');
|
$this->assertFalse($configuration->hasParameter('debug.toolbar.class'), '->configLoad() does not load the toolbar.xml file');
|
||||||
|
|
||||||
$configuration = $loader->configLoad(array('toolbar' => true), $configuration);
|
$configuration = $loader->configLoad(array('toolbar' => true), $configuration);
|
||||||
|
Reference in New Issue
Block a user