DevOps e Escalabilidade

Monitoramento CaptchaAI com Datadog: Métricas e Alertas

Você não pode consertar o que não pode ver. O Datadog oferece visibilidade em tempo real do pipeline de resolução de CAPTCHA – taxas de resolução, percentis de latência, falhas de erros e alertas de anomalia que são acionados antes da interrupção do pipeline.

Principais métricas a serem rastreadas

Métrica Tipo Por que é importante
captcha.solve.count Contador Total de tarefas enviadas
captcha.solve.success Contador Soluções bem-sucedidas
captcha.solve.error Contador Falha na resolução (por tipo de erro)
captcha.solve.latency Histograma Tempo desde o envio até a solução
captcha.queue.depth Medidor Tarefas pendentes na fila
captcha.balance Medidor Saldo restante da API
captcha.worker.active Medidor Processos de trabalho ativos

Python — Integração DogStatsD

import os
import time
import functools
import requests
from datadog import initialize, statsd

# Initialize Datadog
initialize(
    statsd_host=os.environ.get("DD_AGENT_HOST", "localhost"),
    statsd_port=int(os.environ.get("DD_DOGSTATSD_PORT", "8125"))
)

API_KEY = os.environ["CAPTCHAAI_API_KEY"]
session = requests.Session()


def track_captcha_metrics(captcha_type="recaptcha_v2"):
    """Decorator to track solve metrics."""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            tags = [f"captcha_type:{captcha_type}"]
            statsd.increment("captcha.solve.count", tags=tags)

            start = time.time()
            try:
                result = func(*args, **kwargs)
                elapsed = time.time() - start

                if "solution" in result:
                    statsd.increment("captcha.solve.success", tags=tags)
                    statsd.histogram("captcha.solve.latency", elapsed, tags=tags)
                else:
                    error = result.get("error", "unknown")
                    statsd.increment(
                        "captcha.solve.error",
                        tags=tags + [f"error:{error}"]
                    )
                return result
            except Exception as e:
                statsd.increment(
                    "captcha.solve.error",
                    tags=tags + [f"error:{type(e).__name__}"]
                )
                raise
        return wrapper
    return decorator


@track_captcha_metrics(captcha_type="recaptcha_v2")
def solve_recaptcha(sitekey, pageurl):
    resp = session.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:
        return {"error": data.get("request")}

    captcha_id = data["request"]
    for _ in range(60):
        time.sleep(5)
        result = session.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": captcha_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return {"solution": result["request"]}
        if result.get("request") != "CAPCHA_NOT_READY":
            return {"error": result.get("request")}
    return {"error": "TIMEOUT"}


def report_balance():
    """Send balance as a gauge metric."""
    resp = session.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY, "action": "getbalance", "json": 1
    })
    data = resp.json()
    if data.get("status") == 1:
        balance = float(data["request"])
        statsd.gauge("captcha.balance", balance)
        return balance
    return None


def report_queue_depth(depth):
    """Report current queue depth."""
    statsd.gauge("captcha.queue.depth", depth)


def report_worker_count(active, total):
    """Report worker health."""
    statsd.gauge("captcha.worker.active", active)
    statsd.gauge("captcha.worker.total", total)

JavaScript – Integração Datadog

const { StatsD } = require("hot-shots");
const axios = require("axios");

const API_KEY = process.env.CAPTCHAAI_API_KEY;

const dogstatsd = new StatsD({
  host: process.env.DD_AGENT_HOST || "localhost",
  port: parseInt(process.env.DD_DOGSTATSD_PORT || "8125", 10),
  prefix: "captcha.",
  globalTags: [`env:${process.env.NODE_ENV || "development"}`],
});

async function solveCaptchaWithMetrics(sitekey, pageurl, captchaType = "recaptcha_v2") {
  const tags = [`captcha_type:${captchaType}`];
  dogstatsd.increment("solve.count", 1, tags);
  const startTime = Date.now();

  try {
    const result = await solveCaptcha(sitekey, pageurl);
    const elapsed = (Date.now() - startTime) / 1000;

    if (result.solution) {
      dogstatsd.increment("solve.success", 1, tags);
      dogstatsd.histogram("solve.latency", elapsed, tags);
    } else {
      dogstatsd.increment("solve.error", 1, [...tags, `error:${result.error}`]);
    }

    return result;
  } catch (err) {
    dogstatsd.increment("solve.error", 1, [...tags, `error:${err.message}`]);
    throw err;
  }
}

