GitLab logs의 jq로 파싱하기

Tier: Free, Premium, Ultimate Offering: Self-managed

가능한 경우에는 Kibana나 Splunk와 같은 로그 집계 및 검색 도구를 사용하는 것이 좋습니다. 그러나 사용할 수 없는 경우 GitLab 로그를 JSON 형식(12.0 버전 이후 기본 형식)으로 여전히 빠르게 파싱할 수 있습니다. jq를 사용합니다.

note
특히 오류 이벤트 및 기본 사용 통계를 요약하는 경우 GitLab 지원팀이 전용 fast-stats 도구를 제공합니다.

JQ란?

매뉴얼에 기재된 대로, jq는 명령줄 JSON 프로세서입니다. 다음 예시는 GitLab 로그 파일 파싱을 위한 사용 사례를 포함합니다.

로그 파싱

아래 나열된 예시들은 각각의 로그 파일을 해당하는 Linux 패키지 설치 경로와 기본 파일명으로 다루고 있습니다. GitLab 로그 섹션에서 해당 전체 경로를 찾을 수 있습니다.

일반 명령어

색이 칠해진 jq 출력을 less로 파이프

jq . <FILE> -C | less -R

용어 검색 및 매칭 라인들을 예쁘게 출력

grep <TERM> <FILE> | jq .

유효하지 않은 JSON 라인 건너뛰기

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

기본적으로 jq는 유효하지 않은 JSON 라인을 만나면 에러가 발생합니다. 이 명령어는 모든 유효하지 않은 라인을 건너뛰고 나머지를 파싱합니다.

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 로그에서 correlation 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개 이상의 Gitaly 호출이 있는 모든 프로젝트 요청 찾기

grep <PROJECT_NAME> <FILE> | jq 'select(.gitaly_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>

특정 시간 범위 출력

jq 'select(.time >= "2023-01-10T00:00:00Z" and .time <= "2023-01-10T12:00:00Z")' <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 'select(.remote_ip != "127.0.0.1") | [.remote_ip, .username, .route, .ua] | @tsv' api_json.log |
  sort | uniq -c | sort -n | tail

예시 출력:

  89 1.2.3.4, 127.0.0.1  some_user  /api/:version/projects/:id/pipelines  # plus browser details; OK
 567 5.6.7.8, 127.0.0.1      /api/:version/jobs/:id/trace gitlab-runner   # plus version details; OK
1234 98.76.54.31, 127.0.0.1  some_bot  /api/:version/projects/:id/repository/files/:file_path/raw

이 예시는 커스텀 도구나 스크립트로 인해 예상치 못한 높은 요청 수를 유발합니다. 이 경우 사용자 에이전트는 다음과 같을 수 있습니다:

또한 해당 사용자나 봇에 대한 성능 통계를 추출하려면 fast-stats top을 사용할 수 있습니다.

gitlab-rails/importer.log 구문 분석

프로젝트 가져오기 또는 이주 문제 해결을 위해 다음 명령을 실행하세요.

jq 'select(.project_path == "<namespace>/<project>").error_messages' importer.log

일반적인 문제에 대해서는 문제 해결을 참조하세요.

gitlab-workhorse/current 구문 분석

상위 Workhorse 사용자 에이전트 출력

jq --raw-output 'select(.remote_ip != "127.0.0.1") | [.remote_ip, .uri, .user_agent] | @tsv' current |
  sort | uniq -c | sort -n | tail

API ua 예제와 유사하게, 이 출력에서 예기치 않은 사용자 에이전트가 나타나면 최적화되지 않은 스크립트를 나타냅니다. gitlab-runner, GitLab-Shell, 그리고 브라우저가 예상 사용자 에이전트입니다.

러너(runner)가 새 작업을 확인하는 성능 영향을 줄이려면 예를 들어 check_interval 설정을 늘릴 수 있습니다.

gitlab-rails/geo.log 구문 분석

가장 일반적인 Geo 동기화 오류 찾기

만약 geo:status Rake task가 몇몇 아이템이 100%에 이르지 않았다고 반복적으로 보고한다면, 아래 명령은 가장 일반적인 오류에 집중하는 데 도움이 됩니다.

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

특정 오류 메시지에 대한 조언은 Geo 문제 해결 페이지를 참조하세요.

gitaly/current 구문 분석

다음 예제를 사용하여 Gitaly 문제 해결을 진행하세요.

웹 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'
  ...

사용자 및 프로젝트 활동 종류 개요

jq --raw-output '[.username, ."grpc.method", ."grpc.request.glProjectPath"] | @tsv' current | sort | uniq -c | sort -n

치명적인 Git 문제로 영향 받는 모든 프로젝트 찾기

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

gitlab-shell/gitlab-shell.log 구문 분석

SSH를 통한 Git 호출 조사를 위해 GitLab 12.10부터.

프로젝트 및 사용자별 상위 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