دليل

سجلات Linux: journalctl و/var/log وrsyslog وlogrotate

آخر تحديث: · Skillaria.Top

تجمع خدمة 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 يعرض المستوى المحدد وكل ما هو أهم منه:

الرمزالاسممتى يُستخدم
0emergالنظام غير صالح للعمل
1alertيلزم تدخل فوري
2critخطأ حرج
3errخطأ
4warningتحذير
5noticeحدث مهم لكنه طبيعي
6infoرسالة معلوماتية
7debugتصحيح الأخطاء
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.

تحليل عطل خطوة بخطوة

سيناريو «الخدمة توقفت ليلاً» يُحلَّل بترتيب ثابت:

  1. systemctl status myapp — الحالة الحالية وآخر أسطر السجل.
  2. journalctl -u myapp --since "03:00" --until "03:30" — ماذا كتبت الخدمة لحظة التوقف.
  3. journalctl -p err -b — هل توجد أخطاء أخرى في النظام في الوقت نفسه.
  4. journalctl -k --since "03:00" -g "Out of memory|Killed process" — هل قتلت عملية OOM Killer العملية في النواة.
  5. سجلات التطبيق نفسه في /var/log/myapp/، بما فيها الأرشيفات .gz.
  6. إذا أعاد الخادم التشغيل — 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: с нуля до уверенного администрирования».

الانتقال إلى الدورة