1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<?php
require_once __DIR__ . '/config.php';
$errors = load_json(ERRORS_FILE);
$sessions = load_json(SESSIONS_FILE);
$total = count($errors);
$byType = [];
$bySeverity = [];
$byCategory = [];
$byModule = [];
$byDay = [];
$topErrors = [];
foreach ($errors as $e) {
$t = $e['type'] ?? 'unknown';
$byType[$t] = ($byType[$t] ?? 0) + ($e['count'] ?? 1);
$s = $e['severity'] ?? 'error';
$bySeverity[$s] = ($bySeverity[$s] ?? 0) + ($e['count'] ?? 1);
$c = $e['category'] ?? 'runtime';
$byCategory[$c] = ($byCategory[$c] ?? 0) + ($e['count'] ?? 1);
$m = $e['module'] ?? 'unknown';
$byModule[$m] = ($byModule[$m] ?? 0) + ($e['count'] ?? 1);
$day = substr($e['ingested_at'] ?? $e['last_seen'], 0, 10);
$byDay[$day] = ($byDay[$day] ?? 0) + ($e['count'] ?? 1);
$hash = $e['hash'] ?? '';
if ($hash) {
if (!isset($topErrors[$hash])) {
$topErrors[$hash] = ['hash' => $hash, 'message' => $e['message'] ?? '', 'count' => 0, 'type' => $t];
}
$topErrors[$hash]['count'] += $e['count'] ?? 1;
}
}
$totalOccurrences = 0;
foreach ($errors as $e) { $totalOccurrences += (int)($e['count'] ?? 1); }
usort($topErrors, fn($a, $b) => $b['count'] - $a['count']);
$topErrors = array_slice($topErrors, 0, 20);
ksort($byDay);
json_response([
'success' => true,
// total_errors = OCCURRENCES (sum of counts); unique_errors = distinct signatures.
// Before 2026-10-23 the key held the record count while by_type held occurrences,
// so two numbers on the same screen disagreed by ~3,500x.
'total_errors' => $totalOccurrences,
'unique_errors' => $total,
'total_sessions' => count($sessions),
'by_type' => $byType,
'by_severity' => $bySeverity,
'by_category' => $byCategory,
'by_module' => $byModule,
'by_day' => $byDay,
'top_errors' => $topErrors,
'generated_at' => date('c'),
]);
|