شرح Cloudflare Workers Observability لعام

١٧ مايو ٢٠٢٦

Cloudflare Workers Observability Tutorial 2026

للحصول على إمكانية مراقبة (observability) بمستوى الإنتاج لـ Cloudflare Worker في عام 2026، قم بتفعيل Workers Logs في wrangler.toml، وسجل بيانات JSON منظمة بدلاً من النصوص العادية، وقم بخفض head_sampling_rate لإدارة التكلفة في الـ Workers ذات الزيارات العالية، وقم بتصدير تتبعات OTel والسجلات إلى Sentry من خلال مسارات وجهات Cloudflare الجديدة. يربط هذا البرنامج التعليمي هذه العناصر الأربعة معًا — مع Worker قابل للتشغيل، وعرض تجريبي لـ wrangler tail، وكتلة Wrangler الدقيقة لتصدير Sentry، والحسابات المالية لـ Worker يستقبل 15 مليون طلب شهريًا — على wrangler@4.92.01 و @sentry/cloudflare@10.53.12.

ملخص

  • تكون Workers Logs مفعلة افتراضيًا للـ Workers المنشأة حديثًا ولكنها لا تبدأ في استيعاب البيانات إلا بعد إضافة [observability] enabled = true إلى إعدادات Wrangler الخاصة بك.3
  • تحصل خطة Workers المجانية على 200,000 حدث سجل يوميًا مع الاحتفاظ بها لمدة 3 أيام؛ بينما تتضمن الخطة المدفوعة 20 مليون حدث شهريًا مع الاحتفاظ بها لمدة 7 أيام وتكلف 0.60 دولار لكل مليون إضافي.3
  • يحتفظ head_sampling_rate = 0.1 بـ 10% من عمليات الاستدعاء ويقلل التكلفة بنحو 10 أضعاف في الـ Worker ذو الحجم المرتفع — يتم أخذ عينات من الاستدعاءات وليس من أسطر السجلات الفردية، لذا ستظل تحصل على التتبع الكامل للطلبات التي تم أخذ عينات منها.3
  • لتصحيح الأخطاء عبر الجهاز الطرفي (terminal) في الوقت الفعلي، يقوم wrangler tail --status error ببث الاستدعاءات الفاشلة فقط ويتجاوز وضع أخذ العينات في الـ Workers المزدحمة.4
  • لإرسال التتبعات والسجلات إلى Sentry، أضف وجهة من جانب Cloudflare مرة واحدة في لوحة التحكم، ثم وجه [observability.traces] و [observability.logs] إليها من wrangler.toml — لا حاجة لـ Sentry SDK إذا كنت تحتاج فقط إلى بيانات بتنسيق OTel.5
  • إذا كنت تريد التقاط الاستثناءات، وتتبع المسارات (breadcrumbs)، وتتبع الإصدارات باستخدام واجهة Sentry SDK TypeScript، فقم بتثبيت @sentry/cloudflare@10.53.1، وقم بتغليف المعالج الخاص بك بـ Sentry.withSentry، واضبط compatibility_flags = ["nodejs_compat"].26

ما ستتعلمه

  • كيفية تفعيل Workers Logs في wrangler.toml مع كتلة observability الصحيحة
  • كيف يقوم head_sampling_rate فعليًا بأخذ عينات من الطلبات (وليس أسطر السجلات) وكيفية ضبطه
  • كيفية كتابة سجلات JSON منظمة بحيث تقوم لوحة تحكم Workers بفهرسة الحقول تلقائيًا
  • كيفية بث السجلات المباشرة باستخدام wrangler tail وتصفيتها للطلبات التي تهمك
  • كيفية الاختيار بين Workers Logs و Tail Workers و Workers Logpush لإعادة توجيه السجلات خارج المنصة
  • كيفية تصدير تتبعات وسجلات OTel من Worker إلى مشروع Sentry باستخدام وجهات Cloudflare
  • كيفية إضافة @sentry/cloudflare SDK لالتقاط الاستثناءات وتتبع المسارات وسياق التتبع
  • كيفية تقدير الفاتورة لـ Worker يستقبل 15 مليون طلب شهريًا بعد تغيير محاسبة التتبعات في 1 مارس 20267

المتطلبات الأساسية

تحتاج إلى:

  • Node.js 24 LTS (Active) أو Node.js 22 LTS (Maintenance) — كلاهما مدعوم بواسطة Wrangler v4.8
  • حساب Cloudflare — الخطة المجانية كافية لمتابعة أقسام Workers Logs و wrangler tail؛ بينما تتطلب خطوات تصدير OTel و Tail Workers خطة Workers المدفوعة (بحد أدنى 5 دولارات شهريًا).9
  • حساب Sentry — خطة المطورين في Sentry مجانية وتتضمن 5,000 حدث شهريًا مع الاحتفاظ بها لمدة 30 يومًا، وهو ما يكفي تمامًا لمتابعة هذا البرنامج التعليمي. نقاط نهاية تتبعات وسجلات OTLP التي نستخدمها في الخطوة 5 هي حاليًا في المرحلة التجريبية المفتوحة من جانب Sentry.610
  • نظام macOS أو Linux أو Windows مع WSL — يقوم Wrangler بتشغيل خادم التطوير من خلال Workerd؛ يعمل نظام Windows الأصلي ولكن WSL هو المسار الذي تفترضه الوثائق.

تثبيت مجموعة الأدوات:

# Pin Wrangler to a specific patch — `latest` drifts week to week
npm install --save-dev wrangler@4.92.0
npx wrangler --version
# Expected: ⛅️ wrangler 4.92.0

ستحتاج أيضًا إلى مسار Worker منشور لرؤية Workers Logs في لوحة التحكم — يعرض wrangler dev مخرجات وحدة التحكم محليًا، ولكن واجهة مستخدم السجلات لا تعرض إلا استدعاءات الإنتاج.

الخطوة 1: إنشاء هيكل Worker يصدر سجلات واقعية

قم بإنشاء Worker تعليمي باستخدام قالب Hello-World TypeScript. سنضيف سجلات منظمة، ومسار خطأ متعمد، ومسار بطيء بحيث تحتوي البيانات التي نرسلها إلى Sentry على شيء مثير للاهتمام بالفعل.

npm create cloudflare@2.68.2 -- nlt-observability-demo \
  --type=hello-world --lang=ts --git --no-deploy
cd nlt-observability-demo

استبدل src/index.ts بمعالج يسجل البيانات في ثلاثة مستويات ويكشف عن مسارات لتصحيح الأخطاء:

// src/index.ts
export interface Env {
  ENVIRONMENT: string;
}

function logEvent(level: "info" | "warn" | "error", event: Record<string, unknown>) {
  // Always log a plain object — the Workers Logs UI auto-indexes the fields.
  const payload = {
    level,
    timestamp: new Date().toISOString(),
    ...event,
  };
  if (level === "error") {
    console.error(payload);
  } else if (level === "warn") {
    console.warn(payload);
  } else {
    console.log(payload);
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    // Cloudflare augments Request with a `cf` property at runtime; the type
    // ships in @cloudflare/workers-types under IncomingRequestCfProperties.
    const cf = (request as unknown as { cf?: { country?: string } }).cf;
    const requestId = crypto.randomUUID();

    logEvent("info", {
      msg: "request received",
      request_id: requestId,
      method: request.method,
      path: url.pathname,
      country: cf?.country ?? "unknown",
      environment: env.ENVIRONMENT,
    });

if (url.pathname === "/slow") {
      await new Promise((r) => setTimeout(r, 250));
      logEvent("warn", {
        msg: "slow path hit",
        request_id: requestId,
        wait_ms: 250,
      });
      return new Response("slow response\n");
    }

    if (url.pathname === "/boom") {
      logEvent("error", {
        msg: "user triggered boom",
        request_id: requestId,
        path: url.pathname,
      });
      throw new Error("Intentional /boom error for observability testing");
    }

    return new Response(`hello from ${env.ENVIRONMENT}\n`);
  },
};

هناك أمران جديران بالملاحظة قبل المتابعة.

أولاً، يقوم المسجل دائمًا بإصدار كائن، وليس نصًا قالبًا أبدًا. في واجهة مستخدم Workers Logs، يتم فهرسة console.log({ user_id: 123 }) تحت حقل user_id، بينما يتم تخزين console.log("user_id: " + 123) كرسالة غامضة واحدة يمكنك البحث فيها نصيًا فقط.3 البحث في حجم سجلات يبلغ 50 جيجابايت بواسطة حقل مفهرس يكون سريعًا؛ أما البحث النصي فلا.

ثانيًا، يحمل كل سطر سجل request_id. تقوم Workers Logs بالفعل بتمييز كل حدث بمعرف تتبع من جانب Cloudflare، ولكن إضافة request_id الخاص بك يسمح لنفس المعرف بالظهور في تتبعات Sentry اللاحقة، وقاعدة بيانات تطبيقك، وأي واجهات برمجة تطبيقات خارجية يستدعيها الـ Worker — مما يجعل الربط بين الأنظمة أمرًا تافهًا.

الخطوة 2: تفعيل Workers Logs في wrangler.toml

استبدل ملف wrangler.toml الذي تم إنشاؤه بالإعدادات المخصصة للإنتاج أدناه. كتلة observability هي الوحيدة المطلوبة بدقة، ولكن تحديد تاريخ التوافق وتسمية البيئات مبكرًا يوفر عناء الهجرة لاحقًا.

# wrangler.toml
name = "nlt-observability-demo"
main = "src/index.ts"
compatibility_date = "2026-05-15"
compatibility_flags = ["nodejs_compat"]

[vars]
ENVIRONMENT = "development"

[observability]
enabled = true
head_sampling_rate = 1  # 100% — sample everything in dev

[env.staging]
name = "nlt-observability-demo-staging"
vars = { ENVIRONMENT = "staging" }

[env.staging.observability]
enabled = true
head_sampling_rate = 1

[env.production]
name = "nlt-observability-demo-prod"
vars = { ENVIRONMENT = "production" }

[env.production.observability]
enabled = true
head_sampling_rate = 0.1  # 10% — high-volume cost control

ثلاثة تفاصيل يجب استيعابها:

  • observability.enabled = true مطلوب لكتابة السجلات في Workers Logs. مفتاح التبديل في لوحة التحكم يكون مفعلًا افتراضيًا للـ Workers المنشأة حديثًا، ولكن وثائق Cloudflare نفسها صريحة في أنه يجب عليك إضافة الإعداد إلى ملف Wrangler الخاص بك وإعادة النشر ليبدأ الـ Worker فعليًا في استيعاب الأحداث.3
  • يقبل head_sampling_rate أي قيمة في النطاق من 0 إلى 1. إذا كان المعدل 0.1، تقوم Cloudflare بإجراء قرعة لكل استدعاء: 10% من الاستدعاءات يتم تخزين جميع سجلاتها، و90% يتم تجاهلها تمامًا. هذا يختلف جوهريًا عن أخذ العينات على مستوى السطر — استدعاءاتك التي تم أخذ عينات منها تكون سليمة وقابلة للتتبع من request received حتى الاستجابة.3
  • العلم nodejs_compat ليس مطلوباً بشكل صارم لـ Workers Logs، ولكن SDK الخاص بـ @sentry/cloudflare الذي سنضيفه في الخطوة 6 يتطلبه لدعم AsyncLocalStorage.6 ضبطه الآن يتجنب إعادة النشر لاحقاً.

قم بالنشر في بيئة staging وقم بتشغيل بعض الطلبات:

npx wrangler deploy -e staging
curl -i https://nlt-observability-demo-staging.<your-subdomain>.workers.dev/
curl -i https://nlt-observability-demo-staging.<your-subdomain>.workers.dev/slow
curl -is https://nlt-observability-demo-staging.<your-subdomain>.workers.dev/boom | head -1
# المتوقع: HTTP/2 500

في لوحة تحكم Cloudflare، انتقل إلى Workers & Pages ← الـ Worker الخاص بك ← Observability. في غضون 30 ثانية تقريباً، يجب أن ترى ثلاثة سجلات استدعاء (invocation logs)، أحدها باللون الأحمر. انقر فوق استدعاء وسيظهر الجزء الأيمن حقولك المنظمة (request_id، country، environment) كفلاتر قابلة للبحث — وليس كجدار من النص. هذا هو عائد الفهرسة من الخطوة 1.

الخطوة 3: بث السجلات المباشرة باستخدام wrangler tail

لتصحيح الأخطاء النشط، يعد wrangler tail أسرع من لوحة التحكم. فهو يبث الأحداث المنظمة إلى جهازك الطرفي (terminal) عبر WebSocket، ويقبل الفلاتر التي تضيق نطاق تدفق البيانات قبل وصولها إلى الـ shell الخاص بك.

# بث كل استدعاء
npx wrangler tail -e staging

# في نافذة shell أخرى، اطلب الـ Worker عدة مرات
curl https://nlt-observability-demo-staging.<your-subdomain>.workers.dev/
curl -s https://nlt-observability-demo-staging.<your-subdomain>.workers.dev/boom > /dev/null

يعمل wrangler tail على الخطة المجانية وليس له تكلفة لكل طلب، ولكن الـ Worker ذو الحركة المرورية العالية يمكن أن يدفع الـ tail إلى وضع أخذ العينات (sampling mode) — حيث تسقط Cloudflare الرسائل وتحذرك في البث عند حدوث ذلك.4 تساعد الفلاتر عن طريق تقليل حجم الرسائل من جانب الخادم قبل بدء أخذ العينات:

# فقط الاستدعاءات التي كانت نتيجة الـ Worker فيها "error"
# (الاستثناءات غير الملتقطة؛ الـ enum الموثق هو ok | error | canceled[^18])
npx wrangler tail -e staging --status error

# فقط POST + النتيجة=error
npx wrangler tail -e staging --method POST --status error

# مطابقة طلب محدد — مفيد عند تضمين request_id في عناوين URL
npx wrangler tail -e staging --search "abc-123-request-id"

لاحظ أن --status error يقوم بالتصفية حسب نتيجة الاستدعاء التي تسجلها Cloudflare، وليس رمز حالة HTTP الذي أرجعه الـ Worker الخاص بك. المعالج الذي يرجع new Response("not found", { status: 404 }) هو استدعاء ناجح مع outcome=ok؛ المعالج الذي يرمي استثناءً (throws) هو outcome=error؛ وفصل العميل للاتصال في منتصف الاستجابة هو outcome=canceled.11 إذا كنت تريد التصفية حسب حالة HTTP، فاستخدم مصطلح --search على حقل سجل منظم بدلاً من ذلك.

سير عمل عملي أثناء الاستدعاء (on-call) هو إبقاء wrangler tail --status error -e production قيد التشغيل في نافذة tmux أثناء عمليات النشر. في اللحظة التي يبدأ فيها الإصدار في إصدار استثناءات، يظهر الـ stack في جهازك الطرفي مع كائن السجل المنظم الكامل — دون الحاجة للنقر عبر لوحة التحكم.

تفصيل سلوكي يستحق المعرفة: عندما تغير الفلتر في منتصف البث (تقوم بعض الفرق ببرمجة ذلك عبر تبديلات tail --search)، يستغرق الفلتر الجديد ما يصل إلى 60 ثانية ليصبح ساري المفعول من جانب الخادم.12 إذا لم ترَ الأحداث المفلترة على الفور، فانتظر دقيقة قبل افتراض أن شيئاً ما معطل.

الخطوة 4: الاختيار بين Workers Logs و Tail Workers و Logpush

تقدم Cloudflare ثلاث بدائيات متميزة للتعامل مع السجلات، ونادراً ما يكون الخيار الصحيح هو "كلها في وقت واحد". تغطي معظم البرامج التعليمية كل واحدة منها بمعزل عن الأخرى؛ إليك مصفوفة القرار معروضة جنباً إلى جنب:

البدائيةأين تستقر السجلاتالفئةمتى تستخدمها
Workers Logsمتجر تديره Cloudflare، قابل للاستعلام في لوحة التحكم لمدة 3-7 أياممجاني + مدفوعقابلية الملاحظة من الخط الأول؛ تريد الاستعلام دون مغادرة Cloudflare.
Tail WorkersWorker آخر (معالج tail()) تكتبه بنفسكمدفوع + Enterprise13تحتاج إلى توجيه/تحويل مخصص قبل مغادرة السجلات لـ Cloudflare — على سبيل المثال، تنظيف PII، أو الكتابة المزدوجة إلى وجهتين، أو الإرسال إلى SIEM مع مصادقة مخصصة.
Workers LogpushDatadog، New Relic، Splunk، S3، GCS، Azure Blob، وغيرهامدفوع14لديك بالفعل مستودع سجلات وتريد تسليماً تلقائياً بسعر 0.05 دولار لكل مليون حدث مُسلم.14
تصدير OTel إلى Sentry / Honeycomb / Axiom / Grafana / PostHogوجهة OTLP مكونة في لوحة تحكم Cloudflareمدفوعتريد تتبعات وسجلات بتنسيق OTel في أداة تتبع، بدون SDK في كودك.

المصفوفة مهمة للتكلفة. تحاسب Workers Logs وحدها لكل حدث يتم استيعابه (0.60 دولار لكل مليون بعد حزمة الـ 20 مليون المدفوعة). يضيف Logpush مبلغ 0.05 دولار لكل مليون حدث مُسلم فوق ذلك. تحاسب Tail Workers حسب وقت وحدة المعالجة المركزية (CPU) الخاص بها، وليس عدد الطلبات — يمكن لمعالج tail الذي يتصل بـ API خارجي بطيء أن يتجاوز فاتورة الـ Worker المنتج إذا لم تكن حذراً.15

