在 Grafana Loki 中解析嵌套的 JSON 日志(使用 Fluentd 转发)

在 Grafana Loki 中解析嵌套的 JSON 日志(使用 Fluentd 转发)

我的实验室有几个Docker容器如下:

姓名 Docker 映像
Fluentd 流利/fluentd:v1.16-1
Fluent-bit cr.fluentbit.io/fluent/fluent-bit
洛基 grafana/loki
格拉法纳 grafana/grafana-enterprise
球童 球童:建造者

我的目标是收集 Caddy 日志并在 Grafana 中将其可视化。

场景:Fluent-bit 跟踪日志并将其发送到 Fluentd。然后 Fluentd 将日志推送到 Loki。我的目标是使用 Fluentd 作为中央日志收集器。

问题在于 Grafana 端对这些日志的解析。

Caddy 日志采用(嵌套)JSON 格式。示例:

{“level”:“info”,“ts”:“1712949034.535184”,“logger”:“http.log.access.log1”,“msg”:“处理的请求”,“请求”:{“remote_ip”:“172.18.0.1”,“remote_port”:“39664”,“client_ip”:“172.18.0.1”,“proto”:“HTTP / 1.1”,“method”:“POST”,“host”:“grafana.darknet.com”,“uri”:“/ api / short-urls”,“headers”:{“Content-Length”:“580”],“Origin”:“http://grafana.darknet.com”],“Content-Type”:“application / json”],“User-Agent”:“Mozilla / 5.0(X11; Linux x86_64; rv:124.0)Gecko / 20100101 Firefox/124.0”],“Accept”:[“application/json,text/plain,*/*”],“X-Grafana-Org-Id”:[“1”],“Connection”:[“keep-alive”],“Accept-Language”:[“en-US,en;q=0.5”],“Accept-Encoding”:[“gzip, deflate"],"Referer":["http://grafana.darknet.com/explore?schemaVersion=1&panes=%7B%22Efb%22:%7B%22datasource%22:%22f779c221-7bd2-468d-9f9c-96e069b869f8%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bjob%3D%5C%22caddy.log.loki%5C%22%7D%20%7C%20json%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22: %22f779c221-7bd2-468d-9f9c-96e069b869f8%22%7D,%22editorMode%22:%22code%22%7D%5D,%22range%22:%7B%22from%22:%22now-1m%22,%22to%22:%22now%22%7D%7D%7D&orgId=1"],"X-Grafana-Devi ce-Id”:[“f343e938e74b3a57997faff69d24de8a”],“Cookie”:[]}},“bytes_read”:580,“user_id”:“”,“duration”:0.011267887,“size”:72,“status”:200,“resp_headers”:{“X-Xss-Protection”:[“1; mode = block”],“日期”:[“2024 年 4 月 12 日星期五 19:10:34 GMT”],“Content-Length”:[“72”],“服务器”:[“Caddy”],“Cache-Control”:[“no-store”],“Content-Type”:[“application / json”],“X-Content-Type-Options”:[“nosniff”],“X-Frame-Options”:[“deny”]}}

到目前为止我已经尝试了两种不同的配置:

  1. 让 Fluent-bit 将日志发送到 Fluentd,然后 Fluentd 将日志转发给 Loki(标记为caddy.log
    架构:Cady --> Fluent-bit --> Fluentd --> Loki

  2. 让 Fluent-bit 发送日志直的至 Loki (标记为caddy.log.loki)
    架构:Cady --> Fluent-bit --> Loki

这里我有以下 Fluent-bit 配置来发送日志到两个都Loki 和 Fluentd 同时使用,但具有不同的标签:

[INPUT]
    Name tail
    Path /var/log/caddy/*.log
    Parser json
    Tag caddy.log
    Path_Key log_filename

# send logs to Fluentd
[OUTPUT]
    Name forward
    Host fluentd
    Port 24224
    Match caddy.*

# send logs straight to Loki
[OUTPUT]
    name                   loki
    match                  caddy.*
    host                   loki
    port                   3100
    labels                 job=caddy.log.loki

Fluentd 配置:

<source>
  @type  forward
</source>

<match caddy.*>
  @type loki
  url "http://loki:3100"
  extra_labels {"job": "caddy.log"}
  <buffer>
    flush_interval 5s
    flush_at_shutdown true
  </buffer>
</match>

然后在 Grafana 中我可以浏览日志,并且在探索窗口中可以看到两个标签。

如果我选择标签,caddy.log.loki日志将以纯 JSON 显示,如下所示。使用此表达式我可以解析它们:{job="caddy.log.loki"} | json。提取一些嵌套的 JSON,例如:request_client_ip 但并非全部,例如request.headers缺少了,但我可以忍受。

以 JSON 形式显示的日志

如果我选择标签,caddy.log则日志将以“混合”格式显示:

混合格式的日志

似乎发生了一些转换,但我不确定在哪里。我可以用来logfmt解析这些行。但我仍然留下一些未解析的字段(requestresp_headers),如下所示:

使用 logfmt 后

问题:

  • 如果我添加 Fluentd 步骤,为什么日志不再以纯 JSON 形式呈现?
  • 使用 Fluentd 在 Loki/Grafana 中传送和解析嵌套 JSON 日志的最佳方法是什么?

答案1

如果我添加 Fluentd 步骤,为什么日志不再以纯 JSON 形式呈现?

根据fluentd loki 输出插件文档,默认值为line_formatkey_value你没有在配置中指定格式fluentd,因此日志不是 JSON 格式,而是<key>=<value>格式。

使用 Fluentd 在 Loki/Grafana 中传送和解析嵌套 JSON 日志的最佳方法是什么?

您可以尝试添加过滤您的fluentbit配置:

[SERVICE]
    parsers_file    parsers.conf

[INPUT]
    Name        tail
    Path        /var/log/caddy/*.log
    Parser      json
    Tag         caddy.log
    Path_Key    log_filename

[FILTER]
    Name            nest
    Match           caddy.*
    Operation       lift
    Nested_under    request

# Nest filter can be chained
[FILTER]
    Name            nest
    Match           caddy.*
    Operation       lift
    Nested_under    headers
    Add_prefix      req_

[FILTER]
    Name            nest
    Match           caddy.*
    Operation       lift
    Nested_under    resp_headers
    Add_prefix      resp_

# send logs to Fluentd
[OUTPUT]
    Name        forward
    Host        fluentd
    Port        24224
    Match       caddy.*

# send logs straight to Loki
[OUTPUT]
    name                   loki
    match                  caddy.*
    host                   loki
    port                   3100
    labels                 job=caddy.log.loki

结果:

Grafana 探索输出

请注意,没有参数的 LogQL json 解析器将跳过数组(https://grafana.com/docs/loki/latest/query/log_queries/#json),因此如果您想要带有数组的字段,则必须在参数中指定它,例如:

{job="caddy.log.loki"} |= `` | json request_user_agent=`["req_User-Agent"]`

带参数的 LogQL JSON 解析器

相关内容