飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 基础入门

    • Linux 命令概述与环境准备
    • 文件与目录操作(上):ls、cd、pwd
    • 文件与目录操作(下):cat、touch、mkdir、rm、cp、mv
    • 获取帮助与基础工具:man、help、clear、exit、sudo
  • 文件权限

    • 文件权限管理:chmod、chown
  • 系统与监控

    • 进程管理与系统监控:ps、top、kill、df、du、free
    • 用户与环境:whoami、id、env、echo、history
  • 网络命令

    • 网络诊断(上):ping、curl、wget
    • 网络诊断(下):netstat、ss、ip
    • 网络抓包与高级工具:traceroute、tcpdump、nc
    • DNS 与防火墙:nslookup、dig、iptables
  • 文本处理

    • 文本搜索:grep
    • 文本处理(上):awk
    • 文本处理(下):sed
    • 文本排序与统计:sort、uniq、wc
    • 文件查看与查找:head、tail、cut、find
    • 归档压缩与管道组合:tar、gzip、xargs
  • 开发工具

    • 开发工具链(上):gcc、make
    • 开发工具链(下):gdb、time
    • 版本控制:git
    • 远程操作:ssh、scp
    • 编辑器:vim、nano
  • Shell 编程

    • Shell 编程基础(上):变量、管道、重定向
    • Shell 编程基础(下):条件、循环、函数
  • 综合实战

    • 综合实战:日志分析

综合实战:日志分析

实战场景

假设你是一名运维工程师,需要分析 Nginx 访问日志,找出:

  1. 访问最多的 10 个 IP
  2. 访问最多的 10 个 URL
  3. HTTP 状态码分布
  4. 每小时访问量趋势
  5. 响应时间超过 1 秒的请求

日志格式

Nginx 默认访问日志格式:

$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time

示例日志行:

192.168.1.1 - - [15/Jan/2024:10:00:01 +0800] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0" 0.023
192.168.1.2 - - [15/Jan/2024:10:00:02 +0800] "GET /api/users HTTP/1.1" 200 5678 "https://example.com" "Mozilla/5.0" 0.156
192.168.1.1 - - [15/Jan/2024:10:00:03 +0800] "POST /api/login HTTP/1.1" 401 89 "-" "curl/7.68.0" 0.045
192.168.1.3 - - [15/Jan/2024:10:00:04 +0800] "GET /images/logo.png HTTP/1.1" 200 45678 "https://example.com" "Mozilla/5.0" 0.234

字段说明:

