Improved profiler to store and retrieve sub requests data

This commit is contained in:
noel guilbert 2011-02-26 17:24:02 +01:00
parent e16c666266
commit a8eff2b154
7 changed files with 122 additions and 10 deletions

View File

@ -46,6 +46,19 @@ class ProfilerListener
$this->onlyException = $onlyException; $this->onlyException = $onlyException;
} }
/**
* Handles the core.request event
*
* This method initialize the profiler to be able to get it as a scoped
* service when handleResponse() will collect the sub request
*
* @param EventInterface $event An EventInterface instance
*/
public function handleRequest(EventInterface $event)
{
$this->container->get('profiler');
}
/** /**
* Handles the core.exception event. * Handles the core.exception event.
* *
@ -71,10 +84,6 @@ class ProfilerListener
*/ */
public function handleResponse(EventInterface $event, Response $response) public function handleResponse(EventInterface $event, Response $response)
{ {
if (HttpKernelInterface::MASTER_REQUEST !== $event->get('request_type')) {
return $response;
}
if (null !== $this->matcher && !$this->matcher->matches($event->get('request'))) { if (null !== $this->matcher && !$this->matcher->matches($event->get('request'))) {
return $response; return $response;
} }
@ -83,7 +92,13 @@ class ProfilerListener
return $response; return $response;
} }
$this->container->get('profiler')->collect($event->get('request'), $response, $this->exception); $profiler = $this->container->get('profiler');
if (($parent = $this->container->getCurrentScopedStack('request'))) {
$profiler->setParent($parent['request']['profiler']->getToken());
}
$profiler->collect($event->get('request'), $response, $this->exception);
$this->exception = null; $this->exception = null;
return $response; return $response;

View File

@ -27,6 +27,7 @@
<service id="profiler_listener" class="%profiler_listener.class%"> <service id="profiler_listener" class="%profiler_listener.class%">
<tag name="kernel.listener" event="core.response" method="handleResponse" /> <tag name="kernel.listener" event="core.response" method="handleResponse" />
<tag name="kernel.listener" event="core.exception" method="handleException" /> <tag name="kernel.listener" event="core.exception" method="handleException" />
<tag name="kernel.listener" event="core.request" method="handleRequest" />
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
<argument type="service" id="profiler.request_matcher" on-invalid="null" /> <argument type="service" id="profiler.request_matcher" on-invalid="null" />
<argument>%profiler_listener.only_exceptions%</argument> <argument>%profiler_listener.only_exceptions%</argument>

View File

@ -76,4 +76,21 @@ Request
{% else %} {% else %}
<em>No request session attributes</em> <em>No request session attributes</em>
{% endif %} {% endif %}
{% if profiler.parent %}
<h2><a href="{{ path('_profiler', { 'token': profiler.parent }) }}">Parent request: {{ profiler.parent }}</a></h2>
{% include 'WebProfilerBundle:Profiler:bag.html.twig' with { 'bag': profiler.parenttoken.get('request').requestattributes } only %}
{% endif %}
{% if profiler.children|length %}
<h2>Sub requests</h2>
{% for subrequest in profiler.children %}
<h3><a href="{{ path('_profiler', { 'token': subrequest.token }) }}">{{ subrequest.token }}</a></h3>
{% include 'WebProfilerBundle:Profiler:bag.html.twig' with { 'bag': subrequest.get('request').requestattributes } only %}
{% endfor %}
{% endif %}
{% endblock %} {% endblock %}

View File

@ -295,6 +295,22 @@ class Container implements ContainerInterface
$this->scopedServices[$name] = array(); $this->scopedServices[$name] = array();
} }
/**
* Returns the current stacked service scope for the given name
*
* @param string $name The service name
* @return array The service scope
*/
public function getCurrentScopedStack($name)
{
if (!isset($this->scopeStacks[$name]) || 0 === $this->scopeStacks[$name]->count()) {
return null;
}
return $this->scopeStacks[$name]->current();
}
/** /**
* This is called to leave the current scope, and move back to the parent * This is called to leave the current scope, and move back to the parent
* scope. * scope.

View File

@ -35,6 +35,7 @@ class Profiler
protected $url; protected $url;
protected $time; protected $time;
protected $empty; protected $empty;
protected $children;
/** /**
* Constructor. * Constructor.
@ -142,7 +143,7 @@ class Profiler
$this->token = $token; $this->token = $token;
if (false !== $items = $this->storage->read($token)) { if (false !== $items = $this->storage->read($token)) {
list($data, $this->ip, $this->url, $this->time) = $items; list($data, $this->parent, $this->ip, $this->url, $this->time) = $items;
$this->set(unserialize(base64_decode($data))); $this->set(unserialize(base64_decode($data)));
$this->empty = false; $this->empty = false;
@ -151,6 +152,30 @@ class Profiler
} }
} }
/**
* Sets the parent token
*
* @param string $parent The parent token
*/
public function setParent($parent)
{
$this->parent = $parent;
}
/**
* Returns an instance of the parent token
*
* @return Profiler
*/
public function getParentToken()
{
if (null !== $this->parent) {
return $this->loadFromToken($this->parent);
}
return null;
}
/** /**
* Gets the token. * Gets the token.
* *
@ -229,6 +254,23 @@ class Profiler
return $this->storage->find($ip, $url, $limit); return $this->storage->find($ip, $url, $limit);
} }
/**
* Finds children profilers.
*
* @return array An array of Profiler
*/
public function getChildren()
{
if (null === $this->children) {
$this->children = array();
foreach ($this->storage->findChildren($this->token) as $token) {
$this->children[] = $this->loadFromToken($token['token']);
}
}
return $this->children;
}
/** /**
* Collects data for the given Response. * Collects data for the given Response.
* *
@ -248,7 +290,6 @@ class Profiler
$collector->collect($request, $response, $exception); $collector->collect($request, $response, $exception);
} }
$this->parent = '';
$this->ip = $request->server->get('REMOTE_ADDR'); $this->ip = $request->server->get('REMOTE_ADDR');
$this->url = $request->getUri(); $this->url = $request->getUri();
$this->time = time(); $this->time = time();

View File

@ -29,6 +29,15 @@ interface ProfilerStorageInterface
*/ */
function find($ip, $url, $limit); function find($ip, $url, $limit);
/**
* Finds profiler tokens for the given parent token.
*
* @param string $token The parent token
*
* @return array An array of tokens
*/
function findChildren($token);
/** /**
* Reads data associated with the given token. * Reads data associated with the given token.
* *

View File

@ -56,7 +56,7 @@ class SqliteProfilerStorage implements ProfilerStorageInterface
$criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : ''; $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : '';
$db = $this->initDb(); $db = $this->initDb();
$tokens = $this->fetch($db, 'SELECT token, ip, url, time FROM data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args); $tokens = $this->fetch($db, 'SELECT token, ip, url, time, parent FROM data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args);
$this->close($db); $this->close($db);
return $tokens; return $tokens;
@ -69,15 +69,28 @@ class SqliteProfilerStorage implements ProfilerStorageInterface
{ {
$db = $this->initDb(); $db = $this->initDb();
$args = array(':token' => $token); $args = array(':token' => $token);
$data = $this->fetch($db, 'SELECT data, ip, url, time FROM data WHERE token = :token LIMIT 1', $args); $data = $this->fetch($db, 'SELECT data, parent, ip, url, time FROM data WHERE token = :token LIMIT 1', $args);
$this->close($db); $this->close($db);
if (isset($data[0]['data'])) { if (isset($data[0]['data'])) {
return array($data[0]['data'], $data[0]['ip'], $data[0]['url'], $data[0]['time']); return array($data[0]['data'], $data[0]['parent'], $data[0]['ip'], $data[0]['url'], $data[0]['time']);
} else { } else {
return false; return false;
} }
} }
/**
* {@inheritdoc}
*/
public function findChildren($token)
{
$db = $this->initDb();
$args = array(':token' => $token);
$tokens = $this->fetch($db, 'SELECT token FROM data WHERE parent = :token LIMIT 1', $args);
$this->close($db);
return $tokens;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */