Add throttling recovery metrics
This commit is contained in:
@@ -120,6 +120,8 @@ function dmesg_log(): array
|
||||
function throttled_event_status(?int $flags, string $raw, int $activeBit, int $seenBit, string $statePath): array
|
||||
{
|
||||
$now = time();
|
||||
$windowSeconds = 600;
|
||||
$recoverySeconds = 300;
|
||||
$active = $flags !== null && (bool)($flags & $activeBit);
|
||||
$seen = $flags !== null && (bool)($flags & $seenBit);
|
||||
|
||||
@@ -134,6 +136,7 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
'last_cleared_at' => null,
|
||||
'last_duration_seconds' => 0,
|
||||
'updated_at' => null,
|
||||
'events' => [],
|
||||
];
|
||||
|
||||
$fp = @fopen($statePath, 'c+');
|
||||
@@ -145,6 +148,10 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
if (is_array($decoded)) {
|
||||
$state = array_merge($state, array_intersect_key($decoded, $state));
|
||||
}
|
||||
$state['events'] = array_values(array_filter(
|
||||
is_array($state['events'] ?? null) ? $state['events'] : [],
|
||||
static fn($event): bool => is_array($event) && is_numeric($event['start'] ?? null)
|
||||
));
|
||||
|
||||
$wasActive = !empty($state['active']);
|
||||
$activeSince = is_numeric($state['active_since'] ?? null) ? (int)$state['active_since'] : null;
|
||||
@@ -154,6 +161,11 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
if (!$wasActive || $activeSince === null) {
|
||||
$activeSince = $now;
|
||||
$state['last_detected_at'] = $now;
|
||||
$state['events'][] = [
|
||||
'start' => $now,
|
||||
'end' => null,
|
||||
'duration_seconds' => 0,
|
||||
];
|
||||
}
|
||||
$state['active'] = true;
|
||||
$state['active_since'] = $activeSince;
|
||||
@@ -161,11 +173,32 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
if ($wasActive && $activeSince !== null) {
|
||||
$state['last_cleared_at'] = $now;
|
||||
$state['last_duration_seconds'] = max(0, $now - $activeSince);
|
||||
$lastIndex = count($state['events']) - 1;
|
||||
if ($lastIndex >= 0 && empty($state['events'][$lastIndex]['end'])) {
|
||||
$state['events'][$lastIndex]['end'] = $now;
|
||||
$state['events'][$lastIndex]['duration_seconds'] = $state['last_duration_seconds'];
|
||||
} else {
|
||||
$state['events'][] = [
|
||||
'start' => $activeSince,
|
||||
'end' => $now,
|
||||
'duration_seconds' => $state['last_duration_seconds'],
|
||||
];
|
||||
}
|
||||
}
|
||||
$state['active'] = false;
|
||||
$state['active_since'] = null;
|
||||
}
|
||||
|
||||
$keepAfter = $now - 86400;
|
||||
$state['events'] = array_slice(array_values(array_filter(
|
||||
$state['events'],
|
||||
static function ($event) use ($keepAfter, $now): bool {
|
||||
$start = (int)($event['start'] ?? 0);
|
||||
$end = is_numeric($event['end'] ?? null) ? (int)$event['end'] : $now;
|
||||
return $start > 0 && max($start, $end) >= $keepAfter;
|
||||
}
|
||||
)), -200);
|
||||
|
||||
$state['updated_at'] = $now;
|
||||
ftruncate($fp, 0);
|
||||
rewind($fp);
|
||||
@@ -189,6 +222,39 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
? date('Y-m-d H:i:s', (int)$ts)
|
||||
: null;
|
||||
|
||||
$windowStart = $now - $windowSeconds;
|
||||
$recentCount = 0;
|
||||
$recentActiveSeconds = 0;
|
||||
$events = is_array($state['events'] ?? null) ? $state['events'] : [];
|
||||
foreach ($events as $event) {
|
||||
if (!is_array($event) || !is_numeric($event['start'] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
$start = (int)$event['start'];
|
||||
$end = is_numeric($event['end'] ?? null) ? (int)$event['end'] : $now;
|
||||
if ($end < $windowStart || $start > $now) {
|
||||
continue;
|
||||
}
|
||||
$overlapStart = max($start, $windowStart);
|
||||
$overlapEnd = min(max($end, $overlapStart), $now);
|
||||
if ($overlapEnd > $overlapStart) {
|
||||
$recentCount++;
|
||||
$recentActiveSeconds += $overlapEnd - $overlapStart;
|
||||
}
|
||||
}
|
||||
|
||||
$lastClearedAt = is_numeric($state['last_cleared_at'] ?? null) ? (int)$state['last_cleared_at'] : null;
|
||||
$recovering = !$active && $lastClearedAt !== null && ($now - $lastClearedAt) <= $recoverySeconds;
|
||||
$repeated = $recentCount >= 2;
|
||||
$stateLabel = 'normal';
|
||||
if ($active) {
|
||||
$stateLabel = 'active';
|
||||
} elseif ($repeated) {
|
||||
$stateLabel = 'repeated';
|
||||
} elseif ($recovering) {
|
||||
$stateLabel = 'recovering';
|
||||
}
|
||||
|
||||
return [
|
||||
'available' => $flags !== null,
|
||||
'raw' => $raw,
|
||||
@@ -201,6 +267,14 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
|
||||
'duration_seconds' => $duration,
|
||||
'last_duration_seconds' => (int)($state['last_duration_seconds'] ?? 0),
|
||||
'updated_at' => $dateValue($state['updated_at'] ?? null),
|
||||
'state_label' => $stateLabel,
|
||||
'recovering' => $recovering,
|
||||
'repeated_recently' => $repeated,
|
||||
'recovery_window_seconds' => $recoverySeconds,
|
||||
'recent_window_seconds' => $windowSeconds,
|
||||
'recent_event_count' => $recentCount,
|
||||
'recent_active_seconds' => $recentActiveSeconds,
|
||||
'recent_active_percent' => round($recentActiveSeconds / $windowSeconds * 100, 1),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user