LogQL: Loki 日志查询语言

发布时间: 更新时间: 总字数:2198 阅读时间:5m 作者: IP上海 分享 网址

受Prometheus启发,Loki提供了专门的日志查询语言LogQL

介绍

  • LogQL 支持两种查询类型:
    • 日志查询(Log queries) 返回日志行内容
    • 指标查询(Metric queries) 扩展日志查询,根据查询结果计算数值
      • 基于过滤规则,在日志查询得到的日志数据中执行过滤操作
  • LogQL 有两部分组成
    • 日志流选择器(log stream selector) 即标签匹配器(Label matchers),过滤表达式,用于挑选时间序列
    • 日志管道(log pipeline) 可选,附加在日志流选择器后面,用于在日志流选择器筛选出的日志行中进行日志信息过滤
      • 包含一组表达式,自左向右对每个日志行进行过滤,像一个管道(pipeline)
      • 每个表达式都可以过滤、解析以及改变日志行的内容和各自的标签
      • 查询结果需要满足所有的过滤器条件,即多个过滤器表达式间遵循 规则
{container="query-frontend",namespace="loki-dev"} |= "metrics.go" | logfmt | duration > 10s and throughput_mb < 500
  • log stream selector
    • Label matchers {container="query-frontend",namespace="loki-dev"}
  • Log Pipeline 中的表达式大体可以分为三类
    • 过滤表达式
    • 解析器表达式
    • 格式化表达式,包括
      • 行格式化表达式
      • 标签格式化表达式

Log queries

parts of a query
  • log stream selector 过滤表达式,功能类似于以分布式方式针对各日志流进行 grep
    • 标签过滤表达式(Label fileters expression) 针对 log stream selector 过滤的日志流上的每个 日志行标签 进行过滤,如 duration > 10s and throughput_mb < 500,支持的标签过滤器操作符有
      • = 等值比较
      • != 不等
      • =~ 正则表达式模式匹配,遵循完全锚定机制
      • !~ 正则表达式模式不匹配,遵循完全锚定机制
      • >>= 大于、大于或等于
      • <<= 小于、小于或等于
    • 行过滤表达式(Line filters),如:|= "metrics.go",支持的行过滤器操作符有
      • |= 日志行包括指定的字符
      • != 日志行不包括指定的字符
      • |~ 日志行含有正则表达式模式的匹配项,遵循子串锚定机制
      • !~ 日志行不含有正则表达式模式的匹配项,遵循子串锚定机制
  • 可基于原有标签进行过滤,也可先解析日志行内容并转换标签格式,而后再针对解析生的标签进行标签过滤
    • 负责解析并置换标签格式的即为解析器表达式
    • Loki 支持 jsonlogfmtpatternregular expression(regexp)unpack 几种解析器
  • LogQL 支持以 and 或者 or 组合多个标签过滤器
    • 其中 and 可以用逗号 ,、空格 或 管道符 | 替代,它们的意义相同
    • and 的优先级高于 or,同一优先级的过滤器,执行顺序为由左向右
  • 由于 行过滤器 的执行 性能 要优于 标签过滤器,因此尽可能地将 行过滤器 放在 log pipeline 中靠前的位置

解析器表达式( Parser expression )

  • 作用:负责解析日志行内容,并从中提取、生成标签
    • 解析后生成的标签,可用于 标签过滤器表达式 进行过滤或聚合
    • 提取的标签键会由解析器进清理,以满足 Prometheus 指标名称的约定
    • 若出现错误,则日志行不会被过滤,而是会添加一个 __error__ 标签
    • 若提取的标签同原始日志流标签相同,则会在提取的标签键后面附加 _extracted 后缀
    • 提取后重复出现的标签,仅会保留第一个
  • Loki 支持 jsonlogfmtpatternregular expression(regexp)unpack 解析器
    • json 解析器:解析 json 格式的日志内容为标签
    • logfmt 解析器:解析 logfmt 格式的日志内容为标签
    • pattern 解析器:基于自定义的 pattern 表达式,从日志行中显式提取字段生成标签
    • regexp 解析器:基于自定义的正则表达式,从日志行中显式提取字段生成标签
    • unpack 解析器:从 promtailpack stage 解压迁入的所有标签

pattern 解析器

| pattern "<pattern-expression>"

可从日志内容中显式提取字段创建新标签,且指定的表达式 <<pattern-expression>>,要能够同日志行的结构相匹配

示例

# apache combined 日志解析
{container="evaluate-loki-loggen-apache-combined-1"} | pattern "<ip> - <user> <_> \"<method> <uri> <_>\" <status> <size > <> \"<agent>\" <_>"