إذا كنت تبدأ من الصفر في عام 2026 وكانت وجهتك هي Sentry (أو Honeycomb، Axiom، Grafana Cloud، PostHog)، فتجاوز Tail Workers و Logpush تماماً واذهب مباشرة إلى مسار تصدير OTel في الخطوة 5. كانت خطوط أنابيب OTel هي السبب الصريح لإعادة تنظيم Cloudflare لمجموعة أدوات قابلية الملاحظة في أوائل عام 2026.16

الخطوة 5: تصدير تتبعات وسجلات OTel إلى Sentry (لا يتطلب SDK)

هذا هو المسار المصمم لعام 2026 والذي تفتقده معظم البرامج التعليمية: يمكنك بث نفس القياسات عن بُعد التي تشغل لوحة تحكم Cloudflare إلى Sentry دون إضافة سطر واحد من JavaScript إلى الـ Worker الخاص بك. يستمر الـ Worker في استخدام console.log، ويقوم التتبع التلقائي من Cloudflare بتجهيز كل استدعاء لمعالج fetch وكل طلب فرعي صادر بمجرد الاشتراك باستخدام [observability.traces]، وتقوم ميزة "Pipelines" الجديدة في Workers Observability بإعادة توجيه كلا التدفقين إلى نقطة نهاية Sentry OTLP.

تنبيه قبل توصيل هذا: استيعاب تتبعات وسجلات OTLP في Sentry في مرحلة البيتا المفتوحة اعتباراً من مايو 2026 — وهي متاحة لجميع العملاء، ولكن يمكن أن تتغير مساحة السطح.10 كما لا يزال التتبع التلقائي من Cloudflare يحمل علامة Beta. خلال فترة البيتا، يؤدي observability.enabled = true وحده إلى تشغيل السجلات فقط؛ تتطلب التتبعات كتلة [observability.traces] الإضافية التي نضيفها في الخطوة 5ج.7 بدأ الفوترة لاستخدام التتبع في 1 مارس 2026.7

5أ. إنشاء مشروع Sentry ونسخ تفاصيل OTLP الخاصة بك

في Sentry، انتقل إلى Insights ← Projects ← New Project، واختر المنصة التي تطابق ما كنت ستجهزه لولا ذلك (أي نكهة من JavaScript جيدة)، وقم بإنشائه. ثم انتقل إلى Settings ← Projects ← <your project> ← Client Keys (DSN) وانتقل لأسفل إلى OpenTelemetry (OTLP).5 سترى نقطتي نهاية وترويسة مصادقة واحدة:

OTLP Traces Endpoint: https://o0000000.ingest.sentry.io/API/0000000/integration/otlp/v1/traces
OTLP Logs Endpoint:   https://o0000000.ingest.sentry.io/API/0000000/integration/otlp/v1/logs
Header:               x-sentry-auth: sentry sentry_key=abcd1234...

قيمة sentry_key= هي المفتاح العام لمشروع Sentry الخاص بك (نفس المفتاح الموجود داخل DSN)، وليس رمزاً سرياً — فهو يحدد المشروع لطبقة استيعاب Sentry.

5ب. إضافة الوجهات في لوحة تحكم Cloudflare

في لوحة تحكم Cloudflare، انتقل إلى Workers & Pages ← Observability ← Pipelines وانقر على Add destination مرتين — مرة للتتبعات (traces)، ومرة للسجلات (logs).5

لوجهة التتبعات (traces):

  • اسم الوجهة: sentry-traces
  • نوع الوجهة: Traces
  • نقطة نهاية OTLP: نقطة نهاية OTLP Traces من Sentry
  • رأس مخصص (Custom Header): x-sentry-authsentry sentry_key={SENTRY_PUBLIC_KEY} (قم بلصق السلسلة النصية كما عرضها لك Sentry تماماً)

لوجهة السجلات (logs):

  • اسم الوجهة: sentry-logs
  • نوع الوجهة: Logs
  • نقطة نهاية OTLP: نقطة نهاية OTLP Logs
  • رأس مخصص (Custom Header): x-sentry-auth ← نفس القيمة المذكورة أعلاه

احفظ كل وجهة — ستظهر لوحة التحكم خطأً إذا كانت نقطة النهاية غير قابلة للوصول أو إذا كان رأس المصادقة (auth header) غير صحيح، وبذلك يتم اكتشاف الأخطاء المطبعية الشائعة قبل أن يقوم الـ Worker بإرسال أي بيانات.

5c. وجه الـ Worker الخاص بك إلى الوجهات

أضف توجيه التتبع والسجلات إلى wrangler.toml. شكل الكتلة البرمجية (block) مأخوذ مباشرة من صفحة "Export to Sentry" في Cloudflare:5

# Append to wrangler.toml
[observability.traces]
enabled = true
destinations = ["sentry-traces"]  # Must match the Cloudflare dashboard name

[observability.logs]
enabled = true
destinations = ["sentry-logs"]

انشر في بيئة الإنتاج (production):

npx wrangler deploy -e production

إذا كنت تريد تفعيل تصدير OTel لبيئة الإنتاج فقط، فسيتم وضع نفس الكتل البرمجية تحت [env.production.observability.traces] و [env.production.observability.logs]. يتم تكوين الوجهات مرة واحدة في لوحة تحكم Cloudflare على مستوى الحساب، لذا فإن نفس الاسم (sentry-traces) سيعمل بنفس الطريقة بغض النظر عن البيئة التي يتم النشر فيها.5

