حزمة [tracing] هي إطار عمل لتزويد برامج Rust بأدوات القياس (instrumenting) لجمع معلومات تشخيصية منظمة وقائمة على الأحداث.
في الأنظمة غير المتزامنة مثل Tokio، قد يكون تفسير رسائل السجل (log messages) التقليدية أمراً صعباً للغاية. نظراً لأن المهام الفردية يتم مضاعفتها (multiplexed) على نفس الخيط، فإن الأحداث المرتبطة وأسطر السجل تختلط ببعضها البعض مما يجعل من الصعب تتبع تدفق المنطق. يتوسع tracing في التشخيصات بأسلوب السجلات من خلال السماح للمكتبات والتطبيقات بتسجيل أحداث منظمة مع معلومات إضافية حول الزمانية و السببية — على عكس رسالة السجل، فإن [Span] في tracing له وقت بداية ونهاية، وقد يتم الدخول إليه والخروج منه بواسطة تدفق التنفيذ، وقد يوجد داخل شجرة متداخلة من النطاقات المماثلة. لتمثيل الأشياء التي تحدث في لحظة زمنية واحدة، يوفر tracing المفهوم المكمل لـ الأحداث (events). كل من الـ [Span]s والـ [Event]s منظمة، مع القدرة على تسجيل بيانات مصنفة بالإضافة إلى الرسائل النصية.
يمكنك استخدام tracing من أجل:
- إصدار تتبعات موزعة (distributed traces) إلى مجمع [OpenTelemetry]
- تصحيح أخطاء تطبيقك باستخدام [Tokio Console]
- تسجيل السجلات إلى [
stdout] ، أو [ملف سجل] أو [journald] - [تحليل الأداء (profile)] لمعرفة أين يقضي تطبيقك وقته
الإعداد (Setup)
للبدء، أضف [tracing] و [tracing-subscriber] كـ تبعيات (dependencies):
[dependencies]
tracing = "0.1"
tracing-subscriber = "0.3"
توفر حزمة [tracing] واجهة برمجة التطبيقات (API) التي سنستخدمها لإصدار التتبعات. توفر حزمة [tracing-subscriber] بعض الأدوات الأساسية لتوجيه تلك التتبعات إلى المستمعين الخارجيين (مثل stdout).
الاشتراك في التتبعات (Subscribing to Traces)
إذا كنت تقوم بتأليف برنامج تنفيذي (على عكس المكتبة)، فستحتاج إلى تسجيل [مشترك (subscriber)] للتتبع. المشتركون هم أنواع تعالج التتبعات الصادرة عن تطبيقك وتبعياته، ويمكنهم أداء مهام مثل حساب المقاييس، ومراقبة الأخطاء، وإعادة إصدار التتبعات إلى العالم الخارجي.
في معظم الظروف، يجب عليك تسجيل مشترك التتبع الخاص بك في أقرب وقت ممكن في وظيفة main. على سبيل المثال، يقوم نوع [FmtSubscriber] المقدم من [tracing-subscriber] بطباعة التتبعات والأحداث المنسقة إلى stdout ، ويمكن تسجيله كالتالي:
#[tokio::main]
pub async fn main() -> mini_redis::Result<()> {
// إنشاء مشترك يطبع التتبعات المنسقة إلى stdout
let subscriber = tracing_subscriber::FmtSubscriber::new();
// استخدام هذا المشترك لمعالجة التتبعات الصادرة بعد هذه النقطة
tracing::subscriber::set_global_default(subscriber)?;
Ok(())
}
إصدار النطاقات والأحداث (Emitting Spans and Events)
أسهل طريقة لإصدار النطاقات (spans) هي باستخدام تعليق الماكرو [instrument] المقدم من [tracing] ، والذي يعيد كتابة أجسام الوظائف لإصدار نطاقات في كل مرة يتم فيها استدعاؤها؛ مثل:
#[tracing::instrument]
fn trace_me(a: u32, b: u32) -> u32 {
a + b
}
ستصدر كل استدعاء لـ trace_me نطاق تتبع (tracing Span):
1. له مستوى إسهاب (verbosity [level]) هو info.
2. يسمى trace_me.
3. يحتوي على الحقول a و b ، وقيمهما هي وسيطات trace_me.
يمكنك أيضاً إنشاء [Span] يدوياً باستخدام ماكرو [span!] ، أو أي من اختصاراته المستندة إلى المستوى ([error_span!], [warn_span!], [info_span!], [debug_span!], [trace_span!]).
لإصدار الأحداث، استخدم ماكرو [event!] ، أو أي من اختصاراته المستندة إلى المستوى ([error!], [warn!], [info!], [debug!], [trace!]). على سبيل المثال، لتسجيل أن العميل أرسل أمراً غير صالح:
tracing::warn! {
%cause,
"failed to parse command from frame"
};
توفر tracing تسجيلاً منظماً (structured logging) ، لذا يتم "تسجيل" المعلومات كأزواج مفتاح-قيمة.