Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[WCM] Extract the profiler to a new component #5422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The Components
intl
options_resolver
process
profiler/index
property_access/index
routing/index
security/index
Expand Down
4 changes: 4 additions & 0 deletions components/map.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@

* :doc:`/components/process`

* :doc:`/components/profiler/index`

* :doc:`/components/profiler/introduction`

* :doc:`/components/property_access/index`

* :doc:`/components/property_access/introduction`
Expand Down
7 changes: 7 additions & 0 deletions components/profiler/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Profiler
========

.. toctree::
:maxdepth: 2

introduction
73 changes: 73 additions & 0 deletions components/profiler/introduction.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. index::
single: Profiler
single: Components; Profiler

The Profiler Component
======================

The Profiler component provides tools to collected and present a profile of executed code.

.. versionadded:: 2.8
The Profiler component was introduced in Symfony 2.8. Previously, the classes
were located in the HttpKernel component.

Installation
------------

You can install the component in many different ways:

* :doc:`Install it via Composer </components/using_components>` (``symfony/profiler`` on `Packagist`_);
* Use the official Git repository (https://github.com/symfony/Profiler).

Usage
-----

The Profiler component provides several tools to help you debug PHP code.
Enabling them all is as easy as it can get::

use Symfony\Component\Profiler\Profiler;
use Symfony\Component\Profiler\Storage\FileProfilerStorage;

$storage = new FileProfilerStorage(__DIR__.'/cache/profiler');
$profiler = new Profiler($storage);

// $profile is an implementation of ProfileInterface.
$profile = $profiler->profile();

$profiler->save(
$profile,
array(
'url' => http://localhost/',
'ip' => '127.0.0.1',
'method' => 'GET',
'response_code' => 200,
'profile_type' => 'http',
)
);

if your project makes use of the :doc:`EventDispatcher component </components/event_dispatcher/introduction>`, you can automate the profiling by using the corresponding
EventListeners :class:`Symfony\\Component\\Profiler\\EventListener\\HttpProfilerListener`.

.. caution::

You should limit the profiler tools in a production environment to only profile on Exceptions as
profile every request will generate a significant portion of data and increase the response time.

Collecting Data with DataCollectors
-----------------------------------

The Profiler assembles a Profile with data it gets from DataCollectors.

A good deal of Components already provide usefull DataCollectors:

* :doc:`Debug component </components/debug/introduction>`: :class:`Symfony\\Component\\Debug\\Profiler\\ExceptionDataCollector`
* :doc:`EventDispatcher component </components/event_dispatcher/introduction>`: :class:`Symfony\\Component\\EventDispatcher\\Profiler\\EventDataCollector`
* :doc:`Form component </components/form/introduction>`: :class:`Symfony\\Component\\Form\\Extension\\Profiler\\FormDataCollector`
* :doc:`HttpKernel component </components/http_kernel/introduction>`: :class:`Symfony\\Component\\HttpKernel\\Profiler\\RequestDataCollector` & :class:`Symfony\\Component\\HttpKernel\\Profiler\\RouteDataCollector`
* :doc:`Security component </components/security/introduction>`: :class:`Symfony\\Component\\Security\\Core\\Profiler\\SecurityDataCollector`
* :doc:`Translation component </components/translation/introduction>`: :class:`Symfony\\Component\\Translation\\Profiler\\TranslationDataCollector`
* :doc:`VarDumper component </components/var_dumper/introduction>`: :class:`Symfony\\Component\\VarDumper\\Profiler\\DumpDataCollector`
* `Monolog bridge`: :class:`Symfony\\Bridge\\Monolog\\Profiler\\LoggerDataCollector`
* `Twig bridge`: :class:`Symfony\\Bridge\\Twig\\Profiler\\TwigDataCollector`

.. _Packagist: https://packagist.org/packages/symfony/profiler
109 changes: 81 additions & 28 deletions cookbook/profiler/data_collector.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,126 @@
How to Create a custom Data Collector
=====================================

:doc:`The Symfony Profiler </cookbook/profiler/index>` delegates data collecting to
:doc:`The Symfony Profiler </components/profiler/index>` delegates data collecting to
data collectors. Symfony comes bundled with a few of them, but you can easily
create your own.

Creating a custom Data Collector
--------------------------------

Creating a custom data collector is as simple as implementing the
:class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface`::
:class:`Symfony\\Component\\Profiler\\DataCollector\\DataCollectorInterface`::

interface DataCollectorInterface
{
/**
* Collects data for the given Request and Response.
* Returns the collected data.
*
* @param Request $request A Request instance
* @param Response $response A Response instance
* @param \Exception $exception An Exception instance
*/
function collect(Request $request, Response $response, \Exception $exception = null);

/**
* Returns the name of the collector.
* @return ProfileDataInterface
*
* @return string The collector name
* @todo introduce in 3.0
*/
function getName();
public function getCollectedData();
}

if the data should be collected just prior to the Profile being saved add the :class:`Symfony\\Component\\Profiler\\DataCollector\\LateDataCollectorInterface`::

interface LateDataCollectorInterface
{
}

The ``getCollectedData()`` method is responsible for storing the data it wants to give
access to in a :class:`Symfony\\Component\\Profiler\\ProfileData\\ProfileDataInterface`::

interface ProfileDataInterface extends \Serializable
{
public function getName();
}

The ``getName()`` method must return a unique name. This is used to access the
information later on (see :doc:`/cookbook/testing/profiling` for
instance).

The ``collect()`` method is responsible for storing the data it wants to give
access to in local properties.

.. caution::

As the profiler serializes data collector instances, you should not
As the profiler serializes ProfileData instances, you should not
store objects that cannot be serialized (like PDO objects), or you need
to provide your own ``serialize()`` method.

Most of the time, it is convenient to extend
:class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector` and
populate the ``$this->data`` property (it takes care of serializing the
``$this->data`` property)::
Example DataCollector::

class MemoryDataCollector extends DataCollector
class MemoryDataCollector extends AbstractDataCollector implements LateDataCollectorInterface
{
public function collect(Request $request, Response $response, \Exception $exception = null)
private $memoryLimit;

/**
* Constructor.
*/
public function __construct()
{
$this->data = array(
'memory' => memory_get_peak_usage(true),
);
$this->memoryLimit = ini_get('memory_limit');
}

public function getMemory()
/**
* {@inheritdoc}
*/
public function lateCollect()
{
return new MemoryData(memory_get_peak_usage(true), $this->memoryLimit);
}
}

class MemoryData implements ProfileDataInterface
{
private $memory;
private $memoryLimit;

/**
* Constructor.
*
* @param int $memory The current used memory.
* @param int $memoryLimit The memory limit.
*/
public function __construct($memory, $memoryLimit)
{
return $this->data['memory'];
$this->memory = $memory;
$this->memoryLimit = $this->convertToBytes($memoryLimit);
}

/**
* {@inheritdoc}
*/
public function getName()
{
return 'memory';
}

/**
* Returns the memory.
*
* @return int The memory
*/
public function getMemory()
{
return $this->memory;
}

/**
* Returns the PHP memory limit.
*
* @return int The memory limit
*/
public function getMemoryLimit()
{
return $this->memoryLimit;
}

//...
}




.. _data_collector_tag:

Enabling custom Data Collectors
Expand Down
26 changes: 9 additions & 17 deletions cookbook/profiler/profiling_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,37 @@ How to Access Profiling Data Programmatically

Most of the times, the profiler information is accessed and analyzed using its
web-based visualizer. However, you can also retrieve profiling information
programmatically thanks to the methods provided by the ``profiler`` service.

When the response object is available, use the
:method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::loadProfileFromResponse`
method to access to its associated profile::

// ... $profiler is the 'profiler' service
$profile = $profiler->loadProfileFromResponse($response);
programmatically thanks to the methods provided by the ``profiler.storage`` service.

When the profiler stores data about a request, it also associates a token with it;
this token is available in the ``X-Debug-Token`` HTTP header of the response.
Using this token, you can access the profile of any past response thanks to the
:method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::loadProfile` method::
:method:`Symfony\\Component\\Profiler\\Storage\\ProfilerStorageInterface::read` method::

$token = $response->headers->get('X-Debug-Token');
$profile = $container->get('profiler')->loadProfile($token);
$profile = $container->get('profiler.storage')->read($token);

.. tip::

When the profiler is enabled but not the web debug toolbar, inspect the page
with your browser's developer tools to get the value of the ``X-Debug-Token``
HTTP header.

The ``profiler`` service also provides the
:method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::find` method to
The ``profiler.storage`` service also provides the
:method:`Symfony\\Component\\Profiler\\Storage\\ProfilerStorageInterface::findBy` method to
look for tokens based on some criteria::

// get the latest 10 tokens
$tokens = $container->get('profiler')->find('', '', 10, '', '');
$tokens = $container->get('profiler.storage')->findBy(array(), 10, '', '');

// get the latest 10 tokens for all URL containing /admin/
$tokens = $container->get('profiler')->find('', '/admin/', 10, '', '');
$tokens = $container->get('profiler.storage')->findBy(array('url' => '/admin/'), 10, '', '');

// get the latest 10 tokens for local requests
$tokens = $container->get('profiler')->find('127.0.0.1', '', 10, '', '');
$tokens = $container->get('profiler.storage')->findBy(array('ip' => '127.0.0.1'), 10, '', '');

// get the latest 10 tokens for requests that happened between 2 and 4 days ago
$tokens = $container->get('profiler')
->find('', '', 10, '4 days ago', '2 days ago');
$tokens = $container->get('profiler.storage')->findBy(array(), 10, '4 days ago', '2 days ago');

Lastly, if you want to manipulate profiling data on a different machine than the
one where the information was generated, use the ``profiler:export`` and
Expand Down
2 changes: 1 addition & 1 deletion cookbook/profiler/storage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ uses MySQL as the storage for the profiler with a lifetime of one hour:
),
));

The :doc:`HttpKernel component </components/http_kernel/introduction>` currently
The :doc:`Profiler component </components/profiler/introduction>` currently
supports the following profiler storage drivers:

* file
Expand Down
6 changes: 3 additions & 3 deletions cookbook/testing/profiling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ the ``test`` environment)::
// check the number of requests
$this->assertLessThan(
10,
$profile->getCollector('db')->getQueryCount()
$profile->get('db')->getQueryCount()
);

// check the time spent in the framework
$this->assertLessThan(
500,
$profile->getCollector('time')->getDuration()
$profile->get('time')->getDuration()
);
}
}
Expand All @@ -52,7 +52,7 @@ finish. It's easy to achieve if you embed the token in the error message::

$this->assertLessThan(
30,
$profile->getCollector('db')->getQueryCount(),
$profile->get('db')->getQueryCount(),
sprintf(
'Checks that query count is less than 30 (token %s)',
$profile->getToken()
Expand Down