كيف تتوقف عن التخمين وتبدأ في رؤية الكود الخاص بك بوضوح؟
هل سبق لك أن جلست ليلاً أمام الشاشة، تحدق في السجلات التي تصرخ بوجود خطأ ولكنها صامتة عن السبب؟ أو حاولت فهم لماذا تستجيب خدمتك المصغرة بلغة C# خلال 10 ثوانٍ، بينما كانت بالأمس سريعة جداً؟ مألوف؟ مرحباً بك في عالم حيث بدون المراقبة (Observability) يكون الكود الخاص بك صندوقاً أسود.
في هذه المقالة، لن نلقي محاضرات مملة. سنشرح الركائز الثلاث للمراقبة: التتبع، المقاييس والسجلات — ونوضح كيفية دمجها مع C#. ستتعلم كيف تتوقف عن إطفاء الحرائق وتبدأ في منعها. هيا بنا!
ما هي المراقبة (Observability) ولماذا ليست مجرد "تسجيل سجلات"؟
كثيرون يخلطون بين المراقبة وجمع السجلات العادي. لكن الفرق شاسع. المراقبة (Observability) هي خاصية للنظام تسمح لك بطرح أي أسئلة حول حالته دون إضافة كود جديد. الركائز الثلاث التي يقوم عليها كل شيء:
- السجلات (Logs) — أحداث منفصلة. "المستخدم ضغط على زر"، "خطأ في الاتصال". هذا هو "ماذا حدث؟".
- المقاييس (Metrics) — بيانات مجمعة. "عدد الطلبات في الثانية"، "استهلاك الذاكرة". هذا هو "كم وكم مرة؟".
- التتبع (Traces) — مسار الطلب عبر النظام. "الطلب وصل، ذهب إلى قاعدة البيانات، ثم إلى التخزين المؤقت، ثم عاد". هذا هو "لماذا يستغرق وقتاً طويلاً؟".
في بيئة C# و.NET، يتم دمج هذه الركائز الثلاث باستخدام مكتبات مثل OpenTelemetry. والآن سنشرح كيف يبدو ذلك في الكود.
لنقم بتجربة: كتابة تطبيق مع المراقبة (Observability)
تخيل أن لدينا خدمة بسيطة على ASP.NET Core تقوم بمعالجة الطلبات. نريد رؤية:
- كل خطوة من خطوات معالجة الطلب (التتبع).
- عدد الطلبات التي تمت معالجتها وعدد الأخطاء (المقاييس).
- تفاصيل الاستثناءات (السجلات).
الخطوة 1: إعداد تسجيل السجلات باستخدام Serilog
لنبدأ بالأكثر وضوحاً — السجلات. نستخدم Serilog (يمكنك أيضاً استخدام NLog). هو قادر على كتابة سجلات منظمة يسهل تحليلها لاحقاً.
// NuGet: Serilog, Serilog.AspNetCore, Serilog.Sinks.Consoleusing Serilog;
// الإعداد في Program.csLog.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day) .Enrich.WithProperty("Application", "OrderService") .CreateLogger();
var builder = WebApplication.CreateBuilder(args);builder.Host.UseSerilog(); // استبدال المسجل الافتراضي
// مثال على الاستخدام في المتحكم[ApiController][Route("api/[controller]")]public class OrderController : ControllerBase{ private readonly ILogger<OrderController> _logger;
public OrderController(ILogger<OrderController> logger) => _logger = logger;
[HttpPost] public IActionResult CreateOrder(Order order) { _logger.LogInformation("Creating order {OrderId} for user {User}", order.Id, order.UserId); // ... المنطق ... _logger.LogWarning("Order {OrderId} is delayed due to stock issues", order.Id); return Ok(); }}لاحظ: نستخدم عناصر نائبة مسماة ({OrderId}). هذه ليست مجرد نص — إنها بيانات منظمة. في Elasticsearch أو Grafana Loki، ستتمكن من البحث عن جميع السجلات الخاصة بـ OrderId معين.
الخطوة 2: المقاييس مع Prometheus و.NET
المقاييس مسؤولة عن "الأرقام". كم طلباً في الثانية؟ كم خطأ 500؟ في C# نستخدم Meters من System.Diagnostics.Metrics أو مكتبة prometheus-net.
لنقم بإنشاء عداد بسيط للطلبات المعالجة:
// NuGet: prometheus-net.AspNetCoreusing Prometheus;
// في Program.cs نضيف المقاييسvar builder = WebApplication.CreateBuilder(args);