From a3ae3a36f081933488d2d66ec539b25a54e7f04f Mon Sep 17 00:00:00 2001 From: Robin Mulder Date: Fri, 8 Nov 2024 11:27:00 +0100 Subject: [PATCH] Create compatibility with XHGui --- Model/Profiler/Driver/Buggregator.php | 55 ++++++++++++++ Model/Profiler/Driver/XHGui.php | 35 +++++++++ Model/Profiler/XhprofProfiler.php | 41 ++--------- Plugin/AppInterfacePlugin.php | 18 +++-- README.md | 101 ++++++++++++-------------- composer.json | 3 +- etc/di.xml | 18 +++++ 7 files changed, 173 insertions(+), 98 deletions(-) create mode 100644 Model/Profiler/Driver/Buggregator.php create mode 100644 Model/Profiler/Driver/XHGui.php diff --git a/Model/Profiler/Driver/Buggregator.php b/Model/Profiler/Driver/Buggregator.php new file mode 100644 index 0000000..12e5df8 --- /dev/null +++ b/Model/Profiler/Driver/Buggregator.php @@ -0,0 +1,55 @@ +driver->start( + [ + self::IGNORED_FUNCTIONS_KEY => ['SpiralPackages\Profiler\Profiler::end'], + ] + ); + } + + /** + * Terminates the current profiling session and stores the results. + * @param array $tags Optional tags to attach to the profiling data. + * @return void + * @throws FileSystemException + * @throws RuntimeException + */ + public function end(array $tags = []): void + { + $result = $this->driver->end(); + $endpoint = $this->deploymentConfig->get('xhprofprofiler/endpoint'); + $appName = $this->deploymentConfig->get('xhprofprofiler/app_name'); + if (!empty($appName) && !empty($endpoint) && is_string($endpoint) && is_string($appName)) { + $storage = new WebStorage(new NativeHttpClient(), $endpoint); + $storage->store( + $appName, + $tags, + new \DateTimeImmutable(), + $result + ); + } + } +} diff --git a/Model/Profiler/Driver/XHGui.php b/Model/Profiler/Driver/XHGui.php new file mode 100644 index 0000000..a263bed --- /dev/null +++ b/Model/Profiler/Driver/XHGui.php @@ -0,0 +1,35 @@ +initializeDriver($config); + } + + private function initializeDriver(array $config): void + { + $this->driver = new Profiler($config); + } + + public function start(): void + { + $this->driver->enable(); + } + + public function end(array $tags = []): void + { + $this->driver->save($this->driver->disable()); + } +} diff --git a/Model/Profiler/XhprofProfiler.php b/Model/Profiler/XhprofProfiler.php index db760e6..1eae27a 100644 --- a/Model/Profiler/XhprofProfiler.php +++ b/Model/Profiler/XhprofProfiler.php @@ -2,25 +2,13 @@ namespace JustBetter\XhprofProfiler\Model\Profiler; -use Magento\Framework\App\DeploymentConfig; -use Magento\Framework\Exception\FileSystemException; -use Magento\Framework\Exception\RuntimeException; -use SpiralPackages\Profiler\Driver\XhprofDriver; -use SpiralPackages\Profiler\Storage\WebStorage; -use Symfony\Component\HttpClient\NativeHttpClient; +use JustBetter\XhprofProfiler\Api\DriverInterface; class XhprofProfiler { - public const HEADER = 'X-Xhprof-Enabled'; - - public const IGNORED_FUNCTIONS_KEY = 'ignored_functions'; - - public array $tags; - public function __construct( - protected XhprofDriver $driver, - protected DeploymentConfig $deploymentConfig, - array $tags = [] + protected DriverInterface $driver, + protected array $tags = [] ) { $this->tags = $tags; @@ -28,30 +16,11 @@ public function __construct( public function handle(): void { - $this->driver->start( - [ - self::IGNORED_FUNCTIONS_KEY => ['SpiralPackages\Profiler\Profiler::end'], - ] - ); + $this->driver->start(); } - /** - * @throws FileSystemException - * @throws RuntimeException - */ public function terminate(array $tags = []): void { - $result = $this->driver->end(); - $endpoint = $this->deploymentConfig->get('xhprofprofiler/endpoint'); - $appName = $this->deploymentConfig->get('xhprofprofiler/app_name'); - if (!empty($appName) && !empty($endpoint) && is_string($endpoint) && is_string($appName)) { - $storage = new WebStorage(new NativeHttpClient(), $endpoint); - $storage->store( - $appName, - \array_merge($this->tags ?? [], $tags), - new \DateTimeImmutable(), - $result - ); - } + $this->driver->end(array_merge($this->tags ?? [], $tags)); } } diff --git a/Plugin/AppInterfacePlugin.php b/Plugin/AppInterfacePlugin.php index dae73eb..6ce778f 100644 --- a/Plugin/AppInterfacePlugin.php +++ b/Plugin/AppInterfacePlugin.php @@ -1,4 +1,5 @@ isEnabled()) { return $proceed(); @@ -34,12 +38,12 @@ public function aroundLaunch( return $response; } - public function isEnabled(): bool + private function isEnabled(): bool { - if ($this->request->getHeader(XhprofProfiler::HEADER)) { - return filter_var($this->request->getHeader(XhprofProfiler::HEADER), FILTER_VALIDATE_BOOLEAN); + if ($this->request->getHeader(self::HEADER)) { + return filter_var($this->request->getHeader(self::HEADER), FILTER_VALIDATE_BOOLEAN); } - return isset($_ENV['XHPROF_ENABLED']) ? (bool) $_ENV['XHPROF_ENABLED'] : false; + return isset($_ENV['XHPROF_ENABLED']) ? (bool)$_ENV['XHPROF_ENABLED'] : false; } } diff --git a/README.md b/README.md index 8141698..afcd5dd 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This module integrates Xhprof profiling capabilities into your Magento 2 applica - Magento 2.4.7 or higher - Xhprof PHP extension +- Compatible with XHGui - Compatible with Buggregator ## Installation @@ -31,7 +32,16 @@ This module integrates Xhprof profiling capabilities into your Magento 2 applica bin/magento setup:di:compile ``` -## Configuration +## Configuration for Buggregator + +By default this module uses XHGui for processing the profiling data. We can use the Buggregator driver by overriding the default driver via xml: +``` + + + JustBetter\XhprofProfiler\Model\Profiler\Driver\Buggregator + + +``` Configure the module by adding the following configuration to your `app/etc/env.php` file: @@ -48,30 +58,36 @@ return [ - **app_name**: The name of your application. - **endpoint**: The endpoint where the profiling data will be stored. -## Usage +## Compatibility -The profiling is automatically enabled for all requests. The module uses the `AppInterfacePlugin` to start and terminate the profiler around each request. +This module is compatible with [XHGui](https://github.com/perftools/xhgui) and [Buggregator](https://buggregator.dev/). These are graphical interfaces for viewing XHProf profiling data. -### Key Classes and Methods +### To integrate with XHGui: -- **`XhprofProfiler`** - - **Constants:** - - `HEADER`: The header key used to enable Xhprof profiling. - - `IGNORED_FUNCTIONS_KEY`: The key for ignored functions in the profiler. - - **Methods:** - - `__construct()`: Initializes the profiler with the given driver, deployment configuration, and optional tags. - - `handle()`: Starts the profiler. - - `terminate()`: Ends the profiler and stores the profiling data. +1. Follow the installation guide of XHGui at [XHGui](https://github.com/perftools/xhgui) +2. By default we use the default xhprof profiler and the results are getting uploaded to XHGui. +3. Update default configuration via di.xml, check [config.default.php](https://github.com/perftools/xhgui/blob/0.23.x/config/config.default.php) for the possible options. -- **`AppInterfacePlugin`** - - **Methods:** - - `aroundLaunch()`: Wraps around the application launch to start and stop the profiler. - -## Buggregator Compatibility +#### Default XHGui configuration +You can pass custom configuration to the XHGui driver via the arguments like the default configuration. +``` + + + + xhprof + upload + + http://xhgui.xhgui.orb.local/run/import + 3 + token + + + + -This module is compatible with [Buggregator](https://buggregator.dev/), a debug and profiler tool for PHP applications. Buggregator can collect and visualize profiling data generated by this module, providing a comprehensive debugging and performance analysis experience. +``` -To integrate with Buggregator: +### To integrate with Buggregator: 1. Ensure Buggregator is installed and configured in your environment. 2. Configure the endpoint in `app/etc/env.php` to point to Buggregator's profiling data endpoint. @@ -88,45 +104,22 @@ return [ ]; ``` -## Example - -Here is an example of how the profiler is used in the plugin: - -```php -namespace JustBetter\XhprofProfiler\Plugin; - -use JustBetter\XhprofProfiler\Model\Profiler\XhprofProfiler; -use Magento\Framework\App\ResponseInterface; -use Magento\Framework\AppInterface as Application; - -class AppInterfacePlugin -{ - public function __construct( - protected XhprofProfiler $profiler - ) - { - } - - public function aroundLaunch( - Application $subject, - callable $proceed, - ) : ResponseInterface { - $this->profiler->handle(); - $response = $proceed(); - $this->profiler->terminate(); - return $response; - } -} -``` +## Usage -## Exception Handling +The profiling is automatically enabled for all requests. The module uses the `AppInterfacePlugin` to start and terminate the profiler around each request. -The `terminate` method of the `XhprofProfiler` class can throw the following exceptions: -- **FileSystemException**: If there is an issue with the file system. -- **RuntimeException**: If there is a runtime issue. +### Key Classes and Methods -Ensure you have proper exception handling in place when integrating this module. +- **`XhprofProfiler`** + - **Methods:** + - `__construct()`: Initializes the profiler with the given driver and optional tags. + - `handle()`: Starts the profiler. + - `terminate()`: Ends the profiler and stores the profiling data. +- **`AppInterfacePlugin`** + - **Methods:** + - `aroundLaunch()`: Wraps around the application launch to start and stop the profiler. + ## License This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/composer.json b/composer.json index 1e551c0..b76cdbd 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "php": ">=8.2", "magento/framework": "*", "magento/module-config": "^101.2", - "spiral-packages/profiler": "^1.2" + "spiral-packages/profiler": "^1.2", + "perftools/php-profiler": "^1.1" }, "repositories": { "magento": { diff --git a/etc/di.xml b/etc/di.xml index 3912ef6..0675c31 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -3,4 +3,22 @@ + + + JustBetter\XhprofProfiler\Model\Profiler\Driver\XHGui + + + + + + xhprof + upload + + http://xhgui.xhgui.orb.local/run/import + 3 + token + + + +