最新 Linux awk 命令实战教程:从日志分析到性能监控

开发 Linux
今天要介绍的是文本处理的"瑞士军刀" —— awk。无论是分析日志、处理数据,还是提取信息,它都能帮你轻松搞定。

大家好,我是小康。上次我们一起学习了 Linux 的 sed 命令,今天要介绍的是文本处理的"瑞士军刀" —— awk。无论是分析日志、处理数据,还是提取信息,它都能帮你轻松搞定。

第一部分: 初识 awk

作为一名开发老兵,我整理了这些年和 awk 打交道的心得。希望能帮你少走弯路,快速掌握这个强大的工具。

记得刚入行那会儿,面对成堆的日志文件,我跟大多数新手一样一筹莫展。直到遇到了 awk 这个老伙计,才算找到了"趁手的兵器"。

今天,就让我用一个开发工程师的视角,带你认识这个陪伴了我 6 年多的老朋友。

1. 第一次相遇:awk 是个什么样的角色?

就像一个心灵手巧的老师傅,awk 最擅长的就是把大段大段的文本"解剖"开来,精准地找出你想要的信息。它的名字来自三位创始人(Aho、Weinberger、Kernighan)的首字母,虽然不好念,但本事真不小。

2. 从一个真实案例开始

还记得我遇到的第一个挑战:leader 让我从一个几GB的服务日志里找出造成系统故障的元凶。

当时的日志大概长这样:

2024-02-13 10:00:01 [192.168.1.100] "GET /api/users" 200 89ms
2024-02-13 10:00:02 [192.168.1.101] "POST /api/orders" 500 1230ms
2024-02-13 10:00:03 [192.168.1.102] "GET /api/products" 200 45ms

我需要:

  • 找出所有响应时间超过1秒的请求
  • 分析高峰期的访问量
  • ......

用 awk 的解决方案出奇简单:

# 1、找出所有响应时间超过1秒的请求
awk '
{
    # 提取并转换响应时间
    time = $7  # 取最后一个字段
    gsub(/ms/, "", time)  # 去掉ms
    time = time + 0  # 确保转成数字
    
    # 只打印超过1秒(1000ms)的请求
    if(time >= 1000) {
        printf "时间: %s %s\nIP: %s\n请求: %s %s\n响应时间: %dms\n----------\n", 
            $1, $2, substr($3, 2, length($3)-2), $4, $5, time
    }
}' access.log

# 输出:
时间: 2024-02-13 10:00:02
IP: 192.168.1.101
请求: "POST /api/orders"
响应时间: 1230ms
----------

# 2、分析高峰期的访问量
awk '
BEGIN {
    print "每分钟访问量统计:"
    print "-------------------"
}
{
    # 提取时分
    split($2, t, ":")
    minute = t[1] ":" t[2]     # 只取小时和分钟
    count[minute]++
}
END {
    # 按时间排序输出
    n = asorti(count, sorted)
    for(i=1; i<=n; i++) {
        printf "%s:00 - %d次访问\n", sorted[i], count[sorted[i]]
    }
}' access.log

# 输出:
每分钟访问量统计:
-------------------
10:00:00 - 3次访问
10:01:00 - 2次访问
10:02:00 - 1次访问

第二部分 : awk 基本功

老规矩,我们先来看看最常用的 awk 基础命令。这些都是我这些年解决问题的"杀手锏",保证你学了就能用。

1. awk的基本结构

在开始学习具体命令前,我们先来了解awk程序的基本结构:

awk 'BEGIN {动作前}
    pattern {动作}
    END {动作后}' 文件名

就像一个完整的故事有开头、主体和结尾,awk 也有三个主要部分:

(1) BEGIN块:开场白

  • 在读取文件前执行
  • 常用来打印表头、初始化变量
# 例如:输出前先打印个表头
BEGIN {print "=== 进程列表 ==="}

(2) pattern {action}:主体部分

  • pattern:匹配条件,决定要处理哪些行
  • action:具体操作,决定要做什么
# 例如:找出root的进程
$1=="root" {print $0}

(3) END块:收尾工作

  • 在处理完所有行后执行
  • 常用来输出统计结果
