الاستعلام عن journald باستخدام journalctl داخل السكربتات
رشّح إدخالات سجل systemd حسب الوحدة والأولوية والوقت لفرز الحوادث تلقائيًا
الاستعلام عن journald باستخدام journalctl داخل السكربتات درس مجاني في DevOps Bootcamp على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DevOps Bootcamp، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.
لماذا نستخدم journald لفرز الحوادث الأولي؟
تجمع أنظمة Linux الحديثة التي تشغّل systemd كل مخرجات السجلات في السجل — وهو مخزن سجلات منظم وثنائي تديره systemd-journald. وبخلاف الملفات النصية العادية في /var/log، يحمل كل إدخال في السجل بيانات وصفية غنية: اسم الوحدة ومستوى الأولوية وPID وUID والطابع الزمني وغير ذلك.
في نصوص فرز الحوادث الأولي المؤتمتة، تتيح لك هذه البيانات الوصفية ما يلي:
- تصفية السجلات لخدمة واحدة من دون سلاسل
grep - حصر الاستعلامات في نوافذ زمنية دقيقة (آخر 15 دقيقة أو منذ عملية نشر)
- إخراج رسائل الخطأ أو الرسائل الحرجة فقط مع تجاهل الضوضاء
- تمرير المخرجات المنظمة مباشرة إلى مسارات التنبيه
الأداة التي تتيح كل ذلك هي journalctl. يعلّمك هذا الدرس كيفية تشغيلها برمجيًا داخل نصوص Bash.
الاستدعاء الأساسي لـ journalctl
يفرغ الشكل الأبسط من journalctl السجل بأكمله. لكنك نادرًا ما تريد ذلك في النصوص البرمجية — أضف دائمًا مرشحًا واحدًا على الأقل. إليك أكثر الخيارات شيوعًا التي ستجمع بينها:
-u <unit>— التصفية حسب وحدة systemd (مثلًاnginx.service)-p <priority>— التصفية حسب أولوية syslog (من 0=emerg إلى 7=debug)--since/--until— النافذة الزمنية-n <N>— آخر N من الأسطر--no-pager— تعطيل التصفح التفاعلي للصفحات (ضروري في النصوص البرمجية)-o <format>— تنسيق المخرجات (shortوjsonوcatوغير ذلك)
مرّر دائمًا --no-pager في النصوص غير التفاعلية كي لا يحاول journalctl استدعاء less ويتوقف عن الاستجابة.
#!/usr/bin/env bash
# Print the last 20 lines of the nginx service journal
journalctl --no-pager -u nginx.service -n 20التصفية حسب وحدة Systemd
يقبل الخيار -u أي اسم وحدة صالح. ويمكنك توفيره عدة مرات لدمج الوحدات، وهذا مفيد عندما يمتد تطبيق واحد عبر عدة خدمات (مثل واجهة API وقاعدة البيانات الجانبية التابعة لها).
تتبع أسماء الوحدات النمط <name>.service أو <name>.socket أو <name>.timer وغير ذلك. ويُدعم استخدام المحارف البديلة: إذ يطابق -u 'myapp*' كلًا من myapp-api.service وmyapp-worker.service وما شابه ذلك.
في نص فرز الحوادث الأولي، تتلقى عادةً اسم الوحدة كوسيط، ما يجعل المرشح ديناميكيًا.
#!/usr/bin/env bash
# Usage: ./unit_logs.sh nginx.service
UNIT="${1:?Usage: $0 <unit>}"
echo "=== Journal for ${UNIT} (last 50 lines) ==="
journalctl --no-pager -u "${UNIT}" -n 50
# Combine two related units
echo "=== Combined: api + worker ==="
journalctl --no-pager -u myapp-api.service -u myapp-worker.service -n 30مستويات الأولوية والعَلَمة -p
تُطابق العَلَمة -p مستويات الأولوية القياسية في syslog:
0— emerg1— alert2— crit3— err4— warning5— notice6— info7— debug
يمكنكم تحديد مستوى واحد (-p err) لعرض ذلك المستوى فقط، أو نطاق (-p emerg..err) لالتقاط كل شيء من حالات الطوارئ حتى الأخطاء — وهو الخيار الأكثر شيوعًا للتنبيهات المؤتمتة.
تُقبل الأسماء البديلة (err وwarning وcrit) إلى جانب القيم الرقمية.
#!/usr/bin/env bash
# Extract only error-level and above entries for sshd
journalctl --no-pager \
-u sshd.service \
-p emerg..err \
--since "1 hour ago"
# Exit non-zero if any errors were found (useful in CI health checks)
ERROR_COUNT=$(journalctl --no-pager -u sshd.service -p emerg..err \
--since "1 hour ago" --output=cat | wc -l)
if [[ "${ERROR_COUNT}" -gt 0 ]]; then
echo "[ALERT] ${ERROR_COUNT} error(s) detected in sshd" >&2
exit 1
fiالتصفية حسب نافذة زمنية باستخدام --since و--until
تُعدّ عوامل التصفية الزمنية أساس الاستعلامات الخاصة بفترة الحادثة. تقبل journalctl طوابع زمنية مرنة ومقروءة بشريًا:
- نسبية:
"10 minutes ago"و"2 hours ago"و"yesterday" - مطلقة:
"2026-06-11 14:00:00" - كلمات مفتاحية خاصة:
todayوyesterdayو-1h(صيغة مختصرة)
في نصوص النشر البرمجية، من الأنماط الشائعة التقاط الطابع الزمني قبل النشر مباشرة، ثم الاستعلام في السجل بدءًا من تلك النقطة لاكتشاف التراجعات التي أدخلها الإصدار.
#!/usr/bin/env bash
# Record deploy start time, then check logs afterwards
DEPLOY_START=$(date +"%Y-%m-%d %H:%M:%S")
echo "Deploying at ${DEPLOY_START}..."
# ... your deploy steps here ...
sleep 2 # simulate deploy
echo "=== Journal since deploy start ==="
journalctl --no-pager \
-u myapp.service \
--since "${DEPLOY_START}" \
-p emerg..warningالإخراج المنظّم بتنسيق JSON
بالنسبة إلى مسارات المعالجة المقروءة آليًا، مرّروا -o json (كائن JSON واحد في كل سطر، بتنسيق NDJSON) أو -o json-pretty (بتنسيق منسّق). يحتوي كل كائن على جميع حقول السجل:
MESSAGE— نص السجلPRIORITY— الأولوية الرقمية (من 0 إلى 7)_SYSTEMD_UNIT— الوحدة المصدر__REALTIME_TIMESTAMP— عدد الميكروثواني منذ العصر_PIDو_UIDو_HOSTNAME— بيانات وصفية للعملية
يمكنكم تمرير دفق NDJSON هذا إلى jq لاستخراج الحقول أو تصفيتها أو إعادة تنسيقها لأنظمة التنبيه اللاحقة مثل PagerDuty وwebhooks الخاصة بـ Slack أو مستوعبات SIEM.
#!/usr/bin/env bash
# Extract error messages as a clean list for a Slack notification
MESSAGES=$(journalctl --no-pager \
-u nginx.service \
-p emerg..err \
--since "30 minutes ago" \
-o json \
| jq -r '.MESSAGE' \
| sort -u)
if [[ -n "${MESSAGES}" ]]; then
echo "Errors detected:"
echo "${MESSAGES}"
fiمتابعة السجل في الوقت الفعلي
تجعل العَلَمة -f الأمر journalctl يتابع السجل مباشرة — على نحو مماثل للأمر tail -f مع ملف سجل. وعند دمجها مع عوامل تصفية الوحدة والأولوية، تتحول إلى أداة مراقبة موجهة في الوقت الفعلي.
في مسارات المعالجة البرمجية، يتمثل النمط الأكثر فائدة في الاستطلاع المستند إلى المؤشر: احفظ مؤشر السجل الحالي، ثم مرّر --after-cursor=<cursor> في كل عملية استطلاع لقراءة الإدخالات الجديدة فقط منذ آخر فحص. وبذلك تتجنب معالجة الأسطر القديمة مرة أخرى.
استرجعوا أحدث مؤشر باستخدام --show-cursor -n 0 وحلّلوا السطر -- cursor: من الإخراج.
#!/usr/bin/env bash
# Cursor-based polling: read only new journal entries each run
CURSOR_FILE="/tmp/triage_cursor"
if [[ -f "${CURSOR_FILE}" ]]; then
CURSOR=$(cat "${CURSOR_FILE}")
NEW_ENTRIES=$(journalctl --no-pager \
-u myapp.service \
-p emerg..err \
--after-cursor="${CURSOR}" \
-o json)
else
# First run: look back 5 minutes
NEW_ENTRIES=$(journalctl --no-pager \
-u myapp.service \
-p emerg..err \
--since "5 minutes ago" \
-o json)
fi
# Save updated cursor for next poll
journalctl --no-pager -n 0 --show-cursor 2>&1 \
| grep '^-- cursor:' \
| sed 's/-- cursor: //' \
> "${CURSOR_FILE}"
echo "${NEW_ENTRIES}" | jq -r '.MESSAGE // empty'الاستعلامات المقيّدة بجلسة الإقلاع باستخدام -b
تقيّد العَلَمة -b الاستعلام بجلسة إقلاع محددة. ويُعد ذلك ضروريًا بعد حدوث تعطل أو إعادة تشغيل غير متوقعة، لاسترجاع سجلات الإقلاع السابق بدلًا من الإقلاع الحالي.
-b 0— الإقلاع الحالي (الافتراضي)-b -1— الإقلاع السابق-b -2— الإقلاع الذي سبقه--list-boots— عرض جميع جلسات الإقلاع المسجّلة مع طوابعها الزمنية
تفرّغ نصوص ما بعد الحادثة عادةً السجلات الحرجة من الإقلاع السابق (-b -1) لتشخيص سبب تعطل النظام أو فشل خدمة عند بدء التشغيل.
#!/usr/bin/env bash
# Post-mortem: collect critical logs from the previous boot
echo "=== Previous boot sessions ==="
journalctl --list-boots
echo ""
echo "=== Critical entries from previous boot ==="
journalctl --no-pager \
-b -1 \
-p emerg..crit \
-o short-isoالبحث داخل journalctl باستخدام grep مقارنةً بالمطابقات الأصلية
يمكنكم تمرير نمط grep خام بعد جميع العَلَمات، لكن journalctl يدعم أيضًا مطابقات الحقول الأصلية باستخدام الصيغة FIELD=value. تُقيَّم المطابقات الأصلية مقابل البيانات الوصفية المنظّمة، وهي أسرع بكثير من معالجة النص لاحقًا باستخدام grep.
من المطابقات الشائعة المفيدة:
_PID=1234— سجلات عملية محددة_COMM=python3— سجلات أي عملية اسمهاpython3SYSLOG_IDENTIFIER=myapp— سجلات موسومة بمعرّف مخصص
تُعامل عدة وسيطات من الشكل FIELD=value كشرط AND؛ بينما ينشئ الرمز + بينها شرط OR. استخدموا -g <regex> للبحث النصي الكامل باستخدام grep عندما لا تكون البيانات الوصفية المنظّمة كافية.
#!/usr/bin/env bash
# Native field match: errors from the postgres process only
journalctl --no-pager \
_COMM=postgres \
-p emerg..err \
--since "1 hour ago"
# Full-text grep for a specific error string
journalctl --no-pager \
-u postgresql.service \
--since "1 hour ago" \
-g "FATAL|PANIC" \
--output=catإنشاء دالة فرز أولي قابلة لإعادة الاستخدام
بعد إتقان العَلَمات الفردية، يساعد تركيبها في دالة Bash قابلة لإعادة الاستخدام على إبقاء نصوص الفرز الأولي نظيفة ومتسقة. ينبغي أن تحقق الدالة المصممة جيدًا ما يلي:
- تقبل الوحدة ونطاق الأولوية والنافذة الزمنية كمعاملات
- تستخدم قيمًا افتراضية آمنة ومنخفضة الضجيج عند حذف الوسيطات
- تعيد رمز خروج غير صفري عند العثور على أخطاء (للتكامل مع مسارات CI)
- تكتب النتائج إلى stdout وإلى ملف سجل يحمل طابعًا زمنيًا لإنشاء مسارات تدقيق
#!/usr/bin/env bash
# triage.sh — reusable journal triage function
triage_unit() {
local unit="${1:?unit required}"
local priority="${2:-emerg..err}"
local since="${3:-1 hour ago}"
local logfile="/tmp/triage_${unit//[^a-zA-Z0-9]/_}_$(date +%s).log"
echo "[$(date -Iseconds)] Triaging ${unit} | prio=${priority} | since='${since}'" | tee "${logfile}"
journalctl --no-pager \
-u "${unit}" \
-p "${priority}" \
--since "${since}" \
-o short-iso \
| tee -a "${logfile}"
local count
count=$(wc -l < "${logfile}")
# Subtract 1 for the header line
(( count-- ))
if [[ "${count}" -gt 0 ]]; then
echo "[ALERT] ${count} line(s) logged to ${logfile}" >&2
return 1
fi
return 0
}
# Example: triage nginx errors in the last 30 minutes
triage_unit nginx.service "emerg..err" "30 minutes ago"نص برمجي مؤتمت للفرز الأولي للحوادث
يجمع النص البرمجي الكامل التالي جميع المفاهيم في أداة عملية مؤتمتة للفرز الأولي. فهو يقرأ قائمة بالخدمات الحرجة، ويستعلم في السجل عن كل خدمة ضمن نافذة رجوع قابلة للتهيئة، ويجمع النتائج، ثم ينهي التنفيذ برمز فشل إذا اكتُشفت أي أخطاء — مما يجعله مناسبًا كمهمة cron أو كخطوة لفحص صحة CI.
#!/usr/bin/env bash
# incident_triage.sh — automated multi-service journal triage
set -euo pipefail
LOOKBACK="${1:-15 minutes ago}"
PRIORITY="emerg..err"
SERVICES=(nginx.service postgresql.service myapp-api.service myapp-worker.service)
REPORT="/tmp/incident_report_$(date +%Y%m%d_%H%M%S).txt"
FAILED=0
{
echo "Incident Triage Report"
echo "Generated : $(date -Iseconds)"
echo "Lookback : ${LOOKBACK}"
echo "Priority : ${PRIORITY}"
echo "-----------------------------------"
} > "${REPORT}"
for svc in "${SERVICES[@]}"; do
ENTRIES=$(journalctl --no-pager \
-u "${svc}" \
-p "${PRIORITY}" \
--since "${LOOKBACK}" \
--output=cat 2>/dev/null || true)
COUNT=$(echo "${ENTRIES}" | grep -c . || true)
if [[ "${COUNT}" -gt 0 ]]; then
echo "[FAIL] ${svc}: ${COUNT} error(s)" | tee -a "${REPORT}"
echo "${ENTRIES}" >> "${REPORT}"
echo "-----------------------------------" >> "${REPORT}"
FAILED=1
else
echo "[OK] ${svc}"
fi
done
echo ""
echo "Full report: ${REPORT}"
exit "${FAILED}"اختبار المعرفة: التصفية حسب نطاق الأولوية
أنتم تكتبون نصًا برمجيًا لتنبيه المهندسين المناوبين فقط عندما تسجّل خدمة رسائل بدرجة خطأ أو أعلى في الشدة (أي: error أو critical أو alert أو emergency). ما مجموعة عَلمات journalctl التي تلتقط هذا النطاق تحديدًا؟
مراجعة الدرس: استخدام journalctl في النصوص البرمجية
تعلّمتم في هذا الدرس كيفية الاستعلام برمجيًا في سجل systemd لإجراء الفرز الأولي للحوادث تلقائيًا:
- مرّروا دائمًا
--no-pagerفي النصوص البرمجية لمنع التوقف التفاعلي. - التصفية حسب الوحدة (
-u) تقيّد الاستعلامات بخدمة واحدة أو أكثر؛ كما تُدعم الأنماط الشاملة واستخدام عدة عَلمات-u. - التصفية حسب الأولوية (
-p emerg..err) تلتقط مستويات الشدة التي تهمكم فقط — تذكّروا أن الأرقام الأقل تعني شدة أكبر. - النوافذ الزمنية (
--since/--until) تعزل مخرجات السجل ضمن نافذة نشر أو فترة رجوع باستخدام طوابع زمنية مقروءة بشريًا. - تقييد الإقلاع (
-b -1) يتيح لنصوص ما بعد الحادثة قراءة سجلات جلسة تعطل سابقة. - إخراج JSON (
-o json) وjqيتيحان إنشاء مسارات معالجة منظّمة تغذي أنظمة التنبيه أو SIEM. - الاستطلاع المستند إلى المؤشر باستخدام
--after-cursorيتجنب إعادة معالجة الإدخالات القديمة عند تكرار التشغيل. - مطابقات الحقول الأصلية (
_COMM=وSYSLOG_IDENTIFIER=) أسرع من تمرير البيانات إلىgrep.
يمنحكم جمع هذه العَلَمات داخل دالة Bash قابلة لإعادة الاستخدام أداة فرز أولي جاهزة لبيئات الإنتاج، تتكامل بسلاسة مع cron ومسارات CI وسير عمل التنبيه للمناوبين.
الأسئلة الشائعة
هل درس «الاستعلام عن journald باستخدام journalctl داخل السكربتات» مجاني؟
نعم — نص درس «الاستعلام عن journald باستخدام journalctl داخل السكربتات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة DevOps Bootcamp، انتقل إلى CoddyKit PRO. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.
ماذا ستتعلم في «الاستعلام عن journald باستخدام journalctl داخل السكربتات»؟
رشّح إدخالات سجل systemd حسب الوحدة والأولوية والوقت لفرز الحوادث تلقائيًا تتمرن على DevOps Bootcamp مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ DevOps Bootcamp؟
لا تُشترط خبرة سابقة. DevOps Bootcamp على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «الاستعلام عن journald باستخدام journalctl داخل السكربتات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس DevOps Bootcamp هذا؟
نعم. كل درس في DevOps Bootcamp يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تحليل سجلات الويب والتطبيقات على نطاق واسع
- متابعة السجلات والتنبيهات المتدفقة في الوقت الفعلي
- الاستعلام عن journald باستخدام journalctl داخل السكربتات
- حساب المقاييس والمدرّجات التكرارية من تدفقات السجلات