查询示例
这些 LogQL 查询示例附带查询目的的解释。
日志查询示例
基于 IP 地址过滤的示例
返回不在 IPv4 地址范围内的日志行
{job_name="myapp"} != ip("192.168.4.5-192.168.4.20")
此示例匹配所有 IPv4 子网值
192.168.4.5/16
中的日志行,但不包括 IP 地址192.168.4.2
{job_name="myapp"} | logfmt | addr = ip("192.168.4.5/16") | addr != ip("192.168.4.2")
有助于安全评估的示例
从 Linux
/var/log/secure
中提取登录失败的用户和 IP 地址{job="security"} |~ "Invalid user.*" | regexp "(^(?P<user>\\S+ {1,2}){8})" | regexp "(^(?P<ip>\\S+ {1,2}){10})" | line_format "IP = {{.ip}}\tUSER = {{.user}}"
从 Linux
/var/log/secure
中获取成功登录{job="security"} != "grafana_com" |= "session opened" != "sudo: " | regexp "(^(?P<user>\\S+ {1,2}){11})" | line_format "USER = {{.user}}"
指标查询示例
返回 MySQL 作业每台主机在过去几分钟内所有非超时错误的每秒速率,且仅包含持续时间超过十秒的错误。
sum by (host) (rate({job="mysql"} |= "error" != "timeout" | json | duration > 10s [1m]))
多重过滤阶段示例
查询结果是通过从左到右依次评估查询的各个部分来收集的。为了提高查询效率,过滤阶段应按从左到右的顺序排列
- 流选择器
- 行过滤器
- 标签过滤器
考虑以下查询
{cluster="ops-tools1", namespace="loki-dev", job="loki-dev/query-frontend"} |= "metrics.go" != "out of order" | logfmt | duration > 30s or status_code != "200"
在此查询中,流选择器为
{cluster="ops-tools1", namespace="loki-dev", job="loki-dev/query-frontend"}
这里有两个行过滤器:|= "metrics.go"
和 !="out of order"
。在通过流选择器标识的日志行中,查询结果仅包含那些包含字符串“metrics.go”且不包含字符串“out of order”的日志行。
logfmt
解析器生成 duration
和 status_code
标签,以便标签过滤器可以使用它们。
标签过滤器 | duration > 30s or status_code!="200"
进一步过滤日志行。它包含那些 status_code
标签值非 200 的日志行,以及 duration
标签值大于 30 秒的日志行,
虽然每个查询都有一个流选择器,但并非所有查询都包含行过滤器和标签过滤器。
使用多个解析器的示例
考虑这条 logfmt 日志行。要提取这条 logfmt 日志行的方法和路径,
level=debug ts=2020-10-02T10:10:42.092268913Z caller=logging.go:66 traceID=a9d4d8a928d8db1 msg="POST /api/prom/api/v1/query_range (200) 1.5s"
要提取方法和路径,可以使用多个解析器(logfmt 和 regexp)
{job="loki-ops/query-frontend"} | logfmt | line_format "{{.msg}}" | regexp "(?P<method>\\w+) (?P<path>[\\w|/]+) \\((?P<status>\\d+?)\\) (?P<duration>.*)"
这是因为 | line_format
将日志行重新格式化为 POST /api/prom/api/v1/query_range (200) 1.5s
,然后可以使用 | regexp ...
解析器对其进行解析。
日志行格式化示例
以下查询展示了如何重新格式化日志行,使其更易于在屏幕上阅读。
{cluster="ops-tools1", name="querier", namespace="loki-dev"}
|= "metrics.go" != "loki-canary"
| logfmt
| query != ""
| label_format query="{{ Replace .query \"\\n\" \"\" -1 }}"
| line_format "{{ .ts}}\t{{.duration}}\ttraceID = {{.traceID}}\t{{ printf \"%-100.100s\" .query }} "
标签格式化用于净化查询,而行格式化减少信息量并创建表格输出。
对于这些给定的日志行
level=info ts=2020-10-23T20:32:18.094668233Z caller=metrics.go:81 org_id=29 traceID=1980d41501b57b68 latency=fast query="{cluster=\"ops-tools1\", job=\"loki-ops/query-frontend\"} |= \"query_range\"" query_type=filter range_type=range length=15m0s step=7s duration=650.22401ms status=200 throughput_mb=1.529717 total_bytes_mb=0.994659
level=info ts=2020-10-23T20:32:18.068866235Z caller=metrics.go:81 org_id=29 traceID=1980d41501b57b68 latency=fast query="{cluster=\"ops-tools1\", job=\"loki-ops/query-frontend\"} |= \"query_range\"" query_type=filter range_type=range length=15m0s step=7s duration=624.008132ms status=200 throughput_mb=0.693449 total_bytes_mb=0.432718
结果将是
2020-10-23T20:32:18.094668233Z 650.22401ms traceID = 1980d41501b57b68 {cluster="ops-tools1", job="loki-ops/query-frontend"} |= "query_range"
2020-10-23T20:32:18.068866235Z 624.008132ms traceID = 1980d41501b57b68 {cluster="ops-tools1", job="loki-ops/query-frontend"} |= "query_range"
可以从日志行中去除 ANSI 序列,使其更易于进一步解析
{job="example"} | decolorize
这样,这条日志行
[2022-11-04 22:17:57.811] \033[0;32http\033[0m: GET /_health (0 ms) 204
变成
[2022-11-04 22:17:57.811] http: GET /_health (0 ms) 204
展开(Unwrap)示例
计算按路径划分的 nginx-ingress 延迟的 p99
quantile_over_time(0.99, {cluster="ops-tools1",container="ingress-nginx"} | json | __error__ = "" | unwrap request_time [1m]) by (path)
计算按组织 ID 划分的处理字节数
sum by (org_id) ( sum_over_time( {cluster="ops-tools1",container="loki-dev"} |= "metrics.go" | logfmt | unwrap bytes_processed [1m]) )
向量聚合示例
按日志吞吐量最高获取前 10 个应用程序
topk(10,sum(rate({region="us-east1"}[5m])) by (name))
获取指定作业在过去五分钟内的日志行计数,按级别分组
sum(count_over_time({job="mysql"}[5m])) by (level)
按区域获取 NGINX 日志中对 /home
端点的 HTTP GET 请求速率
avg(rate(({job="nginx"} |= "GET" | json | path="/home")[10s])) by (region)