# 例如:最后输出总行数
END {print "共有"NR"个进程"}

此外,awk 还提供了一些常用的内置变量:

  • $0:整行内容
  • 2..:第1、2列
  • NR:当前行号
  • NF:当前行的列数

2. 实例讲解

理解了基本结构,我们来看些实际例子。假设我们有一个进程列表 process.txt:

root     1234  5.0  2.5 mysql    running
admin    2345  3.2  1.5 nginx    running
root     3456  8.5  4.0 java     stopped
nobody   4567  2.1  1.0 nginx    running

(1) 提取特定列

# 看看谁在运行这些进程
awk '{print $1}' process.txt

# 输出:
root
admin
root
nobody

# 查看进程名和状态
awk '{print $5, $6}' process.txt

# 输出:
mysql running
nginx running
java stopped
nginx running

(2) 条件过滤(最常用)

# 找出 CPU 使用率超过5%的进程
awk '$3 > 5 {print $5 "进程CPU使用率:", $3"%"}' process.txt

# 输出:
java进程CPU使用率: 8.5%

# 找出状态为 running 的进程
awk '$6=="running" {print $1,$5}' process.txt

# 输出:
root mysql
admin nginx
nobody nginx

2. 实用统计功能

(1) 常用统计

# 统计进程数量, NR: NR 是 awk 的一个内置变量,表示当前已经处理的记录(行)数量。
awk 'END {print "总进程数:", NR}' process.txt

# 输出:
总进程数: 4

# 我们也可以在处理过程中看到NR的变化
awk '{print "当前处理第" NR "行"}' process.txt

# 输出:
当前处理第1行
当前处理第2行
当前处理第3行
当前处理第4行

# 计算所有进程的平均CPU使用率
awk '{sum += $3} END {print "平均CPU使用率:", sum/NR"%"}' process.txt

# 输出:
平均CPU使用率: 4.7%

(2) 分组统计(特别常用)

# 看看每个用户开了多少个进程
awk '{count[$1]++} END {
    for(user in count) {
        print user "的进程数:", count[user]
    }
}' process.txt

# 输出:
root的进程数: 2
admin的进程数: 1
nobody的进程数: 1

# 统计每种状态的进程数
awk '{states[$6]++} END {
    for(state in states) {
        print state, states[state]
    }
}' process.txt

# 输出:
running 3
stopped 1

3. 实战常用技巧

(1) 匹配特定内容

# 找出 java 相关的进程
awk '/java/ {print $0}' process.txt # $0 代表当前行的整行内容

# 输出:
root     3456  8.5  4.0 java     stopped

# 找出包含特定字符的行并突出显示重要信息
awk '/nginx/ {print "进程ID:"$2, "内存:"$4"%"}' process.txt

# 输出:
进程ID:2345 内存:1.5%
进程ID:4567 内存:1.0%

(2) 多条件组合(经常用到)

# 找出 CPU 高、状态为 running 的进程
awk '$3 > 3 && $6=="running" {
    print "警告 -", $5, "进程CPU使用率:", $3"%"
}' process.txt

# 输出:
警告 - mysql 进程CPU使用率: 5.0%
警告 - nginx 进程CPU使用率: 3.2%

4. 小贴士

(1) 实用的判断方法:

# 找出异常的进程(CPU或内存使用过高)
awk '$3 > 5 || $4 > 3 {
    print $5 "进程异常:"
    print "  CPU:", $3"%"
    print "  内存:", $4"%"
}' process.txt

# 输出:
java进程异常:
  CPU: 8.5%
  内存: 4.0%

(2) 累加统计:

bash
# 计算 nginx 进程的总内存占用
awk '/nginx/ {total += $4} 
     END {print "nginx总内存占用:", total"%"}' process.txt

# 输出:
nginx总内存占用: 2.5%

记住:

  • $1,$2,$3... 代表第几列
  • NR 代表当前行号
  • print 和 printf 都是打印命令
  • 用 $0 可以打印整行

这些都是我平时工作中最常用的简单命令,基本够用了。等你熟悉了这些,我们再学更高级的用法。

第三部分: awk高级应用指南(性能分析)

接下来我们来点高级的,带大家用 awk 处理日常工作中最常见的几个场景。每一步我们都从简单的开始,循序渐进地掌握。

1. 基础日志处理

先从一个简单的接口日志开始:

2024-02-14 10:00:01 [api=/user/login] cost=100ms status=200
2024-02-14 10:00:02 [api=/user/info] cost=50ms status=200
2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500
2024-02-14 10:00:04 [api=/order/create] cost=150ms status=200

(1) 提取重要信息(简单)

# 只看接口名和响应时间
awk '{print $3, $4}' api.log

# 输出:
[api=/user/login] cost=100ms
[api=/user/info] cost=50ms
[api=/user/login] cost=800ms
[api=/order/create] cost=150ms

(2) 查找异常请求(常用)

# 找出响应时间超过500ms的慢请求
awk '
    {
        # 提取响应时间的数字部分
        gsub(/cost=|ms/, "", $4)     # 去掉"cost="和"ms"
        
        # 如果响应时间超过500ms
        if($4 > 500) {
            print "慢请求: " $0
        }
    }
' api.log

# 输出:
慢请求: 2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500

2. 接口性能分析

(1) 计算接口的平均响应时间(入门级)

# 计算每个接口的平均响应时间
awk '
{
    # 提取接口名称
    api=$3
    # 提取响应时间的数字部分
    gsub(/.*=|ms.*/, "", $4)
    # 累加响应时间
    sum[api] += $4
    # 统计请求次数
    count[api]++
}
END {
    print "接口平均响应时间:"
    for(api in sum) {
        printf "%s: %.2fms\n", api, sum[api]/count[api]
    }
}' api.log

# 输出:
接口平均响应时间:
[api=/user/login]: 450.00ms
[api=/user/info]: 50.00ms
[api=/order/create]: 150.00ms

(2) 统计接口QPS(常用)

先从一个简单的接口日志开始:

2024-02-14 10:00:01 [api=/user/login] cost=100ms status=200
2024-02-14 10:00:02 [api=/user/info] cost=50ms status=200
2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500
2024-02-14 10:00:04 [api=/order/create] cost=150ms status=200

# 命令:计算每秒的请求数(QPS)
awk '{
    # 把时间列拼接起来: $1是日期,$2是时间
    # 例如: "2024-02-14 10:00:01"
    time = $1" "$2

    # substr 函数用于截取字符串
    # 从拼接的时间字符串中取前19位,精确到秒
    # 如: "2024-02-14 10:00:01"
    second = substr(time, 1, 19)

    # 用时间作为key,计数+1
    count[second]++
}
END {
    # 处理完所有行后,打印统计结果
    print "每秒请求数(QPS):"
    # 遍历统计结果
    for(s in count) {
        print s ": " count[s] "次/秒"
    }
}' api.log

(3) 分析响应时间分布(进阶)

# 按区间统计响应时间分布
awk '
BEGIN {
    print "响应时间分布统计:"
}
{
    # 提取cost=后面的数字,去掉ms
    split($4, arr, "=|ms")    # 用=或ms分割,如:"cost=100ms" -> arr[2]="100"
    time = arr[2]             # 提取数字部分
    
    # 按区间统计请求数
    if(time <= 100) {
        range["0-100ms"]++       # 统计小于等于100ms的请求
    } else if(time <= 200) {
        range["101-200ms"]++     # 统计101ms到200ms的请求
    } else {
        range["200ms+"]++        # 统计大于200ms的请求
    }
    total++    # 总请求数加1
}
END {
    # 遍历每个区间并打印统计结果
    for(r in range) {
        percent = range[r]/total*100
        printf "%s: %d个请求 (%.1f%%)\n", r, range[r], percent
    }
}' api.log

# 现在输出应该是:
响应时间分布统计:
0-100ms: 2个请求 (50.0%)
101-200ms: 1个请求 (25.0%)
200ms+: 1个请求 (25.0%)

3. 错误分析

统计错误率(常用)

2024-02-14 10:00:01 [api=/user/login] cost=100ms status=200
2024-02-14 10:00:02 [api=/user/info] cost=50ms status=200
2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500
2024-02-14 10:00:04 [api=/order/create] cost=150ms status=200

# 计算接口错误率
awk '
{
    api=$3
    status=$5
    gsub(/.*=/, "", status)
    
    # 统计总请求和错误请求
    total[api]++
    if(status >= 400) {
        errors[api]++
    }
}
END {
    print "接口错误率统计:"
    for(api in total) {
        if(errors[api] > 0) {
            err_rate = errors[api]/total[api]*100
            printf "%s: %.1f%% (%d/%d)\n", 
                   api, err_rate, errors[api], total[api]
        }
    }
}' api.log

# 输出:
接口错误率统计:
[api=/user/login]: 50.0% (1/2)

4. 生成性能报告(高级)

把前面学到的都用上,生成一个完整的性能报告:

# 生成完整的接口性能分析报告
awk '
BEGIN {
    print "=== 接口性能分析报告 ==="
    print "时间范围:" strftime("%Y-%m-%d %H:%M:%S")
    print "\n1. 总体统计"
}
{
    # 记录基础信息
    api=$3
    gsub(/.*=|ms.*/, "", $4)
    cost=$4
    gsub(/.*=/, "", $5)
    status=$5
    
    # 统计总请求
    total_reqs++
    
    # 按接口统计
    reqs[api]++
    total_cost[api] += cost
    
    # 记录最大最小响应时间
    if(cost > max_cost[api]) max_cost[api] = cost
    if(min_cost[api] == 0 || cost < min_cost[api]) 
        min_cost[api] = cost
    
    # 统计错误
    if(status >= 400) errors[api]++
}
END {
    # 1. 打印总体统计
    printf "总请求数:%d\n", total_reqs
    
    # 2. 打印接口详情
    print "\n2. 接口详情"
    for(api in reqs) {
        printf "\n接口:%s\n", api
        printf "  总调用次数:%d\n", reqs[api]
        printf "  平均响应时间:%.2fms\n", 
               total_cost[api]/reqs[api]
        printf "  最大响应时间:%dms\n", max_cost[api]
        printf "  最小响应时间:%dms\n", min_cost[api]
        if(errors[api] > 0) {
            printf "  错误率:%.1f%%\n", 
                   errors[api]/reqs[api]*100
        }
    }
}' api.log

# 输出:
=== 接口性能分析报告 ===
时间范围:2024-02-14 10:00:00

1. 总体统计
总请求数:4

2. 接口详情

接口:[api=/user/login]
  总调用次数:2
  平均响应时间:450.00ms
  最大响应时间:800ms
  最小响应时间:100ms
  错误率:50.0%

接口:[api=/user/info]
  总调用次数:1
  平均响应时间:50.00ms
  最大响应时间:50ms
  最小响应时间:50ms

接口:[api=/order/create]
  总调用次数:1
  平均响应时间:150.00ms
  最大响应时间:150ms
  最小响应时间:150ms

5. 实用小技巧

(1) 处理大文件时先取样分析:

head -1000 big_log.txt | awk '你的命令'

(2) 实时监控错误和慢请求:

测试用例:
❯ cat api.log
# api.log 示例数据:
2024-02-14 10:00:01 [api=/user/login] cost=100ms status=200    # 正常请求
2024-02-14 10:00:02 [api=/user/info] cost=550ms status=200     # 慢请求(>500ms)
2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500    # 慢请求且报错
2024-02-14 10:00:04 [api=/order/create] cost=150ms status=404  # 错误请求
2024-02-14 10:00:05 [api=/user/profile] cost=200ms status=200  # 正常请求

# 监控命令:
tail -f api.log | awk '
$4 ~ /cost=[5-9][0-9][0-9]ms/ || $5 ~ /status=[45][0-9][0-9]/ {
    # 检查是否是慢请求
    if($4 ~ /cost=[5-9][0-9][0-9]ms/) {
        msg="慢请求"
    }
    
    # 检查是否有错误状态码
    if($5 ~ /status=[45][0-9][0-9]/) {
        msg=msg?msg" 且 状态码异常":"状态码异常"
    }
    
    # 打印告警信息
    print "\033[31m告警:" $0 " # " msg "\033[0m"
    
    # 重置消息变量
    msg=""
}'

# 输出(红色显示):
告警:2024-02-14 10:00:02 [api=/user/info] cost=550ms status=200        # 因为响应时间>500ms
告警:2024-02-14 10:00:03 [api=/user/login] cost=800ms status=500       # 因为响应时间>500ms且状态码500
告警:2024-02-14 10:00:04 [api=/order/create] cost=150ms status=404     # 因为状态码404

记住:

  • 先从简单的统计开始
  • 需要时再加更多的统计维度
  • 复杂的分析可以分步骤进行
  • 多用print调试你的统计逻辑

学会了这些,你就能应对大部分的日志分析工作了!

第四部分:实战篇 - 应用日志分析

接着我们来分析实际工作中最常见的几种应用日志。咱们由浅入深,一步步来。

1. 基础日志分析

(1) 简单的应用日志

先来看一个最基础的应用日志:

2024-02-14 10:00:01 [INFO] UserService - 用户登录成功,用户名=admin
2024-02-14 10:00:02 [ERROR] OrderService - 订单创建失败:数据库连接超时
2024-02-14 10:00:03 [WARN] UserService - 密码错误,用户名=test
2024-02-14 10:00:04 [ERROR] PaymentService - 支付失败:余额不足

(2) 基础日志过滤(最简单的用法)

# 命令1:显示所有ERROR日志
awk '/ERROR/' app.log

# 输出:
2024-02-14 10:00:02 [ERROR] OrderService - 订单创建失败:数据库连接超时
2024-02-14 10:00:04 [ERROR] PaymentService - 支付失败:余额不足

# 命令2:查看特定服务的日志
awk '/UserService/' app.log

# 输出:
2024-02-14 10:00:01 [INFO] UserService - 用户登录成功,用户名=admin
2024-02-14 10:00:03 [WARN] UserService - 密码错误,用户名=test

(3) 统计日志级别(常用功能)

# 命令:统计每种日志级别的数量
awk '
    # 匹配有方括号的行
    /\[.*\]/ {
        # 提取方括号中的内容,存入arr数组
        match($0, /\[(.*?)\]/, arr)
        # 对应的日志级别计数加1
        level[arr[1]]++
    }
    # 所有行处理完后执行
    END {
        print "日志级别统计:"
        # 遍历统计结果并打印
        for(l in level) {
            print l ": " level[l] "条"
        }
    }
' app.log

# 输出:
日志级别统计:
INFO: 1条
ERROR: 2条
WARN: 1条

2. 接口调用日志分析

(1) 接口日志示例

2024-02-14 10:00:01 [api=/user/login] cost=120ms status=200
2024-02-14 10:00:02 [api=/order/create] cost=500ms status=500
2024-02-14 10:00:03 [api=/user/info] cost=80ms status=200

(2) 分析接口响应时间

# 命令:统计每个接口的平均响应时间
awk '
{
    # 提取接口名和响应时间
    api=$3                      # 获取接口名称列
    gsub(/\[|\]/, "", api)     # 去掉方括号
    gsub(/.*=|ms/, "", $4)     # 提取响应时间的数字部分
    
    # 统计数据
    apis[api] += $4            # 累加响应时间
    count[api]++               # 统计调用次数
}
END {
    print "接口平均响应时间:"
    for(a in apis) {
        printf "%s: %.2fms\n", a, apis[a]/count[a]
    }
}' api.log

# 输出:
接口平均响应时间:
api=/user/login: 120.00ms
api=/order/create: 500.00ms
api=/user/info: 80.00ms

3. 错误日志分析

(1) 异常堆栈日志

> cat Service.log
2024-02-14 10:00:01 [ERROR] NullPointerException: 空指针异常
    at com.example.UserService.getUser(UserService.java:15)
    at com.example.UserController.login(UserController.java:10)
2024-02-14 10:00:02 [ERROR] SQLException: 数据库连接失败
    at com.example.OrderService.create(OrderService.java:25)

(2) 提取完整异常信息

# 命令:提取异常信息及其堆栈
awk '
    # 匹配错误行
    /ERROR/ {
        print "\n发现异常:"
        print $0            # 打印错误行
        print "异常堆栈:"
    }
    # 匹配堆栈信息(以空格开头的行)
    /^[[:space:]]/ {
        print $0           # 打印堆栈行
    }
' Service.log

# 输出:
发现异常:
2024-02-14 10:00:01 [ERROR] NullPointerException: 空指针异常
异常堆栈:
    at com.example.UserService.getUser(UserService.java:15)
    at com.example.UserController.login(UserController.java:10)

发现异常:
2024-02-14 10:00:02 [ERROR] SQLException: 数据库连接失败
异常堆栈:
    at com.example.OrderService.create(OrderService.java:25)

4. 性能问题分析

(1) 数据库慢查询日志

2024-02-14 10:00:01 [SLOW_QUERY] cost=2.5s sql="SELECT * FROM orders WHERE user_id=123"
2024-02-14 10:00:05 [SLOW_QUERY] cost=1.8s sql="UPDATE users SET status=1"
2024-02-14 10:00:10 [SLOW_QUERY] cost=3.1s sql="SELECT * FROM order_items"

(2) 分析慢查询

# 命令:分析超过2秒的慢查询
awk '
{
    # 提取执行时间,去掉s得到纯数字
    time_str = $4
    gsub("cost=|s", "", time_str)  # 将cost=和s都替换为空
    time = time_str + 0            # 转换为数字
    
    # 提取完整SQL语句
    sql = substr($0, index($0, "sql="))
    
    # 如果查询时间超过2秒
    if(time > 2) {
        printf "\n时间:%s %s\n", $1, $2
        printf "耗时:%.1f秒\n", time
        printf "SQL:%s\n", sql
        printf "----------\n"
    }
}' slow_query.log

# 输出:
时间:2024-02-14 10:00:01
耗时:2.5秒
SQL:"SELECT * FROM orders WHERE user_id=123"
----------

时间:2024-02-14 10:00:10
耗时:3.1秒
SQL:"SELECT * FROM order_items"
----------

5. 监控告警分析

(1) 告警日志

2024-02-14 10:00:01 [ALERT] service=order-service type=cpu_high value=92%
2024-02-14 10:00:05 [ALERT] service=user-service type=memory_high value=85%
2024-02-14 10:00:10 [ALERT] service=order-service type=disk_usage value=95%

(2) 统计告警情况

# 命令:按服务统计告警
awk '
BEGIN {
    print "=== 告警分析报告 ==="
    print "分析时间:" strftime("%Y-%m-%d %H:%M:%S")
    print "-------------------"
}
/\[ALERT\]/ {    # 只处理包含[ALERT]的行
    # 提取基本信息
    gsub(/service=|type=|value=|%|threshold=/, " ", $0)
    for(i=1; i<=NF; i++) {
        if($i == "[ALERT]") {
            service = $(i+1)    # 服务名
            type = $(i+2)       # 告警类型
            value = $(i+3)      # 当前值
            threshold = $(i+4)  # 阈值
        }
    }
    
    # 计算超出阈值的百分比
    exceed = value - threshold
    
    # 根据超出程度分级
    if(exceed >= 20) {
        level = "严重"
    } else if(exceed >= 10) {
        level = "警告"
    } else {
        level = "注意"
    }
    
    # 统计信息
    services[service]++
    types[type]++
    levels[level]++
    
    # 记录最大值和时间
    if(max_value[type] < value) {
        max_value[type] = value
        max_time[type] = $1 " " $2
    }
    
    # 保存详细信息
    details[++count] = sprintf("时间:%s %s\n服务:%-15s 类型:%-12s 当前值:%d%% (超出阈值:%d%%) 级别:%s",
        $1, $2, service, type, value, exceed, level)
}
END {
    # 1. 告警级别统计
    print "\n1. 告警级别分布:"
    for(l in levels) {
        printf "%-6s: %d次\n", l, levels[l]
    }
    
    # 2. 服务告警统计
    print "\n2. 服务告警统计:"
    for(svc in services) {
        printf "%-20s: %d次告警\n", svc, services[svc]
    }
    
    # 3. 告警类型统计
    print "\n3. 告警类型统计:"
    for(t in types) {
        printf "%-15s: %d次\n", t, types[t]
        printf "  最大值: %d%% (发生时间: %s)\n", max_value[t], max_time[t]
    }
    
    # 4. 详细告警记录
    print "\n4. 详细告警记录:"
    print "-------------------"
    for(i=1; i<=count; i++) {    # 使用count而不是NR
        print details[i] "\n----------"
    }
}' alert.log

