Contents
تخبرك مقاييس النقطة الزمنية بما يحدث الآن. تخبرك بيانات السلاسل الزمنية بما تغير، ومتى تغير، وما إذا كان هناك شيء ما يتجه نحو مشكلة. يقوم تتبع اختبار CAPTCHA بحل المعدلات وزمن الوصول والتكلفة بمرور الوقت لرصد التدهور قبل أن يؤثر على مسار التدفق لديك.
ما يجب تتبعه
متري
النوع
لماذا
معدل الحل (%)
مقياس
كشف تغييرات جودة الموفر
حل الكمون (ملي ثانية)
الرسم البياني
بقعة التباطؤ، مهلة الخطة
معدل الخطأ حسب الكود
عداد
تحديد أنماط الخطأ الناشئة
تكلفة الحل ($)
مقياس
تتبع الميزانية، والكشف عن الشذوذ
عمق قائمة الانتظار
مقياس
تخطيط القدرات
انتهت صلاحية الرموز قبل الاستخدام
عداد
إشارة ضبط TTL
رصيد واجهة برمجة التطبيقات
مقياس
إعادة ملء المحفّز
بروميثيوس + بايثون (بوابة الدفع) أداة الخاص بك 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
استفسارات بروميثيوس # 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])
إنفلوكس دي بي + بايثون كتابة حل المقاييس 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)
استعلامات InfluxDB (تدفق) // 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")
تنفيذ JavaScript (بروميثيوس) 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);
مقارنة قاعدة البيانات
ميزة
بروميثيوس
InfluxDB
TimescaleDB
الأفضل ل
المراقبة التشغيلية
إنترنت الأشياء / مقاييس الترابط العالي
التحليلات المستندة إلى SQL
لغة الاستعلام
PromQL
الجريان
SQL
الاحتفاظ
على أساس التكوين
على أساس السياسة
الاحتفاظ بـ PostgreSQL
تكامل جرافانا
أصلي
أصلي
أصلي
منحنى التعلم
منخفض
متوسط
منخفض (إذا كنت تعرف SQL)
استضافة ذاتية
نعم
نعم
نعم (امتداد PostgreSQL)
استكشاف الأخطاء وإصلاحها
المشكلة
السبب
الإجراء
يُنشأ الرمز المميز لكن الجهة المستهدفة ترفضه
مفتاح الموقع أو الصفحة أو سياق الجلسة لا يتطابق
التقط المعلمات من جديد وأعد استخدام الرمز داخل جلسة HTTP أو المتصفح نفسها
تنتهي عملية الاستطلاع بمهلة
الفاصل الزمني أو وقت الانتظار أو معالجة الأخطاء صارمة أكثر من اللازم
استطلع كل 5 إلى 10 ثوانٍ وافصل بين انتهاء المهلة والأخطاء الفعلية وسجّل السبب
ينجح المثال محليًا لكنه يفشل داخل سير العمل
رد النداء أو حقل النموذج أو حقن الرمز مفقود في السلسلة الفعلية
تحقق من المسار الكامل بين أداة الحل والطلب النهائي إلى الموقع المستهدف
الخطوات التالية أدلة ذات صلة