مقدمة: لماذا يعتبر التسجيل (Logging) أمرًا حيويًا لتطبيقات Rust
التسجيل (Logging) ليس مجرد تسجيل للأحداث في ملف. في بيئة الإنتاج (production)، تتيح السجلات عالية الجودة تشخيص الأخطاء بسرعة، وتتبع الأداء، وتحليل سلوك النظام. Rust، كونه لغة برمجة أنظمة، يقدم أدوات مرنة وعالية الأداء لهذه المهمة. في هذه المقالة، سنشرح أفضل ممارسات التسجيل في Rust: من اختيار الكريت (crate) إلى إعداد السجلات المنظمة (structured logs) وتدوير الملفات (rotation).
1. الأساسيات: كريتات log و env_logger
يقدم نظام Rust البيئي نهجًا معياريًا. يوفر كريت log طبقة تجريد (واجهة)، بينما يتم توصيل تطبيق محدد (الخلفية) بواسطة كريت منفصل، مثل env_logger أو pretty_env_logger.
التثبيت والإعداد
أضف التبعيات إلى ملف Cargo.toml:
[dependencies]log = "0.4"env_logger = "0.10"مثال أساسي
use log::{info, warn, error};
fn main() { env_logger::init();
info!("تم تشغيل التطبيق"); let user_id = 42; warn!("المستخدم {} غير موجود في ذاكرة التخزين المؤقت", user_id); error!("خطأ في الاتصال بقاعدة البيانات: {:?}", "timeout");}هام: افتراضيًا، لا يتم عرض السجلات حتى تقوم بتعيين متغير البيئة RUST_LOG. قم بتشغيل البرنامج كالتالي:
RUST_LOG=info cargo runمستويات التسجيل
يدعم كريت log خمسة مستويات قياسية (من الأعلى أولوية إلى الأقل):
error— أخطاء حرجة تتطلب تدخلاً فوريًا.warn— تحذيرات بشأن مشاكل محتملة.info— معلومات عامة حول سير التنفيذ.debug— معلومات تصحيح أخطاء للمطورين.trace— أحداث مفصلة للغاية (تُستخدم غالبًا في الحلقات).
التصفية حسب الوحدات (modules): RUST_LOG=my_crate=debug,other_crate=info.
2. التسجيل المتقدم: كريت tracing
للتطبيقات المعقدة (خوادم الويب، الخدمات المصغرة)، يُوصى باستخدام كريت tracing. يوفر مفهوم span (فترات زمنية) وتسجيلًا منظمًا مع سياق (context).
تثبيت tracing
[dependencies]tracing = "0.1"tracing-subscriber = "0.3"مثال مع span
use tracing::{info, instrument, span, Level};use tracing_subscriber;
fn main() { tracing_subscriber::fmt::init();
let parent_span = span!(Level::INFO, "معالجة_الطلب", request_id = 123); let _guard = parent_span.enter(); process_data();}
#[instrument]fn process_data() { info!("بدأت معالجة البيانات"); std::thread::sleep(std::time::Duration::from_millis(50)); info!("اكتملت معالجة البيانات");}الخاصية #[instrument] تنشئ تلقائيًا span للدالة وتسجل وقت التنفيذ. سيحتوي المخرَج على طوابع زمنية متداخلة، وهو أمر لا غنى عنه لتحليل الأداء (profiling).
3. السجلات المنظمة (JSON) وتدوير الملفات (Rotation)
في بيئة الإنتاج، غالبًا ما يتم جمع السجلات مركزيًا (ELK, Loki, Grafana). لهذا، من المناسب إخراج السجلات بتنسيق JSON.
الإخراج بتنسيق JSON باستخدام tracing-subscriber
use tracing_subscriber::fmt::format::Json;use tracing_subscriber::prelude::*;
fn main() { let format = Json::new() .with_timer(tracing_subscriber::fmt::time::UtcTime::rfc3339()) .with_target(true) .with_level(true);
tracing_subscriber::fmt() .event_format(format) .init();
tracing::info!("تم تشغيل الخادم على المنفذ 8080");}الآن ستبدو السجلات كالتالي: