使用 jq 解析极狐GitLab 日志

我们建议尽可能使用 Kibana 和 Splunk 等日志聚合和搜索工具,但如果它们不可用,您仍然可以使用 jq 快速解析 JSON 格式的极狐GitLab 日志

什么是 JQ?

正如其手册中所述,jq 是一个命令行 JSON 处理器。以下示例包括用于解析极狐GitLab 日志文件的用例。

解析日志

下面列出的示例通过它们的相对综合路径和默认文件名来处理它们各自的日志文件。 在极狐GitLab 日志部分中找到相应的完整路径。

一般命令

通过流水线将彩色的 jq 输出 less

jq . <FILE> -C | less -R

搜索一个词并漂亮地打印所有匹配的行

grep <TERM> <FILE> | jq .

跳过无效的 JSON 行

jq -cR 'fromjson?' file.json | jq <COMMAND>

默认情况下,当遇到不是有效 JSON 的行时,jq 会出错,会跳过所有无效行并解析其余行。

打印 JSON 日志的时间范围

cat log.json | (head -1; tail -1) | jq '.time'

如果文件已被轮替和压缩,请使用 zcat

zcat @400000006026b71d1a7af804.s | (head -1; tail -1) | jq '.time'

zcat some_json.log.25.gz | (head -1; tail -1) | jq '.time'

按时间顺序跨多个 JSON 日志获取相关 ID 的活动

grep -hR <correlationID> | jq -c -R 'fromjson?' | jq -C -s 'sort_by(.time)'  | less -R

解析 gitlab-rails/production_json.loggitlab-rails/api_json.log

查找所有状态码为 5XX 的请求

jq 'select(.status >= 500)' <FILE>

最慢的 10 个请求

jq -s 'sort_by(-.duration_s) | limit(10; .[])' <FILE>

查找并漂亮打印与项目相关的所有请求

grep <PROJECT_NAME> <FILE> | jq .

查找总持续时间 > 5 秒的所有请求

jq 'select(.duration_s > 5000)' <FILE>

查找超过 5 次调用的所有项目请求

grep <PROJECT_NAME> <FILE> | jq 'select(.rugged_calls > 5)'

查找 Gitaly 持续时间 > 10 秒的所有请求

jq 'select(.gitaly_duration_s > 10000)' <FILE>

查找队列持续时间 > 10 秒的所有请求

jq 'select(.queue_duration_s > 10000)' <FILE>

Gitaly 调用次数排名前 10 的请求

jq -s 'map(select(.gitaly_calls != null)) | sort_by(-.gitaly_calls) | limit(10; .[])' <FILE>

解析 gitlab-rails/production_json.log

按请求量及其三个最长持续时间打印前三个控制器方法

jq -s -r 'group_by(.controller+.action) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration_s) | "CT: \(length)\tMETHOD: \(.[0].controller)#\(.[0].action)\tDURS: \(.[0].duration_s),  \(.[1].duration_s),  \(.[2].duration_s)"' production_json.log

输出示例

CT: 2721   METHOD: SessionsController#new  DURS: 844.06,  713.81,  704.66
CT: 2435   METHOD: MetricsController#index DURS: 299.29,  284.01,  158.57
CT: 1328   METHOD: Projects::NotesController#index DURS: 403.99,  386.29,  384.39

解析 gitlab-rails/api_json.log

打印具有请求计数的前三个路由及其三个最长持续时间

jq -s -r 'group_by(.route) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration_s) | "CT: \(length)\tROUTE: \(.[0].route)\tDURS: \(.[0].duration_s),  \(.[1].duration_s),  \(.[2].duration_s)"' api_json.log

输出示例

CT: 2472 ROUTE: /api/:version/internal/allowed   DURS: 56402.65,  38411.43,  19500.41
CT: 297  ROUTE: /api/:version/projects/:id/repository/tags       DURS: 731.39,  685.57,  480.86
CT: 190  ROUTE: /api/:version/projects/:id/repository/commits    DURS: 1079.02,  979.68,  958.21

打印顶级 API 用户代理

jq --raw-output '[.route, .ua] | @tsv' api_json.log | sort | uniq -c | sort -n

输出示例

  89 /api/:version/usage_data/increment_unique_users  # plus browser details
 567 /api/:version/jobs/:id/trace       gitlab-runner # plus version details
1234 /api/:version/internal/allowed     GitLab-Shell

此示例响应似乎很正常。如果输出包含许多,自定义工具或脚本可能会导致高负载:

  • 第三方库,如 python-requestscurl
  • 极狐GitLab CLI 客户端。

您还可以使用 fast-stats top 来提取性能统计信息。

解析 gitlab-workhorse/current

打印顶级 Workhorse 用户代理

jq --raw-output '[.uri, .user_agent] | @tsv' current | sort | uniq -c | sort -n

输出示例

  89 /api/graphql # plus browser details
 567 /api/v4/internal/allowed   GitLab-Shell
1234 /api/v4/jobs/request       gitlab-runner # plus version details

API ua 数据类似,与此常见顺序的偏差可能表明可以优化脚本。

例如,可以通过增加 check_interval 设置来减少 runner 检查新作业的性能影响。

解析 gitlab-rails/geo.log

查找最常见的 Geo 同步错误

如果 geo:status Rake 任务反复报告某些项目从未达到 100%,则以下命令有助于关注最常见的错误。

jq --raw-output 'select(.severity == "ERROR") | [.project_path, .message] | @tsv' geo.log | sort | uniq -c | sort | tail

解析 gitaly/current

使用以下示例对 Gitaly 进行故障排除。

查找从 Web UI 发送的所有 Gitaly 请求

jq 'select(."grpc.meta.client_name" == "gitlab-web")' current

查找所有失败的 Gitaly 请求

jq 'select(."grpc.code" != null and ."grpc.code" != "OK")' current

查找所有耗时超过 30 秒的请求

jq 'select(."grpc.time_ms" > 30000)' current

按请求量及其三个最长持续时间打印前十个项目

jq --raw-output --slurp '
  map(
    select(
      ."grpc.request.glProjectPath" != null
      and ."grpc.request.glProjectPath" != ""
      and ."grpc.time_ms" != null
    )
  )
  | group_by(."grpc.request.glProjectPath")
  | sort_by(-length)
  | limit(10; .[])
  | sort_by(-."grpc.time_ms")
  | [
      length,
      .[0]."grpc.time_ms",
      .[1]."grpc.time_ms",
      .[2]."grpc.time_ms",
      .[0]."grpc.request.glProjectPath"
    ]
  | @sh' current \
| awk 'BEGIN { printf "%7s %10s %10s %10s\t%s\n", "CT", "MAX DURS", "", "", "PROJECT" }
  { printf "%7u %7u ms, %7u ms, %7u ms\t%s\n", $1, $2, $3, $4, $5 }'

输出示例

   CT    MAX DURS                              PROJECT
  206    4898 ms,    1101 ms,    1032 ms      'groupD/project4'
  109    1420 ms,     962 ms,     875 ms      'groupEF/project56'
  663     106 ms,      96 ms,      94 ms      'groupABC/project123'
  ...

查找受致命 Git 问题影响的所有项目

grep "fatal: " current | \
    jq '."grpc.request.glProjectPath"' | \
    sort | uniq

解析 gitlab-shell/gitlab-shell.log

用于通过 SSH 调查 Git 调用。

按项目和用户查找前 20 个调用:

jq --raw-output --slurp '
  map(
    select(
      .username != null and
      .gl_project_path !=null
    )
  )
  | group_by(.username+.gl_project_path)
  | sort_by(-length)
  | limit(20; .[])
  | "count: \(length)\tuser: \(.[0].username)\tproject: \(.[0].gl_project_path)" ' \
  gitlab-shell.log

按项目、用户和命令查找前 20 个调用:

jq --raw-output --slurp '
  map(
    select(
      .command  != null and
      .username != null and
      .gl_project_path !=null
    )
  )
  | group_by(.username+.gl_project_path+.command)
  | sort_by(-length)
  | limit(20; .[])
  | "count: \(length)\tcommand: \(.[0].command)\tuser: \(.[0].username)\tproject: \(.[0].gl_project_path)" ' \
  gitlab-shell.log