Linux: مشروع المرحلة 3 المصغّر — تحليل سجلات الخادم

هذا المشروع الختامي للمرحلة 3. ستدمج إعادة التوجيه والأنابيب وgrep وawk وsed وsort وuniq وكل مهارات معالجة البيانات لإجراء تحليل كامل الأبعاد لسجلات وصول Nginx وتوليد تقرير.

📋 المتطلبات المسبقة: يجب إكمال

1. ما ستتعلمه


2. موقع شياو مينغ أصبح بطيئًا

(1) نقطة الألم: المدير يريد بيانات، لكن سجل الـ10 غيغابايت يستحيل تصفحه

موقع شياو مينغ أصبح بطيئًا مؤخرًا، والمدير طلب "أعطني بيانات." سجل access.log الخاص بـNginx يولّد مئات الميغابايت يوميًا — فتحه مستحيل، والبحث بكلمات مفتاحية كالبحث عن إبرة في كومة قش.

(2) تحليل بسلسلة أنابيب

استخدم شياو مينغ مهارات المرحلة 3، مستخرجًا المقاييس الأساسية سطرًا بسطر بأوامر الأنابيب:

BASH
# أكثر 10 عناوين IP تكرارًا
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

# أكثر 10 عناوين URL طلبًا
cat access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -10

> 💡 نصيحة: نمط أنبوب تحليل السجلات ثابت: `awk استخراج الحقول → sort → uniq -c إزالة التكرار والعدّ → sort -rn تنازلي حسب العدد → head أخذ أعلى N`. تذكّر هذا القالب — أي تحليل Top N للسجلات يمكنه استخدامه.

# الطلبات في كل ساعة
cat access.log | awk -F: '{print $2":00"}' | sort | uniq -c | sort -rn

الإخراج:

TEXT
    210 192.168.1.100
    198 10.0.0.45
    195 192.168.1.200
    190 10.0.0.88
    180 172.16.0.50
    150 /index.html
    120 /api/users
    110 /api/login
    100 /about
     90 /contact
     85 10:00
     80 14:00
     75 09:00
     70 22:00
     65 18:00

(3) الفائدة: تقرير في 5 دقائق

جمّع شياو مينغ نتائج التحليل في تقرير — اتجاهات الوصول، وأعلى 10 طلبات بطيئة، والصفحات الأكثر أخطاء 404. قال المدير: "جيد، لنضف المزيد من الخوادم."


3. نقاط المعرفة

(1) صياغة سجل Nginx القياسية (combined)

TEXT

192.168.1.100 - - [07/Jul/2026:10:15:30 +0000] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
│              │ │ │                           │                           │    │    │
│              │ │ └─ User-Agent               │                           │    │    └─ Response bytes
│              │ └───────────────────────────── Referer                    │    └────── Status code
│              └─────────────────────────────────────────────────────────── Request line (method/URL/protocol)
└─── Client IP                                   Timestamp

ℹ️ ملاحظة: في صياغة combined لـNginx، الحقول مفصولة بمسافات، لكن بعض الحقول تحتوي مسافات بداخلها (مثل سطر الطلب والطابع الزمني ملفوفان بأقواس وعلامات اقتباس). عندما يقسم awk بمسافات، $1 هو IP، و$7 هو URL، و$9 هو رمز الحالة، و$10 هو البايتات — مواضع هذه الحقول ثابتة ويمكن استخراجها مباشرة بـawk.

مواضع الحقول (مفصولة بمسافات):

