面向chatgpt运维:根据自定义的日志格式统计每个接口的平均消耗时间

结果:


Crafted by Genie


You

如何使用awk统计访问接口消耗时间,使用逗号分隔,msg是接口名,cost是消耗时间,我的日志是app.log,格式如下:{"level":"info","ts":"2023/03/31 08:58:03","msg":"/api/v1/goods/project","status":200,"uid":0,"method":"GET","query":"city=%E5%8E%A6%E9%97%A8&area=%E6%B5%B7%E6%B2%A7%E5%8C%BA&card_type=3&page=1&is_select=1","ip":"39.144.251.61","body":"","errors":"","cost":"1.18631ms"}

Genie

可以使用以下命令来统计访问接口消耗时间:

awk -F',' '{match($0,/msg\":\"[^\"]+/); msg=substr($0,RSTART+6,RLENGTH-6);
match($0,/cost\":\"[^\"]+/); cost=substr($0,RSTART+7,RLENGTH-8);
print msg","cost}' app.log

这个命令首先使用逗号分隔符(-F',')将日志中的每一行拆分成多个字段,然后使用正则表达式匹配出接口名(msg)和消耗时间(cost)。最后,将接口名和消耗时间用逗号拼接起来并打印出来。

注:该命令假设日志中所有行都具有正确的格式。如果某些行不符合格式,该命令可能会产生错误结果。

You

在这个命令的基础上,统计每个接口的平均时间,考虑cost时间单位不同的情况

Genie

如果cost时间单位不同,需要先将其转换为同一单位,例如毫秒。以下示例代码可以实现统计每个接口的平均时间:

awk -F',' '{
    match($0,/msg\":\"[^\"]+/);
    msg=substr($0,RSTART+6,RLENGTH-6);

    match($0,/cost\":\"[^\"]+/);
    cost_str=substr($0,RSTART+7,RLENGTH-8);

    if (index(cost_str, "ms") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-2);
    } else if (index(cost_str, "s") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-1)*1000;
    } else {
        cost = cost_str;
    }

    cost_sum[msg] += cost;
    count[msg]++;
}
END {
    for (msg in cost_sum) {
        avg_cost = cost_sum[msg]/count[msg];
        print msg "," avg_cost "ms";
    }
}' app.log

这个命令统计了每个接口的总消耗时间和出现次数,最后在 END 中通过计算得到了每个接口的平均消耗时间。在计算中,如果 cost 的单位是秒或者毫秒,就将其转换为毫秒再进行计算。最终输出结果以逗号分隔,并且带有单位 "ms" 表示时间单位是毫秒。

You

在这个基础上,帮我按时间排序

Genie

要按照平均消耗时间对接口进行排序,可以在 END 中使用 asorti 函数对 cost_sum 数组按照值进行排序。以下是修改后的代码:

awk -F',' '{
    match($0,/msg\":\"[^\"]+/);
    msg=substr($0,RSTART+6,RLENGTH-6);

    match($0,/cost\":\"[^\"]+/);
    cost_str=substr($0,RSTART+7,RLENGTH-8);

    if (index(cost_str, "ms") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-2);
    } else if (index(cost_str, "s") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-1)*1000;
    } else {
        cost = cost_str;
    }

    cost_sum[msg] += cost;
    count[msg]++;
}
END {
    for (msg in cost_sum) {
        avg_cost = cost_sum[msg]/count[msg];
        result[msg] = avg_cost "ms";
    }
    asorti(result, sorted_result, "@val_num_asc");
    for (i in sorted_result) {
        print sorted_result[i];
    }
}' app.log

这个命令首先遍历日志中所有行,并统计每个接口的总消耗时间和出现次数。然后,在 END 中,将结果存储在 result 数组中,并使用 asorti 函数将其按照值排序(指定参数 "@val_num_asc" 表示升序排序)。最后,遍历排序后的数组并输出结果。

这个命令可以按照平均消耗时间从小到大排序输出每个接口和平均时间。如果要按照从大到小的顺序排序,只需要将 "@val_num_asc" 修改为 "@val_num_desc" 即可。

You

消耗时间也要列出来

Genie

好的,那么我在上面的代码基础上增加一列平均时间对应的消耗时间:

awk -F',' '{
    match($0,/msg\":\"[^\"]+/);
    msg=substr($0,RSTART+6,RLENGTH-6);

    match($0,/cost\":\"[^\"]+/);
    cost_str=substr($0,RSTART+7,RLENGTH-8);

    if (index(cost_str, "ms") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-2);
    } else if (index(cost_str, "s") > 0) {
        cost = substr(cost_str, 1, length(cost_str)-1)*1000;
    } else {
        cost = cost_str;
    }

    cost_sum[msg] += cost;
    count[msg]++;
}
END {
    printf "%-30s%-20s%-20s\n", "接口名", "平均时间", "消耗时间";
    for (msg in cost_sum) {
        avg_cost = cost_sum[msg]/count[msg];
        result[msg] = avg_cost "ms";
        cost_result[msg] = cost_sum[msg] "ms (" count[msg] "次)";
    }
    asorti(result, sorted_result, "@val_num_asc");
    for (i in sorted_result) {
        printf "%-30s%-20s%-20s\n", sorted_result[i], result[sorted_result[i]], cost_result[sorted_result[i]];
    }
}' app.log

这个命令在遍历日志时,依然统计每个接口的总消耗时间和出现次数,并将该结果存储在 cost_sumcount 数组中。

END 中,使用 printf 函数输出表头,并将结果存储到两个数组中: result 存储接口的平均时间, cost_result 存储消耗时间和出现次数。

最后,使用 asortiresult 数组按照值排序,并遍历排序后的数组输出结果,同时将对应的平均时间和消耗时间一同输出。

上面的代码还是有问题,一个是截取cost字段值的时候,少截取了一个字符,排序也不起作用,手动修改如下

awk -F',' '{
    match($0,/msg\":\"[^\"]+/);
    msg=substr($0,RSTART+6,RLENGTH-6);

    match($0,/cost\":\"[^\"]+/);
    cost_str=substr($0,RSTART+7,RLENGTH-8);

if (index(cost_str, "µ") > 0) {
    cost = substr(cost_str, 1, length(cost_str)-2)/1000;
} else if (index(cost_str, "m") > 0) {
    cost = substr(cost_str, 1, length(cost_str)-1);
}  else
{
 cost=cost_str*1000
}

    cost_sum[msg] += cost;
    count[msg]++;
}
END {
    printf "%-30s%-20s%-20s\n", "接口名", "平均时间(ms)", "消耗时间";
    for (msg in cost_sum) {
        avg_cost = cost_sum[msg]/count[msg];
        result[msg] = avg_cost +0;
        cost_result[msg] = cost_sum[msg] "ms (" count[msg] "次)";
    }
    asorti(result, sorted_result, "@val_num_asc");
    for (i in sorted_result) {
        printf "%-30s%-20s%-20s\n", sorted_result[i], result[sorted_result[i]], cost_result[sorted_result[i]];
    }
}' app.log| sort -k 2 -n -r 

posted @ 2023-03-31 17:27  西门飘柔  阅读(70)  评论(0编辑  收藏  举报