68 lines
2.3 KiB
PHP
68 lines
2.3 KiB
PHP
<?php
|
|
// opus-arch-predictive-heal.php — Cap 14 Predictive auto-heal (Doctrine 88)
|
|
// Linear regression on load/disk/fpm to predict failures
|
|
header('Content-Type: application/json');
|
|
|
|
$metric = $_GET['metric'] ?? 'load';
|
|
$window = (int)($_GET['window'] ?? 60); // minutes
|
|
|
|
// Gather time series
|
|
$ts_file = '/var/log/weval/metrics-' . $metric . '.log';
|
|
// V54 ALWAYS_APPEND sample before regression
|
|
@mkdir('/var/log/weval', 0755, true);
|
|
$_v54_load = (float)explode(' ', file_get_contents('/proc/loadavg'))[0];
|
|
$_v54_disk_out = []; exec('df -h / | tail -1', $_v54_disk_out);
|
|
preg_match('/(\d+)%/', implode(' ', $_v54_disk_out), $_v54_dm);
|
|
$_v54_disk_pct = (int)($_v54_dm[1] ?? 0);
|
|
$_v54_fpm_out = []; exec('pgrep -c php-fpm', $_v54_fpm_out);
|
|
$_v54_fpm = (int)($_v54_fpm_out[0] ?? 0);
|
|
$_v54_map = ['load' => $_v54_load, 'disk' => $_v54_disk_pct, 'fpm' => $_v54_fpm];
|
|
@file_put_contents($ts_file, time() . ',' . $_v54_map[$metric] . chr(10), FILE_APPEND);
|
|
|
|
$lines = array_slice(file($ts_file), -max(10, $window));
|
|
$pts = [];
|
|
foreach ($lines as $l) {
|
|
$parts = explode(',', trim($l));
|
|
if (count($parts) >= 2) $pts[] = ['x'=>(float)$parts[0], 'y'=>(float)$parts[1]];
|
|
}
|
|
$n = count($pts);
|
|
if ($n < 5) {
|
|
echo json_encode(['ok'=>false, 'error'=>'insufficient_data', 'n'=>$n]);
|
|
exit;
|
|
}
|
|
|
|
// Linear regression y = a + b*x
|
|
$sx = $sy = $sxy = $sxx = 0;
|
|
foreach ($pts as $p) {
|
|
$sx += $p['x']; $sy += $p['y'];
|
|
$sxy += $p['x']*$p['y']; $sxx += $p['x']*$p['x'];
|
|
}
|
|
$b = ($n*$sxy - $sx*$sy) / ($n*$sxx - $sx*$sx + 0.0001);
|
|
$a = ($sy - $b*$sx) / $n;
|
|
|
|
// Predict next hour
|
|
$next_hour = time() + 3600;
|
|
$predicted = $a + $b * $next_hour;
|
|
|
|
// Alert thresholds
|
|
$thresholds = ['load'=>5.0, 'disk'=>85, 'fpm'=>150];
|
|
$alert = $predicted >= ($thresholds[$metric] ?? 999);
|
|
|
|
$actions = [];
|
|
if ($alert) {
|
|
if ($metric === 'load') $actions[] = 'systemctl restart php-fpm';
|
|
if ($metric === 'disk') $actions[] = 'find /tmp -mmin +60 -delete; docker image prune -f';
|
|
if ($metric === 'fpm') $actions[] = 'systemctl reload php-fpm';
|
|
}
|
|
|
|
echo json_encode([
|
|
'ok'=>true,
|
|
'metric'=>$metric,
|
|
'n_samples'=>$n,
|
|
'regression'=>['slope'=>$b, 'intercept'=>$a],
|
|
'predicted_next_hour'=>round($predicted, 2),
|
|
'threshold'=>$thresholds[$metric] ?? null,
|
|
'alert'=>$alert,
|
|
'recommended_actions'=>$actions,
|
|
]);
|