قم بزيارة الـ Worker عدة مرات وتحقق من Sentry. تحذر الوثائق من أن الأمر قد يستغرق بضع دقائق بعد أول عملية نشر لظهور البيانات.5 بمجرد ظهورها، انتقل إلى Explore ← Traces في Sentry — سترى تتبعاً لكل استدعاء للـ Worker، مع فترات زمنية (spans) لأي طلبات فرعية (fetch subrequests) قام بها الـ Worker. تعرض Explore ← Logs بيانات JSON المنظمة التي قمنا بإعدادها في الخطوة 1، مع نفس الحقول (request_id، country، environment) التي أصبحت الآن قابلة للبحث داخل Sentry أيضاً.

تفصيل سلوكي ستحتاج إلى توضيحه في دليل التشغيل (runbook) الخاص بك: بدأ تفعيل تغيير محاسبة التتبع في Cloudflare في 1 مارس 2026. يتم الآن احتساب كل فترة زمنية (span) مقابل نفس الحصة والسعر لكل مليون مثل السجلات — 20 مليوناً متضمنة في الخطة المدفوعة (Paid)، و0.60 دولار لكل مليون إضافي.7 الـ Worker الذي يرسل تتبعاً واحداً لكل طلب ويكون خاملاً بخلاف ذلك لن يكلفك الكثير، ولكن نمط التشعب (fan-out) (استدعاء واحد للـ Worker يقوم بستة طلبات فرعية يولد سبع فترات زمنية) يمكن أن يضاعف الفاتورة بسرعة. اضبط head_sampling_rate وفقاً لذلك.

الخطوة 6: إضافة SDK الخاص بـ @sentry/cloudflare لالتقاط الاستثناءات وسياق أغنى

مسار تصدير OTel سريع الإعداد وممتاز للتتبعات والسجلات المنظمة، لكنه لا يمنحك مجموعة ميزات SDK الكاملة من Sentry: مثل فتات الخبز (breadcrumbs)، وتتبع الإصدارات (release tracking)، والسياقات المخصصة، واستدعاءات Sentry.captureException في كودك الخاص، والقدرة على إثراء الأحداث بالوسوم (tags) ومعرفات المستخدمين. لهذا الغرض، قم بتثبيت SDK.

npm install @sentry/cloudflare@10.53.1

قم بتحديث src/index.ts لتغليف المعالج (handler) بـ Sentry.withSentry:

// src/index.ts
import * as Sentry from "@sentry/cloudflare";

export interface Env {
  ENVIRONMENT: string;
  SENTRY_DSN: string;
  CF_VERSION_METADATA: { id: string; tag: string };
}

const handler: ExportedHandler<Env> = {
  async fetch(request, env): Promise<Response> {
    const url = new URL(request.url);
    const requestId = crypto.randomUUID();

    // Attach the request_id to every Sentry event for this invocation
    Sentry.setTag("request_id", requestId);

    if (url.pathname === "/slow") {
      // Wrap a real subrequest, not setTimeout — performance.now() only
      // advances after I/O in the Workers runtime, so a setTimeout-only
      // span would report 0ms in production.
      return await Sentry.startSpan(
        { op: "http.client", name: "fetch cloudflare trace" },
        async () => {
          const upstream = await fetch("https://www.cloudflare.com/cdn-cgi/trace");
          const body = await upstream.text();
          return new Response(body, { headers: { "content-type": "text/plain" } });
        },
      );
    }

    if (url.pathname === "/boom") {
      throw new Error("Intentional /boom error for observability testing");
    }

    return new Response(`hello from ${env.ENVIRONMENT}\n`);
  },
};

export default Sentry.withSentry(
  (env) => ({
    dsn: env.SENTRY_DSN,
    environment: env.ENVIRONMENT,
    // 10% tracing in prod, 100% in staging — adjust per environment via vars
    tracesSampleRate: env.ENVIRONMENT === "production" ? 0.1 : 1.0,
    enableLogs: true,
    sendDefaultPii: true,
  }),
  handler,
);

أضف الأجزاء المطابقة في wrangler:

# wrangler.toml — additions
# Required by @sentry/cloudflare for AsyncLocalStorage
compatibility_flags = ["nodejs_compat"]

# Auto-detect the release from the deployed Worker version
[version_metadata]
binding = "CF_VERSION_METADATA"

# Source maps for readable stack traces in Sentry
upload_source_maps = true

ثم قم بتخزين DSN كسر (secret) (لا تضعه أبداً كمدخل في [vars]، على الرغم من أن المفتاح العام لـ DSN ليس سراً من الناحية التقنية — لكن الحفاظ على توحيد الأسرار عادة تستحق البناء):

npx wrangler secret put SENTRY_DSN -e production
# Paste your Sentry project's DSN when prompted

قم بالنشر وتفعيل مسار /boom. بعد تأخير قصير — تشير وثائق Sentry إلى أن الأمر يستغرق "بضع لحظات" لظهور الأحداث — سيعرض عرض المشكلات (Issues view) الاستثناء مع تتبع كامل للمكدس (stack trace)، و request_id الذي قمت بوسمه، ومعرف الإصدار الذي تم اكتشافه تلقائياً من CF_VERSION_METADATA.id (SDK الإصدار 10.35.0 فما فوق يقرأه دون استخراج يدوي)،6 وأي فتات خبز (breadcrumbs) جمعها SDK على طول الطريق.

هناك قيدان معروفان يجب وضعهما في اعتبار فريقك:

  • مدة الفترات الزمنية (Span durations) هي 0 مللي ثانية للأعمال التي تعتمد على المعالج فقط — و setTimeout يُحسب كعمل للمعالج. في بيئة تشغيل Cloudflare Workers، تتقدم performance.now() و Date.now() فقط بعد عمليات الإدخال/الإخراج (I/O)، كإجراء وقائي ضد هجمات القنوات الجانبية للتوقيت (timing-side-channel attacks).17 الفترة الزمنية التي تغلف فقط عمليات حسابية متزامنة، أو setTimeout/scheduler.wait بدون أي عمليات إدخال/إخراج أخرى، ستظهر بقيمة 0ms في بيئة الإنتاج (بينما لا تزال تعمل بشكل طبيعي في wrangler dev). قم بتتبع حدود الإدخال/الإخراج الحقيقية — مثل fetch، و KV get، و R2 put، واستعلام D1 — وستمتلئ المدد الزمنية.
  • لا تدفع مرتين مقابل القياس عن بُعد (telemetry). إذا قمت بإعداد تصدير OTel في الخطوة 5 و SDK هنا، فستحصل على نفس التتبع مرتين في Sentry. اختر مساراً واحداً. الـ SDK هو الخيار الصحيح عندما تريد واجهة Sentry الكاملة؛ وخط أنابيب OTel هو الخيار الصحيح عندما تريد إعادة توجيه القياس عن بُعد بدون أي كود إضافي في الـ Worker الخاص بك.

الخطوة 7: تقدير الفاتورة قبل الإطلاق

الخطوة الأكثر استهانة بها في قابلية الملاحظة في بيئة الإنتاج هي إجراء الحسابات مسبقاً. الأرقام لـ Worker يخدم 15 مليون طلب شهرياً، على خطة Workers المدفوعة (أساس 5 دولارات شهرياً9):

الإعدادالسجلات الصادرةالسجلات المحاسب عليهاالفترات الزمنية الصادرةالفترات المحاسب عليها7تكلفة قابلية الملاحظة الشهرية
head_sampling_rate = 1، سجل واحد + سجل استدعاء واحد لكل طلب، بدون تتبعات30 مليون(30 مليون − 20 مليون) × 0.60 دولار/مليون = 6.00 دولار006.00 دولار
head_sampling_rate = 1، سجلات منظمة، تتبعات مفعلة، فترة زمنية واحدة لكل طلب30 مليون6.00 دولار15 مليون(15 مليون تحت الحزمة وحدها، لكن السجلات استهلكت الحزمة بالفعل) ← 15 مليون × 0.60 دولار/مليون = 9.00 دولار15.00 دولار
head_sampling_rate = 0.1، سجل واحد + سجل استدعاء واحد لكل طلب تم أخذ عينة منه، فترة زمنية واحدة لكل طلب تم أخذ عينة منه3 مليون0 (ضمن الحزمة)1.5 مليون0 (ضمن الحزمة)0.00 دولار
نفس الصف 3 بالإضافة إلى Logpush إلى S3 للأحداث التي تم أخذ عينة منها3 مليون تم استيعابها، 3 مليون تم تسليمها01.5 مليون0+ 0.05 دولار/مليون × 3 مليون = 0.15 دولار تسليم

تختبئ ثلاثة دروس في هذا الجدول. أولاً، حزمة الـ 20 مليون في الخطة المدفوعة مشتركة بين السجلات و الفترات الزمنية بدءاً من مارس 2026 — يتم احتسابهما ضمن نفس الحصة.7 ثانياً، head_sampling_rate هو أكبر وسيلة تحكم تملكها: خفض النسبة من 100% إلى 10% في Worker يخدم 15 مليون طلب يخفض فاتورة قابلية الملاحظة بالكامل من 15 دولاراً إلى 0 دولار (باستثناء رسوم الخطة المدفوعة الأساسية البالغة 5 دولارات شهرياً). ثالثاً، Logpush هو تكلفة تسليم إضافية فوق استيعاب سجلات Workers — إذا كانت وجهتك هي Sentry عبر OTel، فستتخطى تكلفة Logpush تماماً.

الخيار العملي الافتراضي للإنتاج لمعظم الفرق هو head_sampling_rate = 0.1 إلى 0.25 في بيئة الإنتاج. العقبة التي تستحق الفهم قبل الإطلاق: أخذ العينات الرأسي (head sampling) يقرر لكل استدعاء، قبل تشغيل المعالج، لذا فإن الطلب الذي يتم استبعاده من العينة والذي يطرح استثناءً لاحقًا يفقد سجلاته (logs) مع كل شيء آخر. لا تزال Cloudflare تسجل المقاييس المجمعة (عدد الطلبات، معدل الخطأ، زمن انتقال P95) بدقة كاملة في لوحة تحكم المقاييس (Metrics Dashboard)،18 لذا سترى أن الأخطاء حدثت — لكن لا يمكنك التعمق في الطلبات الفاشلة الفردية ضمن الـ 90% التي تم إسقاطها.

إذا كنت بحاجة إلى الاحتفاظ بكل خطأ بغض النظر عن أخذ العينات، فإن مخرج الطوارئ الموثق هو إعداد Tail Worker في الخطة المدفوعة (Paid plan). تصف وثائق Cloudflare الـ Tail Workers بأنها تعمل بعد كل استدعاء للمنتج، بشكل منفصل عن قرار أخذ العينات الرأسي لـ Workers-Logs، لذا يمكنك توجيه أحداث الاستثناءات إلى مخزن ثانٍ دون تضخيم استيعاب Workers Logs الأساسي الخاص بك.13 داخل المعالج الرئيسي، قم بتسجيل الخطأ بشكل هيكلي حتى يكون لدى الـ Tail Worker سياق غني للعمل معه:

// Always emit a structured exception log; head sampling decides whether
// it lands in Workers Logs, but a Tail Worker (Paid plan) will see it.
try {
  return await handleRequest(request, env);
} catch (err) {
console.error({
    msg: "request_failed",
    request_id: requestId,
    err_name: (err as Error).name,
    err_message: (err as Error).message,
  });
  throw err;
}

التحقق

بعد النشر بالإعدادات الكاملة أعلاه، قم بإجراء هذا الفحص السريع:

# 1. Confirm Workers Logs is on
npx wrangler deployments list -e production
# The latest deployment's "observability" field should be enabled.

# 2. Generate a known test event
curl -is https://nlt-observability-demo-prod.<your-subdomain>.workers.dev/boom \
  | head -1