async function solveCaptcha(sitekey, pageurl) {
  const submitResp = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: pageurl,
      json: 1,
    },
  });

  if (submitResp.data.status !== 1) {
    return { error: submitResp.data.request };
  }

  const captchaId = submitResp.data.request;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const pollResp = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
    });
    if (pollResp.data.status === 1) return { solution: pollResp.data.request };
    if (pollResp.data.request !== "CAPCHA_NOT_READY") {
      return { error: pollResp.data.request };
    }
  }
  return { error: "TIMEOUT" };
}

async function reportBalance() {
  try {
    const resp = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "getbalance", json: 1 },
    });
    if (resp.data.status === 1) {
      const balance = parseFloat(resp.data.request);
      dogstatsd.gauge("balance", balance);
      return balance;
    }
  } catch (err) {
    console.error("Balance check failed:", err.message);
  }
  return null;
}

// Report balance every minute
setInterval(reportBalance, 60000);

module.exports = { solveCaptchaWithMetrics, reportBalance };

JSON do painel Datadog

Importe este modelo JSON para o Datadog para criar um painel de monitoramento CAPTCHA:

{
  "title": "CaptchaAI Pipeline",
  "widgets": [
    {
      "definition": {
        "type": "timeseries",
        "title": "Solve Rate (Success vs Error)",
        "requests": [
          {"q": "sum:captcha.solve.success{*}.as_count()"},
          {"q": "sum:captcha.solve.error{*}.as_count()"}
        ]
      }
    },
    {
      "definition": {
        "type": "timeseries",
        "title": "Solve Latency (p50, p95, p99)",
        "requests": [
          {"q": "avg:captcha.solve.latency{*}"},
          {"q": "percentile:captcha.solve.latency{*},0.95"},
          {"q": "percentile:captcha.solve.latency{*},0.99"}
        ]
      }
    },
    {
      "definition": {
        "type": "query_value",
        "title": "API Balance",
        "requests": [{"q": "avg:captcha.balance{*}"}]
      }
    },
    {
      "definition": {
        "type": "timeseries",
        "title": "Queue Depth",
        "requests": [{"q": "avg:captcha.queue.depth{*}"}]
      }
    }
  ]
}

Definições de alerta

Alerta Condição Gravidade
Saldo baixo captcha.balance < 10 Aviso
Equilíbrio crítico captcha.balance < 2 Crítico
Alta taxa de erro Taxa de erro > 10% em 5 minutos Aviso
Pico de latência latência p95 > 120s em 10 minutos Aviso
Backup de fila Profundidade da fila > 100 crescendo por 5 min Aviso
Trabalhador caído captcha.worker.active == 0 Crítico
# Datadog monitor definition (API create)
- type: metric alert
  name: "CaptchaAI Low Balance"
  query: "avg(last_5m):avg:captcha.balance{*} < 10"
  message: "CaptchaAI balance is low: {{value}}. Top up to avoid solve failures."
  tags:

    - team:scraping
    - service:captcha

Solução de problemas

Problema Causa Correção
Métricas não aparecem Agente DogStatsD não está em execução Verifique DD_AGENT_HOST; verifique docker ps para contêiner de agente
Histograma de latência vazio Nenhuma solução bem-sucedida rastreada Verifique se statsd.histogram() foi chamado no caminho de sucesso
Tags faltando Formato de tag incorreto Utilize o formato key:value; sem espaços nas tags
Métricas duplicadas Vários repórteres correndo Garanta apenas um relator de equilíbrio por implantação

Perguntas frequentes

Preciso de um agente Datadog para cada trabalhador?

Execute um agente DogStatsD por host. Todos os trabalhadores nesse host enviam métricas para o agente local, que encaminha para a entrada do Datadog.

Quanto custam as métricas personalizadas do Datadog?

O Datadog cobra por série temporal de métricas personalizadas. As 7 métricas acima com algumas combinações de tags normalmente ficam dentro dos limites do nível gratuito. Verifique os preços do Datadog para saber os custos exatos.

Posso usar rastreamentos do Datadog APM em vez de métricas personalizadas?

Sim. Envolva sua função de resolução com ddtrace para obter rastreamento automático. No entanto, as métricas personalizadas oferecem mais controle sobre agregação e alertas.

Artigos relacionados

Próximas etapas

Obtenha observabilidade em seu pipeline CAPTCHA -comece com uma chave de API CaptchaAIe conecte-se ao Datadog.

Guias relacionados:

Os comentários estão desativados para este artigo.