一个错误都没有,5xx 的数量却只有真实值的三分之一
目标
在 Pod 里的真正的 Loki 上亲手接上四种 LogQL 解析器,分别数出解析出错的行和没有报错却悄悄没能取出值的行,求出真正的 5xx 数量。
为什么重要
Loki 不为正文建立索引。所以要用正文里的值来过滤,就必须在每次查询时用解析器取出来,解析器选错了,数字就会悄悄减少。json 会用 __error__ 标签报告失败,但 logfmt 不会——遇到格式不同的行,它不生成任何标签就过去了,没有标签的话,后面的标签过滤器会悄悄丢掉那一行。仪表板上既没有错误也没有警告。所以查询新的流之前,总要先测量两个数字——解析失败的行数,以及没有失败却没取出值的行数。
步骤
- 在
/root/lk-parsers中启动 Loki,把date +%s写入/root/lk-parsers/anchor.txt,然后用python3 /opt/lab/d5/gen.py parsers "$(cat anchor.txt)"放入数据。接着数出从基准时刻往前一小时内,{app="mixed"}和{app="orders"}各有多少行,以mixed=<정수>和orders=<정수>(占位符为整数)两行写入/root/lk-parsers/01-boot.txt。 - 用
logfmt解析器数出orders流中status为 500 的行有多少行。查询写入/root/lk-parsers/02-logfmt.logql,答案以lines=<정수>(占位符为整数)写入/root/lk-parsers/02-logfmt.txt。 - 给
mixed流接上json解析器,分别数出解析成功的行和带有__error__标签的行。答案以ok=<정수>和err=<정수>(占位符为整数)两行写入/root/lk-parsers/03-json.txt,并把__error__的一个实际值以一行写入/root/lk-parsers/03-json-name.txt。 - 给
mixed流接上logfmt解析器时,数出没有报错、status标签却没有生成的行有多少行。查询写入/root/lk-parsers/04-silent.logql,答案以lines=<정수>(占位符为整数)写入/root/lk-parsers/04-silent.txt。 - 只选出正文含有
legacy的行,用pattern解析器取出状态码,数出该值为 500 的行。查询写入/root/lk-parsers/05-pattern.logql,答案以lines=<정수>(占位符为整数)写入/root/lk-parsers/05-pattern.txt。查询里必须包含pattern解析器。 - 在同样的遗留行中,用
regexp解析器取出所花的时间(毫秒),数出大于 1000 的行。查询写入/root/lk-parsers/06-regexp.logql,答案以lines=<정수>(占位符为整数)写入/root/lk-parsers/06-regexp.txt。查询里必须包含regexp解析器。 - 把
mixed流的行分成三种格式来数,做出/root/lk-parsers/tally.tsv。不要表头,共三行,每行是用制表符分隔的两列<형식><탭><줄수>(占位符依次为格式、制表符、行数)。格式名称依次为json、legacy、logfmt,三行之和必须等于第 1 步数出的mixed的总行数。 - 求出
mixed流中状态码为 500 的行的真正总数,以total=<정수>(占位符为整数)写入/root/lk-parsers/08-total.txt,在下一行写一个以reason=开头的句子(去掉空格后至少 40 个字)。用自己的话写出为什么只用一个解析器无法数出这个数字。
参考
- 工作目录是
/root/lk-parsers。Loki 要在第 1 步里亲手启动。 - 数据生成器是
/opt/lab/d5/gen.py,使用parsers数据。评分器不读这个文件。 - 查询用反引号包起来更安全——在双引号里,反斜杠会被当作转义。
- 常见错误:用
since=1h来测量。时间一流逝,答案就变了,重新评分时会失败。要用anchor.txt里的基准时刻给出start和end。 - 常见错误:习惯性地加
| __error__=""。在数坏行之前就把它们删掉,“格式混在一起”这个事实本身就看不到了。 - 日志查询与解析器 · LogQL 概述 · 标签 · HTTP API
拿到一个格式混杂的流
在 /root/lk-parsers 中启动 Loki,把 date +%s 写入 /root/lk-parsers/anchor.txt,然后用 python3 /opt/lab/d5/gen.py parsers "$(cat anchor.txt)" 放入数据。接着数出从基准时刻往前一小时内,{app="mixed"} 和 {app="orders"} 各有多少行,以 mixed=<정수> 和 orders=<정수>(占位符为整数)两行写入 /root/lk-parsers/01-boot.txt。
/ready 返回 ready 要等 20 秒左右。区间用 anchor.txt 的值以纳秒给出 start 和 end。不用解析器,只用选择器来数就行。
格式整洁时,一行 logfmt 就够了
用 logfmt 解析器数出 orders 流中 status 为 500 的行有多少行。查询写入 /root/lk-parsers/02-logfmt.logql,答案以 lines=<정수>(占位符为整数)写入 /root/lk-parsers/02-logfmt.txt。
解析器用管道接在选择器后面。解析器生成的标签,可以在其后用作标签过滤器。这与用行过滤器 |= "status=500" 这样查找字符串是不同的——这次要用解析器取出的值。
json 解析器会报告失败
给 mixed 流接上 json 解析器,分别数出解析成功的行和带有 __error__ 标签的行。答案以 ok=<정수> 和 err=<정수>(占位符为整数)两行写入 /root/lk-parsers/03-json.txt,并把 __error__ 的一个实际值以一行写入 /root/lk-parsers/03-json-name.txt。
解析器失败时会加上 __error__ 标签。分别选出该标签为空的行和不为空的行即可。标签的值是什么,直接看结果里的 stream 就能看到——__error_details__ 也会一起带上。
数出没有报错、却什么也没取出来的行
给 mixed 流接上 logfmt 解析器时,数出没有报错、status 标签却没有生成的行有多少行。查询写入 /root/lk-parsers/04-silent.logql,答案以 lines=<정수>(占位符为整数)写入 /root/lk-parsers/04-silent.txt。
在 LogQL 里,“不存在的标签”与空字符串等同比较。利用这个性质,就能选出“解析器没能生成值的行”。这个数字是本实验里最可怕的数字——仪表板上哪里都不会出现,却在悄悄削减合计。
位置固定的行适合用 pattern
只选出正文含有 legacy 的行,用 pattern 解析器取出状态码,数出该值为 500 的行。查询写入 /root/lk-parsers/05-pattern.logql,答案以 lines=<정수>(占位符为整数)写入 /root/lk-parsers/05-pattern.txt。查询里必须包含 pattern 解析器。
遗留行的形态是 legacy handler finished code 500 in 123ms。pattern 在要提取的位置用尖括号写上名称,其余照原样写成文字。在解析器前面放一个行过滤器,只把遗留行传下去,这一点很重要——其他格式的行里没有这种形态。
用正则表达式解析器取出数字并比较
在同样的遗留行中,用 regexp 解析器取出所花的时间(毫秒),数出大于 1000 的行。查询写入 /root/lk-parsers/06-regexp.logql,答案以 lines=<정수>(占位符为整数)写入 /root/lk-parsers/06-regexp.txt。查询里必须包含 regexp 解析器。
regexp 只会把命名捕获组变成标签——没有名字的括号会被丢弃。取出的值是字符串,但用不等号比较时,LogQL 会把它转成数字。同样的答案也可以用 pattern 得出——比一比哪一种更好读。
应用 ① ——按格式做一张行数表
把 mixed 流的行分成三种格式来数,做出 /root/lk-parsers/tally.tsv。不要表头,共三行,每行是用制表符分隔的两列 <형식><탭><줄수>(占位符依次为格式、制表符、行数)。格式名称依次为 json、legacy、logfmt,三行之和必须等于第 1 步数出的 mixed 的总行数。
JSON 行就是 json 解析器不报错的行。遗留行的正文里有 legacy。剩下的是 logfmt 行,这些行用 logfmt 能生成 status。一定要确认三个数字之和与总数相符——不符的话,说明某处数了两遍或漏掉了。
应用 ② ——真正的 5xx 数量,以及把这个事实留下来
求出 mixed 流中状态码为 500 的行的真正总数,以 total=<정수>(占位符为整数)写入 /root/lk-parsers/08-total.txt,在下一行写一个以 reason= 开头的句子(去掉空格后至少 40 个字)。用自己的话写出为什么只用一个解析器无法数出这个数字。
在一个查询里接两个解析器,也不能同时读取两种格式。要按格式分别数,再相加。想一想第 4 步数出的“悄悄漏掉的行”去了哪里,就能看出要分成几路。写答案时,也要确认三路的数字各是多少。