Slow Request Analyzer
Groups slow request logs by route, percentile, and suspected cause.
Function signature
ogAnalyzeSlowRequests(records = array(), options = array())
Categories
- SEO and Routing
Parameters
recordsRequest records with route and duration_ms keys.optionsOptions: threshold_ms. Recognized keys: `threshold_ms`.Return value
Short public-safe status message.
- count
- average_ms
- max_ms
- p95_ms
- slow_count
- slow_percent
- threshold_ms
- routes
Compatibility
Existing function name and call order preserved; metadata signature corrected to source.
Minimum PHP version: 7.4
Security notes
Validate request method, identity, permissions, policy arrays, URLs, signatures, and caller-owned allowlists before use; keep secrets and internal paths out of public output.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Groups request timing records by route and reports slow-request metrics.
*
* @param array $records Request records with route and duration_ms keys.
* @param array $options Options: threshold_ms.
* @return array Route-level timing summary.
*/
function ogAnalyzeSlowRequests($records = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
if (!is_array($records)) {
$result['message'] = 'Records must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$threshold_ms = 1000;
if (!empty($options['threshold_ms'])) {
$threshold_ms = (int)$options['threshold_ms'];
}
if ($threshold_ms < 1) {
$threshold_ms = 1000;
}
$route_values = array();
foreach ($records as $record) {
if (!is_array($record)) {
continue;
}
if (empty($record['duration_ms']) || !is_numeric($record['duration_ms'])) {
continue;
}
$route = '/unknown';
if (!empty($record['route'])) {
$route = (string)$record['route'];
}
$duration = (float)$record['duration_ms'];
if (empty($route_values[$route])) {
$route_values[$route] = array();
}
$route_values[$route][] = $duration;
}
$route_report = array();
foreach ($route_values as $route => $values) {
sort($values, SORT_NUMERIC);
$count = count($values);
$slow_count = 0;
foreach ($values as $duration) {
if ($duration >= $threshold_ms) {
$slow_count++;
}
}
$p95_index = (int)ceil($count * 0.95) - 1;
if ($p95_index < 0) {
$p95_index = 0;
}
if ($p95_index >= $count) {
$p95_index = $count - 1;
}
$route_report[$route] = array(
'count' => $count,
'average_ms' => array_sum($values) / $count,
'max_ms' => max($values),
'p95_ms' => $values[$p95_index],
'slow_count' => $slow_count,
'slow_percent' => ($slow_count / $count) * 100
);
}
uasort($route_report, function($left, $right) {
if ($left['p95_ms'] == $right['p95_ms']) {
return 0;
}
if ($left['p95_ms'] < $right['p95_ms']) {
return 1;
}
return -1;
});
$result['success'] = true;
$result['message'] = 'Slow request report built.';
$result['data'] = array(
'threshold_ms' => $threshold_ms,
'routes' => $route_report
);
return $result;
}