字段示例含义
$1192.168.1.1客户端 IP
$4[15/Jan/2024:10:00:01访问时间(含前括号)
$6"GET请求方法(含引号)
$7/index.html请求 URL
$9200HTTP 状态码
$101234响应大小(字节)
$12"-"Referer
$13"Mozilla/5.0"User-Agent
$140.023请求处理时间(秒)

创建测试日志

#!/bin/bash

# 生成测试日志
cat > generate_log.sh
#!/bin/bash

ips=("192.168.1.1" "192.168.1.2" "192.168.1.3" "10.0.0.1" "10.0.0.2")
urls=("/index.html" "/api/users" "/api/login" "/images/logo.png" "/css/style.css" "/js/app.js")
methods=("GET" "POST")
codes=(200 200 200 200 301 404 500)

for i in $(seq 1 1000); do
    ip=${ips[$RANDOM % ${#ips[@]}]}
    url=${urls[$RANDOM % ${#urls[@]}]}
    method=${methods[$RANDOM % ${#methods[@]}]}
    code=${codes[$RANDOM % ${#codes[@]}]}
    size=$((RANDOM % 10000 + 100))
    time=$(printf "%.3f" $(echo "scale=3; $RANDOM/1000" | bc -l))
    
    hour=$(printf "%02d" $((RANDOM % 24)))
    min=$(printf "%02d" $((RANDOM % 60)))
    sec=$(printf "%02d" $((RANDOM % 60)))
    
    echo "$ip - - [15/Jan/2024:$hour:$min:$sec +0800] \"$method $url HTTP/1.1\" $code $size \"-\" \"Mozilla/5.0\" $time"
done
# Ctrl+D

chmod +x generate_log.sh
./generate_log.sh > access.log

分析脚本

#!/bin/bash

# analyze.sh - Nginx 日志分析脚本

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

if [ ! -f "$LOG_FILE" ]; then
    echo "Error: Log file '$LOG_FILE' not found"
    echo "Usage: $0 <log_file>"
    exit 1
fi

echo "========================================"
echo "Nginx 日志分析报告"
echo "日志文件: $LOG_FILE"
echo "总请求数: $(wc -l < "$LOG_FILE")"
echo "========================================"
echo

# 1. Top 10 IP
echo "【Top 10 访问 IP】"
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -n 10 | awk '{printf "%6s %s\n", $1, $2}'
echo

# 2. Top 10 URL
echo "【Top 10 访问 URL】"
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -n 10 | awk '{printf "%6s %s\n", $1, $2}'
echo

# 3. HTTP 状态码分布
echo "【HTTP 状态码分布】"
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn | awk '{printf "%6s %s\n", $1, $2}'
echo

# 4. 每小时访问量
echo "【每小时访问量】"
awk '{print substr($4, 14, 2)}' "$LOG_FILE" | sort | uniq -c | sort -k2 | awk '{printf "%02d:00 %6s\n", $2, $1}'
echo

# 5. 慢请求(> 1秒)
echo "【慢请求统计(> 1秒)】"
awk '$14 > 1.0 {print $1, $7, $9, $14}' "$LOG_FILE" | head -n 10
echo "慢请求总数: $(awk '$14 > 1.0 {count++} END{print count+0}' "$LOG_FILE")"
echo

# 6. 平均响应时间
echo "【平均响应时间】"
awk '{sum+=$14; count++} END{printf "%.3f 秒\n", sum/count}' "$LOG_FILE"
echo

# 7. 4xx 和 5xx 错误统计
echo "【错误请求统计】"
echo "4xx 错误: $(awk '$9 ~ /^4/ {count++} END{print count+0}' "$LOG_FILE")"
echo "5xx 错误: $(awk '$9 ~ /^5/ {count++} END{print count+0}' "$LOG_FILE")"
echo

# 8. 响应大小统计
echo "【响应大小统计】"
awk '{sum+=$10; count++} END{printf "平均: %.0f 字节\n最大: %s 字节\n", sum/count, max}' "$LOG_FILE"

进阶:实时日志监控

#!/bin/bash

# monitor.sh - 实时监控日志

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

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

echo "开始监控日志: $LOG_FILE"
echo "按 Ctrl+C 停止"
echo

# 使用 tail -f 实时追踪,配合 awk 分析
tail -f "$LOG_FILE" | awk '
{
    ip = $1
    url = $7
    status = $9
    size = $10
    time = $14
    
    # 统计 IP
    ip_count[ip]++
    
    # 统计 URL
    url_count[url]++
    
    # 统计状态码
    status_count[status]++
    
    # 统计总请求数
    total++
    
    # 每 10 条输出一次统计
    if (total % 10 == 0) {
        print "\n=== 实时统计 (总请求: " total ") ==="
        print "Top 3 IP:"
        for (i in ip_count) {
            print "  " ip_count[i] " " i
        }
        print "状态码分布:"
        for (s in status_count) {
            print "  " status_count[s] " " s
        }
    }
    
    # 检测异常(5xx 错误)
    if (status ~ /^5/) {
        print "[ALERT] 5xx error: " status " " url " " ip
    }
    
    # 检测慢请求
    if (time > 1.0) {
        print "[SLOW] " time "s " url " " ip
    }
}'

本篇小结

  • Nginx 日志字段:IP、时间、方法、URL、状态码、大小、Referer、User-Agent、处理时间
  • 分析流程:提取字段 → 排序 → 统计 → 排序 → 取 Top N
  • 黄金组合:awk '{print $N}' | sort | uniq -c | sort -rn | head
  • 实时监控:tail -f log | awk '...' 实时处理新增日志
  • 异常检测:$9 ~ /^5/ 检测 5xx 错误,$14 > 1.0 检测慢请求
  • 完整脚本结构:参数检查 → 数据统计 → 格式化输出

动手实践

  1. 生成测试日志:

    # 使用上面的 generate_log.sh 生成 1000 条日志
    ./generate_log.sh > access.log
    wc -l access.log
    
  2. 手动分析练习:

    # Top 10 IP
    awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -n 10
    
    # Top 10 URL
    awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -n 10
    
    # 状态码分布
    awk '{print $9}' access.log | sort | uniq -c | sort -rn
    
    # 每小时访问量
    awk '{print substr($4, 14, 2)}' access.log | sort | uniq -c | sort -k2
    
    # 慢请求
    awk '$14 > 1.0 {print $1, $7, $9, $14}' access.log | head -n 10
    
  3. 运行分析脚本:

    # 创建上面的 analyze.sh
    chmod +x analyze.sh
    ./analyze.sh access.log
    
  4. 实时监控练习(需要持续产生日志):

    # 终端 1:持续生成日志
    while true; do
        echo "192.168.1.1 - - [$(date '+%d/%b/%Y:%H:%M:%S %z')] \"GET /api/test HTTP/1.1\" 200 123 \"-\" \"Mozilla/5.0\" $(printf '%.3f' $(echo "scale=3; $RANDOM/1000" | bc -l))" >> access.log
        sleep 1
    done
    
    # 终端 2:实时监控
    tail -f access.log | awk '$9 ~ /^5/ {print "[ERROR]", $0}'
    
  5. 扩展练习:修改分析脚本,增加以下功能:

    • 统计每个 IP 的平均响应时间
    • 找出访问最频繁的 User-Agent
    • 统计每个 URL 的错误率(4xx+5xx / 总请求)
  6. 思考:如果日志文件达到 10GB,awk '{print $1}' | sort | uniq -c | sort -rn 这个命令会遇到什么问题?如何优化大文件日志分析的性能?