# Expected: HTTP/2 500

# 3. Tail it
npx wrangler tail -e production --status error --search "user triggered boom"
# Wait <60s; you should see the structured error event you logged.

# 4. Cross-check Sentry
# Open Sentry → Issues. You should see one new issue with the request_id
# you used. Open it; the Trace tab should show one span tree.

# 5. Check log ingest is metered correctly
# Cloudflare Dashboard → Workers & Pages → Observability → Workers Logs.
# The "Events ingested" counter should match your request count
# multiplied by your `head_sampling_rate` and by (1 + custom_logs_per_request).

إذا نجحت الخطوات من 1 إلى 3 ولكن علامة تبويب تتبع Sentry ظلت فارغة بعد خمس دقائق، فإن السبب الأكثر شيوعًا هو قيمة ترويسة x-sentry-auth في وجهة Cloudflare — أعد نسخها من لوحة "OpenTelemetry (OTLP)" في Sentry بدلاً من كتابتها يدويًا.

الأخطاء الشائعة

"Error: Wrangler requires at least Node.js v20.0.0." قم بتحديث Node — يتطلب Wrangler 4.16 وما بعده إصدار Node 20+، على الرغم من أن الحد الأدنى للإصدار v4 تم توثيقه في الأصل على أنه Node 18.19 قم بتثبيت Node 22 LTS (الصيانة) أو، ويفضل، Node 24 LTS (LTS النشط حتى أكتوبر 2026).

AsyncLocalStorage is not defined بعد ربط @sentry/cloudflare. أضف compatibility_flags = ["nodejs_compat"] إلى wrangler.toml وأعد النشر. تستخدم Sentry SDK ميزة AsyncLocalStorage الخاصة بـ Node لتحديد نطاق السياق عبر القفزات غير المتزامنة، ولا يعرضها وقت تشغيل Workers إلا عند تعيين هذا العلم.6

تظهر تتبعات Sentry جميع النطاقات (spans) بمدة 0ms. هذا متوقع للكود المرتبط بالمعالج (CPU-bound) في وقت تشغيل Workers. تتقدم performance.now() و Date.now() فقط بعد حدود الإدخال/الإخراج (I/O boundary)، لذا فإن النطاقات التي تغلف عمليات حسابية بحتة — بما في ذلك setTimeout أو scheduler.wait بدون أي إدخال/إخراج آخر — تبلغ عن صفر. قم بتغليف مكالمات الإدخال/الإخراج الحقيقية (fetch، KV get، R2 put، استعلام D1) في Sentry.startSpan وستمتلئ المدد.17

واجهة مستخدم Workers Logs لا تظهر أي سجلات على الرغم من أن wrangler tail تظهرها. هناك سببان محتملان. الأول، أن كتلة [observability] في تكوين Wrangler لم يتم نشرها — تأكد باستخدام npx wrangler deployments list من أن أحدث نشر يحمل observability: enabled. الثاني، أنك تجاوزت سقف الـ 5 مليارات يوميًا لكل حساب وقامت Cloudflare بتفعيل عينة رأسية إجبارية بنسبة 1% لبقية يوم UTC.3 كلاهما يتم تصفيره في منتصف الليل بتوقيت UTC.

يدخل Tail في وضع أخذ العينات فورًا على Worker مشغول. استخدم الفلاتر بقوة (--status error، --search "...") — يقلل الفلتر الحجم من جانب الخادم قبل بدء أخذ العينات. تذكر أن الفلاتر تستغرق ما يصل إلى 60 ثانية لتصبح سارية المفعول بعد التغيير.12 لتصحيح الأخطاء المستمر على Worker ذو حركة مرور عالية، إما أن ترسل نسخة من السجلات إلى Tail Worker (مدفوع) أو استخدم Query Builder في لوحة تحكم Workers Logs، والذي يعمل على التدفق الكامل المستوعب بدلاً من تدفق tail المأخوذ منه عينات.18

الخطوات التالية

