> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# عرض توضيحي لـ HackerNews Analyzer

> زوّد تطبيق Node.js بالتتبّع باستخدام agent وأرسل السجلات والتتبّعات والمقاييس وإعادة تشغيل الجلسة إلى ClickStack

export const AgentPrompt = ({prompt, title = "إعداد بمساعدة الوكيل", description, outline, outlineLabel = "ما سيقوم به الوكيل", repositoryUrl, repositoryLabel = "ClickHouse/agent-skills"}) => {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    const copyWithTextArea = () => {
      const textArea = document.createElement("textarea");
      textArea.value = prompt;
      textArea.style.position = "fixed";
      textArea.style.opacity = "0";
      document.body.appendChild(textArea);
      textArea.select();
      document.execCommand("copy");
      document.body.removeChild(textArea);
    };
    try {
      if (navigator?.clipboard?.writeText) {
        try {
          await navigator.clipboard.writeText(prompt);
        } catch {
          copyWithTextArea();
        }
      } else {
        copyWithTextArea();
      }
      setCopied(true);
      window.setTimeout(() => setCopied(false), 2000);
    } catch {}
  };
  return <div className="ch-agent-prompt-wrapper" data-mdast="ignore">
      <div className="ch-agent-prompt-main-row">
        <div className="ch-agent-prompt-left">
          <span className="ch-agent-prompt-title">{title}</span>
        </div>
        <div className="ch-agent-prompt-prompt-area" style={{
    overflow: "hidden"
  }}>
          <code className="ch-agent-prompt-prompt-text" style={{
    overflowX: "auto"
  }}>
            {prompt}
          </code>
        </div>
        <button type="button" className="ch-agent-prompt-copy-button" style={{
    boxSizing: "border-box",
    justifyContent: "center",
    minWidth: "8.25rem",
    whiteSpace: "nowrap"
  }} onClick={handleCopy} aria-label={copied ? "تم النسخ" : "نسخ الموجّه"}>
          {copied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <polyline points="20 6 9 17 4 12" />
            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
            </svg>}
          <span style={{
    display: "grid",
    justifyItems: "center"
  }}>
            <span style={{
    gridArea: "1 / 1",
    visibility: copied ? "hidden" : "visible"
  }}>نسخ الموجّه</span>
            <span style={{
    gridArea: "1 / 1",
    visibility: copied ? "visible" : "hidden"
  }}>تم النسخ</span>
          </span>
        </button>
      </div>
      {(description || repositoryUrl) && <div className="ch-agent-prompt-sub-row">
          {description && <span className="ch-agent-prompt-description">{description}</span>}
          {repositoryUrl && <a className="ch-agent-prompt-repository-link" href={repositoryUrl} target="_blank" rel="noopener noreferrer">
              {repositoryLabel}
            </a>}
        </div>}
      {outline?.length > 0 && <details className="ch-agent-prompt-outline">
          <summary className="ch-agent-prompt-outline-summary">
            <svg width="12" height="12" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" className="ch-agent-prompt-outline-chevron" aria-hidden="true">
              <path d="M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd" />
            </svg>
            <span>{outlineLabel}</span>
          </summary>
          <ol className="ch-agent-prompt-outline-list">
            {outline.map((item, index) => <li key={index}>{item}</li>)}
          </ol>
        </details>}
    </div>;
};

<Note>
  **باختصار**

  استنسخ [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer)، واملأ ملف `.env` بنقطة نهاية OTLP والرمز المميز الخاصين بك، ثم ألصق توجيه agent. لا تحتاج الواجهة الخلفية إلى أي عمليات استيراد لـ OpenTelemetry؛ إذ يوصّل agent الحزمة `@hyperdx/node-opentelemetry` عند بدء العملية.

  الوقت المطلوب: نحو 10 دقائق
</Note>

HackerNews Analyzer هو تطبيق Node.js يستعلم عن مجموعة بيانات HackerNews المستضافة في العرض التجريبي العام لـ ClickHouse. كل مخطط وجدول ومربع بحث هو استعلام ClickHouse حقيقي، لذا ينتج كل تفاعل trace تكون الـ span الرئيسية فيه هي استدعاء HTTPS من الواجهة الخلفية إلى ClickHouse.

هذه مهمة مختلفة عن [العرض التجريبي لإعادة تشغيل الجلسة](/ar/clickstack/example-datasets/session-replay)، الذي يضيف instrumentation إلى تطبيق يعمل في المتصفح فقط باستخدام ClickStack محلي عبر Docker. هنا تحصل على auto-instrumentation للواجهة الخلفية، وspans لاستعلامات ClickHouse، وإعادة تشغيل الجلسة من التطبيق نفسه.

<h2 id="prerequisites">
  المتطلبات الأساسية
</h2>

* Node 18+ وnpm
* نقطة نهاية لـ ClickStack OTLP/HTTP ورمز مميز للاستيعاب:
  * **ClickHouse Cloud:** افتح الخدمة، ثم **ClickStack** → **تهيئة exporter لـ OpenTelemetry** → **متغيرات البيئة**. البروتوكول هو `http/protobuf`. تكون headers بالشكل `authorization=<ingestion token>`، من دون بادئة `Bearer`.
  * **collector محلي:** استخدم `http://localhost:4318`. إذا كان collector غير مؤمَّن، فاترك `authorization=` فارغًا.

<h2 id="clone-the-repository">
  استنسخ المستودع
</h2>

استنسخ [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer)، وثبّت التبعيات، وانسخ قالب ملف البيئة:

```bash theme={null}
git clone https://github.com/ClickHouse/hn-news-analyzer.git
cd hn-news-analyzer
npm install
cp .env.example .env
```

ستملأ ملف `.env` في الخطوات التالية، ثم جهّز التطبيق لإرسال بيانات التتبّع من هذا الدليل.

<h2 id="instrument-the-application">
  أضِف أدوات القياس عن بُعد إلى التطبيق
</h2>

<Steps>
  <Step title="شغّل التطبيق" id="run-the-application">
    من الدليل المستنسخ `hn-news-analyzer`، شغّل التطبيق. يتصل مصدر بيانات ClickHouse افتراضيًا بالعنقود التجريبي العام للقراءة فقط، لذا يعمل دون الحاجة إلى أي إعداد إضافي:

    ```bash theme={null}
    ./run.sh
    ```

    افتح [http://localhost:5001](http://localhost:5001). سترى محدِّدًا للسنة، وإحصاءات موجزة، ومخططًا للنشاط، وجدولي أبرز المستخدمين والنطاقات، ومربع بحث. استكشف التطبيق بالنقر: بدّل السنوات وتعمّق في القصص.

    <Frame>
      <img src="https://mintcdn.com/private-7c7dfe99-parallel-read-in-order-multi-part/j4TqNPW6aWoq7zwy/images/clickstack/getting-started/hackernews_main.webp?fit=max&auto=format&n=j4TqNPW6aWoq7zwy&q=85&s=8893dcb341dbb8cffdf3d78821ce949c" alt="تطبيق HackerNews Analyzer يعمل محليًا" width="2872" height="1474" data-path="images/clickstack/getting-started/hackernews_main.webp" />
    </Frame>

    في هذه المرحلة، يكون التطبيق قيد التشغيل لكنه غير مزوَّد بأدوات التتبّع. لا يعرض ClickStack أي بيانات، إذ ينتظر بيانات التتبّع.
  </Step>

  <Step title="تهيئة البيئة" id="configure-environment">
    تقرأ حِزم SDK متغيرات exporter القياسية لـ OpenTelemetry. وهي غير مُضمَّنة برمجيًا في شيفرة المصدر. افتح `.env` واضبط:

    ```bash theme={null}
    OTEL_SERVICE_NAME=hn-analyzer-api
    OTEL_EXPORTER_OTLP_ENDPOINT=<your-otlp-http-endpoint>
    OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    OTEL_EXPORTER_OTLP_HEADERS=authorization=<your-ingestion-token>
    OTEL_TRACES_EXPORTER=otlp
    OTEL_METRICS_EXPORTER=otlp
    OTEL_LOGS_EXPORTER=otlp
    ```

    `OTEL_EXPORTER_OTLP_ENDPOINT` هي نقطة نهاية OTLP/HTTP (المنفذ `4318`). و`OTEL_EXPORTER_OTLP_HEADERS` هو رأس التفويض، بالصيغة `authorization=<token>` من دون بادئة `Bearer`.

    إذا لم يفرض الجامع مصادقة، فاترك الرمز فارغًا (`OTEL_EXPORTER_OTLP_HEADERS=authorization=`). يجب أن يبقى المتغير موجودًا؛ إذ تتخطى حزمة SDK التهيئة إذا لم يكن معيّنًا أو كان فارغًا بالكامل.

    تعيد Browser SDK استخدام هذه القيم نفسها. يضمّن `vite.config.ts` نقطة النهاية والرمز في الحزمة العامة وقت البناء، لذا استخدم رمز استيعاب مؤقتًا، وليس رمزًا مخصصًا للإنتاج.
  </Step>

  <Step title="زوّد التطبيق بأدوات القياس عن بُعد" id="instrument">
    اختر مسارًا واحدًا. تنتهي المسارات الثلاثة بالتطبيق نفسه المزوّد بأدوات القياس.

    <Tabs>
      <Tab title="إضافة أدوات القياس باستخدام agent" id="instrument-with-an-agent">
        بعد استنساخ المستودع وتعبئة ملف `.env`، الصق هذا الـprompt في agent برمجي **من داخل ذلك الدليل** لإضافة أدوات القياس إلى التطبيق.

        <AgentPrompt
          prompt="استخدم curl لتنزيل هذا الملف وقراءته واتباع تعليماته: github.com/ClickHouse/hn-news-analyzer/blob/main/agent.md"
          description="بعد استنساخ hn-news-analyzer وتعبئة .env، شغّل هذا الـprompt من داخل ذلك الدليل. يعمل مع Claude Code وCursor وCodex وغير ذلك من coding agents."
          outline={[
"تأكد من أنك في دليل hn-news-analyzer المستنسخ وأن ملف .env يحتوي بالفعل على قيم OTEL_EXPORTER_OTLP_*. توقّف إذا كان أي منهما مفقودًا.",
"ثبّت @hyperdx/node-opentelemetry وغيّر run.sh لاستخدام opentelemetry-instrument.",
"ثبّت @hyperdx/browser وفعّل HyperDX.init وHyperDX.addAction.",
"شغّل التطبيق، وتأكد من اجتياز فحوصات health لـOTLP، ثم اطلب مني التنقل في التطبيق على http://localhost:5001.",
]}
        />
      </Tab>

      <Tab title="إضافة أدوات القياس يدويًا" id="instrument-manually">
        تتضمن إضافة أدوات القياس ثلاثة أجزاء: تثبيت SDKs، وتغيير أمر التشغيل، وتفعيل Browser SDK. ولا يغيّر أي منها business logic للتطبيق.

        <h3 id="install-node-sdk">
          تثبيت Node SDK
        </h3>

        ```bash theme={null}
        npm install @hyperdx/node-opentelemetry
        ```

        <h3 id="enable-run-sh-wrapper">
          تفعيل wrapper في run.sh
        </h3>

        يوجد سطرا `exec` في نهاية `run.sh`. علّق سطر `node` العادي وأزل التعليق عن السطر المزوّد بأدوات القياس:

        ```diff theme={null}
         # قبل: node عادي، بلا أدوات قياس:
        -exec node scripts/entrypoint.js
        +# exec node scripts/entrypoint.js

         # بعد: المصدر نفسه، مُغلّف بواسطة opentelemetry-instrument:
        -# exec npx opentelemetry-instrument scripts/entrypoint.js
        +exec npx opentelemetry-instrument scripts/entrypoint.js
        ```

        استمر في التشغيل عبر `scripts/entrypoint.js`. يستدعي هذا البرنامج الوسيط `require('console')` حتى يلتف التقاط console حول `console.log`. يؤدي توجيه `opentelemetry-instrument` مباشرةً إلى `dist/server/index.js` إلى إرسال traces، لكنه يُسقط logs بصمت.

        <h3 id="enable-browser-sdk">
          تفعيل Browser SDK
        </h3>

        ```bash theme={null}
        npm install @hyperdx/browser
        ```

        في `src/web/telemetry.ts`، أزل التعليق عن سطر الاستيراد وكتلة `HyperDX.init({...})` و`HyperDX.addAction` في `recordAction()`:

        ```diff theme={null}
        -// import HyperDX from '@hyperdx/browser';
        +import HyperDX from '@hyperdx/browser';

         export function initTelemetry(): void {
        -  // HyperDX.init({
        -  //   url: __OTLP_ENDPOINT__,
        -  //   apiKey: __OTLP_AUTH_TOKEN__,
        -  //   service: 'hn-analyzer-web',
        -  //   tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
        -  //   consoleCapture: true,
        -  //   advancedNetworkCapture: true,
        -  // });
        +  HyperDX.init({
        +    url: __OTLP_ENDPOINT__,
        +    apiKey: __OTLP_AUTH_TOKEN__,
        +    service: 'hn-analyzer-web',
        +    tracePropagationTargets: [/localhost:5001/i, /\/api\//i],
        +    consoleCapture: true,
        +    advancedNetworkCapture: true,
        +  });
         }
        ```

        إن `__OTLP_ENDPOINT__` و`__OTLP_AUTH_TOKEN__` ثوابت وقت الترجمة البرمجية، ويحقنها `vite.config.ts` من قيم `OTEL_EXPORTER_OTLP_*` نفسها التي تستخدمها الواجهة الخلفية.

        <Warning>
          يُضمَّن token الاستيعاب في حزمة المتصفح العامة، ويمكن لأي شخص يفحص علامة تبويب Network قراءته. استخدم token مؤقتًا.
        </Warning>
      </Tab>

      <Tab title="استخدم فرعًا مجهزًا مسبقًا بأدوات القياس" id="use-the-instrumented-branch">
        لتجاوز إضافة أدوات القياس والبدء بتطبيق مجهز بها مسبقًا، نفّذ checkout لفرع [`instrumented`](https://github.com/ClickHouse/hn-news-analyzer/tree/instrumented).

        ```bash theme={null}
        git checkout instrumented
        npm install
        ```

        لا تشغّل `./reset.sh` على هذا الفرع إلا إذا أردت إزالة SDKs.
      </Tab>
    </Tabs>
  </Step>

  <Step title="أنشئ حركة مرور واعرض بيانات التتبّع" id="generate-traffic-and-view-telemetry">
    أعد تشغيل التطبيق لتفعيل أمر التشغيل الجديد وحزمة المتصفح التي أُنشئت حديثًا:

    ```bash theme={null}
    # Ctrl-C the previous run, then:
    ./run.sh
    ```

    تأكد من أن رسالة بدء التشغيل تطبع ثلاثة أسطر «Health check passed» لـ `/v1/traces` و`/v1/metrics` و`/v1/logs`. أعد تحميل علامة تبويب المتصفح لكي يقدّم Vite الحزمة المحدّثة، ثم بدّل بين السنوات وانقر على القصص لإنشاء حركة مرور.

    افتح واجهة مستخدم ClickStack:

    1. انتقل إلى **Search** وطبّق عامل تصفية لآخر 5 دقائق. ستظهر سجلات `hn-analyzer-api` تباعًا.

    <Frame>
      <img src="https://mintcdn.com/private-7c7dfe99-parallel-read-in-order-multi-part/j4TqNPW6aWoq7zwy/images/clickstack/getting-started/instrument_app_clickstack_logs.webp?fit=max&auto=format&n=j4TqNPW6aWoq7zwy&q=85&s=e93104dd5b9ee8d297a451510c1273b3" alt="بحث ClickStack يعرض سجلات hn-analyzer-api من آخر خمس دقائق" width="3018" height="1578" data-path="images/clickstack/getting-started/instrument_app_clickstack_logs.webp" />
    </Frame>

    2. انقر على طلب وتتبّع الـ trace صعودًا. سترى span لمعالج Express، وspan HTTP تابعًا يشير إلى `sql-clickhouse.clickhouse.com` مع مدة شبكة فعلية، وسجلات `console.log` مرتبطة بالـ trace نفسه.

    <Frame>
      <img src="https://mintcdn.com/private-7c7dfe99-parallel-read-in-order-multi-part/j4TqNPW6aWoq7zwy/images/clickstack/getting-started/instrument_app_clickstack_traces.webp?fit=max&auto=format&n=j4TqNPW6aWoq7zwy&q=85&s=a421c9aebd0d2e5966c5193f70c89667" alt="trace في ClickStack يتضمن span لمعالج Express وspan HTTP تابعًا إلى ClickHouse" width="2398" height="1590" data-path="images/clickstack/getting-started/instrument_app_clickstack_traces.webp" />
    </Frame>

    3. افتح **Session Replay** لتشغيل فيديو قابل للتمرير لجلسة متصفح، متزامن مع المخطط الزمني للـ trace.

    <Frame>
      <img src="https://mintcdn.com/private-7c7dfe99-parallel-read-in-order-multi-part/j4TqNPW6aWoq7zwy/images/clickstack/getting-started/instrument_app_clickstack_sessions.webp?fit=max&auto=format&n=j4TqNPW6aWoq7zwy&q=85&s=6d9af2c26c59ee42f2df33f40fd40f62" alt="إعادة تشغيل جلسة ClickStack متزامنة مع المخطط الزمني للـ trace" width="2408" height="1580" data-path="images/clickstack/getting-started/instrument_app_clickstack_sessions.webp" />
    </Frame>

    تظهر السجلات والمقاييس والتتبعات وإعادات تشغيل الجلسات في واجهة المستخدم نفسها، وتستخدم لغة الاستعلام نفسها، وترتبط تلقائيًا.
  </Step>
</Steps>

<h2 id="learn-more">
  تعرّف على المزيد
</h2>

* [HackerNews Analyzer](https://github.com/ClickHouse/hn-news-analyzer): المستودع التجريبي الذي يوضّح هذا الدليل كيفية تزويده بأدوات القياس.
* [إعادة تشغيل الجلسة](/ar/clickstack/features/session-replay): نظرة عامة على الميزة، وخيارات SDK، وعناصر التحكّم في الخصوصية.
* [عرض توضيحي لإعادة تشغيل الجلسة](/ar/clickstack/example-datasets/session-replay): عرض توضيحي مستقل مع مثيل ClickStack محلي.
* [البدء مع ClickStack](/ar/clickstack/getting-started/index): انشر ClickStack وأدخِل أولى بياناتك.
* [كل مجموعات البيانات التجريبية](/ar/clickstack/example-datasets/index): مجموعات بيانات تجريبية وأدلة أخرى.
