Skip to content

Commit ae932db

Browse files
authored
Merge pull request #4 from PHPDevsr/copilot/add-excimer-profiling-dashboard
feat: add Excimer auto-sampling profiler with flamegraph dashboard
2 parents 549dd41 + 9e6081e commit ae932db

16 files changed

Lines changed: 2008 additions & 29 deletions

.github/workflows/test-phpstan.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
with:
4545
php-version: ${{ matrix.php-versions }}
4646
tools: phpstan
47-
extensions: intl
47+
extensions: intl, json, mbstring, xml, excimer
4848
coverage: none
4949
env:
5050
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test-phpunit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
with:
4444
php-version: ${{ matrix.php-versions }}
4545
tools: composer, phpunit
46-
extensions: intl
46+
extensions: intl, json, mbstring, xml, excimer
4747
coverage: xdebug
4848
env:
4949
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test-rector.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
with:
4141
php-version: ${{ matrix.php-versions }}
4242
tools: phpstan
43-
extensions: intl, json, mbstring, xml
43+
extensions: intl, json, mbstring, xml, excimer
4444
coverage: none
4545
env:
4646
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,174 @@
11
# php-profiler
2-
PHP Profiling with Excimer
2+
3+
PHP Sampling Profiler using the [Excimer](https://www.mediawiki.org/wiki/Excimer) extension, with automatic per-request collection and a built-in flamegraph dashboard.
4+
5+
---
6+
7+
## Features
8+
9+
- **Zero-code instrumentation** – add one line to `php.ini` and every request is profiled automatically.
10+
- **Flamegraph dashboard** – interactive SVG flamegraph with zoom, tooltips, and frame highlighting.
11+
- **Endpoint ranking** – requests grouped by URI path, sorted by total sample count.
12+
- **Merged view** – all requests for the same endpoint are merged into a single flamegraph.
13+
- **Export JSON** – download the merged folded-stacks profile for offline analysis.
14+
- **Automatic cleanup** – keeps the newest 10 000 profiles; older files are pruned on each request.
15+
16+
---
17+
18+
## Requirements
19+
20+
| Requirement | Version |
21+
|---|---|
22+
| PHP | ≥ 8.3 |
23+
| [ext-excimer](https://pecl.php.net/package/excimer) | any |
24+
25+
---
26+
27+
## Installation
28+
29+
```bash
30+
composer require phpdevsr/php-profiler
31+
```
32+
33+
Or clone / install directly to `/opt/php-profiler`:
34+
35+
```bash
36+
git clone https://github.com/PHPDevsr/php-profiler /opt/php-profiler
37+
```
38+
39+
---
40+
41+
## Quick-start
42+
43+
### 1 – Enable auto-profiling in `php.ini`
44+
45+
```ini
46+
auto_prepend_file = /opt/php-profiler/profiler.php
47+
```
48+
49+
Optionally override the data directory:
50+
51+
```ini
52+
; defaults to /opt/php-profiler/data
53+
auto_prepend_file = /opt/php-profiler/profiler.php
54+
```
55+
56+
Or via an environment variable:
57+
58+
```bash
59+
PHP_PROFILER_DATA_DIR=/var/lib/php-profiler/data
60+
```
61+
62+
### 2 – Expose the dashboard (Nginx example)
63+
64+
```nginx
65+
# Serve the dashboard at /profiler/
66+
location /profiler/ {
67+
alias /opt/php-profiler/dashboard/;
68+
69+
# Restrict to localhost only
70+
allow 127.0.0.1;
71+
deny all;
72+
73+
index index.php;
74+
try_files $uri $uri/ /profiler/index.php?$query_string;
75+
76+
location ~ \.php$ {
77+
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
78+
fastcgi_index index.php;
79+
include fastcgi_params;
80+
fastcgi_param SCRIPT_FILENAME $request_filename;
81+
}
82+
}
83+
```
84+
85+
Apache example:
86+
87+
```apache
88+
Alias /profiler /opt/php-profiler/dashboard
89+
90+
<Directory /opt/php-profiler/dashboard>
91+
Options -Indexes
92+
AllowOverride None
93+
Require ip 127.0.0.1
94+
DirectoryIndex index.php
95+
</Directory>
96+
```
97+
98+
### 3 – Open the dashboard
99+
100+
```
101+
http://127.0.0.1/profiler/
102+
```
103+
104+
Make a few HTTP requests to your application, then refresh the dashboard to see endpoint rankings and flamegraphs.
105+
106+
---
107+
108+
## Library API
109+
110+
You can also use the `Profiler` class directly in your code:
111+
112+
```php
113+
use PHPDevsr\Profiler\Profiler;
114+
115+
$profiler = new Profiler(period: 0.01); // 10 ms sampling interval
116+
117+
$profiler->start();
118+
// … code to profile …
119+
$profiler->stop();
120+
121+
// Raw folded-stacks string (Excimer format, compatible with flamegraph tools)
122+
$folded = $profiler->getFoldedStacks();
123+
124+
// Parsed log: array of ['stack' => string[], 'count' => int]
125+
$log = $profiler->getLog();
126+
```
127+
128+
### FileStorage
129+
130+
```php
131+
use PHPDevsr\Profiler\Storage\FileStorage;
132+
133+
$storage = new FileStorage('/var/lib/php-profiler/data');
134+
135+
$storage->save([
136+
'id' => uniqid('', true),
137+
'timestamp' => microtime(true),
138+
'endpoint' => '/api/users',
139+
'method' => 'GET',
140+
'duration_ms' => 45.2,
141+
'sample_count' => 12,
142+
'folded_stacks' => $profiler->getFoldedStacks(),
143+
]);
144+
145+
// Endpoint statistics (sorted by total samples, descending)
146+
$stats = $storage->getEndpointStats();
147+
148+
// Profiles for one endpoint
149+
$profiles = $storage->findByEndpoint('/api/users');
150+
151+
// Delete oldest files when total exceeds $maxFiles
152+
$storage->cleanup(maxFiles: 10_000);
153+
```
154+
155+
---
156+
157+
## Development
158+
159+
```bash
160+
# Run tests
161+
composer test
162+
163+
# Static analysis
164+
composer phpstan
165+
166+
# Rector dry-run
167+
composer rector
168+
```
169+
170+
---
171+
172+
## License
173+
174+
MIT — see [LICENSE](LICENSE).

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
],
2020
"homepage": "https://github.com/PHPDevsr/php-profiler",
2121
"require": {
22-
"php": "^8.3 || ^8.4 || ^8.5"
22+
"php": "^8.3 || ^8.4 || ^8.5",
23+
"ext-excimer": "*"
2324
},
2425
"require-dev": {
2526
"nexusphp/tachycardia": "^2.4",

0 commit comments

Comments
 (0)