# 输出:
告警统计:
=== 告警分析报告 ===
分析时间:2025-02-14 21:34:52
-------------------

1. 告警级别分布:
注意    : 3次
警告    : 2次

2. 服务告警统计:
order-service       : 3次告警
user-service        : 2次告警

3. 告警类型统计:
memory_high    : 2次
  最大值: 95% (发生时间: 2024-02-14 10:00:20)
cpu_high       : 2次
  最大值: 92% (发生时间: 2024-02-14 10:00:01)
disk_usage     : 1次
  最大值: 95% (发生时间: 2024-02-14 10:00:10)

4. 详细告警记录:
-------------------
时间:2024-02-14 10:00:01
服务:order-service   类型:cpu_high     当前值:92% (超出阈值:12%) 级别:警告
----------
时间:2024-02-14 10:00:05
服务:user-service    类型:memory_high  当前值:85% (超出阈值:5%) 级别:注意
----------
时间:2024-02-14 10:00:10
服务:order-service   类型:disk_usage   当前值:95% (超出阈值:5%) 级别:注意
----------
时间:2024-02-14 10:00:15
服务:user-service    类型:cpu_high     当前值:88% (超出阈值:8%) 级别:注意
----------
时间:2024-02-14 10:00:20
服务:order-service   类型:memory_high  当前值:95% (超出阈值:15%) 级别:警告
----------

这些是日常工作中最常用到的日志分析场景。我们从最简单的日志过滤开始,逐步深入到了复杂的统计分析。记住,解决复杂的问题时,可以先拆分成小步骤,一步一步来处理。

总结

看到这里,相信你已经掌握了 awk 这个文本处理利器的基本使用。从最初的字段提取,到复杂的日志分析,再到性能监控,只要灵活运用,awk 几乎能解决所有的文本处理需求。

不过,真实的工作环境中,往往需要 多个命令配合使用 才能达到最好的效果。就像武侠小说里的武功招式,单招玩得再熟,也不如组合技来得实用。

比如:

# 先用grep找出错误日志,再用awk分析
grep "ERROR" app.log | awk '{print $1,$2}'

# 用sed处理格式,再用awk统计
sed 's/"//g' access.log | awk '{count[$1]++} END{for(ip in count) print ip,count[ip]}'

下一篇,我将为大家带来 grep、sed、awk 这三剑客的组合应用,教你如何在实战中发挥它们的最大威力。相信这些实用的"组合技",一定能帮你在日常工作中事半功倍。

责任编辑:赵宁宁 来源: 跟着小康学编程
相关推荐

2013-02-22 09:49:29

Nagios监控性能评测

2019-03-21 14:30:15

Linux文本分析命令

2023-12-10 21:35:45

Linux服务器日志分析

2017-06-15 12:42:07

Linux常用性能分析命令

2016-12-23 10:56:34

linuxshellawk

2022-03-23 08:45:20

系统性能CPU

2022-07-26 10:28:00

Linux监控命令

2021-03-15 07:39:48

LinuxAwk 语言

2019-07-31 10:18:17

Web 开发Python

2023-06-28 11:49:56

Linux命令

2025-02-08 10:54:02

2022-06-13 11:33:59

RedoMySQL

2024-10-17 16:47:05

磁盘I/O计算机

2014-04-09 11:05:11

2014-02-18 10:45:48

2024-12-18 18:53:48

2015-08-03 15:48:22

Linux日志

2022-01-10 08:50:13

URL前端页面

2023-03-01 08:40:43

监控诊断数据

2013-11-01 10:43:35

日志分析Awstats实战Apache
点赞
收藏

51CTO技术栈公众号