GitLab 로그를 jq로 구문 분석하기

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

가능한 경우 Kibana 및 Splunk와 같은 로그 집계 및 검색 도구를 사용하는 것을 권장하지만, 사용할 수 없는 경우에도 GitLab 로그를 JSON 형식으로 빠르게 구문 분석할 수 있습니다 jq를 사용하여.

note
특히 오류 이벤트 및 기본 사용 통계를 요약하기 위해 GitLab 지원 팀은 전문화된 fast-stats 도구를 제공합니다.

JQ란 무엇입니까?

그의 매뉴얼에 명시된 바와 같이, jq는 명령줄 JSON 프로세서입니다. 다음 예시는 GitLab 로그 파일을 구문 분석하는 데 필요한 사용 사례를 포함합니다.

로그 구문 분석

아래 나열된 예시는 각각의 로그 파일을 상대적인 리눅스 패키지 설치 경로와 기본 파일 이름으로 다룹니다. 상대적인 전체 경로는 GitLab 로그 섹션에서 확인하세요.

압축된 로그

로그 파일이 순환될 때, Unix 타임스탬프 형식으로 이름이 바뀌고 gzip로 압축됩니다. 결과 파일 이름은 @40000000624492fa18da6f34.s와 같이 나타납니다. 이 파일들은 더 최신 로그 파일과는 다르게 구문 분석하기 전에 다루어야 합니다:

  • 파일의 압축을 해제하려면 gunzip -S .s @40000000624492fa18da6f34.s를 사용하고 압축된 로그 파일의 이름으로 파일 이름을 교체하세요.
  • 파일을 직접 읽거나 파이프하려면 zcat 또는 zless를 사용하세요.
  • 파일 내용 검색을 원할 경우 zgrep을 사용하세요.

일반 명령어

색상이 적용된 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 로그에서 시간 순서대로 상관 관계 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 파싱

요청량에 따른 상위 3개 컨트롤러 메서드 및 그들의 3개 가장 긴 지속 시간 출력

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 파싱

요청 수에 따른 상위 3개 경로 및 그들의 3개 가장 긴 지속 시간 출력

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  # 브라우저 세부 정보 포함; OK
 567 5.6.7.8, 127.0.0.1      /api/:version/jobs/:id/trace gitlab-runner   # 버전 세부 정보 포함; OK
1234 98.76.54.31, 127.0.0.1  some_bot  /api/:version/projects/:id/repository/files/:file_path/raw

이 예시는 예상치 못한 높은 수의 요청을 발생시키는 커스텀 도구 또는 스크립트를 보여줍니다.

이 상황에서 사용자 에이전트는 전문화된 서드 파티 클라이언트일 수 있으며,

curl과 같은 일반 도구일 수도 있습니다.

또한 사용자 또는 봇에 대한 성능 통계 추출을 위해 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 및 브라우저가 포함됩니다.

새 작업을 확인하는 러너의 성능 영향을 줄이려면

check_interval 설정을 늘리는 것이 좋습니다.

gitlab-rails/geo.log 파싱

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

geo:status Rake 작업

반복적으로 일부 항목이 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

요청 양에 따른 상위 10개 프로젝트와 그들의 세 가지 가장 긴 지속 시간 출력

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 호출 조사를 위해.

프로젝트와 사용자에 따른 상위 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