GitLab logs를 jq로 파싱하기

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

가능한 경우 Kibana 및 Splunk와 같은 로그 집계 및 검색 도구를 사용하는 것이 좋지만 사용할 수 없는 경우 GitLab logs를 JSON 형식으로 빠르게 파싱할 수 있습니다. jq를 사용하여 파싱할 수 있습니다.

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

JQ란?

그것의 매뉴얼에 언급된대로, jq는 명령 줄 JSON 프로세서입니다. 다음 예제는 GitLab 로그 파일을 파싱하기 위해 대상을 둔 사용 사례를 포함합니다.

로그 파싱

리스트된 예제는 각각의 로그 파일을 해당하는 상대적인 리눅스 패키지 설치 경로와 기본 파일 이름으로 다룹니다. GitLab logs 섹션에서 해당되는 전체 경로를 찾을 수 있습니다.

압축된 로그

로그 파일이 회전될 때, 파일은 Unix 타임스탬프 형식으로 이름이 변경되고 gzip로 압축됩니다. 결과 파일 이름은 @40000000624492fa18da6f34.s와 같이 보입니다. 이러한 파일은 최근 로그 파일과 다르게 파싱하기 위해 별도로 처리되어야 합니다.

  • 파일의 압축을 푸려면, gunzip -S .s @40000000624492fa18da6f34.s를 사용하여 압축된 로그 파일의 이름으로 대체합니다.
  • 파일을 직접 읽거나 pipe로 이용하려면 zcat 또는 zless를 사용합니다.
  • 파일 내용을 검색하려면 zgrep을 사용합니다.

일반적인 명령어

색깔로 칠한 jq 출력을 less에 pipe

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

요청 볼륨 상위 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개 루트 및 가장 긴 지속시간 출력

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

이 예시는 특정 도구나 스크립트로 인해 예상치 못한 수의 요청이 발생하는 상황을 보여줍니다. 이러한 상황에서의 사용자 에이전트는 제3자 클라이언트curl과 같은 일반 도구 등이 될 수 있습니다.

또한 해당 사용자나 봇의 성능 통계를 얻으려면 빠른 통계의 상위 항목을 사용할 수도 있습니다.

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, 그리고 브라우저가 포함됩니다.

예를 들어, 새로운 작업을 검사하는 러너의 성능 영향을 줄일 수 있도록 체크 간격 설정을 증가시킴으로써 러너의 성능 영향을 줄일 수 있습니다.

gitlab-rails/geo.log 구문 분석

가장 흔한 Geo 동기화 오류 찾기

만약 the 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 호출을 조사하기 위한 것입니다.

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