OpenTelemetry

معلومة مفيدة: هذه الميزة تجريبية، ويجب عليك تفعيلها يدويًا عن طريق إضافة experimental.instrumentationHook = true; في ملف next.config.js.

يعد المراقبة والرصد (Observability) أمرًا بالغ الأهمية لفهم وتحسين سلوك وأداء تطبيق Next.js الخاص بك.

مع زيادة تعقيد التطبيقات، يصبح تحديد وتشخيص المشكلات أكثر صعوبة. من خلال استخدام أدوات المراقبة مثل التسجيل والمقاييس، يمكن للمطورين الحصول على رؤى حول سلوك التطبيق وتحديد مجالات التحسين. تمكنك المراقبة من معالجة المشكلات بشكل استباقي قبل أن تصبح كبيرة، وتقديم تجربة مستخدم أفضل. لذلك، يوصى بشدة باستخدام أدوات المراقبة في تطبيقات Next.js لتحسين الأداء وترشيد الموارد وتعزيز تجربة المستخدم.

نوصي باستخدام OpenTelemetry لتتبع أداء تطبيقاتك. إنها طريقة محايدة للمنصة لتتبع التطبيقات تتيح لك تغيير مزود المراقبة دون تغيير الكود الخاص بك. اقرأ وثائق OpenTelemetry الرسمية لمزيد من المعلومات حول OpenTelemetry وكيفية عمله.

تستخدم هذه الوثائق مصطلحات مثل Span، Trace أو Exporter في جميع أنحاء المستند، ويمكن العثور على جميعها في دليل OpenTelemetry للمراقبة.

يدعم Next.js تتبع OpenTelemetry مباشرةً، مما يعني أننا قمنا بالفعل بتتبع Next.js نفسه. عند تفعيل OpenTelemetry، سنقوم تلقائيًا بتغليف كل الكود الخاص بك مثل getStaticProps في spans مع سمات مفيدة.

البدء

OpenTelemetry قابل للتوسيع ولكن إعداده بشكل صحيح يمكن أن يكون مطولًا. لهذا السبب أعددنا حزمة @vercel/otel لمساعدتك في البدء بسرعة.

استخدام @vercel/otel

للبدء، يجب تثبيت @vercel/otel:

Terminal
npm install @vercel/otel

بعد ذلك، قم بإنشاء ملف instrumentation.ts (أو .js) مخصص في الدليل الجذري للمشروع (أو داخل مجلد src إذا كنت تستخدم واحدًا):

import { registerOTel } from '@vercel/otel'

export function register() {
  registerOTel({ serviceName: 'next-app' })
}
import { registerOTel } from '@vercel/otel'

export function register() {
  registerOTel({ serviceName: 'next-app' })
}

راجع وثائق @vercel/otel لخيارات التكوين الإضافية.

معلومة مفيدة

  • يجب أن يكون ملف instrumentation في جذر مشروعك وليس داخل مجلد app أو pages. إذا كنت تستخدم مجلد src، فضع الملف داخل src بجانب pages و app.
  • إذا كنت تستخدم خيار التكوين pageExtensions لإضافة لاحقة، فستحتاج أيضًا إلى تحديث اسم ملف instrumentation ليتطابق.
  • لقد أنشأنا مثالًا أساسيًا with-opentelemetry يمكنك استخدامه.

تكوين OpenTelemetry يدويًا

توفر حزمة @vercel/otel العديد من خيارات التكوين وتلبي معظم حالات الاستخدام الشائعة. ولكن إذا لم تكن مناسبة لاحتياجاتك، يمكنك تكوين OpenTelemetry يدويًا.

أولاً، تحتاج إلى تثبيت حزم OpenTelemetry:

Terminal
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http

الآن يمكنك تهيئة NodeSDK في ملف instrumentation.ts. على عكس @vercel/otel، فإن NodeSDK غير متوافق مع وقت تشغيل الحافة (edge runtime)، لذا تحتاج إلى التأكد من أنك تستوردها فقط عندما يكون process.env.NEXT_RUNTIME === 'nodejs'. نوصي بإنشاء ملف جديد instrumentation.node.ts تستورده بشكل مشروط فقط عند استخدام node:

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.ts')
  }
}
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await import('./instrumentation.node.js')
  }
}
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'

const sdk = new NodeSDK({
  resource: new Resource({
    [SEMRESATTRS_SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'

const sdk = new NodeSDK({
  resource: new Resource({
    [SEMRESATTRS_SERVICE_NAME]: 'next-app',
  }),
  spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()

هذا يعادل استخدام @vercel/otel، ولكن من الممكن تعديل وتوسيع بعض الميزات التي لا يتم كشفها بواسطة @vercel/otel. إذا كنت بحاجة إلى دعم وقت تشغيل الحافة، فسيتعين عليك استخدام @vercel/otel.

اختبار التتبع الخاص بك

تحتاج إلى جامع OpenTelemetry مع خلفية متوافقة لاختبار تتبع OpenTelemetry محليًا. نوصي باستخدام بيئة تطوير OpenTelemetry الخاصة بنا.

إذا كان كل شيء يعمل بشكل جيد، يجب أن تكون قادرًا على رؤية نطاق الخادم الجذري المسمى كـ GET /requested/pathname. جميع النطاقات الأخرى من هذا التتبع المحدد ستكون متداخلة تحته.

يتتبع Next.js نطاقات أكثر من تلك المنبعثة افتراضيًا. لمشاهدة المزيد من النطاقات، يجب عليك تعيين NEXT_OTEL_VERBOSE=1.

النشر

استخدام جامع OpenTelemetry

عند النشر مع جامع OpenTelemetry، يمكنك استخدام @vercel/otel. سيعمل هذا على كل من Vercel وعند الاستضافة الذاتية.

النشر على Vercel

لقد تأكدنا من أن OpenTelemetry يعمل مباشرةً على Vercel.

اتبع وثائق Vercel لربط مشروعك بمزود المراقبة.

الاستضافة الذاتية

النشر على منصات أخرى هو أيضًا مباشر. ستحتاج إلى تشغيل جامع OpenTelemetry الخاص بك لاستقبال ومعالجة بيانات المراقبة من تطبيق Next.js الخاص بك.

للقيام بذلك، اتبع دليل البدء بجامع OpenTelemetry، والذي سيرشدك خلال إعداد الجامع وتكوينه لاستقبال البيانات من تطبيق Next.js الخاص بك.

بمجرد تشغيل الجامع الخاص بك، يمكنك نشر تطبيق Next.js الخاص بك على المنصة التي تختارها باتباع أدلة النشر الخاصة بهم.

مصدرات مخصصة

جامع OpenTelemetry ليس ضروريًا. يمكنك استخدام مصدر OpenTelemetry مخصص مع @vercel/otel أو تكوين OpenTelemetry يدويًا.

نطاقات مخصصة

يمكنك إضافة نطاق مخصص باستخدام واجهات برمجة تطبيقات OpenTelemetry.

Terminal
npm install @opentelemetry/api

يوضح المثال التالي دالة تجلب نجوم GitHub وتضيف نطاقًا مخصصًا fetchGithubStars لتتبع نتيجة طلب الجلب:

import { trace } from '@opentelemetry/api'

export async function fetchGithubStars() {
  return await trace
    .getTracer('nextjs-example')
    .startActiveSpan('fetchGithubStars', async (span) => {
      try {
        return await getValue()
      } finally {
        span.end()
      }
    })
}

سيتم تنفيذ دالة register قبل تشغيل الكود الخاص بك في بيئة جديدة. يمكنك البدء في إنشاء نطاقات جديدة، ويجب أن تتم إضافتها بشكل صحيح إلى التتبع المصدر.

النطاقات الافتراضية في Next.js

يقوم Next.js تلقائيًا بتتبع عدة نطاقات لتوفير رؤى مفيدة حول أداء التطبيق الخاص بك.

تتبع السمات على النطاقات اتفاقيات OpenTelemetry الدلالية. نضيف أيضًا بعض السمات المخصصة تحت مساحة الاسم next:

  • next.span_name - يكرر اسم النطاق
  • next.span_type - كل نوع نطاق له معرف فريد
  • next.route - نمط المسار للطلب (مثل /[param]/user).
  • next.rsc (صواب/خطأ) - ما إذا كان الطلب هو طلب RSC، مثل الجلب المسبق.
  • next.page
    • هذه قيمة داخلية تستخدمها موجه التطبيق.
    • يمكنك التفكير فيها كمسار لملف خاص (مثل page.ts، layout.ts، loading.ts وغيرها)
    • يمكن استخدامها كمعرف فريد فقط عند اقترانها بـ next.route لأن /layout يمكن استخدامها لتحديد كل من /(groupA)/layout.ts و /(groupB)/layout.ts

[http.method] [next.route]

  • next.span_type: BaseServer.handleRequest

يمثل هذا النطاق النطاق الجذري لكل طلب وارد إلى تطبيق Next.js الخاص بك. يتتبع طريقة HTTP، المسار، الهدف، ورمز حالة الطلب.

السمات:

render route (app) [next.route]

  • next.span_type: AppRender.getBodyResult.

يمثل هذا النطاق عملية عرض مسار في موجه التطبيق.

السمات:

  • next.span_name
  • next.span_type
  • next.route

fetch [http.method] [http.url]

  • next.span_type: AppRender.fetch.

يمثل هذا النطاق طلب الجلب المنفذ في الكود الخاص بك.

السمات:

يمكن إيقاف هذا النطاق عن طريق تعيين NEXT_OTEL_FETCH_DISABLED=1 في بيئتك. هذا مفيد عندما تريد استخدام مكتبة تتبع جلب مخصصة.

executing api route (app) [next.route]

  • next.span_type: AppRouteRouteHandlers.runHandler.

يمثل هذا النطاق تنفيذ معالج مسار API في موجه التطبيق.

السمات:

  • next.span_name
  • next.span_type
  • next.route

getServerSideProps [next.route]

  • next.span_type: Render.getServerSideProps.

يمثل هذا النطاق تنفيذ getServerSideProps لمسار معين.

السمات:

  • next.span_name
  • next.span_type
  • next.route

getStaticProps [next.route]

  • next.span_type: Render.getStaticProps.

يمثل هذا النطاق تنفيذ getStaticProps لمسار معين.

السمات:

  • next.span_name
  • next.span_type
  • next.route

render route (pages) [next.route]

  • next.span_type: Render.renderDocument.

يمثل هذا النطاق عملية عرض المستند لمسار معين.

السمات:

  • next.span_name
  • next.span_type
  • next.route

generateMetadata [next.page]

  • next.span_type: ResolveMetadata.generateMetadata.

يمثل هذا النطاق عملية إنشاء بيانات وصفية لصفحة معينة (يمكن أن يحتوي مسار واحد على عدة نطاقات من هذه).

السمات:

  • next.span_name
  • next.span_type
  • next.page

resolve page components

  • next.span_type: NextNodeServer.findPageComponents.

يمثل هذا النطاق عملية حل مكونات الصفحة لصفحة معينة.

السمات:

  • next.span_name
  • next.span_type
  • next.route

resolve segment modules

  • next.span_type: NextNodeServer.getLayoutOrPageModule.

يمثل هذا النطاق تحميل وحدات الكود لتخطيط أو صفحة.

السمات:

  • next.span_name
  • next.span_type
  • next.segment

start response

  • next.span_type: NextNodeServer.startResponse.

يمثل هذا النطاق ذو الطول الصفر الوقت الذي تم فيه إرسال البايت الأول في الاستجابة.