LabHub
学习 学习路径 课程

Loki — 不索引日志的日志库

日志全都在,我却不知道该问什么

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

파드 안의 진짜 Loki 에 LogQL 을 직접 던져, 스트림 선택자와 줄 필터로 원하는 줄만 꺼내고 돌아온 JSON 의 모양까지 읽을 수 있게 됩니다.

왜 중요한가

Loki 에 질문을 던지는 일은 두 층으로 나뉜다. 먼저 선택자가 어느 스트림의 청크를 읽을지 정하고, 그 다음 줄 필터가 읽어 온 줄을 하나씩 맞춰 본다. 이 순서를 모르면 '왜 이 질의는 빠르고 저 질의는 느린가' 를 영원히 설명하지 못한다. 본문은 색인되어 있지 않으므로 줄 필터는 선택자가 고른 만큼을 전부 읽는다 — 그래서 사고 조사에서 가장 먼저 하는 일이 선택자와 시간 구간을 좁히는 일이다. limit 과 direction 도 사고 조사의 결과를 바꾼다. 방향을 모르고 limit 을 걸면 가장 중요한 첫 오류 대신 마지막 오류만 보게 된다.

단계

  1. /root/lk-logql 에서 Loki 를 띄우고, date +%s 값을 /root/lk-logql/anchor.txt 에 한 줄로 적은 뒤 python3 /opt/lab/d5/gen.py logql "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 지금 Loki 에 스트림이 몇 개인지 세어 /root/lk-logql/01-boot.txtstreams=<정수> 한 줄로 적으세요.
  2. 기준 시각에서 과거 한 시간 동안 appweb 이고 levelerror 인 줄이 몇 줄인지 구하세요. 쓴 질의를 /root/lk-logql/02-selector.logql 에, 줄 수를 /root/lk-logql/02-selector.txtlines=<정수> 한 줄로 적습니다.
  3. 같은 한 시간 동안 세 서비스(web·api·worker) 전체에서 본문에 timeout 이 든 줄이 몇 줄인지 구하세요. 질의는 /root/lk-logql/03-line.logql, 답은 /root/lk-logql/03-line.txtlines=<정수> 로 적습니다.
  4. 세 서비스 전체에서 본문에 refused 가 들어 있고 rpc 는 들어 있지 않은 줄을 세세요. 질의는 /root/lk-logql/04-chain.logql, 답은 /root/lk-logql/04-chain.txtlines=<정수> 로 적습니다.
  5. 세 서비스 전체에서 본문에 500 또는 503 이라는 세 자리 숫자가 든 줄을 정규식 줄 필터 하나로 세세요. 질의는 /root/lk-logql/05-regex.logql, 답은 /root/lk-logql/05-regex.txtlines=<정수> 로 적습니다. 질의에는 정규식 줄 필터 연산자가 반드시 들어가야 합니다.
  6. {app="web",level="error"} 를 같은 한 시간 구간에 limit=5 로 두 번 질의하세요. 한 번은 direction=forward, 한 번은 direction=backward 입니다. 결과를 /root/lk-logql/06-order.txt 에 세 줄로 적습니다 — forward_first=<나노초 타임스탬프>, backward_first=<나노초 타임스탬프>, total=<구간 전체 줄 수>.
  7. 아무 로그 질의나 한 번 던져 원본 JSON 을 보고 /root/lk-logql/07-shape.txt 에 세 줄을 적으세요. result_type= 뒤에는 data.resultType 의 값, ts_unit= 뒤에는 values 의 첫 칸이 어떤 시간 단위인지(ns·us·ms·s 중 하나), entry_len= 뒤에는 values 의 원소 하나가 몇 칸짜리 배열인지 정수로 적습니다.
  8. webapi 두 서비스에서 본문에 timeout 또는 refused 가 든 줄만 골라, 그 중 가장 이른 줄의 나노초 타임스탬프와 전체 줄 수를 구하세요. 질의는 /root/lk-logql/08-triage.logql, 답은 /root/lk-logql/08-triage.txtlines=<정수>first_ts=<나노초> 두 줄로 적습니다. 질의에는 정규식 줄 필터가 들어가야 하고, worker 는 들어가면 안 됩니다.

참고

Loki 를 띄우고 하루치 대신 한 시간치를 넣는다

/root/lk-logql 에서 Loki 를 띄우고, date +%s 값을 /root/lk-logql/anchor.txt 에 한 줄로 적은 뒤 python3 /opt/lab/d5/gen.py logql "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 지금 Loki 에 스트림이 몇 개인지 세어 /root/lk-logql/01-boot.txtstreams=<정수> 한 줄로 적으세요.

설정은 /opt/lab/loki/loki.yaml 을 복사해 씁니다. /readyready 를 돌려줄 때까지 20초쯤 걸리니 고정 sleep 대신 조건을 보는 반복문을 쓰세요. 스트림 수는 /opt/lab/loki/streams.sh 가 세어 줍니다 — 스트림은 서로 다른 라벨 조합의 개수입니다.

선택자만으로 볼 곳을 정한다

기준 시각에서 과거 한 시간 동안 appweb 이고 levelerror 인 줄이 몇 줄인지 구하세요. 쓴 질의를 /root/lk-logql/02-selector.logql 에, 줄 수를 /root/lk-logql/02-selector.txtlines=<정수> 한 줄로 적습니다.

스트림 선택자는 중괄호 안의 라벨 매처입니다. 조건을 쉼표로 이으면 둘 다 만족하는 스트림만 고릅니다. 구간은 start·end 를 나노초로 주세요 — anchor.txt 의 값에 1000000000 을 곱하면 나노초입니다.

줄 필터로 본문을 뒤진다

같은 한 시간 동안 세 서비스(web·api·worker) 전체에서 본문에 timeout 이 든 줄이 몇 줄인지 구하세요. 질의는 /root/lk-logql/03-line.logql, 답은 /root/lk-logql/03-line.txtlines=<정수> 로 적습니다.

줄 필터는 선택자 뒤에 옵니다. 문자열을 그대로 찾는 연산자와 정규식으로 찾는 연산자가 다릅니다. 본문은 색인되어 있지 않아서, 줄 필터는 선택자가 고른 스트림의 줄을 전부 읽어 가며 맞춰 봅니다.

필터를 이어 붙여 걸러 낸다

세 서비스 전체에서 본문에 refused 가 들어 있고 rpc 는 들어 있지 않은 줄을 세세요. 질의는 /root/lk-logql/04-chain.logql, 답은 /root/lk-logql/04-chain.txtlines=<정수> 로 적습니다.

줄 필터는 여러 개를 이어 쓸 수 있고 왼쪽부터 차례로 적용됩니다. '들어 있지 않다' 를 뜻하는 연산자가 따로 있습니다. 두 조건을 하나의 정규식으로 합치려 하지 마세요 — 부정은 이어 쓰는 쪽이 읽기 쉽습니다.

정규식 줄 필터

세 서비스 전체에서 본문에 500 또는 503 이라는 세 자리 숫자가 든 줄을 정규식 줄 필터 하나로 세세요. 질의는 /root/lk-logql/05-regex.logql, 답은 /root/lk-logql/05-regex.txtlines=<정수> 로 적습니다. 질의에는 정규식 줄 필터 연산자가 반드시 들어가야 합니다.

정규식 줄 필터는 RE2 문법입니다. 문자 하나가 여러 값 중 하나일 수 있다는 것을 대괄호로 적습니다. 두 개의 |= 를 이어 쓰면 '둘 다 든 줄' 이 되어 답이 달라집니다.

limit 과 direction — 무엇이 잘려 나가는가

{app="web",level="error"} 를 같은 한 시간 구간에 limit=5 로 두 번 질의하세요. 한 번은 direction=forward, 한 번은 direction=backward 입니다. 결과를 /root/lk-logql/06-order.txt 에 세 줄로 적습니다 — forward_first=<나노초 타임스탬프>, backward_first=<나노초 타임스탬프>, total=<구간 전체 줄 수>.

limit 은 '앞에서부터 몇 줄' 이 아니라 '정렬 방향 기준 몇 줄' 입니다. 방향을 바꾸면 같은 limit 이 정반대의 줄을 돌려줍니다. 사고 조사에서 이걸 모르면 가장 중요한 첫 오류를 못 보고 마지막 오류만 보게 됩니다. 전체 줄 수는 limit 을 넉넉히 주고 셉니다.

돌아온 JSON 을 읽는다

아무 로그 질의나 한 번 던져 원본 JSON 을 보고 /root/lk-logql/07-shape.txt 에 세 줄을 적으세요. result_type= 뒤에는 data.resultType 의 값, ts_unit= 뒤에는 values 의 첫 칸이 어떤 시간 단위인지(ns·us·ms·s 중 하나), entry_len= 뒤에는 values 의 원소 하나가 몇 칸짜리 배열인지 정수로 적습니다.

curl ... | jq . 로 그대로 봅니다. 로그 질의와 지표 질의는 resultType 이 다릅니다. 타임스탬프의 자릿수를 세어 보면 단위를 알 수 있습니다 — epoch 초는 열 자리입니다. 이 모양을 알아야 자동화 스크립트를 쓸 수 있습니다.

응용 — 한 질의로 사고 구간을 좁힌다

webapi 두 서비스에서 본문에 timeout 또는 refused 가 든 줄만 골라, 그 중 가장 이른 줄의 나노초 타임스탬프와 전체 줄 수를 구하세요. 질의는 /root/lk-logql/08-triage.logql, 답은 /root/lk-logql/08-triage.txtlines=<정수>first_ts=<나노초> 두 줄로 적습니다. 질의에는 정규식 줄 필터가 들어가야 하고, worker 는 들어가면 안 됩니다.

선택자에서 두 서비스만 고르는 매처와, 둘 중 하나를 찾는 정규식을 함께 씁니다. 가장 이른 줄을 찾으려면 정렬 방향을 앞쪽으로 두거나, 받은 결과를 직접 정렬합니다. 이게 사고 조사의 첫 동작입니다 — 범위를 좁히고 시작 시각을 못박는 일.