As métricas pontuais informam o que está acontecendo agora. Os dados de série temporal informam o que mudou, quando mudou e se algo tende a se tornar um problema. Acompanhe as taxas de resolução de CAPTCHA, a latência e o custo ao longo do tempo para detectar a degradação antes que ela afete seu pipeline.
O que rastrear
| Métrica | Tipo | Por que |
|---|---|---|
| Taxa de resolução (%) | Medidor | Detecte alterações na qualidade do provedor |
| Resolva a latência (ms) | Histograma | Identifique lentidão, planeje tempos limite |
| Taxa de erro por código | Contador | Identifique padrões de erro emergentes |
| Custo por solução ($) | Medidor | Acompanhamento de orçamento, detecção de anomalias |
| Profundidade da fila | Medidor | Planejamento de capacidade |
| Os tokens expiraram antes do uso | Contador | Sinal de sintonia TTL |
| Saldo da API | Medidor | Gatilho de recarga |
Prometheus + Python (gateway push)
Instrumente seu solucionador
import os
import time
import requests
from prometheus_client import CollectorRegistry, Counter, Histogram, Gauge, push_to_gateway
registry = CollectorRegistry()
SOLVE_TOTAL = Counter(
"captcha_solve_total", "Total CAPTCHA solve attempts",
["type", "status"], registry=registry
)
SOLVE_LATENCY = Histogram(
"captcha_solve_latency_seconds", "CAPTCHA solve latency",
["type"], buckets=[5, 10, 15, 20, 30, 45, 60, 90, 120],
registry=registry
)
SOLVE_COST = Counter(
"captcha_solve_cost_dollars", "Total cost of CAPTCHA solves",
["type"], registry=registry
)
API_BALANCE = Gauge(
"captcha_api_balance_dollars", "CaptchaAI account balance",
registry=registry
)
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
PUSHGATEWAY = os.environ.get("PUSHGATEWAY_URL", "localhost:9091")
def solve_with_metrics(sitekey, pageurl, captcha_type="recaptcha_v2"):
start = time.time()
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
SOLVE_TOTAL.labels(type=captcha_type, status="submit_error").inc()
push_metrics()
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
elapsed = time.time() - start
SOLVE_TOTAL.labels(type=captcha_type, status="solved").inc()
SOLVE_LATENCY.labels(type=captcha_type).observe(elapsed)
SOLVE_COST.labels(type=captcha_type).inc(0.00299)
push_metrics()
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
SOLVE_TOTAL.labels(type=captcha_type, status="error").inc()
push_metrics()
return {"error": result.get("request")}
SOLVE_TOTAL.labels(type=captcha_type, status="timeout").inc()
push_metrics()
return {"error": "TIMEOUT"}
def push_metrics():
try:
push_to_gateway(PUSHGATEWAY, job="captcha_solver", registry=registry)
except Exception:
pass # Don't fail solving because metrics push failed
def update_balance():
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "getbalance"
})
try:
balance = float(resp.text)
API_BALANCE.set(balance)
push_metrics()
except ValueError:
pass
Consultas do Prometeu
# Success rate over last hour
rate(captcha_solve_total{status="solved"}[1h])
/ rate(captcha_solve_total[1h]) * 100
# P95 solve latency
histogram_quantile(0.95, rate(captcha_solve_latency_seconds_bucket[1h]))
# Error rate by type
rate(captcha_solve_total{status="error"}[1h])
# Hourly cost
increase(captcha_solve_cost_dollars_total[1h])
InfluxDB + Python
Escrever métricas de resolução
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
INFLUX_URL = os.environ.get("INFLUX_URL", "http://localhost:8086")
INFLUX_TOKEN = os.environ.get("INFLUX_TOKEN", "")
INFLUX_ORG = os.environ.get("INFLUX_ORG", "captcha")
INFLUX_BUCKET = os.environ.get("INFLUX_BUCKET", "captcha_metrics")
influx_client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
write_api = influx_client.write_api(write_options=SYNCHRONOUS)
def record_solve_metric(captcha_type, status, elapsed_ms, cost=0.0, error=None):
point = (
Point("captcha_solve")
.tag("type", captcha_type)
.tag("status", status)
.field("elapsed_ms", elapsed_ms)
.field("cost", cost)
.field("success", 1 if status == "solved" else 0)
)
if error:
point = point.tag("error_code", error)
write_api.write(bucket=INFLUX_BUCKET, record=point)
def record_balance(balance):
point = Point("captcha_balance").field("balance", balance)
write_api.write(bucket=INFLUX_BUCKET, record=point)
Consultas InfluxDB (Flux)
// Success rate over last 24 hours (1-hour windows)
from(bucket: "captcha_metrics")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "captcha_solve" and r._field == "success")
|> aggregateWindow(every: 1h, fn: mean)
|> map(fn: (r) => ({r with _value: r._value * 100.0}))
|> yield(name: "success_rate")
// Average solve time by type
from(bucket: "captcha_metrics")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "captcha_solve" and r._field == "elapsed_ms" and r.status == "solved")
|> group(columns: ["type"])
|> aggregateWindow(every: 1h, fn: mean)
|> yield(name: "avg_latency")
// Cumulative cost
from(bucket: "captcha_metrics")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "captcha_solve" and r._field == "cost")
|> cumulativeSum()
|> yield(name: "cumulative_cost")
Implementação JavaScript (Prometheus)
const client = require("prom-client");
const axios = require("axios");
const register = new client.Registry();
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const solveTotal = new client.Counter({
name: "captcha_solve_total",
help: "Total CAPTCHA solve attempts",
labelNames: ["type", "status"],
registers: [register],
});
const solveLatency = new client.Histogram({
name: "captcha_solve_latency_seconds",
help: "CAPTCHA solve latency",
labelNames: ["type"],
buckets: [5, 10, 15, 20, 30, 45, 60, 90, 120],
registers: [register],
});
async function solveWithMetrics(sitekey, pageurl, type = "recaptcha_v2") {
const start = Date.now();
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) {
solveTotal.inc({ type, status: "submit_error" });
return { error: submit.data.request };
}
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) {
const elapsed = (Date.now() - start) / 1000;
solveTotal.inc({ type, status: "solved" });
solveLatency.observe({ type }, elapsed);
return { solution: poll.data.request };
}
if (poll.data.request !== "CAPCHA_NOT_READY") {
solveTotal.inc({ type, status: "error" });
return { error: poll.data.request };
}
}
solveTotal.inc({ type, status: "timeout" });
return { error: "TIMEOUT" };
}
// Expose metrics endpoint
const express = require("express");
const app = express();
app.get("/metrics", async (req, res) => {
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
app.listen(9090);
Comparação de banco de dados
| Recurso | Prometeu | InfluxoDB | Escala de tempoDB |
|---|---|---|---|
| mais adequado para | Monitoramento operacional | IoT/métricas de alta cardinalidade | Análise baseada em SQL |
| Linguagem de consulta | PromQL | Fluxo | SQL |
| Retenção | Baseado em configuração | Baseado em políticas | Retenção PostgreSQL |
| Integração Grafana | Nativo | Nativo | Nativo |
| Curva de aprendizado | Baixo | Médio | Baixo (se você conhece SQL) |
| Auto-hospedado | Sim | Sim | Sim (extensão PostgreSQL) |
Solução de problemas
| Problema | Causa | Correção |
|---|---|---|
| Lacunas de métricas no painel | O gateway push não está recebendo dados | Verifique a rede entre o solucionador e o gateway push |
| O histograma de latência mostra percentis errados | Os limites do bucket não correspondem à carga de trabalho | Ajustar intervalos: [5, 10, 15, 20, 30, 45, 60, 90, 120] para resolução de CAPTCHA |
| As métricas de custo não correspondem ao gasto real | Preços diferentes por tipo de CAPTCHA | Tag custo por tipo; usar preços reais por tipo |
| Muita cardinalidade | Muitos valores de rótulo | Limitar rótulos a type, status, error_code |
Perguntas frequentes
Qual banco de dados de série temporal devo usar?
Prometheus, se você já o possui para monitoramento de infraestrutura - basta adicionar métricas CAPTCHA. InfluxDB, se desejar um armazenamento de métricas independente. TimescaleDB, se desejar consultas SQL em dados de séries temporais.
Por quanto tempo devo reter as métricas CAPTCHA?
Mantenha dados de alta resolução (por segundo) por 7 dias, agregados (por hora) por 90 dias e resumos diários indefinidamente. Isso equilibra o custo de armazenamento com a visibilidade das tendências.
Posso detectar automaticamente a degradação da taxa de resolução?
Sim. Defina alertas sobre médias móveis – por exemplo, alerta quando a taxa de sucesso de 1 hora cair abaixo de 90% ou quando a latência P95 exceder 45 segundos. Os alertas Prometheus Alertmanager e InfluxDB suportam isso.
Próximas etapas
Acompanhe o desempenho da resolução de CAPTCHA ao longo do tempo -obtenha sua chave API CaptchaAIe comece a coletar métricas.
Guias relacionados: