لمراقبة مسار حل CAPTCHA على CaptchaAI داخل New Relic تحتاج إلى ثلاثة عناصر: أحداث مخصصة تسجّل كل عملية حل، ولوحة NRQL تُظهر معدّل النجاح وزمن الحل، وسياسات تنبيه تُنذرك قبل أن يشعر المستخدم بأي بطء. يربط هذا الدليل CaptchaAI بـ New Relic APM في Python وNode.js، فترى كل مرحلة — من إرسال الطلب إلى تسليم الرمز — كبيانات قابلة للقياس على لوحتك بدل أن تكتشف الأعطال من شكاوى المستخدمين لاحقًا.
ماذا تراقب في مسار حل CAPTCHA
يمرّ كل طلب بثلاث مراحل: الإرسال، ثم انتظار الحل عبر الاستطلاع الدوري، ثم استخدام الرمز الناتج. راقب في كل مرحلة المؤشر الذي يكشف اعتلالها مبكرًا — زمن الإرسال وأخطاء الـ API عند الإرسال، ومدة الاستطلاع ونسبة انتهاء المهلة أثناء الانتظار، ومعدّل النجاح عند استخدام الرمز:
[Submit Task] → [Wait for Solution] → [Apply Token]
↓ ↓ ↓
Submit latency Poll duration Token usage
API errors Timeout rate Success rate
أدوات القياس المخصصة في New Relic مع Python
يلتقط الكود التالي كل عملية حل داخل مهمة خلفية واحدة في New Relic. يسجّل نوع CAPTCHA وعنوان الصفحة كسمات مخصصة، ثم يبعث حدثي CaptchaSolveSuccess وCaptchaSolveError مع زمن الحل وعدد مرات الاستطلاع — وهي البيانات التي ستبني عليها لوحاتك وتنبيهاتك لاحقًا. كما تسجّل الدالة report_balance رصيد الحساب كحدث مستقل حتى تراقبه من اللوحة نفسها:
import os
import time
import requests
import newrelic.agent
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
session = requests.Session()
@newrelic.agent.background_task(name="captcha_solve", group="CaptchaAI")
def solve_captcha(sitekey, pageurl, captcha_type="recaptcha_v2"):
"""Solve a CAPTCHA with full New Relic instrumentation."""
# Add custom attributes for filtering
newrelic.agent.add_custom_attributes([
("captcha_type", captcha_type),
("target_url", pageurl),
])
# Submit phase
submit_result = _submit_task(sitekey, pageurl, captcha_type)
if "error" in submit_result:
newrelic.agent.record_custom_event("CaptchaSolveError", {
"error": submit_result["error"],
"phase": "submit",
"captcha_type": captcha_type,
})
return submit_result
# Poll phase
captcha_id = submit_result["captcha_id"]
poll_result = _poll_result(captcha_id, captcha_type)
# Record solve event
event_data = {
"captcha_type": captcha_type,
"captcha_id": captcha_id,
"success": "solution" in poll_result,
}
if "solution" in poll_result:
event_data["solve_time"] = poll_result.get("elapsed", 0)
newrelic.agent.record_custom_event("CaptchaSolveSuccess", event_data)
else:
event_data["error"] = poll_result.get("error", "unknown")
newrelic.agent.record_custom_event("CaptchaSolveError", event_data)
return poll_result
@newrelic.agent.function_trace(name="captcha_submit")
def _submit_task(sitekey, pageurl, captcha_type):
payload = {
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
}
resp = session.post("https://ocr.captchaai.com/in.php", data=payload)
data = resp.json()
newrelic.agent.add_custom_attributes([
("submit_status", data.get("status")),
])
if data.get("status") != 1:
return {"error": data.get("request")}
return {"captcha_id": data["request"]}
@newrelic.agent.function_trace(name="captcha_poll")
def _poll_result(captcha_id, captcha_type):
start = time.time()
poll_count = 0
for _ in range(60):
time.sleep(5)
poll_count += 1
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:
elapsed = time.time() - start
newrelic.agent.add_custom_attributes([
("poll_count", poll_count),
("solve_time_seconds", round(elapsed, 2)),
])
return {"solution": result["request"], "elapsed": elapsed}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
def report_balance():
"""Record balance as a custom event."""
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"])
newrelic.agent.record_custom_event("CaptchaBalance", {
"balance": balance,
"low": balance < 10,
})
return balance
return None
ضبط وكيل New Relic
فعّل الأحداث المخصصة وتتبّع المعاملات في ملف الإعداد حتى تصل بياناتك إلى New Relic. الخيار custom_insights_events.enabled شرط أساسي لظهور أحداث الحل، بينما يحدّد transaction_threshold أي المعاملات تُحفظ تتبّعاتها الكاملة:
# newrelic.ini
[newrelic]
app_name = CaptchaAI Pipeline
license_key = YOUR_NEW_RELIC_LICENSE_KEY
monitor_mode = true
log_level = info
transaction_tracer.enabled = true
transaction_tracer.transaction_threshold = 5.0
custom_insights_events.enabled = true
custom_insights_events.max_samples_stored = 5000
تكامل New Relic مع Node.js
إن كان مسارك يعمل على Node.js، يوفّر المقطع التالي القياس نفسه عبر startBackgroundTransaction وبأسماء الأحداث والسمات ذاتها، ما يبقي لوحاتك موحّدة سواء أرسلت الطلبات من Python أو Node.js. لاحظ حلقة monitorBalance التي تسجّل الرصيد دوريًا كل دقيقة:
const newrelic = require("newrelic");
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
async function solveCaptchaWithNewRelic(sitekey, pageurl, captchaType = "recaptcha_v2") {
return newrelic.startBackgroundTransaction(
"CaptchaSolve",
"CaptchaAI",
async () => {
const transaction = newrelic.getTransaction();
newrelic.addCustomAttributes({
captchaType,
targetUrl: pageurl,
});
const startTime = Date.now();
try {
// Submit
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) {
newrelic.recordCustomEvent("CaptchaSolveError", {
error: submitResp.data.request,
phase: "submit",
captchaType,
});
transaction.end();
return { error: submitResp.data.request };
}
const captchaId = submitResp.data.request;
newrelic.addCustomAttributes({ captchaId });
// Poll
let pollCount = 0;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
pollCount++;
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) {
const elapsed = (Date.now() - startTime) / 1000;
newrelic.recordCustomEvent("CaptchaSolveSuccess", {
captchaType,
solveTime: elapsed,
pollCount,
});
newrelic.addCustomAttributes({
solveTime: elapsed,
pollCount,
});
transaction.end();
return { solution: pollResp.data.request, elapsed };
}
if (pollResp.data.request !== "CAPCHA_NOT_READY") {
newrelic.recordCustomEvent("CaptchaSolveError", {
error: pollResp.data.request,
phase: "poll",
captchaType,
});
transaction.end();
return { error: pollResp.data.request };
}
}
newrelic.recordCustomEvent("CaptchaSolveError", {
error: "TIMEOUT",
phase: "poll",
captchaType,
pollCount,
});
transaction.end();
return { error: "TIMEOUT" };
} catch (err) {
newrelic.noticeError(err);
transaction.end();
throw err;
}
}
);
}
// Balance monitoring
async function monitorBalance() {
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);
newrelic.recordCustomEvent("CaptchaBalance", { balance });
}
} catch (err) {
newrelic.noticeError(err);
}
}
setInterval(monitorBalance, 60000);
module.exports = { solveCaptchaWithNewRelic };
لوحات المعلومات واستعلامات NRQL
بعد أن تتدفّق الأحداث إلى New Relic، تحوّلها استعلامات NRQL إلى لوحة تعرض معدّل النجاح، ومتوسط زمن الحل حسب النوع، وتوزيع الأخطاء، وزمن الحل عند النسبة المئوية 95 (P95)، إضافة إلى منحنى الرصيد وعدد المهام في الدقيقة. أنشئ لوحة معلومات New Relic بالاستعلامات التالية:
-- Solve success rate (last hour)
SELECT percentage(count(*), WHERE success = true)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago
-- Average solve time by CAPTCHA type
SELECT average(solveTime)
FROM CaptchaSolveSuccess
FACET captchaType
SINCE 1 hour ago TIMESERIES
-- Error breakdown
SELECT count(*)
FROM CaptchaSolveError
FACET error
SINCE 1 hour ago
-- P95 solve latency
SELECT percentile(solveTime, 95)
FROM CaptchaSolveSuccess
SINCE 1 hour ago TIMESERIES
-- Balance over time
SELECT latest(balance)
FROM CaptchaBalance
SINCE 24 hours ago TIMESERIES 5 minutes
-- Tasks per minute
SELECT rate(count(*), 1 minute)
FROM CaptchaSolveSuccess, CaptchaSolveError
SINCE 1 hour ago TIMESERIES
سياسات التنبيه في New Relic
لا تكفي اللوحة وحدها لأن أحدًا لن يراقبها ليل نهار. حوّل المؤشرات الحرجة إلى تنبيهات تنطلق تلقائيًا عبر البريد أو قناة الفريق. ابدأ بأربع سياسات تغطّي الجودة والسرعة والرصيد وتصاعد الأخطاء:
| التنبيه | شرط NRQL | العتبة |
|---|---|---|
| انخفاض معدّل الحل | SELECT percentage(count(*), WHERE success = true) |
أقل من 85% لمدة 5 دقائق |
| ارتفاع زمن الحل عند P95 | SELECT percentile(solveTime, 95) FROM CaptchaSolveSuccess |
أكثر من 120 ثانية لمدة 10 دقائق |
| انخفاض الرصيد | SELECT latest(balance) FROM CaptchaBalance |
أقل من 10 دولار |
| تصاعد الأخطاء | SELECT count(*) FROM CaptchaSolveError |
أكثر من 50 خطأ خلال 5 دقائق |
معالجة الأعطال الشائعة
معظم مشكلات هذا التكامل مصدرها إعداد وكيل New Relic لا مسار الحل نفسه. راجع الجدول التالي قبل الغوص في السجلات:
| المشكلة | السبب المحتمل | الحل |
|---|---|---|
| الأحداث المخصصة لا تظهر في New Relic | الخيار custom_insights_events.enabled معطّل |
فعّله في ملف newrelic.ini |
| تتبّعات المعاملات مفقودة | عتبة التتبّع مرتفعة جدًا | اخفض transaction_threshold إلى 1.0 ثانية |
| قيم السمات مبتورة | القيمة أطول من الحد المسموح | أبقِ قيم السمات أقل من 255 حرفًا |
| لا تصل أي بيانات بعد النشر | مفتاح الترخيص خاطئ أو الوكيل لا يبدأ | تحقّق عبر newrelic-admin validate-config newrelic.ini |
سيناريو تشغيلي: مراقبة الذروة في موسم التخفيضات
تخيّل فريق أتمتة في متجر إلكتروني بالخليج يشغّل مسار مقارنة أسعار يحل reCAPTCHA v2 وCloudflare Turnstile آلاف المرات يوميًا. مع اقتراب موسم الجمعة البيضاء يقفز حجم الطلبات، فيرتفع زمن الحل عند P95 تدريجيًا قبل أن ينهار معدّل النجاح. بدون مراقبة، يكتشف الفريق العطل من طلبات ناقصة في نهاية اليوم.
مع تنبيهات New Relic يتغيّر المشهد: ينطلق تنبيه P95 حين يتجاوز 120 ثانية، فيوسّع المهندس المناوب عدد الـ threads في خطته على CaptchaAI قبل أن يتأثر المستخدم. وفي الوقت نفسه، ينبّه شرط الرصيد الفريق حين يقترب من 10 دولار، فيُشحن الحساب قبل أن يتوقّف المسار في ذروة الحملة. هذه هي الفائدة العملية من ربط CaptchaAI بـ New Relic: قرار مبكر بدل تحقيق متأخر.
أسئلة شائعة
هل يعمل هذا التكامل مع أنواع CAPTCHA غير reCAPTCHA v2؟
نعم. تستخدم الأمثلة recaptcha_v2 كقيمة افتراضية فقط؛ مرّر أي نوع مدعوم عبر معامل captcha_type وستظهر النتائج مصنّفة حسب النوع في لوحة NRQL عبر FACET captchaType. من الأنواع التي تراقبها بالطريقة نفسها:
- reCAPTCHA v3 لتقييم درجة السلوك دون تفاعل المستخدم.
- Cloudflare Turnstile كبديل خفيف عن reCAPTCHA.
- GeeTest v3 في المواقع التي تعتمد تحدّي التمرير.
بهذا تقارن زمن الحل ومعدّل النجاح لكل نوع على حدة من لوحة واحدة.
كيف أراقب الرصيد وأتجنّب توقّف المسار بسبب نفاده؟
تسجّل الدالة report_balance رصيد حسابك كحدث CaptchaBalance، ثم تُنشئ تنبيهًا ينطلق حين ينخفض الرصيد عن 10 دولار. اربط هذا التنبيه بقناة إشعارات فريقك لتشحن الرصيد مبكرًا، فلا تتوقّف عمليات الحل في منتصف حملة نشطة.
ما الفرق بين مراقبة CaptchaAI عبر New Relic وDatadog؟
يعتمد الحلّان على الأحداث المخصصة ونفس مسار الإرسال والاستطلاع، فالكود الأساسي واحد تقريبًا. يتميّز New Relic بلغة استعلام NRQL المرنة واللوحات الجاهزة، بينما تختار بعض الفرق Datadog لأنه متكامل مسبقًا مع بقية بنيتها. القاعدة العملية: ابقَ على أداة الرصد التي يستخدمها فريقك أصلًا.
كم مرة يستطلع الكود النتيجة قبل اعتبار المهمة فاشلة؟
تستطلع الحلقة النتيجة حتى 60 مرة بفاصل 5 ثوانٍ، أي مهلة قصوى تناهز 5 دقائق، ثم تُسجَّل المهمة كخطأ TIMEOUT. اضبط عدد المحاولات وطول الفاصل بما يناسب زمن الحل المرصود لديك لكل نوع من أنواع CAPTCHA.
خطوات تالية
- ابدأ سريعًا وحلّ أول كابتشا في 5 دقائق
- دليل حلّ reCAPTCHA v2 عبر الـ API خطوة بخطوة
- حلّ Cloudflare Turnstile عبر الـ API
- حلّ GeeTest v3 عبر الـ API