Structured Logging هو نهج لتسجيل السجلات حيث يتم تمثيل كل رسالة بتنسيق قابل للقراءة آلياً مع أزواج مفتاح-قيمة، بدلاً من النص غير المنظم. على عكس السلاسل المسطحة، تحتوي السجلات المنظمة على بيانات وصفية: الطابع الزمني، المستوى، الوحدة، معرف الطلب — ويمكن فهرستها بواسطة أنظمة التحليل. وفقاً لـ O'Reilly Effective Logging، فإن الانتقال إلى التنسيقات المنظمة يقلل وقت البحث عن الحوادث من ساعات إلى دقائق بفضل إمكانية التصفية حسب الحقول. هذا هو المعيار الفعلي في التطوير المحمول والخوادم الحديث: JSON وlogfmt يسمحان بمعالجة السجلات بواسطة البرامج، وليس بالعينين.
النقاط الرئيسية
Structured Logging هو طريقة لتسجيل السجلات حيث يحتوي كل رسالة على حقول مسماة بقيم محددة النوع. بدلاً من سلسلة مثل User 42 logged in from device ABC، يبدو السجل المنظم كمجموعة من الحقول: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.
الميزة الرئيسية للسجلات المنظمة على النصية هي إمكانية المعالجة البرمجية. يتطلب تحليل السجلات النصية تعبيرات منتظمة وافتراضات حول تنسيق السلسلة. يتم تحليل السجلات المنظمة دون فقدان: كل حقل له نوع واسم معروفين، مما يسمح ببناء استعلامات مثل البحث عن جميع أخطاء المصادقة في الساعة الأخيرة للمستخدم 42 دون معالجة إضافية.
وفقاً لـ Honeycomb.io (2023)، الفرق التي تستخدم structured logging في الإنتاج تكتشف الحوادث في المتوسط أسرع بـ4 مرات مقارنة بالفرق التي تعتمد على السجلات النصية وgrep.
Structured Logging يدعم عدة تنسيقات للتسلسل. يعتمد اختيار التنسيق على البنية التحتية: JSON مناسب للتكامل مع Elasticsearch والأنظمة السحابية، logfmt للعرض في الطرفية عبر tail وgrep، Protocol Buffers للأنظمة عالية الأداء ذات قيود عرض النطاق.
| التنسيق | مثال | متى تستخدم |
|---|---|---|
| JSON | {"event":"login","user_id":42} | ELK Stack، المجمعات السحابية، الخدمات المصغرة |
| Logfmt | event=login user_id=42 duration_ms=150 | الطرفية، tail، heroku logs |
| MessagePack | المكافئ الثنائي لـJSON | الأنظمة عالية التحميل، إنترنت الأشياء |
JSON هو التنسيق الأكثر شيوعاً للسجلات المنظمة. وهو مدعوم أصلياً من جميع أنظمة الجمع: Logstash، Fluentd، Amazon CloudWatch، Google Cloud Logging. سجلات JSON سهلة القراءة للبشر والتحليل بواسطة أي لغة برمجة دون مكتبات إضافية. العيب الرئيسي هو الإسهاب: كل زوج مفتاح-قيمة يتطلب علامات اقتباس ونقطتين، مما يزيد حجم البيانات المخزنة بنسبة 30–50% مقارنة بـlogfmt.
Logfmt تم تطويره في Heroku للرؤية في الطرفية. إنه أكثر ضغطاً من JSON، ويحافظ على قابلية القراءة البشرية، ويمكن معالجته بسهولة باستخدام cut وawk. مثال: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt لا يتطلب هروب معظم الأحرف ومناسب تماماً لتسجيل stdout في الحاويات.
في التطبيقات المحمولة، يحل Structured Logging ثلاث مشاكل رئيسية: إيجاد أسباب الأعطال دون إعادة إنتاجها على الجهاز، تتبع جلسات المستخدم، وتحليل الأداء حسب إصدارات التطبيق.
السجلات النصية على الأجهزة المحمولة عديمة الفائدة تقريباً — لا يمكن للمطور تطبيق grep على سجلات جهاز المستخدم. يتم إرسال السجلات المنظمة إلى الأنظمة السحابية (Firebase، Sentry، Datadog) ويتم فهرستها هناك. يمكن بناء استعلام مثل عرض جميع الأعطال على iOS 17.4، إصدار التطبيق 3.2، في وحدة الدفع والحصول على تحديد دقيق في ثوانٍ.
وفقاً لـ Sentry (2024)، التطبيقات التي تستخدم breadcrumbs منظمة لديها سياق أكثر بنسبة 60% في كل تقرير عطل مقارنة بالتطبيقات التي تسجل فقط نص الخطأ. هذا يؤثر مباشرة على سرعة إصلاح الخلل.
ELK Stack — Elasticsearch، Logstash، Kibana — يظل البنية التحتية القياسية للعمل مع السجلات المنظمة. Logstash يستقبل السجلات بتنسيق JSON، ويحولها ويرسلها إلى Elasticsearch للفهرسة، Kibana يوفر واجهة بصرية للاستعلامات ولوحات المعلومات.
للتطبيقات المحمولة، الحلول السحابية شائعة: Firebase Crashlytics مع سجلات مخصصة، Sentry مع breadcrumbs، Datadog مع تتبع APM. تستقبل السجلات المنظمة مباشرة من SDK المحمول ولا تتطلب نشر خلفية خاصة. Firebase يقدم حزمة مجانية لتقارير الأعطال، Sentry يضيف التتبع الموزع، وDatadog يتكامل مع APM لتتبع أداء الطلبات على العميل والخادم في وقت واحد.
Grafana Loki — بديل لـElasticsearch محسّن للسجلات. Loki لا يفهرس محتوى الرسائل افتراضياً بل يستخدم التصنيفات (labels) للتصفية. هذا أرخص بكثير في التخزين وأسرع للاستعلامات على مجموعة ثابتة من الحقول.
// التسجيل المنظم عبر Swift Logger بتنسيق JSON
struct StructuredLog {
let event: String
let attributes: [String: Any]
let level: String
func serialize() -> String {
var base = "event=\(event) level=\(level)"
for (key, value) in attributes {
base += " \(key)=\(value)"
}
return base
}
}
القاعدة الأولى للتسجيل المنظم: كل رسالة يجب أن تحتوي على معرف طلب أو جلسة. بدون سياق، السجل الفردي عديم الفائدة — من المستحيل معرفة أي مستخدم أو طلب ينتمي إليه. أضف correlation ID عند بدء الجلسة وقم بتمريره عبر جميع طبقات التطبيق.
القاعدة الثانية: تحديد نوع الحقول. الحقول الرقمية (duration_ms, status_code, retry_count) يجب إرسالها كأرقام وليس كسلاسل نصية. Elasticsearch والأنظمة المماثلة تفهرس الأرقام والسلاسل بشكل مختلف: الأرقام يمكن تجميعها (متوسط، وسيط، نسبة مئوية)، السلاسل تدعم البحث النصي الكامل. التحديد الخاطئ للنوع يمنع بناء لوحات تحليلية.
القاعدة الثالثة: تجنب الكائنات المتداخلة. سجلات JSON بعمق تداخل أكثر من مستويين يصعب تصفيتها وعرضها. بدلاً من {"user": {"name": "Alice", "role": "admin"}}، استخدم مفاتيح مسطحة: user_name=Alice user_role=admin.
// التسجيل المنظم على Android عبر Timber + logfmt
class StructuredTree : Timber.Tree() {
override fun log(priority: Int, tag: String?,
message: String?, t: Throwable?) {
val level = priorityToLevel(priority)
val logfmt = "level=$level tag=$tag message=$message"
sendToRemote(logfmt)
}
}
الحد الأدنى من الحقول لكل رسالة منظمة: timestamp بصيغة ISO 8601، level (debug/info/warn/error/fatal)، logger (اسم الوحدة أو الفئة)، message (وصف الحدث قابل للقراءة البشرية). بالإضافة: correlation_id، user_id (إذا كان معروفاً)، version (إصدار التطبيق)، platform (iOS/Android)، environment (dev/staging/prod).
بدون correlation_id، تتحول السجلات المنظمة إلى مجموعة من السجلات المتناثرة التي لا يمكن ربطها في سيناريو مستخدم واحد. قم بإنشاء UUID عند كل تشغيل للتطبيق وأضفه إلى جميع سجلات الجلسة. عملياً، يجب تمرير correlation_id عبر جميع الطبقات: من أحداث واجهة المستخدم إلى طلبات الشبكة والمهام الخلفية — وإلا ستبقى بعض السجلات بدون سياق ولن تشارك في التحليلات. مع التتبع الشامل، يسمح UUID واحد بجمع الصورة الكاملة لرحلة المستخدم.
على iOS، يمكن تنفيذ التسجيل المنظم عبر غلاف حول os_log يقوم بتسلسل الحقول إلى تنسيق logfmt. على Android، عبر Timber مع Tree مخصص يقوم بتحويل الرسائل إلى JSON أو logfmt قبل الإرسال إلى الخادم.
import OSLog
struct StructuredLogger {
let subsystem: String
let category: String
func log(level: OSLogType,
event: String,
context: [String: Any]) {
let oslogger = Logger(
subsystem: subsystem,
category: category
)
let fields = context.map {
"\($0.key)=\($0.value)"
}.joined(separator: " ")
oslogger.log(level: level,
"\(event) \(fields)")
}
}
الاختيار بين السجلات المنظمة والنصية يعتمد على مرحلة المشروع. في المراحل المبكرة من التطوير، السجلات النصية أبسط وأسرع — يكتب المطور رسالة مباشرة بدون أغلفة إضافية. ولكن بمجرد أن يتجاوز المشروع حدود فريق واحد أو خادم واحد، تصبح السجلات المنظمة إلزامية.
| المعيار | السجلات النصية | السجلات المنظمة |
|---|---|---|
| قابلية القراءة | عالية في الطرفية | متوسطة (تتطلب pretty-print) |
| البحث | grep حسب النص الفرعي | استعلامات حسب الحقول والقيم |
| التجميع | غير مدعوم | متوسط، وسيط، نسب مئوية |
| التكامل | يتطلب تحليلاً | أصلي في ELK/Loki/Datadog |
| حجم التخزين | أصغر (بدون بيانات وصفية) | أكبر (حقول + قيم) |
الأسئلة الشائعة
لإرسال الخادم، استخدم JSON — مدعوم أصلياً من Firebase Crashlytics وSentry وDatadog. للعرض المحلي في سجلات Xcode أو Android Studio، استخدم logfmt — إنه أكثر ضغطاً ويُقرأ بدون تنسيق.
نعم، السجلات المنظمة على العميل تسمح بإضافة سياق لكل تقرير عطل: إصدار نظام التشغيل، حالة الشبكة، آخر إجراءات المستخدم. بدون breadcrumbs منظمة، يحتوي تقرير العطل فقط على مكدس الاستدعاءات بدون سيناريو المستخدم.
Logfmt أكثر ضغطاً (حجم أقل بنسبة 30–50%) وأسهل للقراءة في الطرفية. JSON يدعم الكائنات والمصفوفات المتداخلة ولكنه يتطلب هروب علامات الاقتباس. يعتمد الاختيار على البنية التحتية: لـELK — JSON، للعرض في الطرفية — logfmt.
أنشئ مثيلاً واحداً من UUID عند بدء التطبيق، واحفظه في singleton أو حاوية DI، ومرره إلى جميع مسجلات السجلات عبر المنشئ. بديل — استخدام التخزين المحلي للخيط أو Continuation Local Storage في coroutines Kotlin.
يمكن، لكن لا يُنصح — عند الخلط تُفقد إمكانية الفهرسة التلقائية. إذا كانت بعض السجلات نصية، يجب تحليلها بتعبيرات منتظمة مما يقلل الأداء وموثوقية البحث. من الأفضل ترحيل جميع السجلات إلى التنسيق المنظم.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا