مستوى المقال: مبتدئ. لو عندك سيرفر واحد وبتتعامل مع لوجات لينكس لأول مرة، المقال ده مكتوب ليك بالظبط. مش محتاج تكون مهندس DevOps.
لو المساحة الفاضية في قرص سيرفرك بتقل كل أسبوع من غير ما تزوّد أي حاجة، غالبًا السبب ملف لوج واحد بيكبر بلا حدود. في آخر المقال هتعرف تخلّي السيرفر يدوّر اللوجات لوحده كل ليلة، وتقفل المشكلة دي للأبد في أقل من 10 دقايق.
المشكلة باختصار
أي تطبيق بيكتب لوج باستمرار: كل طلب، كل خطأ، كل تحذير بيتسجّل في ملف زي /var/log/app.log. الملف ده مبيوقفش لوحده. بيفضل يكبر طول ما التطبيق شغّال.
الافتراض إن عندك تطبيق بيخدم 50 ألف طلب في اليوم، وكل طلب بيسجّل سطر أو اتنين. ده بيوصل لـ 1.9 جيجابايت في اليوم بسهولة. قرص 40 جيجا هيمتلئ في أقل من 3 أسابيع. وأول ما يمتلئ، التطبيق نفسه بيقع، لأنه مش قادر يكتب ولا سطر جديد.
يعني إيه تدوير اللوجات؟ (بمثال بسيط الأول)
تخيّل حارس عقار بيكتب كل اللي بيحصل في دفتر واحد. لو عمره ما بدأ صفحة جديدة، الدفتر هيبقى كتاب ضخم، والدُرج اللي بيحطه فيه هيمتلئ، ومحدش هيقدر يلاقي حدث قديم وسط آلاف الصفحات المتلزقة.
الحل اللي أي إدارة منظمة بتعمله بسيط: كل ليلة نبدأ دفتر جديد، نكتب على الدفتر القديم تاريخه ونحطه مضغوط في الأرشيف، وأي دفتر أقدم من أسبوعين نتخلّص منه. كده الدُرج بيفضل نضيف، واللوج القريب لسه موجود لو احتجته.
ده بالظبط اللي بيعمله logrotate: أداة موجودة أصلاً في أغلب توزيعات لينكس، بتشتغل مرة كل يوم عن طريق cron، وبتطبّق نفس المنطق على ملفات اللوج بدل الدفاتر.
إزاي بيشتغل فعلاً (الشرح الدقيق)
logrotate بيقرأ قواعد من /etc/logrotate.conf ومن ملفات صغيرة جوه /etc/logrotate.d/. لكل ملف لوج، القاعدة بتحدد: امتى ندوّر (يومي، أسبوعي، أو عند حجم معيّن)، كام نسخة نحتفظ بيها، ونضغط ولا لأ.
لما شرط القاعدة يتحقق، logrotate بيعمل الخطوات دي بالترتيب: يعيد تسمية app.log إلى app.log.1، يفتح ملف app.log جديد فاضي، يضغط النسخة القديمة بـ gzip (بتوفّر حوالي 90% من الحجم لأن النص بيتضغط كويس جدًا)، وأخيرًا يمسح أقدم نسخة لو عدّينا حد الاحتفاظ.
نقطة خفية لازم تعرفها: التطبيق لازم يعرف إن الملف اتغيّر
هنا بيقع أغلب المبتدئين. معظم التطبيقات بتفتح ملف اللوج مرة واحدة وبتفضل ماسكاه في الذاكرة. لما logrotate يعيد تسمية الملف، التطبيق بيفضل بيكتب في الملف القديم (اللي اتسمى دلوقتي app.log.1)، وملف app.log الجديد بيفضل فاضي للأبد. النتيجة: القرص لسه بيمتلئ وانت فاكر إنك حليت المشكلة.
الحل له طريقتين. الأولى نبعت للتطبيق إشارة يقفل الملف ويفتحه من جديد بعد التدوير (postrotate). الثانية، الأسهل للمبتدئ، نستخدم copytruncate: بينسخ محتوى الملف ثم يفرّغ الملف الأصلي في مكانه من غير ما يعيد تسميته، فالتطبيق يفضل بيكتب في نفس الملف بشكل طبيعي.
الخطوات: فعّلها في أقل من 10 دقايق
هنفترض إن تطبيقك بيكتب لوجاته في /var/log/myapp/. اعمل قاعدة جديدة بالأمر ده:
sudo tee /etc/logrotate.d/myapp > /dev/null <<'EOF'
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
EOFكل سطر معناه:
daily: دوّر يوميًا.rotate 14: احتفظ بأحدث 14 نسخة (14 يوم) وامسح الأقدم.compress: اضغط النسخ القديمة بـ gzip.delaycompress: أجّل ضغط أحدث نسخة يوم واحد، عشان لو التطبيق لسه بيكتب فيها ميحصلش تعارض.missingok: متطلعش خطأ لو الملف مش موجود.notifempty: متدوّرش الملف لو فاضي.copytruncate: انسخ ثم فرّغ الملف في مكانه، من غير ما التطبيق يحتاج يعرف حاجة.
دلوقتي جرّب القاعدة من غير ما تغيّر أي حاجة فعليًا (وضع المحاكاة)، وبعدين نفّذها بالإجبار مرة واحدة عشان تتأكد إنها شغّالة:
# جرّب من غير تنفيذ فعلي — هيوريك هيعمل إيه بالظبط
sudo logrotate -d /etc/logrotate.d/myapp
# نفّذ التدوير دلوقتي بالإجبار للتجربة
sudo logrotate -f /etc/logrotate.d/myapp
# اتأكد إن النسخ المضغوطة اتعملت
ls -lh /var/log/myapp/لو شفت ملفات زي app.log.1 وapp.log.2.gz ظهرت، يبقى كله تمام. مش محتاج تعمل أي جدولة يدوية: logrotate بيتنفّذ يوميًا تلقائيًا من خلال cron.daily.
النتيجة بالأرقام
خد بالك من الفرق. قبل التدوير: ملف واحد بيكبر 1.9 جيجا في اليوم بلا سقف، والقرص بيمتلئ في أقل من 3 أسابيع. بعد التدوير بإعداد rotate 14 مع الضغط: النسخة القديمة بتنكمش حوالي 90%، فبدل ~26 جيجا لوجات متراكمة، بتستقر عند حوالي 3 إلى 4 جيجا ثابتة مهما طال الزمن. القرص بقى تحت السيطرة، ومحدش بيصحى على تطبيق واقع.
الـ trade-off وما يجب الانتباه له
كل حل له ثمن. الضغط بـ gzip بيستهلك شوية CPU وقت التدوير، لكنه لحظي ومهمل بالنسبة لأي سيرفر عادي. الأهم هو copytruncate: في جزء من الثانية بين النسخ والتفريغ، أي سطر بيتكتب فيه ممكن يضيع. للوجات عادية ده مقبول تمامًا. لكن لو اللوج ده مالي أو تدقيقي (audit) ومينفعش تفقد ولا سطر، سيب copytruncate واستخدم postrotate مع إشارة تخلي التطبيق يعيد فتح الملف بأمان. بتكسب دقة كاملة، بتخسر إنك محتاج تعرف الإشارة الصح لتطبيقك.
متى لا تستخدم هذه الطريقة
- جوه حاوية Docker أو Kubernetes: ما تستخدمش logrotate. خلّي تطبيقك يكتب على
stdoutوسيب محرّك الحاويات أو منصة السجلات يتولى الدوران، حسب مبدأ Twelve-Factor. - لو التطبيق بيدوّر لوجاته بنفسه: مكتبات زي Logback أو pino أو winston عندها تدوير داخلي. متعملش تدوير مرتين، هتتعارض.
- لو محتاج بحث وتحليل فوري للّوجات: logrotate بيدير مساحة القرص بس. لو عايز تبحث وتربط أحداث عبر سيرفرات كتير، ابعت اللوجات لنظام مركزي زي Loki أو ELK بدل ما تعتمد على ملفات مضغوطة على القرص.
الخطوة التالية
افتح الترمنال على سيرفرك ونفّذ sudo logrotate -d /etc/logrotate.conf. الأمر ده هيوريك كل ملفات اللوج المغطّاة بقواعد بالفعل، وبالتالي أي ملف بيكبر ومش ظاهر في القائمة هو خطرك القادم. ابدأ بأكبر ملف في /var/log (لاقيه بـ sudo du -ah /var/log | sort -rh | head) واعمله قاعدة زي اللي فوق.
مصادر
- صفحة الدليل الرسمية للأداة: logrotate(8) — man7.org (توصيف
compress,copytruncate,delaycompress,rotate). - مبدأ التعامل مع السجلات في التطبيقات الحديثة والحاويات: The Twelve-Factor App — Logs.
- دليل عملي على مستوى التوزيعة: Arch Wiki — Logrotate.