一个错误都没有,5xx 的数量却只有真实值的三分之一
한국어 원문으로 표시합니다.
목표
파드 안의 진짜 Loki 에서 네 가지 LogQL 파서를 직접 붙여 보고, 파싱 오류가 난 줄과 오류 없이 조용히 값을 못 꺼낸 줄을 각각 세어 진짜 5xx 건수를 구합니다.
왜 중요한가
Loki 는 본문을 색인하지 않는다. 그래서 본문 속 값으로 거르려면 질의할 때마다 파서로 꺼내야 하고, 파서를 잘못 고르면 숫자가 조용히 줄어든다. json 은 실패를 __error__ 라벨로 신고하지만 logfmt 는 신고하지 않는다 — 형식이 다른 줄을 만나면 아무 라벨도 만들지 않고 지나가고, 라벨이 없으면 뒤따르는 라벨 필터는 그 줄을 조용히 버린다. 대시보드에는 오류도 경고도 안 뜬다. 그래서 새 스트림을 질의하기 전에 늘 두 숫자를 먼저 재야 한다 — 파싱이 실패한 줄 수와, 실패하지도 않았는데 값이 안 나온 줄 수.
단계
/root/lk-parsers에서 Loki 를 띄우고date +%s를/root/lk-parsers/anchor.txt에 적은 뒤python3 /opt/lab/d5/gen.py parsers "$(cat anchor.txt)"로 자료를 넣으세요. 그리고 기준 시각에서 과거 한 시간 동안{app="mixed"}와{app="orders"}가 각각 몇 줄인지 세어/root/lk-parsers/01-boot.txt에mixed=<정수>와orders=<정수>두 줄로 적으세요.orders스트림에서status가 500 인 줄이 몇 줄인지logfmt파서로 세세요. 질의는/root/lk-parsers/02-logfmt.logql, 답은/root/lk-parsers/02-logfmt.txt에lines=<정수>로 적습니다.mixed스트림에json파서를 붙여, 파싱에 성공한 줄과__error__라벨이 붙은 줄을 각각 세세요. 답은/root/lk-parsers/03-json.txt에ok=<정수>와err=<정수>두 줄로 적고,__error__의 실제 값 하나를/root/lk-parsers/03-json-name.txt에 한 줄로 적으세요.mixed스트림에logfmt파서를 붙였을 때 오류는 나지 않았는데status라벨이 만들어지지 않은 줄이 몇 줄인지 세세요. 질의는/root/lk-parsers/04-silent.logql, 답은/root/lk-parsers/04-silent.txt에lines=<정수>로 적습니다.- 본문에
legacy가 든 줄만 골라pattern파서로 상태 코드를 꺼내고, 그 값이 500 인 줄을 세세요. 질의는/root/lk-parsers/05-pattern.logql, 답은/root/lk-parsers/05-pattern.txt에lines=<정수>로 적습니다. 질의에는pattern파서가 반드시 들어가야 합니다. - 같은 레거시 줄에서
regexp파서로 걸린 시간(밀리초)을 꺼내, 1000 보다 큰 줄을 세세요. 질의는/root/lk-parsers/06-regexp.logql, 답은/root/lk-parsers/06-regexp.txt에lines=<정수>로 적습니다. 질의에는regexp파서가 반드시 들어가야 합니다. mixed스트림의 줄을 형식 세 가지로 갈라 세어/root/lk-parsers/tally.tsv를 만드세요. 머리글 없이 세 줄이고 각 줄은 탭으로 나눈 두 칸<형식><탭><줄수>입니다. 형식 이름은 순서대로json,legacy,logfmt이고, 세 줄의 합은 1단계에서 센mixed전체 줄 수와 같아야 합니다.mixed스트림에서 상태 코드가 500 인 줄의 진짜 총 건수를 구해/root/lk-parsers/08-total.txt에total=<정수>로 적고, 그 다음 줄에reason=으로 시작하는 한 문장(공백 뺀 40자 이상)을 적으세요. 왜 파서 하나로는 이 숫자를 셀 수 없는지 자기 말로 씁니다.
참고
- 작업 디렉터리는
/root/lk-parsers입니다. Loki 는 1단계에서 직접 띄웁니다. - 자료 생성기는
/opt/lab/d5/gen.py이고parsers자료를 씁니다. 채점기는 이 파일을 읽지 않습니다. - 질의는 역따옴표로 감싸는 쪽이 안전합니다 — 큰따옴표 안에서는 역슬래시가 이스케이프로 해석됩니다.
- 흔한 실수:
since=1h로 재는 것. 시간이 흐르면 답이 달라져 재채점에서 떨어집니다.anchor.txt의 기준 시각으로start·end를 주세요. - 흔한 실수:
| __error__=""를 습관적으로 붙이는 것. 깨진 줄을 세기 전에 지우면 형식이 섞여 있다는 사실 자체가 안 보입니다. - 로그 질의와 파서 · LogQL 개요 · 라벨 · HTTP API
형식이 섞인 스트림을 손에 쥔다
/root/lk-parsers 에서 Loki 를 띄우고 date +%s 를 /root/lk-parsers/anchor.txt 에 적은 뒤 python3 /opt/lab/d5/gen.py parsers "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 기준 시각에서 과거 한 시간 동안 {app="mixed"} 와 {app="orders"} 가 각각 몇 줄인지 세어 /root/lk-parsers/01-boot.txt 에 mixed=<정수> 와 orders=<정수> 두 줄로 적으세요.
/ready 가 ready 를 돌려줄 때까지 20초쯤 걸립니다. 구간은 anchor.txt 의 값으로 start·end 를 나노초로 주세요. 파서 없이 선택자만으로 세면 됩니다.
형식이 깔끔할 때는 logfmt 한 줄이면 된다
orders 스트림에서 status 가 500 인 줄이 몇 줄인지 logfmt 파서로 세세요. 질의는 /root/lk-parsers/02-logfmt.logql, 답은 /root/lk-parsers/02-logfmt.txt 에 lines=<정수> 로 적습니다.
파서는 선택자 뒤에 파이프로 붙입니다. 파서가 만든 라벨은 그 뒤에서 라벨 필터로 쓸 수 있습니다. 줄 필터로 |= "status=500" 처럼 문자열을 찾는 것과는 다릅니다 — 이번에는 파서로 꺼낸 값을 쓰세요.
json 파서는 실패를 신고한다
mixed 스트림에 json 파서를 붙여, 파싱에 성공한 줄과 __error__ 라벨이 붙은 줄을 각각 세세요. 답은 /root/lk-parsers/03-json.txt 에 ok=<정수> 와 err=<정수> 두 줄로 적고, __error__ 의 실제 값 하나를 /root/lk-parsers/03-json-name.txt 에 한 줄로 적으세요.
파서가 실패하면 __error__ 라벨이 붙습니다. 그 라벨이 비어 있는 줄과 비어 있지 않은 줄을 각각 고르면 됩니다. 라벨 값이 무엇인지는 결과의 stream 을 그대로 들여다보면 보입니다 — __error_details__ 도 함께 붙습니다.
오류도 없이 아무것도 안 꺼낸 줄을 센다
mixed 스트림에 logfmt 파서를 붙였을 때 오류는 나지 않았는데 status 라벨이 만들어지지 않은 줄이 몇 줄인지 세세요. 질의는 /root/lk-parsers/04-silent.logql, 답은 /root/lk-parsers/04-silent.txt 에 lines=<정수> 로 적습니다.
LogQL 에서 '없는 라벨' 은 빈 문자열과 같게 비교됩니다. 그 성질을 쓰면 '파서가 값을 못 만든 줄' 을 고를 수 있습니다. 이 숫자가 이 실습에서 가장 무서운 숫자입니다 — 대시보드 어디에도 안 뜨는데 합계를 깎아 먹습니다.
자리가 고정된 줄에는 pattern 이 맞다
본문에 legacy 가 든 줄만 골라 pattern 파서로 상태 코드를 꺼내고, 그 값이 500 인 줄을 세세요. 질의는 /root/lk-parsers/05-pattern.logql, 답은 /root/lk-parsers/05-pattern.txt 에 lines=<정수> 로 적습니다. 질의에는 pattern 파서가 반드시 들어가야 합니다.
레거시 줄은 legacy handler finished code 500 in 123ms 모양입니다. pattern 은 꺼낼 자리에 꺾쇠로 이름을 적고 나머지는 글자 그대로 씁니다. 파서 앞에 줄 필터를 두어 레거시 줄만 넘기는 것이 중요합니다 — 다른 형식 줄에는 이 모양이 없습니다.
정규식 파서로 숫자를 꺼내 비교한다
같은 레거시 줄에서 regexp 파서로 걸린 시간(밀리초)을 꺼내, 1000 보다 큰 줄을 세세요. 질의는 /root/lk-parsers/06-regexp.logql, 답은 /root/lk-parsers/06-regexp.txt 에 lines=<정수> 로 적습니다. 질의에는 regexp 파서가 반드시 들어가야 합니다.
regexp 는 이름 있는 잡기 그룹만 라벨로 만듭니다 — 이름 없는 괄호는 버려집니다. 꺼낸 값은 문자열이지만 부등호로 비교하면 LogQL 이 숫자로 바꿔 줍니다. 같은 답을 pattern 으로도 낼 수 있습니다 — 어느 쪽이 읽기 쉬운지 견주어 보세요.
응용 ① — 형식별로 몇 줄인지 표로 만든다
mixed 스트림의 줄을 형식 세 가지로 갈라 세어 /root/lk-parsers/tally.tsv 를 만드세요. 머리글 없이 세 줄이고 각 줄은 탭으로 나눈 두 칸 <형식><탭><줄수> 입니다. 형식 이름은 순서대로 json, legacy, logfmt 이고, 세 줄의 합은 1단계에서 센 mixed 전체 줄 수와 같아야 합니다.
JSON 줄은 json 파서가 오류를 내지 않는 줄입니다. 레거시 줄은 본문에 legacy 가 있습니다. 남은 것이 logfmt 줄인데, 이 줄들은 logfmt 로 status 가 만들어집니다. 세 숫자의 합이 전체와 맞는지 꼭 확인하세요 — 안 맞으면 어딘가를 두 번 셌거나 빠뜨린 것입니다.
응용 ② — 진짜 5xx 건수와 그 사실을 남긴다
mixed 스트림에서 상태 코드가 500 인 줄의 진짜 총 건수를 구해 /root/lk-parsers/08-total.txt 에 total=<정수> 로 적고, 그 다음 줄에 reason= 으로 시작하는 한 문장(공백 뺀 40자 이상)을 적으세요. 왜 파서 하나로는 이 숫자를 셀 수 없는지 자기 말로 씁니다.
한 질의에 파서를 두 개 이어 붙여도 두 형식을 함께 읽지는 못합니다. 형식마다 따로 세고 더하세요. 4단계에서 센 '조용히 빠진 줄' 이 어디로 갔는지 생각하면 몇 갈래로 나눠야 하는지 보입니다. 답을 적을 때는 세 갈래의 숫자가 각각 얼마였는지도 확인해 두세요.