📦 deps(thirdparty): update snapshots
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
---
|
||||
name: claude-monitor
|
||||
description: Monitor de performance do Claude Code e sistema local. Diagnostica lentidao, mede CPU/RAM/disco, verifica API latency e gera relatorios de saude do sistema.
|
||||
risk: safe
|
||||
source: community
|
||||
date_added: '2026-03-06'
|
||||
author: renat
|
||||
tags:
|
||||
- monitoring
|
||||
- performance
|
||||
- diagnostics
|
||||
- system-health
|
||||
tools:
|
||||
- claude-code
|
||||
- antigravity
|
||||
- cursor
|
||||
- gemini-cli
|
||||
- codex-cli
|
||||
---
|
||||
|
||||
# Claude Monitor — Diagnóstico de Performance
|
||||
|
||||
## Overview
|
||||
|
||||
Monitor de performance do Claude Code e sistema local. Diagnostica lentidao, mede CPU/RAM/disco, verifica API latency e gera relatorios de saude do sistema.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- When the user mentions "lento" or related topics
|
||||
- When the user mentions "lentidao" or related topics
|
||||
- When the user mentions "lag" or related topics
|
||||
- When the user mentions "lagado" or related topics
|
||||
- When the user mentions "travando" or related topics
|
||||
- When the user mentions "claude lento" or related topics
|
||||
|
||||
## Do Not Use This Skill When
|
||||
|
||||
- The task is unrelated to claude monitor
|
||||
- A simpler, more specific tool can handle the request
|
||||
- The user needs general-purpose assistance without domain expertise
|
||||
|
||||
## How It Works
|
||||
|
||||
Skill para diagnosticar e resolver problemas de lentidão no Claude Code e no sistema.
|
||||
Determina se o gargalo é local (PC) ou remoto (API Claude) e sugere ações corretivas.
|
||||
|
||||
## Quando Usar
|
||||
|
||||
- Usuário reclama que o Claude Code está lento ou travando
|
||||
- Troca de sessões de conversa demora para carregar
|
||||
- Respostas do Claude demoram muito
|
||||
- PC parece lento enquanto usa o Claude Code
|
||||
- Qualquer menção a performance, lag, lentidão
|
||||
|
||||
## 1. Diagnóstico Rápido (Health_Check.Py)
|
||||
|
||||
Rode SEMPRE como primeiro passo:
|
||||
|
||||
```bash
|
||||
python C:\Users\renat\skills\claude-monitor\scripts\health_check.py
|
||||
```
|
||||
|
||||
O script analisa em ~3 segundos:
|
||||
- **CPU**: Uso atual e por core. >80% = gargalo provável
|
||||
- **RAM**: Total, usada, disponível. >85% = pressão de memória
|
||||
- **Browsers**: Processos e RAM por browser. >5GB total = excesso de abas
|
||||
- **Claude Code**: Processos e RAM consumida
|
||||
- **Disco**: Espaço livre. <10% = impacto em swap/performance
|
||||
- **Rede**: Latência ao endpoint da API Claude
|
||||
- **Diagnóstico**: Classificação automática do problema com sugestões
|
||||
|
||||
## 2. Interpretar O Resultado
|
||||
|
||||
O script retorna um JSON com `diagnosis` contendo:
|
||||
|
||||
- `bottleneck`: "cpu" | "ram" | "browsers" | "disk" | "network" | "claude_api" | "ok"
|
||||
- `severity`: "critical" | "warning" | "ok"
|
||||
- `suggestions`: Lista de ações recomendadas
|
||||
- `summary`: Resumo em português para mostrar ao usuário
|
||||
|
||||
**Mostre o `summary` ao usuário** e ofereça executar as sugestões.
|
||||
|
||||
## 3. Ações Corretivas Automáticas
|
||||
|
||||
Baseado no diagnóstico, ofereça ao usuário:
|
||||
|
||||
#### Se CPU alta (>80%):
|
||||
- Listar processos consumindo mais CPU
|
||||
- Sugerir fechar processos pesados desnecessários
|
||||
- Verificar se Windows Update está rodando em background
|
||||
|
||||
#### Se browsers pesados (>5GB RAM ou >40 processos):
|
||||
```bash
|
||||
python C:\Users\renat\skills\claude-monitor\scripts\health_check.py --browsers-detail
|
||||
```
|
||||
Mostra RAM por browser e sugere quais fechar. **Nunca fechar processos sem permissão explícita do usuário.**
|
||||
|
||||
#### Se disco cheio (>85%):
|
||||
- Mostrar pastas maiores
|
||||
- Sugerir limpeza de Temp, cache de browsers, lixeira
|
||||
|
||||
#### Se rede lenta (latência >500ms):
|
||||
- Testar conexão com api.anthropic.com
|
||||
- Sugerir verificar VPN, proxy, ou conexão WiFi
|
||||
|
||||
## 4. Monitor Contínuo (Opcional)
|
||||
|
||||
Se o usuário quiser monitoramento em background:
|
||||
|
||||
```bash
|
||||
python C:\Users\renat\skills\claude-monitor\scripts\monitor.py --interval 30 --duration 300
|
||||
```
|
||||
|
||||
Parâmetros:
|
||||
- `--interval`: Segundos entre cada amostra (default: 30)
|
||||
- `--duration`: Duração total em segundos (default: 300 = 5 min)
|
||||
- `--output`: Caminho do arquivo de log (default: monitor_log.json)
|
||||
- `--alert-cpu`: Threshold de CPU para alerta (default: 80)
|
||||
- `--alert-ram`: Threshold de RAM % para alerta (default: 85)
|
||||
|
||||
O monitor salva snapshots periódicos e gera um relatório ao final com:
|
||||
- Picos de CPU e RAM
|
||||
- Tendência (melhorando/piorando/estável)
|
||||
- Eventos de alerta detectados
|
||||
- Recomendação final
|
||||
|
||||
## 5. Benchmark Da Api Claude (Opcional)
|
||||
|
||||
Para testar se a lentidão é da API:
|
||||
|
||||
```bash
|
||||
python C:\Users\renat\skills\claude-monitor\scripts\api_bench.py
|
||||
```
|
||||
|
||||
Mede o tempo de resposta do processo Claude Code local (não faz chamadas à API).
|
||||
Compara com tempos típicos e indica se está dentro do esperado.
|
||||
|
||||
## Thresholds De Referência
|
||||
|
||||
| Métrica | OK | Warning | Critical |
|
||||
|---------|-----|---------|----------|
|
||||
| CPU % | <60% | 60-85% | >85% |
|
||||
| RAM usada % | <70% | 70-85% | >85% |
|
||||
| RAM browsers | <3 GB | 3-6 GB | >6 GB |
|
||||
| Processos browser | <30 | 30-60 | >60 |
|
||||
| Disco livre | >15% | 10-15% | <10% |
|
||||
| Latência rede | <200ms | 200-500ms | >500ms |
|
||||
|
||||
## Dicas Para O Usuário
|
||||
|
||||
Quando apresentar o diagnóstico, inclua estas dicas contextuais:
|
||||
|
||||
- **Muitas abas = muito CPU/RAM**: Cada aba de browser é um processo separado.
|
||||
50 abas = 50 processos competindo por recursos.
|
||||
- **Claude Code é pesado**: Ele roda vários processos Electron. É normal consumir 3-5 GB.
|
||||
Mas se estiver usando >6 GB com várias sessões, considere fechar sessões antigas.
|
||||
- **Troca de sessão lenta**: Geralmente causada por CPU alta ou muitos processos competindo.
|
||||
A sessão precisa carregar o histórico da conversa, e se o CPU está ocupado, demora.
|
||||
- **Disco quase cheio**: Afeta a velocidade do swap (memória virtual) e pode causar
|
||||
lentidão generalizada.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Python 3.10+
|
||||
- psutil (instalado automaticamente pelo script se não disponível)
|
||||
- Nenhuma API key necessária
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Provide clear, specific context about your project and requirements
|
||||
- Review all suggestions before applying them to production code
|
||||
- Combine with other complementary skills for comprehensive analysis
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Using this skill for tasks outside its domain expertise
|
||||
- Applying recommendations without understanding your specific context
|
||||
- Not providing enough project context for accurate analysis
|
||||
|
||||
## Limitations
|
||||
- Use this skill only when the task clearly matches the scope described above.
|
||||
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
|
||||
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Monitor — Benchmark de Conectividade API
|
||||
|
||||
Testa latência e conectividade com a API do Claude.
|
||||
Não faz chamadas à API (não precisa de API key).
|
||||
Apenas verifica se a rede está funcionando e se o endpoint responde.
|
||||
|
||||
Uso:
|
||||
python api_bench.py # 5 testes de latência
|
||||
python api_bench.py --samples 10 # 10 testes
|
||||
python api_bench.py --json # Output JSON
|
||||
"""
|
||||
|
||||
import json
|
||||
import socket
|
||||
import ssl
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "psutil", "--quiet"])
|
||||
import psutil
|
||||
|
||||
|
||||
ENDPOINTS = [
|
||||
{"name": "Claude API", "host": "api.anthropic.com", "port": 443},
|
||||
{"name": "Anthropic CDN", "host": "cdn.anthropic.com", "port": 443},
|
||||
{"name": "Google DNS", "host": "8.8.8.8", "port": 53},
|
||||
]
|
||||
|
||||
|
||||
def create_tls_context():
|
||||
"""Cria contexto TLS restringindo conexoes a TLS 1.2+."""
|
||||
context = ssl.create_default_context()
|
||||
if hasattr(ssl, "TLSVersion"):
|
||||
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
else:
|
||||
context.options |= getattr(ssl, "OP_NO_TLSv1", 0)
|
||||
context.options |= getattr(ssl, "OP_NO_TLSv1_1", 0)
|
||||
return context
|
||||
|
||||
|
||||
def test_tcp_latency(host, port, timeout=5):
|
||||
"""Testa latência TCP para um host:port."""
|
||||
try:
|
||||
start = time.time()
|
||||
sock = socket.create_connection((host, port), timeout=timeout)
|
||||
latency = (time.time() - start) * 1000 # ms
|
||||
sock.close()
|
||||
return {"reachable": True, "latency_ms": round(latency, 1)}
|
||||
except (socket.timeout, socket.error, OSError) as e:
|
||||
return {"reachable": False, "latency_ms": None, "error": str(e)}
|
||||
|
||||
|
||||
def test_tls_handshake(host, port=443, timeout=5):
|
||||
"""Testa tempo do handshake TLS."""
|
||||
try:
|
||||
context = create_tls_context()
|
||||
start = time.time()
|
||||
with socket.create_connection((host, port), timeout=timeout) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=host) as ssock:
|
||||
handshake_time = (time.time() - start) * 1000
|
||||
return {
|
||||
"success": True,
|
||||
"handshake_ms": round(handshake_time, 1),
|
||||
"tls_version": ssock.version(),
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
def test_dns(hostname):
|
||||
"""Testa resolução DNS."""
|
||||
try:
|
||||
start = time.time()
|
||||
ip = socket.gethostbyname(hostname)
|
||||
dns_time = (time.time() - start) * 1000
|
||||
return {"resolved": True, "ip": ip, "dns_ms": round(dns_time, 1)}
|
||||
except socket.gaierror as e:
|
||||
return {"resolved": False, "error": str(e)}
|
||||
|
||||
|
||||
def check_network_interfaces():
|
||||
"""Verifica interfaces de rede ativas."""
|
||||
stats = psutil.net_if_stats()
|
||||
active = []
|
||||
for name, info in stats.items():
|
||||
if info.isup and info.speed > 0:
|
||||
active.append({
|
||||
"name": name,
|
||||
"speed_mbps": info.speed,
|
||||
"mtu": info.mtu,
|
||||
})
|
||||
return active
|
||||
|
||||
|
||||
def run_benchmark(samples=5):
|
||||
"""Roda o benchmark completo."""
|
||||
results = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"samples": samples,
|
||||
"endpoints": [],
|
||||
"dns": None,
|
||||
"tls": None,
|
||||
"network_interfaces": check_network_interfaces(),
|
||||
}
|
||||
|
||||
# DNS
|
||||
results["dns"] = test_dns("api.anthropic.com")
|
||||
|
||||
# TLS handshake
|
||||
results["tls"] = test_tls_handshake("api.anthropic.com")
|
||||
|
||||
# Latência por endpoint
|
||||
for ep in ENDPOINTS:
|
||||
latencies = []
|
||||
for _ in range(samples):
|
||||
result = test_tcp_latency(ep["host"], ep["port"])
|
||||
latencies.append(result)
|
||||
time.sleep(0.2)
|
||||
|
||||
valid = [r["latency_ms"] for r in latencies if r["reachable"] and r["latency_ms"]]
|
||||
|
||||
ep_result = {
|
||||
"name": ep["name"],
|
||||
"host": ep["host"],
|
||||
"port": ep["port"],
|
||||
"tests": latencies,
|
||||
}
|
||||
|
||||
if valid:
|
||||
ep_result["avg_ms"] = round(sum(valid) / len(valid), 1)
|
||||
ep_result["min_ms"] = round(min(valid), 1)
|
||||
ep_result["max_ms"] = round(max(valid), 1)
|
||||
ep_result["success_rate"] = round(len(valid) / samples * 100, 0)
|
||||
else:
|
||||
ep_result["avg_ms"] = None
|
||||
ep_result["success_rate"] = 0
|
||||
|
||||
results["endpoints"].append(ep_result)
|
||||
|
||||
# Diagnóstico
|
||||
api_ep = results["endpoints"][0]
|
||||
if api_ep.get("avg_ms") is None:
|
||||
results["diagnosis"] = {
|
||||
"status": "critical",
|
||||
"message": "API do Claude INACESSIVEL. Verifique sua conexao de internet.",
|
||||
}
|
||||
elif api_ep["avg_ms"] > 500:
|
||||
results["diagnosis"] = {
|
||||
"status": "warning",
|
||||
"message": (
|
||||
f"Latencia alta para API ({api_ep['avg_ms']}ms). "
|
||||
f"Conexao lenta pode causar atrasos no Claude Code."
|
||||
),
|
||||
}
|
||||
elif api_ep["avg_ms"] > 200:
|
||||
results["diagnosis"] = {
|
||||
"status": "ok",
|
||||
"message": (
|
||||
f"Latencia moderada ({api_ep['avg_ms']}ms). "
|
||||
f"Dentro do aceitavel mas pode ser melhor."
|
||||
),
|
||||
}
|
||||
else:
|
||||
results["diagnosis"] = {
|
||||
"status": "ok",
|
||||
"message": (
|
||||
f"Conexao excelente ({api_ep['avg_ms']}ms). "
|
||||
f"A rede NAO e o gargalo."
|
||||
),
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def format_results(results):
|
||||
"""Formata resultados para exibição."""
|
||||
lines = ["## Benchmark de Conectividade\n"]
|
||||
|
||||
# DNS
|
||||
dns = results["dns"]
|
||||
if dns.get("resolved"):
|
||||
lines.append(f"- DNS: api.anthropic.com -> {dns['ip']} ({dns['dns_ms']}ms)")
|
||||
else:
|
||||
lines.append(f"- DNS: FALHOU ({dns.get('error', 'desconhecido')})")
|
||||
|
||||
# TLS
|
||||
tls = results["tls"]
|
||||
if tls.get("success"):
|
||||
lines.append(f"- TLS: {tls['tls_version']} handshake em {tls['handshake_ms']}ms")
|
||||
else:
|
||||
lines.append(f"- TLS: FALHOU ({tls.get('error', 'desconhecido')})")
|
||||
|
||||
lines.append("")
|
||||
|
||||
# Endpoints
|
||||
lines.append("### Latencia por Endpoint")
|
||||
for ep in results["endpoints"]:
|
||||
if ep.get("avg_ms"):
|
||||
lines.append(
|
||||
f"- **{ep['name']}**: {ep['avg_ms']}ms avg "
|
||||
f"(min {ep['min_ms']}ms, max {ep['max_ms']}ms) "
|
||||
f"[{ep['success_rate']:.0f}% sucesso]"
|
||||
)
|
||||
else:
|
||||
lines.append(f"- **{ep['name']}**: INACESSIVEL")
|
||||
|
||||
# Interfaces
|
||||
lines.append("\n### Interfaces de Rede")
|
||||
for iface in results["network_interfaces"]:
|
||||
speed = iface["speed_mbps"]
|
||||
if speed >= 1000:
|
||||
speed_str = f"{speed/1000:.0f} Gbps"
|
||||
else:
|
||||
speed_str = f"{speed} Mbps"
|
||||
lines.append(f"- {iface['name']}: {speed_str}")
|
||||
|
||||
# Diagnóstico
|
||||
lines.append(f"\n### Diagnostico")
|
||||
diag = results["diagnosis"]
|
||||
status_map = {"critical": "[!!!]", "warning": "[!]", "ok": "[OK]"}
|
||||
lines.append(f"{status_map[diag['status']]} {diag['message']}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Claude Monitor - Benchmark de Conectividade")
|
||||
parser.add_argument("--samples", type=int, default=5, help="Numero de testes por endpoint")
|
||||
parser.add_argument("--json", action="store_true", help="Output JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"Testando conectividade ({args.samples} amostras por endpoint)...\n")
|
||||
results = run_benchmark(args.samples)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(results, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(format_results(results))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Configurações e thresholds para o Claude Monitor.
|
||||
"""
|
||||
|
||||
# Thresholds de alerta
|
||||
THRESHOLDS = {
|
||||
"cpu": {
|
||||
"ok": 60,
|
||||
"warning": 85,
|
||||
# acima de warning = critical
|
||||
},
|
||||
"ram_percent": {
|
||||
"ok": 70,
|
||||
"warning": 85,
|
||||
},
|
||||
"browsers_ram_gb": {
|
||||
"ok": 3.0,
|
||||
"warning": 6.0,
|
||||
},
|
||||
"browsers_processes": {
|
||||
"ok": 30,
|
||||
"warning": 60,
|
||||
},
|
||||
"disk_free_percent": {
|
||||
"critical_below": 10,
|
||||
"warning_below": 15,
|
||||
},
|
||||
"network_latency_ms": {
|
||||
"ok": 200,
|
||||
"warning": 500,
|
||||
},
|
||||
}
|
||||
|
||||
# Nomes de processos de browser conhecidos
|
||||
BROWSER_NAMES = ["chrome", "msedge", "firefox", "brave", "opera", "vivaldi"]
|
||||
|
||||
# Nomes de processos do Claude Code
|
||||
CLAUDE_NAMES = ["claude"]
|
||||
|
||||
# Endpoint para teste de latência
|
||||
API_ENDPOINT = "api.anthropic.com"
|
||||
|
||||
# Monitor defaults
|
||||
MONITOR_DEFAULTS = {
|
||||
"interval": 30,
|
||||
"duration": 300,
|
||||
"alert_cpu": 80,
|
||||
"alert_ram": 85,
|
||||
}
|
||||
|
||||
|
||||
def classify(value, metric_name):
|
||||
"""Classifica um valor como 'ok', 'warning' ou 'critical'."""
|
||||
t = THRESHOLDS.get(metric_name, {})
|
||||
|
||||
# Métricas onde "abaixo" é ruim (disco livre)
|
||||
if "critical_below" in t:
|
||||
if value < t["critical_below"]:
|
||||
return "critical"
|
||||
elif value < t["warning_below"]:
|
||||
return "warning"
|
||||
return "ok"
|
||||
|
||||
# Métricas onde "acima" é ruim (CPU, RAM, latência)
|
||||
if value <= t.get("ok", 999999):
|
||||
return "ok"
|
||||
elif value <= t.get("warning", 999999):
|
||||
return "warning"
|
||||
return "critical"
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Monitor — Diagnóstico Rápido de Performance
|
||||
|
||||
Analisa CPU, RAM, browsers, disco e rede em ~3 segundos.
|
||||
Identifica o gargalo principal e sugere ações corretivas.
|
||||
|
||||
Uso:
|
||||
python health_check.py # Diagnóstico completo
|
||||
python health_check.py --browsers-detail # Detalhe de browsers
|
||||
python health_check.py --json # Output JSON puro
|
||||
python health_check.py --quick # Só resumo (sem teste de rede)
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Garante que psutil está disponível
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
print("Instalando psutil...")
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "psutil", "--quiet"])
|
||||
import psutil
|
||||
|
||||
# Importa config do mesmo diretório
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from config import (
|
||||
BROWSER_NAMES, CLAUDE_NAMES, API_ENDPOINT,
|
||||
THRESHOLDS, classify
|
||||
)
|
||||
|
||||
|
||||
def check_cpu():
|
||||
"""Verifica uso de CPU."""
|
||||
cpu_percent = psutil.cpu_percent(interval=1)
|
||||
cpu_count = psutil.cpu_count()
|
||||
per_cpu = psutil.cpu_percent(interval=0, percpu=True)
|
||||
|
||||
return {
|
||||
"percent": cpu_percent,
|
||||
"cores": cpu_count,
|
||||
"per_core": per_cpu,
|
||||
"status": classify(cpu_percent, "cpu"),
|
||||
}
|
||||
|
||||
|
||||
def check_ram():
|
||||
"""Verifica uso de RAM."""
|
||||
ram = psutil.virtual_memory()
|
||||
swap = psutil.swap_memory()
|
||||
|
||||
return {
|
||||
"total_gb": round(ram.total / 1024**3, 1),
|
||||
"used_gb": round(ram.used / 1024**3, 1),
|
||||
"available_gb": round(ram.available / 1024**3, 1),
|
||||
"percent": ram.percent,
|
||||
"swap_used_gb": round(swap.used / 1024**3, 1),
|
||||
"swap_percent": swap.percent,
|
||||
"status": classify(ram.percent, "ram_percent"),
|
||||
}
|
||||
|
||||
|
||||
def check_browsers(detail=False):
|
||||
"""Verifica processos de browser e consumo de RAM."""
|
||||
browsers = {}
|
||||
all_procs = []
|
||||
|
||||
for proc in psutil.process_iter(["pid", "name", "memory_info"]):
|
||||
try:
|
||||
info = proc.info
|
||||
name_lower = info["name"].lower()
|
||||
ram_mb = info["memory_info"].rss / 1024**2
|
||||
|
||||
for bname in BROWSER_NAMES:
|
||||
if bname in name_lower:
|
||||
if bname not in browsers:
|
||||
browsers[bname] = {"count": 0, "ram_mb": 0, "pids": []}
|
||||
browsers[bname]["count"] += 1
|
||||
browsers[bname]["ram_mb"] += ram_mb
|
||||
if detail:
|
||||
browsers[bname]["pids"].append({
|
||||
"pid": info["pid"],
|
||||
"ram_mb": round(ram_mb, 0)
|
||||
})
|
||||
break
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
total_ram_gb = sum(b["ram_mb"] for b in browsers.values()) / 1024
|
||||
total_procs = sum(b["count"] for b in browsers.values())
|
||||
|
||||
# Formata para output
|
||||
for bname in browsers:
|
||||
browsers[bname]["ram_mb"] = round(browsers[bname]["ram_mb"], 0)
|
||||
|
||||
return {
|
||||
"browsers": browsers,
|
||||
"total_ram_gb": round(total_ram_gb, 1),
|
||||
"total_processes": total_procs,
|
||||
"ram_status": classify(total_ram_gb, "browsers_ram_gb"),
|
||||
"process_status": classify(total_procs, "browsers_processes"),
|
||||
}
|
||||
|
||||
|
||||
def check_claude_processes():
|
||||
"""Verifica processos do Claude Code."""
|
||||
claude_procs = []
|
||||
total_ram = 0
|
||||
|
||||
for proc in psutil.process_iter(["pid", "name", "memory_info", "cpu_percent"]):
|
||||
try:
|
||||
info = proc.info
|
||||
name_lower = info["name"].lower()
|
||||
|
||||
for cname in CLAUDE_NAMES:
|
||||
if cname in name_lower:
|
||||
ram_mb = info["memory_info"].rss / 1024**2
|
||||
claude_procs.append({
|
||||
"pid": info["pid"],
|
||||
"name": info["name"],
|
||||
"ram_mb": round(ram_mb, 0),
|
||||
})
|
||||
total_ram += ram_mb
|
||||
break
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
claude_procs.sort(key=lambda x: x["ram_mb"], reverse=True)
|
||||
|
||||
return {
|
||||
"count": len(claude_procs),
|
||||
"total_ram_gb": round(total_ram / 1024, 1),
|
||||
"processes": claude_procs[:10], # Top 10
|
||||
}
|
||||
|
||||
|
||||
def check_disk():
|
||||
"""Verifica espaço em disco."""
|
||||
disk = psutil.disk_usage("C:/")
|
||||
free_percent = 100 - disk.percent
|
||||
|
||||
return {
|
||||
"total_gb": round(disk.total / 1024**3, 0),
|
||||
"used_gb": round(disk.used / 1024**3, 0),
|
||||
"free_gb": round(disk.free / 1024**3, 0),
|
||||
"used_percent": disk.percent,
|
||||
"free_percent": round(free_percent, 1),
|
||||
"status": classify(free_percent, "disk_free_percent"),
|
||||
}
|
||||
|
||||
|
||||
def check_network():
|
||||
"""Testa latência até a API do Claude."""
|
||||
try:
|
||||
start = time.time()
|
||||
sock = socket.create_connection((API_ENDPOINT, 443), timeout=5)
|
||||
latency_ms = round((time.time() - start) * 1000, 0)
|
||||
sock.close()
|
||||
|
||||
return {
|
||||
"latency_ms": latency_ms,
|
||||
"endpoint": API_ENDPOINT,
|
||||
"reachable": True,
|
||||
"status": classify(latency_ms, "network_latency_ms"),
|
||||
}
|
||||
except (socket.timeout, socket.error, OSError) as e:
|
||||
return {
|
||||
"latency_ms": None,
|
||||
"endpoint": API_ENDPOINT,
|
||||
"reachable": False,
|
||||
"status": "critical",
|
||||
"error": str(e),
|
||||
}
|
||||
|
||||
|
||||
def check_top_processes(n=10):
|
||||
"""Lista os N processos que mais consomem RAM."""
|
||||
procs = []
|
||||
for proc in psutil.process_iter(["pid", "name", "memory_info"]):
|
||||
try:
|
||||
info = proc.info
|
||||
procs.append({
|
||||
"name": info["name"],
|
||||
"ram_mb": round(info["memory_info"].rss / 1024**2, 0),
|
||||
"pid": info["pid"],
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
procs.sort(key=lambda x: x["ram_mb"], reverse=True)
|
||||
return procs[:n]
|
||||
|
||||
|
||||
def diagnose(results):
|
||||
"""Analisa os resultados e gera diagnóstico."""
|
||||
issues = []
|
||||
suggestions = []
|
||||
bottleneck = "ok"
|
||||
severity = "ok"
|
||||
|
||||
cpu = results["cpu"]
|
||||
ram = results["ram"]
|
||||
browsers = results["browsers"]
|
||||
disk = results["disk"]
|
||||
network = results.get("network", {})
|
||||
claude = results["claude"]
|
||||
|
||||
# CPU
|
||||
if cpu["status"] == "critical":
|
||||
issues.append(f"CPU a {cpu['percent']}% (CRITICO)")
|
||||
suggestions.append("Fechar aplicativos pesados ou abas de browser desnecessarias")
|
||||
suggestions.append("Verificar se Windows Update ou antivirus esta rodando em background")
|
||||
bottleneck = "cpu"
|
||||
severity = "critical"
|
||||
elif cpu["status"] == "warning":
|
||||
issues.append(f"CPU a {cpu['percent']}% (elevada)")
|
||||
suggestions.append("Considerar fechar algumas abas de browser")
|
||||
if severity != "critical":
|
||||
bottleneck = "cpu"
|
||||
severity = "warning"
|
||||
|
||||
# RAM
|
||||
if ram["status"] == "critical":
|
||||
issues.append(f"RAM a {ram['percent']}% ({ram['used_gb']} de {ram['total_gb']} GB)")
|
||||
suggestions.append("Fechar browsers ou aplicativos para liberar memoria")
|
||||
if severity != "critical":
|
||||
bottleneck = "ram"
|
||||
severity = "critical"
|
||||
elif ram["status"] == "warning":
|
||||
issues.append(f"RAM a {ram['percent']}% (monitorar)")
|
||||
|
||||
# Browsers
|
||||
if browsers["ram_status"] == "critical":
|
||||
issues.append(f"Browsers consumindo {browsers['total_ram_gb']} GB ({browsers['total_processes']} processos)")
|
||||
suggestions.append("Fechar abas desnecessarias nos browsers")
|
||||
browser_detail = []
|
||||
for bname, info in browsers["browsers"].items():
|
||||
browser_detail.append(f" - {bname}: {info['count']} processos, {info['ram_mb']:.0f} MB")
|
||||
suggestions.append("Detalhamento:\n" + "\n".join(browser_detail))
|
||||
if bottleneck == "ok":
|
||||
bottleneck = "browsers"
|
||||
if severity == "ok":
|
||||
severity = "warning"
|
||||
elif browsers["ram_status"] == "warning":
|
||||
issues.append(f"Browsers usando {browsers['total_ram_gb']} GB (moderado)")
|
||||
|
||||
# Disco
|
||||
if disk["status"] == "critical":
|
||||
issues.append(f"Disco quase cheio: apenas {disk['free_gb']:.0f} GB livres ({disk['free_percent']}%)")
|
||||
suggestions.append("Limpar arquivos temporarios, cache e lixeira")
|
||||
suggestions.append("Verificar pasta Downloads e Temp por arquivos grandes")
|
||||
if bottleneck == "ok":
|
||||
bottleneck = "disk"
|
||||
severity = "warning"
|
||||
elif disk["status"] == "warning":
|
||||
issues.append(f"Disco com {disk['free_gb']:.0f} GB livres ({disk['free_percent']}%)")
|
||||
|
||||
# Rede
|
||||
if network.get("status") == "critical":
|
||||
if not network.get("reachable"):
|
||||
issues.append("API do Claude INACESSIVEL")
|
||||
suggestions.append("Verificar conexao com internet")
|
||||
suggestions.append("Verificar se VPN ou proxy esta bloqueando")
|
||||
bottleneck = "network"
|
||||
severity = "critical"
|
||||
else:
|
||||
issues.append(f"Latencia alta para API: {network['latency_ms']}ms")
|
||||
suggestions.append("Verificar qualidade da conexao WiFi/cabo")
|
||||
if bottleneck == "ok":
|
||||
bottleneck = "network"
|
||||
severity = "warning"
|
||||
|
||||
# Claude Code RAM
|
||||
if claude["total_ram_gb"] > 8:
|
||||
issues.append(f"Claude Code usando {claude['total_ram_gb']} GB ({claude['count']} processos)")
|
||||
suggestions.append("Considerar fechar sessoes de conversa antigas no Claude Code")
|
||||
|
||||
# Tudo ok
|
||||
if not issues:
|
||||
issues.append("Sistema saudavel, sem gargalos detectados")
|
||||
suggestions.append("A lentidao pode ser temporaria (pico na API do Claude)")
|
||||
suggestions.append("Tente trocar de sessao novamente em alguns segundos")
|
||||
|
||||
# Gerar resumo em PT-BR
|
||||
summary_lines = ["## Diagnostico de Performance\n"]
|
||||
|
||||
status_emoji = {"critical": "[!!!]", "warning": "[!]", "ok": "[OK]"}
|
||||
summary_lines.append(f"**Status geral: {status_emoji[severity]} {severity.upper()}**\n")
|
||||
|
||||
if bottleneck != "ok":
|
||||
summary_lines.append(f"**Gargalo principal: {bottleneck.upper()}**\n")
|
||||
|
||||
summary_lines.append("### Problemas detectados:")
|
||||
for issue in issues:
|
||||
summary_lines.append(f"- {issue}")
|
||||
|
||||
summary_lines.append("\n### Acoes recomendadas:")
|
||||
for i, sug in enumerate(suggestions, 1):
|
||||
if "\n" in sug:
|
||||
summary_lines.append(f"{i}. {sug}")
|
||||
else:
|
||||
summary_lines.append(f"{i}. {sug}")
|
||||
|
||||
summary_lines.append(f"\n### Numeros-chave:")
|
||||
summary_lines.append(f"- CPU: {cpu['percent']}% | RAM: {ram['percent']}% ({ram['used_gb']}/{ram['total_gb']} GB)")
|
||||
summary_lines.append(f"- Browsers: {browsers['total_processes']} processos, {browsers['total_ram_gb']} GB")
|
||||
summary_lines.append(f"- Claude Code: {claude['count']} processos, {claude['total_ram_gb']} GB")
|
||||
summary_lines.append(f"- Disco C: {disk['free_gb']:.0f} GB livres ({disk['free_percent']}%)")
|
||||
if network.get("latency_ms"):
|
||||
summary_lines.append(f"- Latencia API: {network['latency_ms']}ms")
|
||||
|
||||
return {
|
||||
"bottleneck": bottleneck,
|
||||
"severity": severity,
|
||||
"issues": issues,
|
||||
"suggestions": suggestions,
|
||||
"summary": "\n".join(summary_lines),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Claude Monitor - Diagnostico Rapido")
|
||||
parser.add_argument("--browsers-detail", action="store_true", help="Mostra detalhes por browser")
|
||||
parser.add_argument("--json", action="store_true", help="Output em JSON puro")
|
||||
parser.add_argument("--quick", action="store_true", help="Pula teste de rede")
|
||||
args = parser.parse_args()
|
||||
|
||||
results = {}
|
||||
|
||||
# Coleta dados
|
||||
results["timestamp"] = datetime.now().isoformat()
|
||||
results["cpu"] = check_cpu()
|
||||
results["ram"] = check_ram()
|
||||
results["browsers"] = check_browsers(detail=args.browsers_detail)
|
||||
results["claude"] = check_claude_processes()
|
||||
results["disk"] = check_disk()
|
||||
results["top_processes"] = check_top_processes(15)
|
||||
|
||||
if not args.quick:
|
||||
results["network"] = check_network()
|
||||
|
||||
# Diagnóstico
|
||||
results["diagnosis"] = diagnose(results)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(results, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(results["diagnosis"]["summary"])
|
||||
print(f"\n(Para output completo em JSON, use: python health_check.py --json)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Monitor — Monitor Contínuo de Performance
|
||||
|
||||
Coleta snapshots periódicos de CPU, RAM e browsers.
|
||||
Gera relatório com tendências e alertas ao final.
|
||||
|
||||
Uso:
|
||||
python monitor.py # 5 min, amostras a cada 30s
|
||||
python monitor.py --interval 10 --duration 120 # 2 min, amostras a cada 10s
|
||||
python monitor.py --output meu_log.json # Salvar em arquivo específico
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "psutil", "--quiet"])
|
||||
import psutil
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from config import BROWSER_NAMES, CLAUDE_NAMES, MONITOR_DEFAULTS
|
||||
|
||||
|
||||
def take_snapshot():
|
||||
"""Coleta um snapshot rápido do sistema."""
|
||||
cpu = psutil.cpu_percent(interval=0.5)
|
||||
ram = psutil.virtual_memory()
|
||||
|
||||
# Browser totals
|
||||
browser_ram = 0
|
||||
browser_count = 0
|
||||
for proc in psutil.process_iter(["name", "memory_info"]):
|
||||
try:
|
||||
name = proc.info["name"].lower()
|
||||
for bname in BROWSER_NAMES:
|
||||
if bname in name:
|
||||
browser_ram += proc.info["memory_info"].rss
|
||||
browser_count += 1
|
||||
break
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
# Claude totals
|
||||
claude_ram = 0
|
||||
claude_count = 0
|
||||
for proc in psutil.process_iter(["name", "memory_info"]):
|
||||
try:
|
||||
name = proc.info["name"].lower()
|
||||
for cname in CLAUDE_NAMES:
|
||||
if cname in name:
|
||||
claude_ram += proc.info["memory_info"].rss
|
||||
claude_count += 1
|
||||
break
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
return {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"cpu_percent": cpu,
|
||||
"ram_percent": ram.percent,
|
||||
"ram_used_gb": round(ram.used / 1024**3, 2),
|
||||
"ram_available_gb": round(ram.available / 1024**3, 2),
|
||||
"browser_ram_gb": round(browser_ram / 1024**3, 2),
|
||||
"browser_processes": browser_count,
|
||||
"claude_ram_gb": round(claude_ram / 1024**3, 2),
|
||||
"claude_processes": claude_count,
|
||||
}
|
||||
|
||||
|
||||
def analyze_snapshots(snapshots, alert_cpu, alert_ram):
|
||||
"""Analisa os snapshots coletados e gera relatório."""
|
||||
if not snapshots:
|
||||
return {"error": "Nenhum snapshot coletado"}
|
||||
|
||||
n = len(snapshots)
|
||||
cpu_values = [s["cpu_percent"] for s in snapshots]
|
||||
ram_values = [s["ram_percent"] for s in snapshots]
|
||||
browser_ram_values = [s["browser_ram_gb"] for s in snapshots]
|
||||
|
||||
# Alertas
|
||||
alerts = []
|
||||
for s in snapshots:
|
||||
if s["cpu_percent"] >= alert_cpu:
|
||||
alerts.append({
|
||||
"time": s["timestamp"],
|
||||
"type": "cpu",
|
||||
"value": s["cpu_percent"],
|
||||
"threshold": alert_cpu,
|
||||
})
|
||||
if s["ram_percent"] >= alert_ram:
|
||||
alerts.append({
|
||||
"time": s["timestamp"],
|
||||
"type": "ram",
|
||||
"value": s["ram_percent"],
|
||||
"threshold": alert_ram,
|
||||
})
|
||||
|
||||
# Tendência (compara primeira metade com segunda metade)
|
||||
mid = n // 2
|
||||
if mid > 0:
|
||||
cpu_first = sum(cpu_values[:mid]) / mid
|
||||
cpu_second = sum(cpu_values[mid:]) / (n - mid)
|
||||
ram_first = sum(ram_values[:mid]) / mid
|
||||
ram_second = sum(ram_values[mid:]) / (n - mid)
|
||||
|
||||
cpu_diff = cpu_second - cpu_first
|
||||
ram_diff = ram_second - ram_first
|
||||
|
||||
if abs(cpu_diff) < 5 and abs(ram_diff) < 3:
|
||||
trend = "estavel"
|
||||
elif cpu_diff > 5 or ram_diff > 3:
|
||||
trend = "piorando"
|
||||
else:
|
||||
trend = "melhorando"
|
||||
else:
|
||||
trend = "insuficiente"
|
||||
cpu_diff = 0
|
||||
ram_diff = 0
|
||||
|
||||
# Resumo
|
||||
report = {
|
||||
"samples": n,
|
||||
"duration_seconds": round(
|
||||
(datetime.fromisoformat(snapshots[-1]["timestamp"]) -
|
||||
datetime.fromisoformat(snapshots[0]["timestamp"])).total_seconds(), 0
|
||||
) if n > 1 else 0,
|
||||
"cpu": {
|
||||
"avg": round(sum(cpu_values) / n, 1),
|
||||
"max": round(max(cpu_values), 1),
|
||||
"min": round(min(cpu_values), 1),
|
||||
},
|
||||
"ram": {
|
||||
"avg_percent": round(sum(ram_values) / n, 1),
|
||||
"max_percent": round(max(ram_values), 1),
|
||||
"avg_used_gb": round(sum(s["ram_used_gb"] for s in snapshots) / n, 1),
|
||||
},
|
||||
"browsers": {
|
||||
"avg_ram_gb": round(sum(browser_ram_values) / n, 1),
|
||||
"max_ram_gb": round(max(browser_ram_values), 1),
|
||||
"avg_processes": round(sum(s["browser_processes"] for s in snapshots) / n, 0),
|
||||
},
|
||||
"trend": trend,
|
||||
"trend_detail": {
|
||||
"cpu_change": round(cpu_diff, 1),
|
||||
"ram_change": round(ram_diff, 1),
|
||||
},
|
||||
"alerts_count": len(alerts),
|
||||
"alerts": alerts[:20], # Máximo 20 alertas no relatório
|
||||
}
|
||||
|
||||
# Recomendação final
|
||||
if report["cpu"]["avg"] > alert_cpu:
|
||||
report["recommendation"] = (
|
||||
f"CPU consistentemente alta (media {report['cpu']['avg']}%). "
|
||||
f"Fechar aplicativos pesados e abas de browser desnecessarias."
|
||||
)
|
||||
elif len(alerts) > n * 0.3:
|
||||
report["recommendation"] = (
|
||||
f"Alertas frequentes ({len(alerts)} de {n} amostras). "
|
||||
f"Sistema sob pressao intermitente. Reduzir carga."
|
||||
)
|
||||
elif trend == "piorando":
|
||||
report["recommendation"] = (
|
||||
f"Tendencia de piora detectada (CPU {'+' if cpu_diff > 0 else ''}{cpu_diff:.0f}%, "
|
||||
f"RAM {'+' if ram_diff > 0 else ''}{ram_diff:.0f}%). Monitorar."
|
||||
)
|
||||
else:
|
||||
report["recommendation"] = "Sistema estavel durante o monitoramento."
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def format_report(report):
|
||||
"""Formata o relatório para exibição."""
|
||||
lines = ["## Relatorio de Monitoramento\n"]
|
||||
lines.append(f"- **Amostras**: {report['samples']} em {report['duration_seconds']}s")
|
||||
lines.append(f"- **Tendencia**: {report['trend'].upper()}")
|
||||
lines.append(f"- **Alertas**: {report['alerts_count']}\n")
|
||||
|
||||
lines.append("### CPU")
|
||||
lines.append(f"- Media: {report['cpu']['avg']}%")
|
||||
lines.append(f"- Max: {report['cpu']['max']}% | Min: {report['cpu']['min']}%\n")
|
||||
|
||||
lines.append("### RAM")
|
||||
lines.append(f"- Media: {report['ram']['avg_percent']}% ({report['ram']['avg_used_gb']} GB)")
|
||||
lines.append(f"- Pico: {report['ram']['max_percent']}%\n")
|
||||
|
||||
lines.append("### Browsers")
|
||||
lines.append(f"- Media RAM: {report['browsers']['avg_ram_gb']} GB")
|
||||
lines.append(f"- Pico RAM: {report['browsers']['max_ram_gb']} GB")
|
||||
lines.append(f"- Media processos: {report['browsers']['avg_processes']}\n")
|
||||
|
||||
lines.append(f"### Recomendacao")
|
||||
lines.append(f"{report['recommendation']}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Claude Monitor - Monitor Continuo")
|
||||
parser.add_argument("--interval", type=int, default=MONITOR_DEFAULTS["interval"],
|
||||
help=f"Segundos entre amostras (default: {MONITOR_DEFAULTS['interval']})")
|
||||
parser.add_argument("--duration", type=int, default=MONITOR_DEFAULTS["duration"],
|
||||
help=f"Duracao total em segundos (default: {MONITOR_DEFAULTS['duration']})")
|
||||
parser.add_argument("--output", type=str, default=None,
|
||||
help="Arquivo de saida JSON")
|
||||
parser.add_argument("--alert-cpu", type=int, default=MONITOR_DEFAULTS["alert_cpu"],
|
||||
help=f"Threshold CPU para alerta (default: {MONITOR_DEFAULTS['alert_cpu']})")
|
||||
parser.add_argument("--alert-ram", type=int, default=MONITOR_DEFAULTS["alert_ram"],
|
||||
help=f"Threshold RAM para alerta (default: {MONITOR_DEFAULTS['alert_ram']})")
|
||||
parser.add_argument("--json", action="store_true", help="Output em JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
snapshots = []
|
||||
start_time = time.time()
|
||||
sample_count = 0
|
||||
expected_samples = args.duration // args.interval
|
||||
|
||||
print(f"Monitorando por {args.duration}s (amostra a cada {args.interval}s)...")
|
||||
print(f"Esperando {expected_samples} amostras. Ctrl+C para parar.\n")
|
||||
|
||||
# Permite interromper com Ctrl+C
|
||||
interrupted = False
|
||||
|
||||
def handle_interrupt(sig, frame):
|
||||
nonlocal interrupted
|
||||
interrupted = True
|
||||
print("\nInterrompido pelo usuario. Gerando relatorio...\n")
|
||||
|
||||
signal.signal(signal.SIGINT, handle_interrupt)
|
||||
|
||||
while not interrupted and (time.time() - start_time) < args.duration:
|
||||
snapshot = take_snapshot()
|
||||
snapshots.append(snapshot)
|
||||
sample_count += 1
|
||||
|
||||
# Print inline progress
|
||||
print(
|
||||
f"[{sample_count}/{expected_samples}] "
|
||||
f"CPU: {snapshot['cpu_percent']:5.1f}% | "
|
||||
f"RAM: {snapshot['ram_percent']:5.1f}% | "
|
||||
f"Browsers: {snapshot['browser_ram_gb']:.1f}GB ({snapshot['browser_processes']} proc) | "
|
||||
f"Claude: {snapshot['claude_ram_gb']:.1f}GB ({snapshot['claude_processes']} proc)"
|
||||
)
|
||||
|
||||
# Espera até a próxima amostra
|
||||
elapsed = time.time() - start_time
|
||||
next_sample_at = sample_count * args.interval
|
||||
sleep_time = max(0, next_sample_at - elapsed)
|
||||
if sleep_time > 0 and not interrupted:
|
||||
time.sleep(sleep_time)
|
||||
|
||||
# Analisa
|
||||
report = analyze_snapshots(snapshots, args.alert_cpu, args.alert_ram)
|
||||
|
||||
# Salva log
|
||||
output_data = {
|
||||
"config": {
|
||||
"interval": args.interval,
|
||||
"duration": args.duration,
|
||||
"alert_cpu": args.alert_cpu,
|
||||
"alert_ram": args.alert_ram,
|
||||
},
|
||||
"snapshots": snapshots,
|
||||
"report": report,
|
||||
}
|
||||
|
||||
if args.output:
|
||||
output_path = args.output
|
||||
else:
|
||||
output_path = f"monitor_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(output_data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"\nLog salvo em: {output_path}\n")
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(report, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(format_report(report))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user