سجلات Linux: journalctl و/var/log وrsyslog وlogrotate
تجمع خدمة journald السجلات في معظم توزيعات Linux الحديثة، ويقرأها الأمر journalctl: فيعرض journalctl -u nginx سجلات خدمة واحدة، وتعرض -f الأسطر فور حدوثها، وتصفّي --since و-p حسب الزمن والأهمية. أما السجلات النصية فتقع في /var/log، ويكتبها rsyslog أو التطبيق نفسه، ويضغطها logrotate ويحذف القديم منها كي لا يمتلئ القرص.
حين تتعطل خدمة ليلاً يكون الجواب غالباً موجوداً في السجلات، والمشكلة فقط في معرفة مكانها. في التوزيعات الحديثة (Ubuntu وDebian وRHEL وFedora وArch) تجمع الخدمة journald الأحداث، ويُقرأ الجورنال بالأمر journalctl. وفي الوقت نفسه تكتب برامج كثيرة ملفات نصية عادية في /var/log، ويتابع logrotate حجمها. وفيما يلي شرح عملي لسجلات journalctl في Linux، وأين تقع السجلات الأخرى، وكيف لا تفقد المعلومات المهمة أثناء التدوير.
أين تُحفظ السجلات في Linux
هناك ثلاثة مصادر، ومن المفيد أن تحفظ الصورة في ذهنك:
- journald — سجل ثنائي تابع لـsystemd. يستقبل stdout وstderr لكل الخدمات، ورسائل النواة، وsyslog. يُحفظ في
/var/log/journal/بشكل دائم، أو في/run/log/journal/حتى إعادة التشغيل. - /var/log — ملفات نصية. يكتبها
rsyslog(مثل/var/log/syslogو/var/log/auth.log)، أو التطبيقات نفسها مثل nginx وPostgreSQL وMySQL. - المخزن الحلقي للنواة — رسائل التعريفات والأجهزة، ويعرضها
dmesgأوjournalctl -k.
| الملف | ما بداخله |
|---|---|
/var/log/syslog (Debian/Ubuntu) | السجل النظامي العام |
/var/log/messages (RHEL/Fedora) | الشيء نفسه في عائلة Red Hat |
/var/log/auth.log أو /var/log/secure | الدخول وsudo وSSH |
/var/log/kern.log | رسائل النواة |
/var/log/dpkg.log، /var/log/apt/ | تثبيت الحزم |
/var/log/nginx/ | access.log وerror.log لخادم الويب |
/var/log/wtmp، /var/log/btmp | سجلات الدخول الثنائية، تُقرأ بـlast وlastb |
معظم الملفات في /var/log متاحة لـroot أو لمجموعة adm فقط، لذلك كثيراً ما تحتاج أوامر القراءة إلى sudo.
journalctl: الأوامر الأساسية
بدون معاملات يعرض journalctl الجورنال كله من الأقدم إلى الأحدث عبر المُعرض less. وهذا نادراً ما يُحتاج إليه، فعادةً تضيّق النتائج فوراً.
journalctl # الجورنال كله، من القديم إلى الجديد
journalctl -e # فتحه مباشرةً في النهاية
journalctl -n 50 # آخر 50 سطراً
journalctl -r # بالترتيب العكسي، الجديد في الأعلى
journalctl --no-pager # بدون less، مناسب للسكريبتات وgrep
داخل المُعرض تعمل مفاتيح less المعتادة: / للبحث، وG للنهاية، وq للخروج. والأسطر الطويلة تُقطع حسب عرض الشاشة، والسهمان يساراً ويميناً يحركانها.
سجلات خدمة محددة: journalctl -u
أكثر سيناريو شيوعاً هو معرفة ما كتبته وحدة systemd واحدة. ولا داعي للبحث عن ملف وتصفيته بـgrep:
$ sudo journalctl -u nginx -n 20
Oct 14 03:12:41 web1 systemd[1]: Starting nginx.service - A high performance web server...
Oct 14 03:12:41 web1 nginx[1834]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Failed with result 'exit-code'.
يمكن تكرار الخيار -u: فالأمر journalctl -u nginx -u php8.2-fpm يعرض الخدمتين مختلطتين حسب الزمن، وهذا مفيد حين يقع الخطأ عند التقاء الخدمتين. ولوحدات المستخدم (systemctl --user) استخدم journalctl --user -u الاسم.
السجلات الفورية: journalctl -f
sudo journalctl -u nginx -f
هذا يشبه tail -f: يعرض آخر 10 أسطر ثم ينتظر الجديد. ومن المفيد تركه في طرفية منفصلة أثناء إعادة تشغيل الخدمة أو إعادة إنتاج الخطأ. والخروج بـCtrl+C.
الفلاتر حسب الزمن والتشغيل
إذا عرفت وقت الحادث، فحدد النطاق بالخيارين --since و--until. وهما يفهمان التواريخ الدقيقة والقيم النسبية:
journalctl --since "2026-10-14 02:50" --until "2026-10-14 03:30"
journalctl --since "1 hour ago"
journalctl --since yesterday --until today
journalctl -u nginx --since "10 min ago"
التقسيم المفيد الآخر هو حسب تشغيلات النظام. إذا أعاد الخادم التشغيل من تلقاء نفسه، فالسبب يُبحث عنه في نهاية الجلسة السابقة:
$ journalctl --list-boots
-2 8f1c... Sat 2026-10-12 09:01:12 UTC Sun 2026-10-13 22:47:03 UTC
-1 a7d2... Sun 2026-10-13 22:48:30 UTC Tue 2026-10-14 03:05:51 UTC
0 c3e9... Tue 2026-10-14 03:07:02 UTC Tue 2026-10-14 09:15:40 UTC
$ journalctl -b -1 -e # نهاية التشغيل السابق
$ journalctl -b # التشغيل الحالي فقط
قائمة التشغيلات متاحة فقط إذا كان الجورنال محفوظاً على القرص. وكيفية تفعيل ذلك موضحة أدناه، في قسم إعداد journald.
الفلتر حسب الأهمية: journalctl -p
لكل سجل أولوية syslog من 0 إلى 7. والخيار -p يعرض المستوى المحدد وكل ما هو أهم منه:
| الرمز | الاسم | متى يُستخدم |
|---|---|---|
| 0 | emerg | النظام غير صالح للعمل |
| 1 | alert | يلزم تدخل فوري |
| 2 | crit | خطأ حرج |
| 3 | err | خطأ |
| 4 | warning | تحذير |
| 5 | notice | حدث مهم لكنه طبيعي |
| 6 | info | رسالة معلوماتية |
| 7 | debug | تصحيح الأخطاء |
journalctl -p err -b # كل الأخطاء منذ بداية التشغيل
journalctl -p warning..err -u ssh # نطاق من المستويات لخدمة واحدة
الأمر journalctl -p err -b فحص أول جيد بعد إعادة التشغيل أو التحديث: إذ يبيّن خلال ثوانٍ ما الذي سار بشكل خاطئ.
البحث والفلاتر الأخرى
يحفظ journald لكل سجل حقولاً منظمة، ويمكن التصفية بها دون grep:
journalctl _PID=1834 # حسب رقم العملية
journalctl _COMM=sshd # حسب اسم البرنامج
journalctl _UID=1000 # حسب المستخدم
journalctl /usr/sbin/sshd # حسب مسار الملف التنفيذي
journalctl -k # رسائل النواة فقط (مثل dmesg)
journalctl -t CRON # حسب معرّف syslog
journalctl -g "Out of memory" # بحث في النص، بتعبير نمطي
الخيار -g (--grep) ظهر في systemd 237؛ وفي الأنظمة القديمة استخدم خط الأنابيب العادي journalctl --no-pager | grep .... وتُدمج الفلاتر على حقول مختلفة بمنطق «و»، فالأمر journalctl -u nginx -p err --since today يعرض أخطاء nginx لهذا اليوم فقط.
صيغ العرض
يغيّر الخيار -o الشكل. وأهم الخيارات:
-o short-iso— الوقت بصيغة ISO 8601، ويسهل مقارنته مع سجلات التطبيق.-o verbose— كل حقول السجل، بما فيها_SYSTEMD_UNITو_PIDو_BOOT_ID.-o jsonأوjson-pretty— للمعالجة بالسكريبتات أو عبرjq.-o cat— نص الرسالة فقط، دون التاريخ والمضيف.
journalctl -u myapp -o json --since today | jq -r '.MESSAGE'
إعداد journald: التخزين والحجم
الإعدادات في /etc/systemd/journald.conf، والتعديلات الأفضل وضعها في /etc/systemd/journald.conf.d/*.conf. والمعامل الرئيسي هو Storage:
persistent— يُكتب الجورنال على القرص في/var/log/journalويبقى بعد إعادة التشغيل.volatile— في الذاكرة فقط، في/run/log/journal.auto(الافتراضي) — على القرص إذا كان المجلد/var/log/journalموجوداً.
في بعض الصور الدنيا لا يوجد هذا المجلد، فيختفي التاريخ بعد إعادة التشغيل. لتفعيل الحفظ الدائم:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
ولكي لا يشغل الجورنال القرص كله، حدّد الحدود:
# /etc/systemd/journald.conf.d/size.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=1month
الافتراضي لـSystemMaxUse هو 10% من حجم نظام الملفات، لكن لا يتجاوز 4 غيغابايت.
كيف تنظّف سجل journalctl
$ journalctl --disk-usage
Archived and active journals take up 1.8G in the file system.
sudo journalctl --vacuum-size=300M # الإبقاء على 300 ميغابايت كحد أقصى
sudo journalctl --vacuum-time=2weeks # حذف السجلات الأقدم من أسبوعين
sudo journalctl --rotate # إغلاق الملفات النشطة لكي يمكن حذفها أيضاً
لا تحذف ملفات /var/log/journal بـrm: فالأمر vacuum يفعل ذلك بأمان، ولا يمس الملف النشط.
rsyslog: السجلات النصية الكلاسيكية
rsyslog خدمة تستقبل رسائل syslog (بما فيها المُمرَّرة من journald)، وتوزعها على الملفات حسب القواعد. والإعداد في /etc/rsyslog.conf و/etc/rsyslog.d/*.conf. وتتكون القاعدة من محدّد المصدر.المستوى ثم إجراء:
# /etc/rsyslog.d/50-default.conf (مقتطف)
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
kern.* -/var/log/kern.log
الشرطة قبل المسار تعني الكتابة دون المزامنة مع القرص بعد كل سطر، وهذا أسرع لكن قد تضيع آخر الأسطر عند الانهيار. وبعد تعديل الإعداد تحقق من الصياغة وأعد تشغيل الخدمة:
sudo rsyslogd -N1
sudo systemctl restart rsyslog
أهم سبب للاحتفاظ بـrsyslog إلى جانب journald هو إرسال السجلات إلى خادم مركزي. سطر واحد يرسل كل شيء عبر TCP:
# /etc/rsyslog.d/90-remote.conf
*.* @@logs.example.com:514
الرمز @ الواحد يعني UDP، والرمزان @@ يعنيان TCP. وإذا انهار الخادم بالكامل تبقى نسخة السجلات على جهاز آخر. ولكتابة رسالتك الخاصة في سجل النظام من السكريبت استخدم logger:
logger -t backup -p user.err "فشل نسخ قاعدة البيانات احتياطياً"
journalctl -t backup -n 5
logrotate: تدوير السجلات
تكبر السجلات النصية إلى ما لا نهاية ما لم يقصّها أحد. وهذا هو عمل logrotate: مرة في اليوم (عبر cron أو المؤقت logrotate.timer) يعيد تسمية الملف الحالي، ويضغط القديم، ويحذف الأقدم. والإعدادات العامة في /etc/logrotate.conf، والقواعد الخاصة بالبرامج في /etc/logrotate.d/.
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 myapp adm
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
| التوجيه | المعنى |
|---|---|
daily / weekly / size 100M | متى يتم التدوير |
rotate 14 | كم عدد الملفات القديمة التي تُحفظ |
compress، delaycompress | ضغط بـgzip، لكن ترك أحدث أرشيف غير مضغوط |
missingok، notifempty | عدم الشكوى من غياب الملف، وعدم تدوير الملف الفارغ |
create 0640 user group | صلاحيات الملف الجديد عند إنشائه |
copytruncate | النسخ ثم تصفير الملف — للبرامج التي لا تعرف إعادة فتح السجل |
postrotate ... endscript | أمر بعد التدوير، وغالباً إشارة للتطبيق لإعادة فتح الملف |
للتحقق من القاعدة دون تغيير، وتشغيل التدوير فوراً:
sudo logrotate -d /etc/logrotate.d/myapp # تشغيل تجريبي مع تفاصيل التصحيح
sudo logrotate -f /etc/logrotate.d/myapp # التدوير الآن
الخطأ الشائع هو نسيان postrotate أو copytruncate. عندها يستمر التطبيق في الكتابة إلى app.log.1 المُعاد تسميته عبر مؤشر الملف (file descriptor) القديم، ويبقى الملف الجديد app.log فارغاً.
قراءة السجلات النصية
للملفات في /var/log تكفي الأدوات القياسية:
sudo tail -n 100 /var/log/syslog # آخر الأسطر
sudo tail -F /var/log/nginx/error.log # المتابعة مع الصمود أمام التدوير
sudo less +G /var/log/auth.log # فتحه في النهاية
sudo zgrep "Failed password" /var/log/auth.log.*.gz # البحث في الأرشيفات المضغوطة
sudo grep -c " 500 " /var/log/nginx/access.log # عدد الردود 500
لاحظ tail -F بحرف كبير: على عكس -f، يعيد فتح الملف حين يستبدله logrotate.
تحليل عطل خطوة بخطوة
سيناريو «الخدمة توقفت ليلاً» يُحلَّل بترتيب ثابت:
systemctl status myapp— الحالة الحالية وآخر أسطر السجل.journalctl -u myapp --since "03:00" --until "03:30"— ماذا كتبت الخدمة لحظة التوقف.journalctl -p err -b— هل توجد أخطاء أخرى في النظام في الوقت نفسه.journalctl -k --since "03:00" -g "Out of memory|Killed process"— هل قتلت عملية OOM Killer العملية في النواة.- سجلات التطبيق نفسه في
/var/log/myapp/، بما فيها الأرشيفات.gz. - إذا أعاد الخادم التشغيل —
journalctl -b -1 -e.
الخلاصة
للعمل اليومي مع السجلات في Linux تكفي بضعة أوامر: journalctl -u للخدمة، و-f للتدفق، و--since و-p err لتضييق النتائج، و-b -1 لتحليل إعادة التشغيل. وتُحفظ السجلات النصية في /var/log، ويفرزها rsyslog ويرسلها، بينما يمنع logrotate وjournalctl --vacuum-* السجلات من التهام القرص. وقد جرى شرح عمل journalctl والتدوير وتشخيص الحمل بعمق في درس Linux.
الأسئلة الشائعة
لماذا يعرض journalctl سجلات آخر تشغيل فقط؟
الجورنال محفوظ في الذاكرة (/run/log/journal). أنشئ المجلد /var/log/journal أو اضبط Storage=persistent في journald.conf، ثم أعد تشغيل systemd-journald.
كيف أسمح لمستخدم عادي بقراءة السجل النظامي دون sudo؟
أضفه إلى مجموعة systemd-journal (أو adm في Debian وUbuntu): sudo usermod -aG systemd-journal الاسم، ثم أعد تسجيل الدخول.
هل يمكن رؤية سجل نظام آخر، مثلاً من قرص مربوط؟
نعم، حدد مجلد الجورنال بالخيار -D: journalctl -D /mnt/var/log/journal. والخيار --file يقرأ ملف .journal منفرداً.
هل نحتاج rsyslog إذا كان journald موجوداً؟
ليس بالضرورة. يفيد إذا احتجت إلى ملفات نصية للأدوات القديمة أو لإرسال السجلات إلى خادم مركزي؛ وفي كثير من الصور الدنيا لا يُثبَّت أصلاً.
كيف أصدّر سجلات خدمة إلى ملف لأرسله لزميل؟
نفّذ journalctl -u الاسم --since today --no-pager > service.log، فتحصل على ملف نصي عادي.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Linux: с нуля до уверенного администрирования».
الانتقال إلى الدورة