Las métricas de un momento dado le indican lo que está sucediendo ahora. Los datos de series de tiempo le indican qué cambió, cuándo cambió y si algo tiende a convertirse en un problema. Realice un seguimiento de las tasas de resolución de CAPTCHA, la latencia y el costo a lo largo del tiempo para detectar la degradación antes de que afecte su canalización.
Qué rastrear
| Métrica | Tipo | ¿Por qué? |
|---|---|---|
| Tasa de resolución (%) | Calibre | Detectar cambios en la calidad del proveedor |
| Resolver latencia (ms) | histograma | Detecte desaceleraciones, planifique tiempos de espera |
| Tasa de error por código | Contador | Identificar patrones de error emergentes |
| Costo por resolución ($) | Calibre | Seguimiento de presupuesto, detección de anomalías. |
| Profundidad de la cola | Calibre | Planificación de capacidad |
| Los tokens expiraron antes de su uso. | Contador | Señal de sintonización TTL |
| Saldo API | Calibre | Gatillo de recarga |
Prometeo + Python (Push Gateway)
Instrumente su 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 de Prometeo
# 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
Escribir métricas de resolución
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 de InfluxDB (flujo)
// 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")
Implementación de 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);
Comparación de bases de datos
| Característica | Prometeo | InflujoDB | Escala de tiempoDB |
|---|---|---|---|
| Lo mejor para | Monitoreo operativo | IoT/métricas de alta cardinalidad | Análisis basado en SQL |
| Lenguaje de consulta | PromQL | flujo | SQL |
| Retención | Basado en configuración | Basado en políticas | Retención de PostgreSQL |
| Integración de Grafana | Nativo | Nativo | Nativo |
| Curva de aprendizaje | Bajo | Medio | Bajo (si conoce SQL) |
| Autohospedado | si | si | Sí (extensión PostgreSQL) |
Solución de problemas
| Problema | causa | Solución |
|---|---|---|
| Brechas de métricas en el panel | La puerta de enlace push no recibe datos | Verifique la red entre el solucionador y la puerta de enlace push |
| El histograma de latencia muestra percentiles incorrectos | Los límites del segmento no coinciden con la carga de trabajo | Ajustar cubos: [5, 10, 15, 20, 30, 45, 60, 90, 120] para resolver CAPTCHA |
| Las métricas de costos no coinciden con el gasto real | Diferentes precios por tipo CAPTCHA | Costo de etiqueta por tipo; utilizar precios reales por tipo |
| Demasiada cardinalidad | Demasiados valores de etiqueta | Limitar etiquetas a type, status, error_code |
Preguntas frecuentes
¿Qué base de datos de series temporales debo utilizar?
Prometheus si ya lo tiene para monitoreo de infraestructura, simplemente agregue métricas CAPTCHA. InfluxDB si desea un almacén de métricas independiente. TimescaleDB si desea consultas SQL sobre datos de series temporales.
¿Cuánto tiempo debo conservar las métricas CAPTCHA?
Mantenga datos de alta resolución (por segundo) durante 7 días, agregados (por hora) durante 90 días y resúmenes diarios de forma indefinida. Esto equilibra el costo de almacenamiento con la visibilidad de las tendencias.
¿Puedo detectar la degradación de la tasa de resolución automáticamente?
Sí. Establezca alertas en promedios móviles, por ejemplo, alerta cuando la tasa de éxito de 1 hora cae por debajo del 90 % o cuando la latencia P95 supera los 45 segundos. Tanto las alertas de Prometheus Alertmanager como las de InfluxDB lo admiten.
Próximos pasos
Realice un seguimiento de su rendimiento de resolución de CAPTCHA a lo largo del tiempo.obtenga su clave API CaptchaAIy comenzar a recopilar métricas.
Guías relacionadas:
- Plantillas de panel de Grafana
- SLIZ/SLO Monitoreo
- Historia del CAPTCHA de MongoDB