الحقل المعنى
$1 IP العميل
$4 جزء [ من الطابع الزمني
$7 URL المطلوب
$9 رمز حالة HTTP
$10 بايتات الاستجابة

(2) ▶ مثال: توليد سجلات عينة

أولًا، أنشئ ملف سجل عينة للتحليل:

TEXT
#!/bin/bash
# generate-sample-log.sh

IPS=("192.168.1.100" "10.0.0.45" "192.168.1.200" "10.0.0.88" "172.16.0.50")
URLS=("/index.html" "/api/users" "/api/login" "/about" "/contact" "/images/logo.png" "/api/orders" "/products" "/blog")
STATUSES=(200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 201 301 302 400 401 403 404 500 502 503)

rm -f /tmp/access.log

for i in {1..1000}; do
    IP=${IPS[$RANDOM % ${#IPS[@]}]}
    URL=${URLS[$RANDOM % ${#URLS[@]}]}
    STATUS=${STATUSES[$RANDOM % ${#STATUSES[@]}]}
    SIZE=$((RANDOM % 10000 + 100))
    HOUR=$((RANDOM % 24))
    MIN=$((RANDOM % 60))
    SEC=$((RANDOM % 60))
    echo "$IP - - [07/Jul/2026:$HOUR:$MIN:$SEC +0000] \"GET $URL HTTP/1.1\" $STATUS $SIZE \"-\" \"Mozilla/5.0\"" >> /tmp/access.log
done

echo "Generated 1000 sample log entries to /tmp/access.log"
BASH
chmod +x generate-sample-log.sh
./generate-sample-log.sh

الإخراج:

TEXT
Generated 1000 sample log entries to /tmp/access.log

(3) ▶ مثال: إحصاءات حجم الطلبات

BASH
echo "=== Total Requests ==="
wc -l /tmp/access.log

echo ""
echo "=== Requests per IP ==="
cat /tmp/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "=== Request Method Distribution ==="
cat /tmp/access.log | awk '{print $6}' | tr -d '"' | sort | uniq -c | sort -rn

الإخراج:

TEXT
=== Total Requests ===
1000 /tmp/access.log

=== Requests per IP ===
    210 192.168.1.100
    198 10.0.0.45
    195 192.168.1.200
    190 10.0.0.88
    180 172.16.0.50

=== Request Method Distribution ===
   1000 GET

(4) ▶ مثال: تحليل رموز الحالة

BASH
echo "=== Status Code Distribution ==="
cat /tmp/access.log | awk '{print $9}' | sort | uniq -c | sort -rn

echo ""
echo "=== 4xx Errors (Client Errors) ==="
cat /tmp/access.log | awk '$9 ~ /^4/ {print $9, $7, $1}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "=== 5xx Errors (Server Errors) ==="
cat /tmp/access.log | awk '$9 ~ /^5/ {print $9, $7, $1}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "=== Error Rate ==="
TOTAL=$(wc -l < /tmp/access.log)
ERRORS=$(awk '$9 ~ /^[45]/ {count++} END {print count}' /tmp/access.log)
echo "Total requests: $TOTAL"
echo "Errors: $ERRORS"
echo "Error rate: $(echo "scale=2; $ERRORS * 100 / $TOTAL" | bc)%"

الإخراج:

TEXT
=== Status Code Distribution ===
    960 200
      5 201
      3 301
      2 302
      8 400
      2 401
      3 403
     10 404
      4 500
      2 502
      1 503

=== 4xx Errors (Client Errors) ===
   3 404 /api/login 192.168.1.100
   2 404 /about 10.0.0.45
   2 403 /api/admin 192.168.1.200

=== 5xx Errors (Server Errors) ===
   2 500 /api/data 10.0.0.88
   2 502 /api/users 172.16.0.50
   1 503 /api/health 192.168.1.100

=== Error Rate ===
Total requests: 1000
Errors: 32
Error rate: 3.20%

(5) ▶ مثال: تحليل النقاط الساخنة لعناوين URL

BASH
echo "=== Most Popular URLs ==="
cat /tmp/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "=== URLs with Most 404s ==="
cat /tmp/access.log | awk '$9 == 404 {print $7}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "=== URLs with Largest Response Size ==="
cat /tmp/access.log | awk '{print $10, $7}' | sort -rn | head -10

الإخراج:

TEXT
=== Most Popular URLs ===
    150 /index.html
    120 /api/users
    110 /api/login
    100 /about
     90 /contact

=== URLs with Most 404s === 5 /api/login 3 /old-page 2 /favicon.ico

=== URLs with Largest Response Size === 10098 /images/logo.png 9876 /api/users 8765 /api/orders 7654 /products 6543 /blog

(6) ▶ مثال: تحليل البُعد الزمني

BASH
echo "=== Requests per Hour ==="
cat /tmp/access.log | awk -F: '{print $2":00"}' | sort | uniq -c | sort -rn

echo ""
echo "=== Peak Traffic Hours ==="
cat /tmp/access.log | awk -F: '{print $2}' | sort | uniq -c | sort -rn | head -5

echo ""
echo "=== Requests per Minute (Top 10) ==="
cat /tmp/access.log | awk -F: '{print $2":"$3}' | sort | uniq -c | sort -rn | head -10

الإخراج:

TEXT
=== Requests per Hour ===
     85 10:00
     80 14:00
     75 09:00
     70 22:00
     65 18:00

=== Peak Traffic Hours ===
     85 10
     80 14
     75 09
     70 22
     65 18

=== Requests per Minute (Top 10) ===
      5 10:15
      4 14:30
      4 09:45
      3 22:10
      3 18:05

(7) ▶ مثال: تحليل الأداء

BASH
echo "=== Response Size Analysis (using $10 as simulated response size) ==="
echo "Largest response: $(awk '{print $10}' /tmp/access.log | sort -rn | head -1) bytes"
echo "Average response: $(awk '{sum += $10; count++} END {printf "%.0f", sum/count}' /tmp/access.log) bytes"
echo ""

echo "=== Large Responses (> 5KB) ==="
cat /tmp/access.log | awk '$10 > 5000 {print $10, $7}' | sort -rn | head -10

الإخراج:

TEXT
=== Response Size Analysis (using $10 as simulated response size) ===
Largest response: 10098 bytes
Average response: 5142 bytes

=== Large Responses (> 5KB) ===
10098 /images/logo.png
 9876 /api/users
 8765 /api/orders
 7654 /products
 6543 /blog
 5678 /api/data

(8) ▶ مثال شامل: سكريبت تقرير تحليل السجلات الكامل

BASH
#!/bin/bash
# log-report.sh - Generate Nginx log analysis report

LOG_FILE="${1:-/tmp/access.log}"

if [ ! -f "$LOG_FILE" ]; then
    echo "Error: Log file $LOG_FILE does not exist"
    exit 1
fi

TOTAL=$(wc -l < "$LOG_FILE")

echo "========================================="
echo "     Nginx Access Log Analysis Report"
echo "     File: $LOG_FILE"
echo "     Total requests: $TOTAL"
echo "     Generated at: $(date)"
echo "========================================="
echo ""

# 1. نظرة عامة على رموز الحالة
echo "1. HTTP Status Code Distribution"
echo "--------------------"
cat "$LOG_FILE" | awk '{print $9}' | sort | uniq -c | sort -rn | \
    awk '{printf "  %-5s %s\n", $2, $1}'
echo ""

# 2. أعلى 10 IPs
echo "2. Top 10 IPs by Access Count"
echo "---------------------"
cat "$LOG_FILE" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10 | \
    awk '{printf "  %-20s %s\n", $2, $1}'
echo ""

# 3. أعلى 10 عناوين URL
echo "3. Top 10 URLs by Request Count"
echo "-----------------------"
cat "$LOG_FILE" | awk '{print $7}' | sort | uniq -c | sort -rn | head -10 | \
    awk '{printf "  %-30s %s\n", $1, $2}'
echo ""

# 4. أخطاء 4xx/5xx
echo "4. Error Requests"
echo "-------------"
FOURXX=$(awk '$9 ~ /^4/ {count++} END {print count}' "$LOG_FILE")
FIVEXX=$(awk '$9 ~ /^5/ {count++} END {print count}' "$LOG_FILE")
echo "  4xx errors: $FOURXX ($(echo "scale=1; $FOURXX*100/$TOTAL" | bc)%)"
echo "  5xx errors: $FIVEXX ($(echo "scale=1; $FIVEXX*100/$TOTAL" | bc)%)"
echo ""

# 5. الطلبات في كل ساعة
echo "5. Requests per Hour"
echo "--------------------"
cat "$LOG_FILE" | awk -F: '{print $2":00"}' | sort | uniq -c | sort -rn | head -10 | \
    awk '{printf "  %s: %s\n", $2, $1}'
echo ""

# 6. أكبر الاستجابات
echo "6. Largest Responses (Top 5)"
echo "----------------------"
cat "$LOG_FILE" | awk '{print $10, $7}' | sort -rn | head -5 | \
    awk '{printf "  %s bytes: %s\n", $1, $2}'
echo ""

echo "========================================="
echo "End of Report"
BASH
# تشغيل سكريبت التقرير
chmod +x log-report.sh
./log-report.sh /tmp/access.log

❓ أسئلة شائعة

س: ماذا تعني الحقول في صياغة سجل Nginx؟ ج: الصياغة القياسية combined: IP - مستخدم [وقت] "طريقة URL بروتوكول" رمز_الحالة بايت "Referer" "User-Agent". يمكنك تخصيصها عبر توجيه log_format الخاص بـNginx.

س: هل ستختنق الأنابيب مع ملفات سجلات ضخمة (بمستوى GB)؟ ج: ليس كثيرًا. التدفق الانسيابي للأنابيب يعني أن البيانات تُعالج أثناء قراءتها. لكن sort سيحجب لأنه يحتاج قراءة كل البيانات أولًا. للملفات الكبيرة جدًا، استخدم sort -S 1G لتحديد الذاكرة، أو استخدم مصفوفات awk للإحصاءات بدلًا من ذلك.

س: كيف أعُدّ PV (مشاهدات الصفحة) وUV (الزوار الفريدين) الحقيقيين؟ ج: PV = wc -l (باستثناء الطلبات غير الصفحية مثل الصور/CSS/API). UV = awk '{print $1}' access.log | sort -u | wc -l.

س: كيف أراقب تغييرات السجل باستمرار؟ ج: tail -f يتتبع الأسطر الجديدة في الوقت الفعلي. ادمج مع grep: tail -f access.log | grep " 500 " — يعرض كل أخطاء 500 في الوقت الفعلي.

س: كيف أحسب وقت الاستجابة P99 لنقاط نهاية API؟ ج: يحتاج Nginx لضبط $upstream_response_time أو $request_time. ثم: awk '{print $NF}' access.log | sort -n | awk '{all[NR]=$1} END{p99=int(NR*0.99); print all[p99]}'.


📖 ملخص


📝 تمارين

  1. أساسي (⭐): شغّل سكريبت توليد السجلات العينة لإنشاء 1000 إدخال اختبار، ثم اكتب سلسلة أنابيب لإيجاد أكثر 5 عناوين IP تكرارًا وعدد طلباتها
  2. متوسط (⭐⭐): عُدّ عدد ونسبة رموز الحالة 404 و500، ثم استخدم awk '{print $7}' لاستخراج عناوين URL وإيجاد أكثر 5 صفحات شعبية
  3. متقدم (⭐⭐⭐): أنشئ سكريبت تحليل سجلات يُخرج تقريرًا منسّقًا بـMarkdown يتضمن: إجمالي الطلبات، وأعلى 10 IPs، وتوزيع رموز الحالة، واتجاهات الطلبات بالساعة، وأكثر 5 عناوين URL وصولًا
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%