Pipeline solve CAPTCHA Anda bisa berhenti tanpa ada yang sadar — saldo API habis diam-diam, worker macet, atau latency melonjak saat traffic naik. Datadog menutup celah ini: setiap solve, error, dan sisa saldo jadi metrik real-time, lengkap dengan alert yang aktif sebelum klien atau atasan Anda yang pertama kali sadar ada masalah. Panduan ini membahas metrik custom lewat DogStatsD di Python dan Node.js, dashboard siap pakai dari template JSON, enam alert dasar untuk skenario kegagalan paling umum, dan cara mendiagnosis masalah yang paling sering muncul di lapangan.
Metrik CaptchaAI yang Wajib Dipantau di Datadog
Tujuh metrik ini menutup empat aspek yang menentukan sehat tidaknya pipeline: throughput (task yang diproses), kualitas (berhasil versus gagal), kecepatan (lama solve selesai), dan kapasitas (sisa saldo serta worker). Counter cocok untuk angka yang terus bertambah seperti jumlah task; gauge untuk nilai naik-turun seperti saldo dan queue depth; histogram untuk distribusi seperti latency, karena rata-rata saja menyembunyikan solve paling lambat di p95 dan p99.
| Metrik | Tipe | Mengapa Penting |
|---|---|---|
captcha.solve.count |
Counter | Total task yang di-submit |
captcha.solve.success |
Counter | Solve yang berhasil |
captcha.solve.error |
Counter | Solve yang gagal (per jenis error) |
captcha.solve.latency |
Histogram | Waktu dari submit hingga solusi |
captcha.queue.depth |
Gauge | Task yang pending dalam queue |
captcha.balance |
Gauge | Sisa saldo API |
captcha.worker.active |
Gauge | Worker process yang aktif |
Empat metrik pertama datang dari instrumentasi kode solve Anda sendiri. Tiga sisanya — balance, queue depth, worker active — dilaporkan terpisah dari scheduler, seperti contoh report_balance() di bagian Python berikut.
Integrasi Python: Kirim Metrik ke DogStatsD
Contoh berikut membungkus fungsi solve_recaptcha dengan decorator @track_captcha_metrics, sehingga setiap pemanggilan otomatis mengirim counter solve.count, mencatat error dengan tag jenisnya, dan mengukur latency lewat histogram — tanpa mengubah logic solve itu sendiri. Pola ini praktis kalau Anda punya beberapa fungsi solve untuk tipe CAPTCHA berbeda, karena instrumentasinya cukup ditulis sekali.
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)
functools.wraps menjaga nama dan docstring fungsi asli supaya introspection tidak rusak. Tag captcha_type terpasang di setiap metrik, jadi Anda bisa memecah dashboard per tipe CAPTCHA tanpa query terpisah. Panggil report_balance, report_queue_depth, dan report_worker_count dari scheduler terpisah — cron, Celery beat, atau loop worker — karena ketiganya tidak terikat pada satu solve tertentu.
Integrasi Node.js: DogStatsD dengan hot-shots
Versi Node.js memakai library hot-shots dengan prefix captcha. dan tag global env, supaya metrik staging dan production tidak tercampur. Strukturnya sejalan dengan versi Python: solveCaptchaWithMetrics membungkus pemanggilan solveCaptcha, lalu mencatat count, success, error, dan latency dalam satu alur.
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 };
reportBalance dijalankan lewat setInterval setiap 60 detik, bukan dipicu oleh event solve — cocok untuk metrik gauge yang butuh nilai terbaru secara berkala. Kalau worker Anda berjalan di beberapa proses sekaligus, misalnya PM2 cluster mode atau beberapa container, pastikan hanya satu proses yang menjalankan reportBalance supaya saldo yang sama tidak terkirim berkali-kali.
Dashboard Datadog dari Template JSON
Import JSON ini lewat menu Dashboards > New Dashboard > Import Dashboard JSON di Datadog untuk langsung dapat empat widget: solve rate, latency percentile, saldo API, dan queue depth.
{
"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{*}"}]
}
}
]
}
Tambahkan filter berdasarkan tag captcha_type atau env supaya satu dashboard bisa dipakai bersama tanpa saling menimpa data antar tim. Widget query_value untuk saldo API sebaiknya ditaruh paling atas — ini metrik yang paling sering dilihat sekilas ketika seseorang mengecek apakah pipeline masih hidup.
Alert yang Perlu Disiapkan Lebih Dulu
Enam alert ini menutup skenario kegagalan paling umum: saldo habis, error rate naik, solve melambat, queue menumpuk, dan worker mati total. Saldo kritis dan worker down layak jadi Critical karena keduanya menghentikan pipeline sepenuhnya; empat lainnya cukup Warning karena masih ada waktu untuk investigasi.
| Alert | Kondisi | Severity |
|---|---|---|
| Saldo rendah | captcha.balance < 10 |
Warning |
| Saldo kritis | captcha.balance < 2 |
Critical |
| Error rate tinggi | Error rate > 10% selama 5 menit | Warning |
| Latency spike | p95 latency > 120 detik selama 10 menit | Warning |
| Queue menumpuk | Queue depth > 100 selama 5 menit | Warning |
| Worker down | captcha.worker.active == 0 |
Critical |
Bagi tim scraping atau price-monitoring di Indonesia yang menjalankan worker di region AWS ap-southeast-1 (Singapura) atau GCP asia-southeast2 (Jakarta), traffic padat di jam kerja WIB plus koneksi klien mobile-first sering membuat threshold latency default di atas terlalu longgar. Banyak tim menurunkannya ke 60–90 detik supaya alert menangkap degradasi lebih awal, sebelum antrean task ikut menumpuk.
# 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
Definisi monitor di atas dikirim lewat Datadog API endpoint /api/v1/monitor. Untuk notifikasi di luar email, tambahkan target seperti @slack-nama-channel di field message — atau webhook generik yang diteruskan ke bot Telegram di grup kerja Anda.
Troubleshooting: Metrik atau Alert Tidak Muncul
Sebelum mengubah kode, cek dulu: apakah DogStatsD agent menerima paket (lihat log agent), apakah format tag sudah key:value tanpa spasi, dan apakah hanya satu proses yang mengirim metrik gauge yang sama.
| Masalah | Penyebab | Solusi |
|---|---|---|
| Metrik tidak muncul | DogStatsD agent tidak berjalan | Verifikasi DD_AGENT_HOST; cek docker ps untuk container agent |
| Histogram latency kosong | Tidak ada solve sukses yang terlacak | Periksa apakah statsd.histogram() dipanggil di jalur sukses |
| Tag hilang | Format tag salah | Gunakan format key:value; tidak ada spasi dalam tag |
| Metrik duplikat | Multiple reporter berjalan | Pastikan hanya satu balance reporter per deployment |
Pertanyaan Umum
Apakah DogStatsD agent harus jalan di setiap worker, atau bisa satu agent untuk semua container?
Satu DogStatsD agent per host sudah cukup. Semua proses di host itu — termasuk beberapa container Docker — bisa mengirim metrik ke agent yang sama lewat UDP ke port 8125. Satu agent per container hanya mengalikan biaya custom metric tanpa manfaat tambahan.
Berapa threshold latency yang masuk akal untuk traffic yang banyak datang dari jaringan mobile?
Default p95 di atas 120 detik aman untuk kebanyakan kasus. Tapi untuk situs dengan traffic mobile-first, atau worker di region dengan latensi lebih tinggi, turunkan ke 60–90 detik supaya alert lebih cepat menangkap degradasi.
Bisakah alert Datadog diarahkan ke Slack atau Telegram, bukan cuma email?
Bisa. Datadog punya integrasi native ke Slack dan PagerDuty; untuk grup Telegram, cara paling praktis adalah lewat webhook generik Datadog yang diteruskan ke bot Telegram Anda sendiri.
Apa bedanya counter, gauge, dan histogram, dan kenapa saya perlu ketiganya?
Counter seperti captcha.solve.count hanya bertambah dan cocok untuk total task. Gauge seperti captcha.balance dan captcha.queue.depth mewakili nilai sesaat yang naik-turun. Histogram seperti captcha.solve.latency menyimpan distribusi, jadi Anda bisa melihat p50, p95, dan p99 — bukan cuma rata-rata yang menyembunyikan solve paling lambat.
Perlukah saya membuat dashboard terpisah untuk tiap tipe CAPTCHA seperti reCAPTCHA, Turnstile, dan GeeTest v3?
Tidak perlu. Semua metrik sudah membawa tag captcha_type, jadi satu dashboard dengan filter tag sudah cukup — simpan saved view per tipe hanya kalau tim Anda memang perlu memantau satu tipe secara khusus.
Baca Juga
- Dashboard monitoring penggunaan CaptchaAI
- Monitoring dengan Prometheus dan Grafana
- Pola penanganan error callback CaptchaAI
Jangan tunggu klien yang pertama kali sadar pipeline Anda bermasalah — ambil API key CaptchaAI dan hubungkan solve Anda ke Datadog hari ini.