# 解析后数据
container: evaluate-loki-loggen-apache-combined-1
ip: 78.162.136.208
method: HEAD
status: 301 63715 "http://www.customere-business.io/morph/deliverables/real-time" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7_1) AppleWebKit/5340 (KHTML, like Gecko) Chrome/40.0.893.0 Mobile Safari/5340"
uri: /embrace/b2b/redefine/e-markets
user: nolan5831

regexp 解析器

| regexp "<re>"

说明:

  • 正则表达式模式需要满足 Google RE2 的语法规范
  • 提供的正则表达式必须包含至少一个命名子匹配(例如 (?P<name>re)),每个子匹配将提取不同的标签口
  • 该模式并不要求完全匹配到日志结构
  • 过于复杂,建议使用新式的 pattern 解析器
  • 示例
# https://github.com/grafana/loki/issues/2783
{container="evaluate-loki-loggen-apache-combined-1"} | regexp "^(?P<remote_host>\\S+) (?P<user_identifier>\\S+) (?P<user>\\S+) \\[(?P<ts>[^\\]]+)\\] \\\"(?P<method>\\S+) (?P<path>\\S+) HTTP/(?P<http_version>\\d+\\.\\d+)\\\" (?P<status>\\d+) (?P<bytes_sent>\\d+|-) \"(?P<referer>[^\"]+)\" \"(?P<agent>[^\"]+)\"$"

# 解析后数据
agent
Mozilla/5.0 (X11; Linux i686) AppleWebKit/5350 (KHTML, like Gecko) Chrome/40.0.889.0 Mobile Safari/5350
bytes_sent 59200
container evaluate-loki-loggen-apache-combined-1
http_version 2.0
method GET
path /synergize/functionalities/content/methodologies
referer http://www.legacyfrictionless.io/infomediaries/synergistic/partnerships
remote_host 158.138.20.158
status 500
ts 12/May/2024:04:30:59 +0000
user dooley4421
user_identifier -

日志范围聚合

  • 针对查询出的 日志行数 进行的聚合计算,称为 日志范围聚合
  • 日志范围聚合的方法
    • 给定一个 LogQL 查询表达式,后跟一个时长,时长表示方式同 PromQL
count_over_time({container="evaluate-loki-loggen-apache-combined-1"}[5m])
  • 对带有时长范围的 LogQL 查询表达式,进行聚合函数计算
  • 支持的聚合函数
    • rate(long-range) 计算选出的每个日志流上的日志条目,在给定时间范围内的生成速率
    • count_over_time(log-range) 统计给定时间范围内每个日志流的条目数 53
    • bytes_rate(log-range) 计算先出的每个日志流的日志大小在给定时间范围内的平均增长速率
    • absent_over_time(log-range) 判定选出的每个日志流在指定时间范围内是否存在日志条目,存在日志条目则返回空向量,不存在日志条目,则返回单元素向量;
    • bytes_over_time(log-range) 计算给定时长范围内选出的每个日志流增长的字节数

示例

# 查询 status_code 为 500 的日志
{container="evaluate-loki-loggen-apache-common-1", status=~"5.."}

# 添加正则匹配
{container="evaluate-loki-loggen-apache-common-1", status=~"5.."} |~ ".*open-source.*"

# 逻辑与,表示含有 "error" 但不包含 "timeout" 的行
{container="evaluate-loki-loggen-apache-common-1", status=~"5.."} |= "error" != "timeout"

内置聚合运行符

  • LogQL 内置支持一些聚合运算符,可用于聚合单个向量的元素,从而生成元素数较少的新向量
  • LogQL 内置的聚合运算符,它们都基于指定的标签进行聚合计算
    • avg, min, mak
    • sum, count
    • stddev, stdvar
    • topk, bottom
    • sort(升序), sort_desc(降序)
  • 口聚合运行符表达式语法
    • <aggr-op>([parameter,]<vector expression>)[without | by (<label list >)]
  • 口分组聚合:先分组、后聚合
    • without 从结果向量中删除由 without 子句指定的标签,未指定的那部分标签则用作分组标准;
    • by 功能与 without 刚好相反,它仅使用 by 子句中指定的标签进行聚合,结果向量中出现但未被 by 子句指定的标签则会被忽略;
      • 为了保留上下文信息,使用 by 子句时需要显式指定其结果中原本出现的 job、 instance 等一类的标签
sum(count_over_time({container="evaluate-loki-loggen-apache-combined-1"}[5m])) by (http_method)

Metric queries

说明

  • 部分参考马哥公开课

参考

  1. https://grafana.com/docs/loki/latest/query/
  2. https://grafana.com/docs/loki/latest/query/query_examples/
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数