TT Lab
开始
学习 学习路径 课程

Loki — 不索引日志的日志库

为什么 level="error" 查出来是零条

在 TT Lab 中继续学习

一句话总结

解析器取出的名称如果与已有的流标签冲突,Loki 会悄悄加上 _extracted 把它挤掉。label_format、line_format、keep、drop 是收拾这之后的局面的工具,四个都只改变响应,不触及索引。

为什么需要它

采集器给每个 Pod 都贴了 level 标签。值全是 info——在采集器看来,那个文件是应用的标准输出,所以当成了 info。可是应用在正文里也打印了自己的级别 level=error。

调查的人发出了 {app="payment"} | logfmt | level="error",结果是 0 条。他报告说“一个错误都没有”,实际上那段时间有 30 条。因为解析器取出的 level 与流标签 level 冲突,名称被改成了 level_extracted。他说没有错误的依据,其实是“名称冲突了”。

工作原理

解析器生成标签时,如果已经有同名的标签,Loki 会给后取出的那个加上 _extracted 后缀。原来的标签原样保留。既没有警告,也没有错误。所以第一次查询新的流时,要养成展开一条结果、用眼睛看 metric(或 stream)的键列表的习惯。

整理的工具有四个。

语法 作用
label_format 새이름=기존라벨(占位符依次为新名称、已有标签)或 label_format 이름=\{{.字段}}``(占位符依次为名称、字段) 给标签重新命名,或用模板生成标签
line_format \{{.a}} {{.b}}`` 重写行的正文本身
keep a, b 只保留所列的标签
drop a, b 丢弃所列的标签

模板是 Go 的 text/template。用 {{.필드}}(占位符为字段名)放入值,也可以像 {{.a | trim}} 这样用管道。line_format 会把正文整个换掉,所以它后面的行过滤器看到的是新的正文——顺序就是含义。

这四种语法都只作用于查询结果。索引中存储的流一个字也不会变。所以即使用 label_format 增加标签,流的数量也不会增加,成本也不会增加。对担心基数的值,不要作为标签建立索引,而是留在正文里,查询时像这样取出来用——这就是“不建立索引”这一设计真正占便宜的地方。

在指标查询里,这些工具更重要。想在 sum by (...) 里用的名称如果只在正文里有,就要先用 label_format 做出来;如果还留着取值五花八门的标签,时间序列就会被拆开,所以要用 keep 或 drop 整理。

在现场相遇的样子

名称冲突最常出在 level 上。因为采集器、运行时、应用各自都想说“级别”。如果在团队规约里定下“采集器贴的标签要加前缀”(例如 k8s_),这个事故本身就会消失。

第二是仪表板上难以阅读的日志面板。一行是 200 个字符的 JSON,人是没法扫读的。用 line_format 只留下需要的四五项,同样的面板马上就有用了。不过如果有人要在这个面板里搜索正文,最好加个注释,说明 line_format 必须放在行过滤器之后,这样更体贴。

第三是“加了标签,为什么成本不变”这个问题。这是正常的。查询时刻的标签不会被存储。

下一项实验要做什么

把流标签 level 与正文里的 level= 故意错开的数据放进 Pod 里的 Loki,亲眼看到 level="error" 返回 0 条。找出 _extracted 名称并数一数,用 label_format 覆盖后按想要的名称过滤,再用 line_format 重写行,用 keep 合并时间序列,得出各级别的条数。最后确认,即使改了标签,索引里的流数量也不变。