123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- <?php
- /**
- * Static class that represents profiling tool
- *
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework;
- use Magento\Framework\Profiler\Driver\Factory;
- use Magento\Framework\Profiler\DriverInterface;
- /**
- * @api
- * @since 100.0.2
- */
- class Profiler
- {
- /**
- * Separator literal to assemble timer identifier from timer names
- */
- const NESTING_SEPARATOR = '->';
- /**
- * Whether profiling is active or not
- *
- * @var bool
- */
- private static $_enabled = false;
- /**
- * Nesting path that represents namespace to resolve timer names
- *
- * @var string[]
- */
- private static $_currentPath = [];
- /**
- * Count of elements in $_currentPath
- *
- * @var int
- */
- private static $_pathCount = 0;
- /**
- * Index for counting of $_pathCount for timer names
- *
- * @var array
- */
- private static $_pathIndex = [];
- /**
- * Collection for profiler drivers.
- *
- * @var DriverInterface[]
- */
- private static $_drivers = [];
- /**
- * List of default tags.
- *
- * @var array
- */
- private static $_defaultTags = [];
- /**
- * Collection of tag filters.
- *
- * @var array
- */
- private static $_tagFilters = [];
- /**
- * Has tag filters flag for faster checks of filters availability.
- *
- * @var bool
- */
- private static $_hasTagFilters = false;
- /**
- * Set default tags
- *
- * @param array $tags
- * @return void
- */
- public static function setDefaultTags(array $tags)
- {
- self::$_defaultTags = $tags;
- }
- /**
- * Add tag filter.
- *
- * @param string $tagName
- * @param string $tagValue
- * @return void
- */
- public static function addTagFilter($tagName, $tagValue)
- {
- if (!isset(self::$_tagFilters[$tagName])) {
- self::$_tagFilters[$tagName] = [];
- }
- self::$_tagFilters[$tagName][] = $tagValue;
- self::$_hasTagFilters = true;
- }
- /**
- * Check tags with tag filters.
- *
- * @param array|null $tags
- * @return bool
- */
- private static function _checkTags(array $tags = null)
- {
- if (self::$_hasTagFilters) {
- if (is_array($tags)) {
- $keysToCheck = array_intersect(array_keys(self::$_tagFilters), array_keys($tags));
- if ($keysToCheck) {
- foreach ($keysToCheck as $keyToCheck) {
- if (in_array($tags[$keyToCheck], self::$_tagFilters[$keyToCheck])) {
- return true;
- }
- }
- }
- }
- return false;
- }
- return true;
- }
- /**
- * Add profiler driver.
- *
- * @param DriverInterface $driver
- * @return void
- */
- public static function add(DriverInterface $driver)
- {
- self::$_drivers[] = $driver;
- self::enable();
- }
- /**
- * Retrieve unique identifier among all timers
- *
- * @param string|null $timerName Timer name
- * @return string
- */
- private static function _getTimerId($timerName = null)
- {
- if (!self::$_currentPath) {
- return (string)$timerName;
- } elseif ($timerName) {
- return implode(self::NESTING_SEPARATOR, self::$_currentPath) . self::NESTING_SEPARATOR . $timerName;
- } else {
- return implode(self::NESTING_SEPARATOR, self::$_currentPath);
- }
- }
- /**
- * Get tags list.
- *
- * @param array|null $tags
- * @return array|null
- */
- private static function _getTags(array $tags = null)
- {
- if (self::$_defaultTags) {
- return (array)$tags + self::$_defaultTags;
- } else {
- return $tags;
- }
- }
- /**
- * Enable profiling.
- *
- * Any call to profiler does nothing until profiler is enabled.
- *
- * @return void
- */
- public static function enable()
- {
- self::$_enabled = true;
- }
- /**
- * Disable profiling.
- *
- * Any call to profiler is silently ignored while profiler is disabled.
- *
- * @return void
- */
- public static function disable()
- {
- self::$_enabled = false;
- }
- /**
- * Get profiler enable status.
- *
- * @return bool
- */
- public static function isEnabled()
- {
- return self::$_enabled;
- }
- /**
- * Clear collected statistics for specified timer or for whole profiler if timer id is omitted
- *
- * @param string|null $timerName
- * @return void
- * @throws \InvalidArgumentException
- */
- public static function clear($timerName = null)
- {
- if (strpos($timerName, self::NESTING_SEPARATOR) !== false) {
- throw new \InvalidArgumentException('Timer name must not contain a nesting separator.');
- }
- $timerId = self::_getTimerId($timerName);
- /** @var DriverInterface $driver */
- foreach (self::$_drivers as $driver) {
- $driver->clear($timerId);
- }
- }
- /**
- * Reset profiler to initial state
- *
- * @return void
- */
- public static function reset()
- {
- self::clear();
- self::$_enabled = false;
- self::$_currentPath = [];
- self::$_tagFilters = [];
- self::$_defaultTags = [];
- self::$_hasTagFilters = false;
- self::$_drivers = [];
- self::$_pathCount = 0;
- self::$_pathIndex = [];
- }
- /**
- * Start collecting statistics for specified timer
- *
- * @param string $timerName
- * @param array|null $tags
- * @return void
- * @throws \InvalidArgumentException
- */
- public static function start($timerName, array $tags = null)
- {
- if (!self::$_enabled) {
- return;
- }
- $tags = self::_getTags($tags);
- if (!self::_checkTags($tags)) {
- return;
- }
- if (strpos($timerName, self::NESTING_SEPARATOR) !== false) {
- throw new \InvalidArgumentException('Timer name must not contain a nesting separator.');
- }
- $timerId = self::_getTimerId($timerName);
- /** @var DriverInterface $driver */
- foreach (self::$_drivers as $driver) {
- $driver->start($timerId, $tags);
- }
- /* Continue collecting timers statistics under the latest started one */
- self::$_currentPath[] = $timerName;
- self::$_pathCount++;
- self::$_pathIndex[$timerName][] = self::$_pathCount;
- }
- /**
- * Stop recording statistics for specified timer.
- *
- * Call with no arguments to stop the recently started timer.
- * Only the latest started timer can be stopped.
- *
- * @param string|null $timerName
- * @return void
- * @throws \InvalidArgumentException
- */
- public static function stop($timerName = null)
- {
- if (!self::$_enabled || !self::_checkTags(self::_getTags())) {
- return;
- }
- if ($timerName === null) {
- $timersToStop = 1;
- } else {
- $timerPosition = false;
- if (!empty(self::$_pathIndex[$timerName])) {
- $timerPosition = array_pop(self::$_pathIndex[$timerName]);
- }
- if ($timerPosition === false) {
- throw new \InvalidArgumentException(sprintf('Timer "%s" has not been started.', $timerName));
- } elseif ($timerPosition === 1) {
- $timersToStop = 1;
- } else {
- $timersToStop = self::$_pathCount + 1 - $timerPosition;
- }
- }
- for ($i = 0; $i < $timersToStop; $i++) {
- $timerId = self::_getTimerId();
- /** @var DriverInterface $driver */
- foreach (self::$_drivers as $driver) {
- $driver->stop($timerId);
- }
- /* Move one level up in timers nesting tree */
- array_pop(self::$_currentPath);
- self::$_pathCount--;
- }
- }
- /**
- * Init profiler
- *
- * @param array|string $config
- * @param string $baseDir
- * @param bool $isAjax
- * @return void
- */
- public static function applyConfig($config, $baseDir, $isAjax = false)
- {
- $config = self::_parseConfig($config, $baseDir, $isAjax);
- if ($config['driverConfigs']) {
- foreach ($config['driverConfigs'] as $driverConfig) {
- self::add($config['driverFactory']->create($driverConfig));
- }
- }
- foreach ($config['tagFilters'] as $tagName => $tagValue) {
- self::addTagFilter($tagName, $tagValue);
- }
- }
- /**
- * Parses config
- *
- * @param array|string $profilerConfig
- * @param string $baseDir
- * @param bool $isAjax
- * @return array
- * @SuppressWarnings(PHPMD.NPathComplexity)
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- protected static function _parseConfig($profilerConfig, $baseDir, $isAjax)
- {
- $config = ['baseDir' => $baseDir, 'tagFilters' => []];
- if (is_scalar($profilerConfig)) {
- $config['drivers'] = [
- ['output' => is_numeric($profilerConfig) ? 'html' : $profilerConfig],
- ];
- } else {
- $config = array_merge($config, $profilerConfig);
- }
- $driverConfigs = (array)(isset($config['drivers']) ? $config['drivers'] : []);
- $driverFactory = isset($config['driverFactory']) ? $config['driverFactory'] : new Factory();
- $tagFilters = (array)(isset($config['tagFilters']) ? $config['tagFilters'] : []);
- $result = [
- 'driverConfigs' => self::_parseDriverConfigs($driverConfigs, $config['baseDir']),
- 'driverFactory' => $driverFactory,
- 'tagFilters' => $tagFilters,
- 'baseDir' => $config['baseDir'],
- ];
- return $result;
- }
- /**
- * Parses list of driver configurations
- *
- * @param array $driverConfigs
- * @param string $baseDir
- * @return array
- */
- protected static function _parseDriverConfigs(array $driverConfigs, $baseDir)
- {
- $result = [];
- foreach ($driverConfigs as $code => $driverConfig) {
- $driverConfig = self::_parseDriverConfig($driverConfig);
- if ($driverConfig === false) {
- continue;
- }
- if (!isset($driverConfig['type']) && !is_numeric($code)) {
- $driverConfig['type'] = $code;
- }
- if (!isset($driverConfig['baseDir']) && $baseDir) {
- $driverConfig['baseDir'] = $baseDir;
- }
- $result[] = $driverConfig;
- }
- return $result;
- }
- /**
- * Parses driver config
- *
- * @param mixed $driverConfig
- * @return array|false
- */
- protected static function _parseDriverConfig($driverConfig)
- {
- $result = false;
- if (is_array($driverConfig)) {
- $result = $driverConfig;
- } elseif (is_scalar($driverConfig) && $driverConfig) {
- if (is_numeric($driverConfig)) {
- $result = [];
- } else {
- $result = ['type' => $driverConfig];
- }
- }
- return $result;
- }
- }
|