مراقبة Kotlin: التتبع، المقاييس والسجلات عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا المراقبة (Observability) أمر لا غنى عنه لتطبيقات Kotlin

\n\n

تخيل: تطبيق Kotlin الخاص بك يعمل في بيئة الإنتاج، وفجأة يشتكي المستخدمون من أن الطلبات تستغرق 10 ثوانٍ. تذهب إلى السجلات — صمت. تظهر المقاييس استخدام 100% لوحدة المعالجة المركزية، لكنها لا تخبرك أي نقطة نهاية (endpoint) هي التي تبطئ. هل هذا مألوف؟

\n\n

مرحبًا بك في عالم حيث المراقبة (observability) ليست خيارًا، بل ضرورة. على عكس المراقبة التقليدية التي تجيب ببساطة بـ "نعم/لا" على سؤال "هل النظام حي؟"، تتيح لك المراقبة طرح أسئلة لم تكن تعرفها من قبل. و Kotlin، بفضل إيجازها ونظامها البيئي القوي، مثالي لتبني هذه الثقافة.

\n\n

في هذه المقالة، سنشرح الركائز الثلاث للمراقبة — التتبع، المقاييس والسجلات — ونوضح كيفية دمجها مع Kotlin. لا ماء، فقط أمثلة كود حقيقية.

\n\n

التتبع: رحلة الطلب عبر الخدمات المصغرة

\n\n

التتبع الموزع (tracing) يشبه نظام GPS لطلبك. ترى من خلال أي الخدمات مر الطلب، كم من الوقت استغرق كل خطوة، وأين حدث التأخير. بالنسبة لـ Kotlin، أفضل صديق في هذا المجال هو OpenTelemetry (OTel).

\n\n

إعداد OpenTelemetry في Kotlin

\n\n

أضف التبعيات في ملف build.gradle.kts:

\n\n
dependencies {\n    implementation("io.opentelemetry:opentelemetry-api:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-sdk:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-extension-kotlin:1.36.0")\n}
\n\n

الآن لننشئ متتبعًا بسيطًا:

\n\n
import io.opentelemetry.api.GlobalOpenTelemetry\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.api.trace.Tracer\nimport io.opentelemetry.context.Scope\n\nclass OrderService(private val tracer: Tracer = GlobalOpenTelemetry.getTracer("order-service")) {\n\n    fun processOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("processOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use { // use() ستغلق span تلقائيًا\n            try {\n                // محاكاة العمل\n                Thread.sleep(100)\n                validateOrder(orderId)\n                chargePayment(orderId)\n            } catch (e: Exception) {\n                span.recordException(e)\n                span.setStatus(StatusCode.ERROR, "Order processing failed")\n                throw e\n            }\n        }\n    }\n\n    private fun validateOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("validateOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(50) // محاكاة التحقق\n        }\n    }\n\n    private fun chargePayment(orderId: String) {\n        val span: Span = tracer.spanBuilder("chargePayment")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(150) // محاكاة الدفع\n        }\n    }\n}
\n\n

لاحظ استخدام span.use — هذه دالة امتداد (extension function) من opentelemetry-extension-kotlin، والتي تغلق span تلقائيًا بعد تنفيذ الكتلة. جمال Kotin في العمل!

\n\n

نقل السياق عبر الكوروتينات

\n\n

في Kotlin، نستخدم الكوروتينات بنشاط. يتعامل OpenTelemetry معها بشكل ممتاز من خلال آلية السياق (Context):

\n\n
import kotlinx.coroutines.withContext\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.context.Context\n\nsuspend fun processOrderAsync(orderId: String) = withContext(Context.current()) {\n    val span = tracer.spanBuilder("processOrderAsync").startSpan()\n    span.use {\n        // منطقك غير المتزامن هنا\n    }\n}
\n\n

يكشف التتبع الصورة الكاملة: ترى أن 80% من الوقت يذهب إلى الدفع

المدونات

توصيات الكتب