لديك الآن Worker يصدر سجلات هيكلية، ويأخذ عينات من الاستدعاءات بشكل نظيف، ويظهر الأخطاء في الوقت الفعلي في جهازك الطرفي، ويرسل التتبعات والسجلات إلى Sentry عبر OTLP، ويلتقط الاستثناءات باستخدام Sentry SDK. إلى أين تذهب من هنا:

  • قم بربط نفس نمط وجهة OTel بـ Honeycomb أو Axiom أو Grafana Cloud أو PostHog — تكوين جانب الـ Worker متطابق؛ فقط وجهة لوحة التحكم هي التي تتغير.
  • اجمع هذا الإعداد مع دليل Cloudflare Workers + R2 image-CDN — هذا الـ Worker مرشح ممتاز للتتبع المأخوذ منه عينات لأن مسار إصابة ذاكرة التخزين المؤقت (cache-hit) نشط ومسار التحويل هو المسار الذي تحتاج فعليًا لتصحيح أخطائه.
  • إذا كان الـ Worker الخاص بك يواجه قاعدة بيانات Postgres، فإن دليل تجميع Postgres للإنتاج مع PgBouncer + Supavisor يغطي وسم الاتصالات بـ application_name — نفس الفكرة، مطبقة على طبقة قاعدة البيانات الخاصة بك، بحيث يمكن لمعرف طلب واحد التتبع عبر Worker ← التجميع ← الخلفية.
  • للتنبيه المعتمد على الوكلاء فوق بيانات Sentry الخاصة بك، يتيح خادم Workers Observability MCP من Cloudflare (نقطة النهاية البعيدة https://observability.mcp.cloudflare.com) للعملاء المتوافقين مع MCP الاستعلام عن سجلات ومقاييس Workers الخاصة بك بلغة طبيعية — وهو مفيد لفرز الحالات أثناء المناوبة.20

الحواشي

الحواشي

  1. تم التحقق من إصدار Wrangler مقابل سجل npm في 17 مايو 2026 عبر npm view wrangler version4.92.0. تعرض dist-tags الخاصة بـ npm لـ wrangler أيضًا legacy: 3.114.17 للمستخدمين الذين لا يزالون على الإصدار v3.

  2. تم التحقق من إصدار @sentry/cloudflare عبر npm view @sentry/cloudflare version10.53.1، 17 مايو 2026. 2

  3. وثائق Cloudflare الرسمية، "Workers Logs"، آخر تحديث 06-02-2026. https://developers.cloudflare.com/workers/observability/logs/workers-logs/ 2 3 4 5 6 7

  4. وثائق Cloudflare الرسمية، "Real-time logs". https://developers.cloudflare.com/workers/observability/logs/real-time-logs/ 2

  5. وثائق Cloudflare الرسمية، "Export to Sentry"، آخر تحديث 23-04-2026. https://developers.cloudflare.com/workers/observability/exporting-opentelemetry-data/sentry/ 2 3 4 5 6

  6. وثائق Sentry الرسمية، "Cloudflare". https://docs.sentry.io/platforms/JavaScript/guides/cloudflare/ 2 3 4 5

  7. وثائق Cloudflare الرسمية، "Traces" — يبدأ الفوترة في 1 مارس 2026؛ كل span يعتبر حدث observability واحد، نفس حصة المليون مثل السجلات (logs). https://developers.cloudflare.com/workers/observability/traces/ 2 3 4 5 6

  8. وثائق Cloudflare الرسمية، "Install/Update Wrangler". يدعم Wrangler إصدارات LTS الحالية والنشطة والمدعومة من Node.js. https://developers.cloudflare.com/workers/wrangler/install-and-update/

  9. وثائق Cloudflare الرسمية، "Pricing". خطة Workers Paid تبدأ من 5 دولارات شهرياً كحد أدنى، تشمل 10 ملايين طلب + 30 مليون CPU-ms؛ التكلفة الإضافية هي 0.30 دولار لكل مليون طلب، و0.02 دولار لكل مليون CPU-ms. https://developers.cloudflare.com/workers/platform/pricing/ 2

  10. وثائق Sentry الرسمية، "OpenTelemetry Protocol (OTLP)" — دعم OTLP للآثار (traces) والسجلات (logs) حالياً في المرحلة التجريبية المفتوحة (open beta). https://docs.sentry.io/concepts/otlp/ . حدود خطة Sentry Developer (المجانية) وفقاً لصفحة تسعير Sentry: https://sentry.io/pricing/ 2

  11. وثائق Cloudflare الرسمية، "Wrangler commands". يقبل فلتر wrangler tail --status القيم ok، أو error، أو canceled، مما يعكس تعداد نتائج الاستدعاء المسجلة بواسطة بيئة تشغيل Workers. https://developers.cloudflare.com/workers/wrangler/commands/

  12. وثائق Cloudflare الرسمية، سلوك فلتر wrangler tail — يستغرق ما يصل إلى 60 ثانية حتى تدخل تغييرات الفلتر حيز التنفيذ من جانب الخادم. https://developers.cloudflare.com/workers/wrangler/commands/ 2

  13. وثائق Cloudflare الرسمية، "Tail Workers" — متاحة لعملاء Workers Paid و Enterprise. https://developers.cloudflare.com/workers/observability/logs/tail-workers/ 2

  14. مدونة Cloudflare، "Send Cloudflare Workers logs to a destination of your choice with Workers Trace Events Logpush" — خدمة Workers Logpush متاحة في خطة Workers Paid، بسعر 0.05 دولار لكل مليون حدث يتم تسليمه. https://blog.cloudflare.com/workers-logpush-ga/ 2

  15. مرجع وثائق Cloudflare: يتم فوترة Tail Workers بناءً على وقت المعالج (CPU time). https://developers.cloudflare.com/workers/observability/logs/tail-workers/

  16. سجل تغييرات Cloudflare، "New Best Practices guide for Workers" (15-02-2026) — توصي أفضل الممارسات بتفعيل Workers Logs و Traces وتكوين الـ observability قبل النشر في بيئة الإنتاج. https://developers.cloudflare.com/changelog/post/2026-02-15-workers-best-practices/

  17. وثائق Cloudflare الرسمية، "الأداء والمؤقتات" — performance.now() و Date.now() يتقدمان فقط عند حدود الإدخال/الإخراج (I/O boundaries) كإجراء لتخفيف هجمات التوقيت (timing-attack mitigation). https://developers.cloudflare.com/workers/runtime-apis/performance/ 2

  18. وثائق Cloudflare الرسمية، "المقاييس والتحليلات" — يتم تسجيل المقاييس المجمعة (عدد الطلبات، معدل النجاح، معدل الخطأ، وقت وحدة المعالجة المركزية CPU، المدة، حجم الاستجابة) لكل استدعاء بشكل مستقل عن head_sampling_rate. https://developers.cloudflare.com/workers/observability/metrics-and-analytics/ انظر أيضاً "Query Builder" لتصفية السجلات التي تم استيعابها: https://developers.cloudflare.com/workers/observability/query-builder/ 2

  19. متتبع مشكلات Cloudflare workers-sdk — إصدارات Wrangler v4 الفرعية الأحدث رفعت متطلبات Node العملية إلى v20. https://GitHub.com/cloudflare/workers-sdk/issues/9352

  20. مستودع خادم MCP الرسمي لـ Cloudflare، "workers-observability" — نقطة النهاية البعيدة في https://observability.mcp.cloudflare.com. https://GitHub.com/cloudflare/mcp-server-cloudflare/tree/main/apps/workers-observability


نشرة أسبوعية مجانية

ابقَ على مسار النيرد

بريد واحد أسبوعياً — دورات، مقالات معمّقة، أدوات، وتجارب ذكاء اصطناعي.

بدون إزعاج. إلغاء الاشتراك في أي وقت.