diff --git a/components/index.rst b/components/index.rst index 41f72d049a4..0cf921206fa 100644 --- a/components/index.rst +++ b/components/index.rst @@ -23,6 +23,7 @@ The Components intl options_resolver process + profiler/index property_access/index routing/index security/index diff --git a/components/map.rst.inc b/components/map.rst.inc index 009284614ce..882989ab963 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -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` diff --git a/components/profiler/index.rst b/components/profiler/index.rst new file mode 100644 index 00000000000..a7d43e7fe61 --- /dev/null +++ b/components/profiler/index.rst @@ -0,0 +1,7 @@ +Profiler +======== + +.. toctree:: + :maxdepth: 2 + + introduction diff --git a/components/profiler/introduction.rst b/components/profiler/introduction.rst new file mode 100644 index 00000000000..a2616444ecd --- /dev/null +++ b/components/profiler/introduction.rst @@ -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 ` (``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 `, 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 `: :class:`Symfony\\Component\\Debug\\Profiler\\ExceptionDataCollector` +* :doc:`EventDispatcher component `: :class:`Symfony\\Component\\EventDispatcher\\Profiler\\EventDataCollector` +* :doc:`Form component `: :class:`Symfony\\Component\\Form\\Extension\\Profiler\\FormDataCollector` +* :doc:`HttpKernel component `: :class:`Symfony\\Component\\HttpKernel\\Profiler\\RequestDataCollector` & :class:`Symfony\\Component\\HttpKernel\\Profiler\\RouteDataCollector` +* :doc:`Security component `: :class:`Symfony\\Component\\Security\\Core\\Profiler\\SecurityDataCollector` +* :doc:`Translation component `: :class:`Symfony\\Component\\Translation\\Profiler\\TranslationDataCollector` +* :doc:`VarDumper component `: :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 diff --git a/cookbook/profiler/data_collector.rst b/cookbook/profiler/data_collector.rst index 985738aa5cb..cd8499ca277 100644 --- a/cookbook/profiler/data_collector.rst +++ b/cookbook/profiler/data_collector.rst @@ -4,7 +4,7 @@ How to Create a custom Data Collector ===================================== -:doc:`The Symfony Profiler ` delegates data collecting to +:doc:`The Symfony Profiler ` delegates data collecting to data collectors. Symfony comes bundled with a few of them, but you can easily create your own. @@ -12,65 +12,118 @@ 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 diff --git a/cookbook/profiler/profiling_data.rst b/cookbook/profiler/profiling_data.rst index 761dae943e6..320a828eab1 100644 --- a/cookbook/profiler/profiling_data.rst +++ b/cookbook/profiler/profiling_data.rst @@ -6,22 +6,15 @@ 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:: @@ -29,22 +22,21 @@ Using this token, you can access the profile of any past response thanks to the 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 diff --git a/cookbook/profiler/storage.rst b/cookbook/profiler/storage.rst index e91ef883eaa..f31efa79f4c 100644 --- a/cookbook/profiler/storage.rst +++ b/cookbook/profiler/storage.rst @@ -57,7 +57,7 @@ uses MySQL as the storage for the profiler with a lifetime of one hour: ), )); -The :doc:`HttpKernel component ` currently +The :doc:`Profiler component ` currently supports the following profiler storage drivers: * file diff --git a/cookbook/testing/profiling.rst b/cookbook/testing/profiling.rst index 1789c69dbc9..f74d5d24be5 100644 --- a/cookbook/testing/profiling.rst +++ b/cookbook/testing/profiling.rst @@ -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() ); } } @@ -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()
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: