PHPackages                             magepsycho/magento2-profiler-ui - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. magepsycho/magento2-profiler-ui

ActiveMagento2-module

magepsycho/magento2-profiler-ui
===============================

Admin viewer for MagePsycho\_Profiler JSON reports

1.0.0(today)01↑2900%OSL-3.0JavaScript

Since Aug 8Pushed todayCompare

[ Source](https://github.com/MagePsycho/magento2-profiler-ui)[ Packagist](https://packagist.org/packages/magepsycho/magento2-profiler-ui)[ RSS](/packages/magepsycho-magento2-profiler-ui/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (1)Versions (2)Used By (0)

Magento 2 Enhanced Profiler UI
==============================

[](#magento-2-enhanced-profiler-ui)

[![Magento 2 Enhanced Profiler UI](https://camo.githubusercontent.com/21d85452cbb9037cc0b473fb795e3f117158b344da13996fc3f294103b63db2b/68747470733a2f2f692e696d6775722e636f6d2f643851454852622e706e67)](https://camo.githubusercontent.com/21d85452cbb9037cc0b473fb795e3f117158b344da13996fc3f294103b63db2b/68747470733a2f2f692e696d6775722e636f6d2f643851454852622e706e67)

[![Packagist Version](https://camo.githubusercontent.com/c07fa230abce0c032380450369bf18e94028b7a5071c9f8df78f7dc2981b9d1a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f4d61676550737963686f2f6d6167656e746f322d70726f66696c65722d75693f6c6f676f3d7061636b616769737426736f72743d73656d766572266c6162656c3d7061636b6167697374267374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/magepsycho/magento2-profiler-ui)[![Packagist Downloads](https://camo.githubusercontent.com/5cbbebffa9c4b0c5f495b60e663f25dcad7e70a626dbf49984c10aef4acf44b5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d61676570737963686f2f6d6167656e746f322d70726f66696c65722d75692e7376673f6c6f676f3d7061636b6167697374267374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/magepsycho/magento2-profiler-ui/stats)[![Supported Magento Versions](https://camo.githubusercontent.com/a504a0adb323bd8dfa1ee1ca6d8299fcf2a52d50bb943fc5fb087413b877e124/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d6167656e746f2d253230322e342d627269676874677265656e2e7376673f6c6f676f3d6d6167656e746f266c6f6e6743616368653d74727565267374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/a504a0adb323bd8dfa1ee1ca6d8299fcf2a52d50bb943fc5fb087413b877e124/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d6167656e746f2d253230322e342d627269676874677265656e2e7376673f6c6f676f3d6d6167656e746f266c6f6e6743616368653d74727565267374796c653d666f722d7468652d6261646765)[![License](https://camo.githubusercontent.com/7f4d9e0919247af0bd367bf637b93966120c8f9d01c5b1662316bd4e9d219358/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4f534c2d2d332e302d677265656e3f636f6c6f723d253233323334267374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/7f4d9e0919247af0bd367bf637b93966120c8f9d01c5b1662316bd4e9d219358/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4f534c2d2d332e302d677265656e3f636f6c6f723d253233323334267374796c653d666f722d7468652d6261646765)

Overview
--------

[](#overview)

**Magento 2 Enhanced Profiler UI** is the admin viewer for the `json` reports written by [**MagePsycho\_Profiler**](../Profiler/README.md).

**System → Tools → Enhanced Profiler Reports**

Pick a recorded run from the dropdown and get an interactive view of it: a collapsible tree, a sortable and filterable flat table, or a timeline of every individual call. Admin-side on purpose — the storefront may be headless, and profiler output is not something to expose there in any case.

It **only reads** what `MagePsycho_Profiler` writes. It adds nothing to the recording side, registers no plugins and touches no request path other than its own, so it can be left uninstalled in production without changing what gets profiled.

### Why a separate module

[](#why-a-separate-module)

`MagePsycho_Profiler` is meant to be safe to enable anywhere; it is an output type plus instrumentation and has no HTTP surface of its own. An admin UI is a different proposition — controllers, ACL, an attack surface — so it installs separately and can be left off in production.

Demo
----

[](#demo)

Tree, Flat and Timeline views of a recorded run:

[![Enhanced Profiler UI — tree, flat and timeline views](./docs/enhanced-profiler-ui-demo.gif)](./docs/enhanced-profiler-ui-demo.gif)

Key Features
------------

[](#key-features)

- Admin page at **System → Tools → Enhanced Profiler Reports**, gated behind its own ACL resource
- Three views of the same run — **Tree**, **Flat** and **Timeline** — switched from one radio group
- **Self** column heat-shaded by magnitude, so time that belongs to no child timer is visible at a glance
- Sort on any column, filter by timer id, and narrow by minimum time with sliders seeded from the loaded report
- Timeline of every recorded call, ordered by start, indented by depth, coloured by subsystem with a legend built from the run
- Run picker shows the span count per report, so you know what you are opening
- **Clear all reports** empties the report directory and the index in one action
- Every cell rendered with `textContent` — a report containing `` stays text
- Reads only what `MagePsycho_Profiler` writes; zero recording overhead, safe to leave uninstalled in production

Feature Highlights
------------------

[](#feature-highlights)

### The Report Table

[](#the-report-table)

ColumnMeaningTimer IdLeaf name in tree view, full `a->b->c` path in flat viewCntTimes the timer was startedTimeTotal wall time, **inclusive** of children**Self**Time minus the sum of direct children — where work with no timer of its own shows upAvg`Time / Cnt`Emalloc / RealMemMemory deltas%Share of the root timer**Self** is the column worth learning. On a real `POST /V1/integration/customer/token`, `magento` measured 96.2ms while its children summed to 45.6ms — 53% of the request had no timer on it at all. That gap is invisible in the Time column and obvious in Self.

### Tree, Flat And Timeline

[](#tree-flat-and-timeline)

Three modes, picked from the **View** switch.

Tree and Flat are deliberately exclusive, because a filtered tree lies: hide a parent and its children appear to hang off nothing.

**Tree** (the default) is structural browsing. Real HTML indentation with an expand/collapse control on every row that has children — no `├─` box-drawing, which is a terminal constraint the ASCII log has to live with and a web page does not. **Expand all** / **Collapse all** are in the toolbar; Collapse all keeps the roots open so the top level stays readable. Parent rows are bold, and hovering a row shows its full `a->b->c` path as a tooltip.

[![Tree view — collapsible hierarchy with the Self column heat-shaded](./docs/enhanced-profiler-tree-view.png)](./docs/enhanced-profiler-tree-view.png)

**Flat** is filtering and ranking. It shows the full timer path on every row, since indentation means nothing once rows are reordered or their parents filtered away.

[![Flat view — full timer paths, sorted and filtered](./docs/enhanced-profiler-flat-view.png)](./docs/enhanced-profiler-flat-view.png)

Switching happens on its own: typing in the filter, dragging a slider or clicking a column header drops you into flat view; re-ticking **Tree** clears the filter, sliders and sort so the hierarchy is honest again.

The sliders are seeded from the loaded report, so their range always matches the data in front of you.

**Timeline** is one bar per recorded call, ordered by start, indented by depth, coloured by subsystem (`SQL:`, `CACHE:`, `EVENT:`, …) with a legend built from whatever the run actually contains. This is where you see *when* something happened rather than just how long it took in total — a burst of queries mid-request, a cache stampede, one slow call versus four hundred fast ones.

[![Timeline view — one bar per call, coloured by subsystem](./docs/enhanced-profiler-timeline-view.png)](./docs/enhanced-profiler-timeline-view.png)

Every capture records spans, so Timeline works on any recent report — `MAGE_PROFILER=json` and `MAGE_PROFILER=timeline` are the same thing. The radio only disables for reports recorded with `MAGE_PROFILER_MAX_SPANS=0`, or from before spans were always captured. The Timer Id filter and the min-time slider both narrow the chart.

The x-axis uses **`wall_ms`** (first start to last end), not `total_ms` (the sum of root timers that the `%` column is a share of). On a CLI run those differ by ~40% because the roots are sequential.

### Recording Something To Look At

[](#recording-something-to-look-at)

The viewer reads the `json` output, so a run has to exist before there is anything in the dropdown:

```
MAGE_PROFILER=json bin/magento indexer:reindex          # CLI
MAGE_PROFILER=tabular,json bin/magento cache:clean      # terminal table + report
```

```
document.cookie = 'MAGE_PROFILER=json; path=/';         // web + API, in the browser console
```

The cookie accepts the same values as the environment variable — `tabular,json` and `timeline` both work there too. `json` is what this viewer reads; `tabular` writes a plain-text log instead, which is worth adding on CLI (it prints to STDERR as the command finishes) and rarely worth it on a web request, where there is no terminal to print to.

Cookie activation is gated — developer mode, or a `:` suffix matching `MAGE_PROFILER_SECRET`. See [**MagePsycho\_Profiler**](../Profiler/README.md) for the full activation and security rules.

### Retention

[](#retention)

`MagePsycho_Profiler` prunes as it writes: newest `MAGE_PROFILER_KEEP` runs (default 100), nothing older than `MAGE_PROFILER_KEEP_DAYS` (default 7). A browsing session with the cookie set writes one report per request, AJAX included, so this matters. **Clear all reports** empties the directory and the index.

🛠️ Installation
---------------

[](#️-installation)

This module requires [**MagePsycho\_Profiler**](../Profiler/README.md); Composer pulls it in automatically.

### 1 Using Composer (Preferred)

[](#1-using-composer-preferred)

```
composer require magepsycho/magento2-profiler-ui

```

### 2 Using Modman

[](#2-using-modman)

```
modman init
modman clone git@github.com:MagePsycho/magento2-profiler-ui.git

```

### 3 Using Zip File

[](#3-using-zip-file)

- Download the [Extension Zip File](https://github.com/MagePsycho/magento2-profiler-ui/archive/master.zip)
- Extract &amp; upload the files to `/path/to/magento2/app/code/MagePsycho/ProfilerUi/`

After installation by either means, activate the extension with following steps

1. Enable the module

```
php bin/magento module:enable MagePsycho_ProfilerUi --clear-static-content
php bin/magento setup:upgrade
php bin/magento setup:di:compile

```

2. Flush the store cache

```
php bin/magento cache:flush

```

3. Deploy static content - *in Production mode only*

```
rm -rf pub/static/* var/view_preprocessed/*
php bin/magento setup:static-content:deploy

```

4. Record a run, then open the viewer

```
MAGE_PROFILER=json php bin/magento cache:clean

```

*System → Tools → Enhanced Profiler Reports*

The extension creates no tables of its own.

Configuration
-------------

[](#configuration)

There is **no store configuration**. The viewer has nothing to configure — what it shows is decided by what `MagePsycho_Profiler` recorded, and that module's own settings live at *Stores &gt; Configuration &gt; MagePsycho &gt; Enhanced Profiler*.

Access is controlled by role, not config: *System &gt; Permissions &gt; User Roles &gt; Role Resources* → **Enhanced Profiler Reports** (`MagePsycho_ProfilerUi::viewer`).

The `MagePsycho_Profiler` environment variables that change what the viewer sees:

VariableEffect hereDefault`MAGE_PROFILER_REPORT_DIR`Directory the run picker lists`var/log/profiler``MAGE_PROFILER_MAX_SPANS``0` records no spans, which disables the Timeline radio`5000``MAGE_PROFILER_KEEP`Newest N runs retained`100``MAGE_PROFILER_KEEP_DAYS`Maximum age retained`7`Security
--------

[](#security)

The viewer renders data derived from untrusted input, so a few things are deliberate rather than incidental:

- **Every cell is written with `textContent`, never `innerHTML`.** Timer ids carry client-controlled strings — GraphQL operation names and unmatched REST paths both end up in them — so a report can legitimately contain ``. Rendering it as markup would turn a profiling tool into stored XSS in the admin panel.
- The `x-magento-init` payload is encoded with `JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT`, so no literal `
