การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่
ดึงรหัสสถานะ เวลาแฝง และฟิลด์ไคลเอ็นต์จากบันทึกการเข้าถึงด้วย grep, cut และ awk
การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่ เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
บันทึกการเข้าถึงเว็บคืออะไร
เซิร์ฟเวอร์ HTTP ทุกชนิด ไม่ว่าจะเป็น Apache, Nginx หรือ Caddy จะเขียนหนึ่งบรรทัดลงในบันทึกการเข้าถึงสำหรับทุกคำขอ การทำความเข้าใจโครงสร้างของบรรทัดเหล่านี้เป็นพื้นฐานของงานวิเคราะห์บันทึกทั้งหมด
บรรทัด รูปแบบบันทึกแบบรวม (CLF) โดยทั่วไปมีลักษณะดังนี้:
- IP ของไคลเอนต์ — ผู้ส่งคำขอ
- เวลาประทับ — เวลาที่เหตุการณ์เกิดขึ้น
- บรรทัดคำขอ — วิธีการ เส้นทาง และโพรโทคอล
- รหัสสถานะ — การตอบกลับ HTTP (200, 404, 500…)
- จำนวนไบต์ที่ส่ง — ขนาดเนื้อหาการตอบกลับ
- ผู้อ้างอิง — หน้าต้นทาง
- ตัวระบุผู้ใช้ — ข้อความที่ระบุเบราว์เซอร์หรือบอต
ตัวอย่างบรรทัดจาก /var/log/nginx/access.log:
192.168.1.10 - alice [11/Jun/2026:14:32:01 +0000] "GET /api/orders HTTP/1.1" 200 1482 "-" "curl/7.88.1"
เมื่อมีปริมาณการใช้งานสูง ไฟล์เหล่านี้อาจเติบโตเป็นหลายล้านบรรทัดต่อวัน เป้าหมายของบทเรียนนี้คือการดึง กรอง และรวมค่าจากฟิลด์ต่าง ๆ อย่างมีประสิทธิภาพโดยใช้เครื่องมือ BASH มาตรฐาน
สุ่มดูบันทึกสดด้วย tail และ grep
ก่อนเขียนกระบวนการประมวลผลต่อเนื่องใด ๆ ให้ตรวจสอบบันทึกเพื่อทำความเข้าใจรูปแบบก่อน tail ช่วยให้ดูสตรีมข้อมูลสดได้ ส่วน grep ช่วยจำกัดผลลัพธ์ให้เหลือเฉพาะบรรทัดที่เกี่ยวข้องได้ทันที
รูปแบบที่ใช้บ่อย:
tail -n 1000 access.log— 1,000 บรรทัดล่าสุดtail -f access.log— ติดตามแบบเรียลไทม์tail -f access.log | grep '" 5'— เฉพาะข้อผิดพลาดระดับ 5xx ที่เข้ามา
ประเด็นสำคัญคือ grep จะจับคู่กับทั้งบรรทัด ดังนั้นการยึดรูปแบบด้วยจุดเริ่มต้นจึงมีความสำคัญ การจับคู่ ' 500 ' (ที่มีช่องว่าง) ช่วยป้องกันการจับคู่เส้นทาง URL ที่มีข้อความ 500 โดยไม่ตั้งใจ
#!/usr/bin/env bash
# Watch only HTTP 5xx errors arriving in real time
tail -f /var/log/nginx/access.log \
| grep --line-buffered '" 5[0-9][0-9] 'ดึงรหัสสถานะด้วย cut
cut แยกแต่ละบรรทัดตามตัวคั่นและแสดงฟิลด์ที่เลือก ในรูปแบบบันทึกแบบรวม รหัสสถานะอยู่ที่ฟิลด์ 9 เมื่อแยกด้วยช่องว่าง แต่เครื่องหมายอัญประกาศรอบบรรทัดคำขอทำให้การนับจากจุดอ้างอิงที่ทราบแน่ชัดปลอดภัยกว่า
เคล็ดลับที่เชื่อถือได้คือ เนื่องจากบรรทัดคำขออยู่ภายในเครื่องหมายอัญประกาศเสมอ รหัสสถานะจึงเป็นโทเค็นแรกหลังเครื่องหมายอัญประกาศปิดของฟิลด์คำขอ การใช้ cut -d'"' -f3 จะแยกทุกอย่างหลังเครื่องหมายอัญประกาศของคำขอ จากนั้น cut -d' ' -f2 ครั้งที่สองจะเลือกเฉพาะรหัสสถานะ
การใช้ cut สองขั้นตอนนี้เป็นสำนวนมาตรฐานสำหรับบันทึก CLF ทำงานเร็วและไม่ต้องพึ่งพาส่วนประกอบภายนอก
#!/usr/bin/env bash
# Print only the HTTP status code from each log line
# Input format: ... "GET /path HTTP/1.1" 200 1482 ...
cut -d'"' -f3 /var/log/nginx/access.log \
| cut -d' ' -f2 \
| sort \
| uniq -c \
| sort -rnนับรหัสสถานะด้วย awk
awk มีความสามารถมากกว่า cut เพราะสะสมสถานะข้ามบรรทัดได้ รูปแบบมาตรฐานสำหรับนับจำนวนครั้งที่พบคือใช้อาร์เรย์แบบเชื่อมโยง โดยให้ค่าที่สนใจเป็นกุญแจ
ใน CLF ฟิลด์ $9 (เริ่มนับจาก 1 และคั่นด้วยช่องว่าง) คือรหัสสถานะ awk จะประมวลผลแต่ละบรรทัด เพิ่มตัวนับ แล้วแสดงสรุปที่เรียงลำดับแล้วในบล็อก END
เหตุใดจึงควรเลือก awk แทน cut | sort | uniq -c เพราะ awk ทำงานครบใน<ไม่กี่รอบเดียว>โดยไม่ต้องเรียงลำดับไฟล์ทั้งหมดก่อน ซึ่งสำคัญมากเมื่อบันทึกมีขนาดหลายร้อยกิกะไบต์
#!/usr/bin/env bash
# Count HTTP status codes in a single awk pass
awk '{ count[$9]++ }
END {
for (status in count)
printf "%6d %s\n", count[status], status
}' /var/log/nginx/access.log \
| sort -rnกรองข้อผิดพลาดและดึง IP ของไคลเอนต์
งานปฏิบัติการที่พบบ่อยอย่างหนึ่งคือการค้นหา IP ของไคลเอนต์ที่ทำให้เกิดข้อผิดพลาดมากที่สุด งานนี้รวมการกรอง (เลือกเฉพาะบรรทัดข้อผิดพลาด) เข้ากับการดึงฟิลด์ (IP ที่ฟิลด์ 1)
กลยุทธ์ของกระบวนการประมวลผลต่อเนื่อง:
- ใช้
awkกรองตามช่วงรหัสสถานะและดึง IP ในขั้นตอนเดียว เพื่อหลีกเลี่ยงการใช้grepแยกอีกครั้ง - ส่งต่อไปยัง
sort | uniq -c | sort -rn | headเพื่อดูรายการอันดับต้น ๆ อย่างรวดเร็ว
รูปแบบนี้เร็วพอที่จะใช้กับไฟล์บันทึกขนาด 10 GB บนเซิร์ฟเวอร์เครื่องเดียวได้ โดยไม่ต้องโหลดไฟล์ทั้งหมดเข้าสู่หน่วยความจำ
#!/usr/bin/env bash
# Top 10 IPs generating HTTP 4xx or 5xx errors
awk '$9 ~ /^[45][0-9][0-9]$/ { print $1 }' \
/var/log/nginx/access.log \
| sort \
| uniq -c \
| sort -rn \
| head -10แยกวิเคราะห์เวลาแฝงของการตอบกลับจากบันทึกแอปพลิเคชัน
เซิร์ฟเวอร์แอปพลิเคชัน เช่น Rails, Gunicorn และ Express ที่ใช้ morgan มักบันทึกระยะเวลาของคำขอ Nginx สามารถตั้งค่าให้เขียน $request_time เป็นฟิลด์เพิ่มเติมท้ายแต่ละบรรทัดได้
ตัวอย่างรูปแบบบันทึก Nginx แบบกำหนดเองใน nginx.conf:
log_format timed '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" rt=$request_time';
เมื่อมีเวลาแฝงอยู่ในบันทึกแล้ว คุณสามารถใช้ awk คำนวณค่าเฉลี่ย ค่าสูงสุด และค่าประมาณเปอร์เซ็นไทล์จากคำขอหลายล้านรายการได้ โดยไม่ต้องโหลดข้อมูลลงฐานข้อมูล
#!/usr/bin/env bash
# Compute average and max request_time from Nginx timed log
# Assumes last field is rt=<seconds> e.g. rt=0.042
awk '{
# Extract numeric value after rt=
n = split($NF, a, "=")
if (n == 2 && a[1] == "rt") {
t = a[2] + 0
sum += t
count++
if (t > max) max = t
}
}
END {
if (count > 0)
printf "Requests: %d Avg: %.4fs Max: %.4fs\n", count, sum/count, max
}' /var/log/nginx/timed_access.logสร้างฮิสโตแกรมเวลาแฝงด้วย awk
ค่าเฉลี่ยเพียงค่าเดียวจะบดบังเวลาแฝงช่วงหาง ฮิสโตแกรมจะแสดงการกระจายว่า คำขอส่วนใหญ่ทำงานเร็วแต่มีบางส่วนช้ามาก (หางยาว) หรือการกระจายมีความสม่ำเสมอ
เคล็ดลับคือจัดแต่ละค่าเข้าช่วงที่ปัดเศษแล้ว โดยใช้การคำนวณจำนวนเต็มภายใน awk การคูณด้วย 1000 (แปลงวินาทีเป็นมิลลิวินาที) แล้วใช้การหารจำนวนเต็มจะทำให้ขอบเขตของแต่ละช่วงชัดเจน
วิธีนี้สร้างฮิสโตแกรมแบบข้อความที่อ่านได้โดยตรงในเทอร์มินัล ซึ่งมักเร็วกว่าการส่งข้อมูลไปยัง Grafana เมื่อต้องการตรวจสอบอย่างรวดเร็ว
#!/usr/bin/env bash
# Latency histogram (50ms buckets) from Nginx timed log
awk '{
n = split($NF, a, "=")
if (n == 2 && a[1] == "rt") {
ms = int(a[2] * 1000) # convert to ms
bucket = int(ms / 50) * 50 # round down to 50ms boundary
hist[bucket]++
}
}
END {
for (b in hist)
printf "%6dms %d\n", b, hist[b]
}' /var/log/nginx/timed_access.log \
| sort -nดึง User-Agent และตรวจจับบอต
ฟิลด์ User-Agent (ฟิลด์ 6 เมื่อแยกด้วย ") ใช้ระบุไคลเอนต์ โปรแกรมรวบรวมข้อมูล โปรแกรมขูดข้อมูล และบอตอันตรายมักทำให้ตัวชี้วัดคลาดเคลื่อนและทำให้จำนวนข้อผิดพลาดสูงเกินจริง การกรองสิ่งเหล่านี้ออกช่วยให้เห็นภาพการใช้งานจากผู้ใช้จริงได้ชัดเจนขึ้น
ลักษณะทั่วไปของบอต: bot, crawler, spider, curl, python-requests, Googlebot, Bingbot.
ใช้ grep -iv (กลับเงื่อนไขโดยไม่สนใจตัวพิมพ์เล็กใหญ่) เพื่อแยกบอตที่รู้จักออก หรือใช้ awk แยกด้วย " แล้วจับคู่กับฟิลด์ UA โดยตรง
#!/usr/bin/env bash
# Count top 15 User-Agent strings, excluding known bots
awk -F'"' '{ print $6 }' /var/log/nginx/access.log \
| grep -iv -e 'bot' -e 'crawler' -e 'spider' -e 'curl' \
-e 'python' -e 'wget' -e 'Go-http-client' \
| sort \
| uniq -c \
| sort -rn \
| head -15รวมปริมาณการใช้งานตามปลายทาง
การทราบว่าปลายทางใดได้รับการใช้งานมากที่สุดและสร้างข้อผิดพลาดมากที่สุด จะช่วยจัดลำดับความสำคัญของการปรับปรุงประสิทธิภาพและการวางแผนความจุ เส้นทางคำขออยู่ภายในฟิลด์คำขอที่อยู่ในเครื่องหมายอัญประกาศ
แยกด้วย " เลือกฟิลด์ 2 (บรรทัดคำขอ) จากนั้นตัดวิธีการและโพรโทคอลออกเพื่อแยกเส้นทาง สำหรับ API ที่มีพารามิเตอร์ในเส้นทาง เช่น /users/12345 คุณอาจต้องทำให้เป็นรูปแบบมาตรฐานโดยเปลี่ยนรหัสเป็น /users/:id ด้วย sed หรือรูปแบบ awk ที่ซับซ้อนขึ้น
#!/usr/bin/env bash
# Top 20 requested endpoints (method + path, no query string)
awk -F'"' '{ print $2 }' /var/log/nginx/access.log \
| awk '{ print $1, $2 }' \
| sed 's|/[0-9][0-9]*\b|/:id|g' \
| sort \
| uniq -c \
| sort -rn \
| head -20เชื่อมโยงข้อผิดพลาดกับปลายทางด้วย awk
การวิเคราะห์แบบผ่านครั้งเดียวที่ทรงพลังที่สุดคือการรวมหลายฟิลด์พร้อมกัน ได้แก่ ปลายทาง รหัสสถานะ และเวลาแฝงหากต้องการ อาร์เรย์แบบเชื่อมโยงของ awk ที่ใช้ค่าผสมเป็นกุญแจทำให้วิธีนี้ทั้งชัดเจนและรวดเร็ว
รูปแบบด้านล่างนับข้อผิดพลาด 5xx แยกตามปลายทางในการประมวลผลครั้งเดียว ไม่มีไฟล์ชั่วคราวและไม่มีการเรียงลำดับระหว่างทางจนกว่าจะถึงขั้นตอนสุดท้าย วิธีนี้ใช้ในสคริปต์สังเกตการณ์ระบบจริงเมื่อต้องการคำตอบภายในเวลาไม่ถึงหนึ่งนาทีจากบันทึกขนาดใหญ่
#!/usr/bin/env bash
# Count 5xx errors per endpoint path in a single pass
awk -F'"' '{
# $2 = request line e.g. "GET /api/orders HTTP/1.1"
# $0 in original space-split: $9 = status
split($0, fields, " ")
status = fields[9]
if (status ~ /^5/) {
split($2, req, " ")
path = req[2]
# Normalise numeric IDs
gsub(/\/[0-9]+/, "/:id", path)
errors[path]++
}
}
END {
for (p in errors)
printf "%6d %s\n", errors[p], p
}' /var/log/nginx/access.log \
| sort -rn \
| head -20ประมวลผลบันทึกที่หมุนเวียนและบีบอัด
เซิร์ฟเวอร์ส่วนใหญ่จะหมุนเวียนบันทึกทุกวัน ไฟล์เก่าจะถูกบีบอัดด้วย gzip เป็น access.log.1.gz, access.log.2.gz และอื่น ๆ เครื่องมือมาตรฐานไม่สามารถอ่านไฟล์เหล่านี้โดยตรงได้ แต่มีสองวิธีที่ทำงานได้อย่างเหมาะสม:
zcat— คลายการบีบอัดไปยังเอาต์พุตมาตรฐาน แล้วส่งต่อเข้าสู่กระบวนการประมวลผลต่อเนื่องzgrep— ใช้ grep ค้นหาภายในไฟล์ gzip โดยตรงโดยไม่ต้องแตกไฟล์
หากต้องการวิเคราะห์บันทึกตลอดหนึ่งสัปดาห์ที่มีทั้งไฟล์แบบไม่บีบอัดและไฟล์บีบอัด ให้ใช้การแทนที่กระบวนการหรือรวมไฟล์ด้วย zcat ส่วนโค้ดตัวอย่างด้านล่างประมวลผลไฟล์ที่หมุนเวียนล่าสุด 7 ไฟล์รวมกับบันทึกปัจจุบันที่กำลังทำงานอยู่ ในการเรียกใช้ awk เพียงครั้งเดียว โดยไม่ต้องใช้ไฟล์ชั่วคราว
#!/usr/bin/env bash
# Aggregate status codes across a week of rotated logs
# Handles both plain and gzip-compressed rotation files
LOG_DIR="/var/log/nginx"
{
cat "${LOG_DIR}/access.log" 2>/dev/null
zcat "${LOG_DIR}/access.log".*.gz 2>/dev/null
} | awk '
{ count[$9]++ }
END {
for (s in count)
printf "%6d %s\n", count[s], s
}' | sort -rnฟิลด์ใดเก็บรหัสสถานะ HTTP ในรูปแบบบันทึกแบบรวม
คุณกำลังเขียนคำสั่งบรรทัดเดียวของ awk เพื่อกรองเฉพาะการตอบกลับ HTTP 4xx จากบันทึกการเข้าถึง Nginx มาตรฐานในรูปแบบ Combined Log Format (คั่นด้วยช่องว่าง และครอบบรรทัดคำขอด้วยเครื่องหมายอัญประกาศ) หมายเลขฟิลด์ใดระบุรหัสสถานะ HTTP ได้ถูกต้อง
สรุปบทเรียน: สายงานวิเคราะห์บันทึก
ในบทเรียนนี้ คุณได้สร้างชุดเครื่องมือที่ครบถ้วนสำหรับวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับขนาดใหญ่ โดยใช้เฉพาะยูทิลิตีมาตรฐานของ BASH
เทคนิคสำคัญที่ครอบคลุม:
- เริ่มจากโครงสร้าง — Combined Log Format มีโครงสร้างฟิลด์ที่คาดเดาได้ การรู้โครงสร้างนี้ช่วยให้คุณแยกข้อมูลได้อย่างน่าเชื่อถือด้วย
cut -d'"'หรือการอ้างอิงฟิลด์ของawk - การดึงรหัสสถานะ —
awk '{ count[$9]++ }'นับรหัสทั้งหมดได้ภายในการวนอ่านเพียงรอบเดียว และกรองด้วย$9 ~ /^5/เพื่อค้นหาข้อผิดพลาดจากเซิร์ฟเวอร์ - การวิเคราะห์เวลาแฝง — แยกวิเคราะห์ฟิลด์กำหนดเอง
rt=ด้วยawkเพื่อคำนวณค่าเฉลี่ย ค่าสูงสุด และช่วงของฮิสโตแกรมได้โดยไม่ต้องใช้เครื่องมือภายนอก - การวิเคราะห์ไคลเอ็นต์และบอต — แยกข้อมูลด้วย
"โดยใช้-F'"'เพื่อเข้าถึงฟิลด์ User-Agent จากนั้นส่งต่อผ่านgrep -ivเพื่อแยกบอตออกก่อนรวมผล - การปรับมาตรฐานปลายทาง — ใช้
gsub(/\/[0-9]+/, "/:id")ภายในawkเพื่อรวมเส้นทางที่มีพารามิเตอร์ให้เป็นรูปแบบเดียวก่อนนับ - บันทึกที่ถูกหมุนเวียน — รวม
catและzcatในเชลล์ย่อย เพื่อส่งไฟล์จากการหมุนเวียนทั้งหมดเข้าสู่สายงานเดียวกัน
รูปแบบเหล่านี้นำมาประกอบกันได้ คุณสามารถเชื่อมการกรอง การดึงข้อมูล การปรับมาตรฐาน และการรวมผลไว้ในสายงานเดียว ซึ่งประมวลผลได้หลายร้อยล้านบรรทัดบนฮาร์ดแวร์ทั่วไป หากเชี่ยวชาญพื้นฐานเหล่านี้แล้ว คุณแทบไม่จำเป็นต้องใช้บริการรวมบันทึกโดยเฉพาะสำหรับการตรวจสอบเหตุขัดข้องเฉพาะกิจ
คำถามที่พบบ่อย
บทเรียน “การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่”
ดึงรหัสสถานะ เวลาแฝง และฟิลด์ไคลเอ็นต์จากบันทึกการเข้าถึงด้วย grep, cut และ awk คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม
ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การแยกวิเคราะห์บันทึกเว็บและแอปพลิเคชันในระดับใหญ่
- การติดตามบันทึกแบบเรียลไทม์และการแจ้งเตือนแบบสตรีม
- การสอบถาม journald ด้วย journalctl ในสคริปต์
- การคำนวณตัวชี้วัดและฮิสโตแกรมจากกระแสบันทึก