'ops_screens_health', 'tool' => 'screens_health_real_read']; // Primary source: screens-health.json (generated by screens-health-smart.py every X min) $json_file = '/var/www/html/api/screens-health.json'; if (is_readable($json_file)) { $d = @json_decode(@file_get_contents($json_file), true); if ($d && !empty($d['counts'])) { $c = $d['counts']; $out['generated_at'] = $d['generated_at'] ?? null; $out['total'] = $d['total'] ?? 0; $out['counts'] = $c; $out['phantom_count'] = $d['phantom_count'] ?? 0; $out['elapsed_sec'] = $d['elapsed_sec'] ?? null; $up = (int)($c['UP'] ?? 0); $slow = (int)($c['SLOW'] ?? 0); $broken = (int)($c['BROKEN'] ?? 0); $down = (int)($c['DOWN'] ?? 0); $protected = (int)($c['PROTECTED'] ?? 0); $not_found = (int)($c['NOT_FOUND'] ?? 0); $phantom = (int)($c['PHANTOM'] ?? 0); $total = $up + $slow + $broken + $down + $protected + $not_found + $phantom; $healthy = $up + $slow + $protected; // protected = auth OK pas bug $health_pct = $total > 0 ? round(100 * $healthy / $total, 1) : 0; $out['health_pct'] = $health_pct; $out['summary'] = "{$up} UP · {$slow} SLOW · {$broken} BROKEN · {$down} DOWN · {$protected} PROTECTED · {$phantom} PHANTOM (total {$total}, health {$health_pct}%)"; // Issues list pour Yacine $issues = []; if ($broken > 0) $issues[] = "{$broken} BROKEN pages - inspect by_url.BROKEN"; if ($down > 0) $issues[] = "{$down} DOWN pages - urgent"; if ($not_found > 0) $issues[] = "{$not_found} NOT_FOUND - verifier routes"; if ($phantom > 0) $issues[] = "{$phantom} PHANTOM - purge old dead links"; if ($slow > 50) $issues[] = "{$slow} SLOW (>2s) - optimiser perf"; $out['issues'] = $issues; $out['status'] = count($issues) === 0 ? 'HEALTHY' : (($broken + $down > 0) ? 'DEGRADED' : 'OK_WITH_WARNINGS'); // Sample problematic URLs si disponibles if (!empty($d['by_url']) && is_array($d['by_url'])) { $problems = []; foreach ($d['by_url'] as $url => $info) { if (!is_array($info)) continue; $st = $info['status'] ?? '?'; if (in_array($st, ['BROKEN','DOWN','NOT_FOUND','PHANTOM'])) { if (!isset($problems[$st])) $problems[$st] = []; if (count($problems[$st]) < 10) { $problems[$st][] = ['url' => $url, 'code' => $info['code'] ?? null, 'ms' => $info['ms'] ?? null]; } } } if ($problems) { $out['problem_urls_sample'] = $problems; // Note: code=0 souvent = timeout auth redirect 302, pas vraiment DOWN $has_code_0 = false; foreach ($problems as $bucket => $urls) { foreach ($urls as $u) { if (($u['code'] ?? null) === 0) { $has_code_0 = true; break 2; } } } if ($has_code_0) { $out['diagnostic_note'] = 'Certaines URLs code=0 = scanner timeout sur redirect 302 auth (pas vraiment DOWN). Verifier manuellement.'; } } } } else { $out['warning'] = 'screens-health.json empty or malformed'; } } else { $out['error'] = 'screens-health.json not found at ' . $json_file; } // Secondary source: infra-monitor-api.php (si existe) $infra = @json_decode(@file_get_contents('http://127.0.0.1/api/infra-monitor-api.php'), true); if ($infra) { $out['infra_monitor'] = $infra; } $out['dashboards'] = [ 'weval-ops-screens' => 'https://weval-consulting.com/weval-ops-screens.html (auth requis)', 'automation-hub' => 'https://weval-consulting.com/automation-hub.html', 'visual-management' => 'https://weval-consulting.com/visual-management.html', 'tasks-live' => 'https://weval-consulting.com/tasks-live.html', ]; $out['data_sources'] = [ 'primary' => '/api/screens-health.json (cron screens-health-smart.py)', 'secondary' => '/api/infra-monitor-api.php (live scan)', ]; header("Content-Type: application/json"); echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); exit; } } $_op_msg = ''; $_body = @file_get_contents('php://input'); if ($_body) { $_j = @json_decode($_body, true); if (is_array($_j) && !empty($_j['message'])) $_op_msg = $_j['message']; } if (!$_op_msg) $_op_msg = $_POST['message'] ?? $_GET['message'] ?? ''; if ($_op_msg) wevia_ops_screens_health($_op_msg);