본문으로 건너뛰기

1. LogQL

  • LoqQL은 Grafana Loki의 쿼리 언어입니다.
  • LogQL은 필터링을 위해 레이블과 연산자를 사용합니다.
  • LogQL 쿼리에는 두 가지 유형이 있습니다
    • 로그 쿼리: 로그 라인의 내용을 반환합니다.
    • 메트릭 쿼리: 로그 쿼리를 확장하여 쿼리 결과를 기반으로 값을 계산합니다.

2. 이항 연산자

  • LogQL은 이항 연산자를 지원합니다.
  • 이항 연산자는 두 개의 피연산자를 사용하여 결과를 생성하는 연산자입니다.

2.1 산술 연산자

  • LogQL에서 지원하는 산술 연산자는 다음과 같습니다.
    • +: 덧셈
    • -: 뺄셈
    • *: 곱셈
    • /: 나눗셈
    • %: 나머지
    • ^: 거듭제곱
// 로그 스트림 항목 비율 두 배로 만들기:
sum(rate({app="foo"}[1m])) * 2

// foo 앱에 대한 경고 로그와 오류 로그의 비율 얻기:
sum(rate({app="foo", level="warn"}[1m])) / sum(rate({app="foo", level="error"}[1m]))

2.2 논리 및 집합 연산자

  • 이 논리/집합 이항 연산자는 두 벡터 사이에서만 정의됩니다:
  • and (교집합)
  • or (합집합)
  • unless (보수)
// foo와 bar 앱의 로그 스트림 항목을 모두 가져옵니다
rate({app=~"foo|bar"}[1m]) and rate({app="bar"}[1m])

2.3 비교 연산자

  • LogQL에서 지원하는 비교 연산자는 다음과 같습니다.
    • ==: 같음
    • !=: 같지 않음
    • <: 작음
    • <=: 작거나 같음
    • >: 큼
    • >=: 크거나 같음

3. 쿼리 모범 사례

  • 레퍼런스
  • Loki에서 쿼리를 작성하는 방식은 쿼리 결과를 얼마나 빨리 반환받는지에 영향을 미칩니다.
  • Loki가 쿼리를 파싱하는 방법을 이해하면 효율적이고 성능이 좋은 쿼리를 작성하는 데 도움이 됩니다.
  • Loki는 LogQL 쿼리를 왼쪽에서 오른쪽으로, 작성된 순서대로 평가합니다.
  • 최상의 쿼리 성능을 얻으려면 쿼리 초반에 가능한 많은 잠재적 결과를 제거한 다음, 쿼리를 계속 작성하면서 점진적으로 검색 범위를 좁혀 나가세요.
  • 이 페이지에서는 원치 않는 결과를 효율적으로 필터링하는 쿼리 작성의 권장 순서를 설명합니다.

3.1 권장 순서

  • 먼저 시간 범위 좁히기
    • 검색하려는 기간을 지정하여 Loki가 확인해야 하는 로그 수를 줄이세요.
    • Loki는 일별로 하나의 인덱스 파일을 생성하므로, 여러 날에 걸친 쿼리는 여러 인덱스 파일을 가져옵니다.
    • Loki가 검색해야 하는 파일이 적을수록 쿼리 결과가 더 빨리 반환됩니다.
    • 시간 범위는 일반적으로 쿼리의 일부가 아니지만, 시각화 도구나 Loki API를 통해 시간 범위를 설정할 수 있습니다.
  • 정확한 레이블 선택자 사용
    • 다음으로, 레이블 선택자를 작성하세요.
    • 로그 라인 내에서 사용할 수 있는 가장 구체적인 레이블을 식별하고 그것을 기반으로 먼저 검색하세요.
    • 예를 들어, 로그에 namespace와 app_name 레이블이 포함되어 있고 후자가 더 작은 데이터 하위 집합인 경우, app_name을 기준으로 선택하여 쿼리를 시작하세요
    • 가장 구체적인 레이블 선택자를 사용하면 쿼리 길이를 줄이는 추가적인 이점이 있습니다.
    • app_name이 namespace보다 더 구체적이기 때문에 namespace에 대한 선택자를 추가할 필요가 없습니다.
    • 더 일반적인 레이블 선택자를 추가해도 쿼리에 더 이상 영향을 미치지 않습니다.
  • 정규 표현식보다 단순한 라인 필터 표현식 사용
    • 라인 필터 표현식을 사용할 때는 다음과 같은 더 단순한 필터 연산자를 선호하세요
      • |= (문자열 포함) 및
      • != (문자열 포함하지 않음)
    • 다음과 같은 정규 표현식 필터 연산자보다
      • |~ (정규 표현식과 일치)
      • !~ (정규 표현식과 일치하지 않음)
    • Loki는 처음 두 필터 표현식을 정규 표현식보다 더 빠르게 평가하므로, 항상 로그 라인이 특정 문자열을 포함하는지 또는 포함하지 않는지 관점에서 쿼리를 다시 작성하려고 노력하세요.
    • 정규 표현식은 최후의 수단으로만 사용하세요.
  • 복잡한 텍스트 파서 사용 피하기
    • 라인 필터 표현식 이후에만 파서 표현식을 사용하세요.
    • 라인 필터 표현식 이후에 이를 사용하면 Loki는 라인 필터 표현식과 일치하는 로그 라인에 대해서만 파서 표현식을 평가하므로, Loki가 검색해야 하는 로그의 양이 줄어듭니다.
    • 파서 표현식에는 JSON, logfmt, pattern, regexp 및 unpack 파서가 포함됩니다.

4. Log queries 작성하기

  • 레퍼런스
  • Log queries는 아래와 같이 구성됩니다.
    • 로그 스트림 선택자: 스트림 선택자는 쿼리 결과에 포함할 로그 스트림을 결정합니다
    • 로그 파이프라인: 로그 파이프라인은 선택된 로그 스트림에 적용되는 일련의 단계 표현식

4.1 로그 스트림 선택자

  • 로그 스트림 선택자는 쿼리 결과에 포함할 로그 스트림을 결정합니다.
  • 더 세분화된 로그 스트림 선택자는 검색되는 스트림의 수를 관리 가능한 양으로 줄입니다.
    • 이는 로그 스트림 선택자에 전달된 레이블이 쿼리 실행 성능에 영향을 미친다는 것을 의미합니다.
  • 로그 스트림 선택자는 하나 이상의 쉼표로 구분된 키-값 쌍으로 지정됩니다.
  • 각 키는 로그 레이블이고 각 값은 해당 레이블의 값입니다.
{app="mysql",name="mysql-backup"}
  • 값이 mysql인 app 레이블과 값이 mysql-backup인 name 레이블을 모두 가진 모든 로그 스트림이 쿼리 결과에 포함됩니다.
  • 스트림은 다른 레이블-값 쌍을 포함할 수 있지만, 스트림 선택자 내에 지정된 쌍만 쿼리 결과에 포함될 스트림을 결정하는 데 사용됩니다.

4.1.1 레이블 매칭 연산자

  • 레이블 이름 뒤의 = 연산자는 레이블 매칭 연산자입니다.
  • 다음과 같은 레이블 매칭 연산자가 지원됩니다:
    • =: 정확히 일치
    • !=: 일치하지 않음
    • =~: 정규식 일치
    • !~: 정규식 일치하지 않음

4.2 로그 파이프라인

  • 로그 파이프라인은 로그 스트림을 추가로 처리하고 필터링하기 위해 로그 스트림 선택자에 추가할 수 있습니다.
  • 파이프라인은 일련의 표현식으로 구성됩니다.
  • 로그 파이프라인 표현식은 다음 네 가지 범주 중 하나에 속합니다
    • 필터링 표현식: 라인 필터 표현식 및 레이블 필터 표현식
    • 파싱 표현식
    • 포맷팅 표현식: 라인 포맷 표현식 및 레이블 포맷 표현식
    • 레이블 표현식: 레이블 삭제 표현식 및 레이블 유지 표현식

4.2.1 Line filter expression

  • 라인 필터 표현식은 일치하는 로그 스트림에서 집계된 로그에 대해 로그 라인의 내용을 검색하여 대소문자를 구분하는 표현식과 일치하지 않는 라인을 버립니다.
  • 각 라인 필터 표현식에는 필터 연산자와 텍스트 또는 정규 표현식이 포함됩니다.
  • 지원되는 필터 연산자는 다음과 같습니다:
    • |=: 로그 라인에 문자열 포함
    • !=: 로그 라인에 문자열 미포함
    • |~: 로그 라인에 정규 표현식 일치 포함
    • !~: 로그 라인에 정규 표현식 일치 미포함
예시
{app="tournament-api"}
!= "TRACE"

4.2.2 Label filter expression

  • 레이블 필터 표현식은 원본 및 추출된 레이블을 사용하여 로그 라인을 필터링할 수 있게 합니다.
  • 여러 조건(predicate)을 포함할 수 있습니다.
  • 하나의 조건은 레이블 식별자, 연산자, 그리고 비교할 값으로 구성됩니다.
    • 예를 들어 cluster="namespace"에서 cluster는 레이블 식별자, 연산자는 =, 값은 namespace입니다. 레이블 식별자는 항상 연산자의 왼쪽에 위치합니다.
  • 여러 값 유형을 지원하며, 쿼리 입력에서 자동으로 추론됩니다
    • 문자열, 기간, 숫자, 바이트
  • 문자열 유형은 로그 스트림 선택자에서 사용되는 Prometheus 레이블 매처와 동일하게 작동합니다.
    • 따라서 동일한 연산자(=, !=, =, !)를 사용할 수 있습니다.
  • 기간, 숫자, 바이트를 사용하면 비교 전에 레이블 값이 변환되며 다음 비교 연산자를 지원합니다:
    • == 또는 =: 동등 비교
    • !=: 부등 비교
    • >>=: 초과 및 이상
    • <<=: 미만 및 이하
logfmt | duration > 1m and bytes_consumed > 20MB
  • 위 쿼리는 logfmt 파서로 파싱된 로그 라인에서 duration 레이블이 1분보다 크고 bytes_consumed 레이블이 20MB보다 큰 로그 라인을 반환합니다.

4.2.3 Parser expression

  • 파서 표현식은 로그 내용에서 레이블을 파싱하고 추출할 수 있습니다.
  • 이렇게 추출된 레이블은 레이블 필터 표현식을 사용한 필터링이나 메트릭 집계에 활용될 수 있습니다.
  • 오류가 발생한 경우, 예를 들어 로그 라인이 예상 형식이 아닌 경우, 로그 라인은 필터링되지 않고 대신 새로운 __error__ 레이블이 추가됩니다.
  • 추출된 레이블 키 이름이 원래 로그 스트림에 이미 존재하는 경우, 추출된 레이블 키에는 두 레이블을 구분하기 위해 _extracted 키워드가 접미사로 붙습니다.
json 파서
  • JSON 파서는 두 가지 모드로 작동합니다
  • 매개변수 없이 | json을 사용하면 JSON 문서에서 레이블을 추출합니다.
    • 파이프라인에 | json을 추가하면 로그 라인이 유효한 JSON 문서인 경우 모든 JSON 속성을 레이블로 추출합니다.
    • 중첩된 속성은 _ 구분자를 사용하여 레이블 키로 평탄화됩니다.
    • 참고: 배열은 건너뜁니다.
  • 파이프라인에서 | json label="expression", another="expression"을 사용하면 지정된 JSON 필드만 레이블로 추출합니다.
    • 이런 방식으로 label_format과 마찬가지로 하나 이상의 표현식을 지정할 수 있습니다.
    • 모든 표현식은 따옴표로 묶어야 합니다.

매개변수 없이 파싱 결과

{
"protocol": "HTTP/2.0",
"servers": [
"129.0.1.1",
"10.2.1.3"
],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}
"protocol" => "HTTP/2.0"
"request_time" => "6.032"
"request_method" => "GET"
"request_host" => "foo.grafana.net"
"request_size" => "55"
"request_headers_Accept" => "*/*"
"request_headers_User_Agent" => "curl/7.68.0"
"response_status" => "401"
"response_size" => "228"
"response_latency_seconds" => "6.031"
  • 중첩된 속성은 _ 구분자를 사용하여 레이블 키로 평탄화되었습니다.
  • 배열은 건너뛰었습니다.

매개변수 사용한 결과

{
"protocol": "HTTP/2.0",
"servers": [
"129.0.1.1",
"10.2.1.3"
],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}
  • 위와 같은 JSON 문서에서 다음과 같은 파서 표현식을 사용하여 레이블을 추출할 수 있습니다.
  • | json first_server="servers[0]", ua="request.headers[\"User-Agent\"]"
"first_server" => "129.0.1.1"
"ua" => "curl/7.68.0"
  • 추출 결과는 위와 같습니다.
logfmt 파서
pattern 파서
  • 패턴 파서는 패턴 표현식(| pattern "<pattern-expression>")을 정의하여 로그 라인에서 필드를 명시적으로 추출할 수 있게 합니다.
  • pattern 파서는 작성하기 더 쉽고 빠르며, regexp 파서보다 성능이 뛰어납니다.
0.191.12.2 - - [10/Jun/2021:09:14:29 +0000] "GET /api/plugins/versioncheck HTTP/1.1" 200 2 "-" "Go-http-client/2.0" "13.76.247.102, 34.120.177.193" "TLSv1.2" "US" ""
  • 위와 같은 로그 라인에서 다음과 같은 패턴을 사용하여 레이블을 추출할 수 있습니다.
  • <ip> - - <_> "<method> <uri> <_>" <status> <size> <_> "<agent>" <_>
"ip" => "0.191.12.2"
"method" => "GET"
"uri" => "/api/plugins/versioncheck"
"status" => "200"
"size" => "2"
"agent" => "Go-http-client/2.0"
  • 추출 결과는 위와 같습니다.
regexp 파서
  • pattern 파서는 작성하기 더 쉽고 빠르며, regexp 파서보다 성능이 뛰어납니다.
unpack 파서

4.2.4 line_format 표현식

  • | line_format 표현식은 text/template 형식을 사용하여 로그 라인 내용을 재작성할 수 있습니다.
  • | line_format "{{.label_name}}"과 같은 단일 문자열 매개변수를 받으며, 이는 템플릿 형식입니다.
  • 모든 레이블은 템플릿에 주입되는 변수이며 {{.label_name}} 표기법으로 사용할 수 있습니다.
    • 템플릿에는 큰따옴표 문자열이나 백틱 {{.label_name}}을 사용하여 특수 문자를 이스케이프할 필요 없이 사용할 수 있습니다.

4.2.5 label_format 표현식

  • | label_format 표현식은 레이블을 이름 변경, 수정 또는 추가할 수 있습니다.
  • 매개변수로 쉼표로 구분된 등호 연산 목록을 사용하여 여러 작업을 한 번에 수행할 수 있습니다.
  • 양쪽이 모두 레이블 식별자인 경우, 예를 들어 dst=src에서는 src 레이블을 dst로 이름을 바꾸는 작업을 수행합니다.
  • 오른쪽은 대안적으로 템플릿 문자열(큰따옴표 또는 백틱으로 묶인)일 수 있습니다.
    • 예를 들어 dst="{{.status}} {{.query}}"에서는 dst 레이블 값이 text/template 평가 결과로 대체됩니다.

4.2.6 레이블 삭제 표현식

  • | label_drop 표현식은 레이블을 삭제합니다.

4.2.7 레이블 유지 표현식

  • | label_keep 표현식은 오직 지정된 레이블만 유지하고 나머지 레이블은 삭제합니다.
  • {job="varlogs"}|json|keep level, method="GET"

5. Metric queries

  • 레퍼런스
  • 메트릭 쿼리는 로그 쿼리 결과에 함수를 적용하여 로그 쿼리를 확장합니다. 이 강력한 기능은 로그에서 메트릭을 생성합니다.
  • 메트릭 쿼리는 오류 메시지의 발생 빈도를 계산하거나 지난 3시간 동안 로그 양이 가장 많은 상위 N개의 로그 소스를 찾는 데 사용할 수 있습니다.
  • 파서와 결합하면, 메트릭 쿼리는 로그 라인 내의 샘플 값(예: 지연 시간 또는 요청 크기)에서 메트릭을 계산하는 데도 사용할 수 있습니다.

5.1 Range Vector aggregation(범위 벡터 집계)

  • 범위 벡터는 특정 시간 범위 동안의 데이터 포인트 집합을 의미합니다.
  • Loki는 두 가지 유형의 범위 벡터 집계를 지원합니다
    • Log range aggregations(로그 범위 집계)
    • Unwrapped range aggregations(언래핑된 범위 집계)

5.1.1 시간 지속 기간(Time Duration)

  • 시간 지속 기간은 범위 벡터가 얼마나 많은 시간을 포함할지 정의합니다.
  • Loki는 Prometheus와 동일한 표기법을 사용합니다
    • s: 초
    • m: 분
    • h: 시간
    • d: 일
    • w: 주
    • y: 년
  • 예: [5m]은 5분, [1h30m]은 1시간 30분의 지속 기간을 의미합니다.

5.1.2 Log range aggregations(로그 범위 집계)

  • 로그 범위 집계는 시간 범위에 걸쳐 로그 데이터를 분석하는 강력한 방법입니다
    • 쿼리 뒤에 기간이 오는 형태입니다.
    • 함수는 기간에 걸쳐 쿼리를 집계하는 데 적용됩니다.
    • 기간은 로그 스트림 선택기 뒤나 로그 파이프라인의 끝에 배치할 수 있습니다.
  • 지원되는 함수:
    • rate(log-range)
      • 초당 항목 수를 계산합니다.
      • 특정 시간 범위 동안 로그 항목이 생성되는 속도를 초당 항목 수로 측정합니다.
      • 이는 트래픽이나 활동 수준을 모니터링하는 데 유용합니다.
    • count_over_time(log-range)
      • 주어진 범위 내에서 각 로그 스트림의 항목을 계산합니다.
      • 가장 직관적인 함수로, 단순히 지정된 시간 범위 동안 일치하는 로그 항목의 총 개수를 계산합니다.
    • bytes_rate(log-range)
      • 각 스트림에 대한 초당 바이트 수를 계산합니다.
    • bytes_over_time(log-range)
      • 주어진 범위에 대해 각 로그 스트림이 사용하는 바이트 양을 계산합니다.
    • absent_over_time(log-range)
      • 전달된 범위 벡터에 요소가 있으면 빈 벡터를 반환하고, 전달된 범위 벡터에 요소가 없으면 값이 1인 1-요소 벡터를 반환합니다.
      • absent_over_time은 일정 시간 동안 레이블 조합에 대한 시계열 및 로그 스트림이 존재하지 않을 때 경고하는 데 유용합니다.
count_over_time({job="mysql"}[5m])
  • 위 쿼리는 job 레이블이 mysql인 로그 스트림에서 지난 5분 동안의 항목 수를 계산합니다.

5.1.3 Unwrapped range aggregations(언래핑된 범위 집계)

  • 레퍼런스
  • Unwrapped range aggregations은 로그 데이터 자체가 아닌, 로그에서 추출한 특정 레이블의 값을 시계열 데이터로 변환하는 기능입니다.
  • | unwrap label_identifier 형식으로 사용됩니다.
    • 이 표현식은 어떤 레이블의 값을 숫자 데이터로 추출할지 지정합니다.
    • 레이블 값(문자열)을 자동으로 숫자(float64)로 변환합니다.
    • 변환에 실패하면 __error__ 레이블이 추가됩니다.
함수
  • 언래핑된 범위에서 작동하는 함수는 다음과 같습니다.
  • rate(unwrapped-range)
    • 지정된 간격 내 모든 값의 합계에 대한 초당 비율을 계산합니다.
  • rate_counter(unwrapped-range)
    • 지정된 간격 내 값들의 초당 비율을 계산하며 이를 "카운터 메트릭"으로 취급합니다.
  • sum_over_time(unwrapped-range)
    • 지정된 간격 내 모든 값의 합계를 계산합니다.
  • avg_over_time(unwrapped-range)
    • 지정된 간격 내 모든 포인트의 평균값을 계산합니다.
  • max_over_time(unwrapped-range)
    • 지정된 간격 내 모든 포인트의 최대값을 계산합니다.
  • min_over_time(unwrapped-range)
    • 지정된 간격 내 모든 포인트의 최소값을 계산합니다.
  • first_over_time(unwrapped-range)
    • 지정된 간격 내 모든 포인트의 첫 번째 값을 계산합니다.
  • last_over_time(unwrapped-range)
    • 지정된 간격 내 모든 포인트의 마지막 값을 계산합니다.
  • stdvar_over_time(unwrapped-range)
    • 지정된 간격 내 값들의 모집단 표준 분산을 계산합니다.
  • stddev_over_time(unwrapped-range)
    • 지정된 간격 내 값들의 모집단 표준 편차를 계산합니다.
  • absent_over_time(unwrapped-range)
    • 전달된 범위 벡터에 요소가 있으면 빈 벡터를 반환하고, 전달된 범위 벡터에 요소가 없으면 값이 1인 1-요소 벡터를 반환합니다. (absent_over_time은 특정 시간 동안 레이블 조합에 대한 시계열 및 로그 스트림이 존재하지 않을 때 알림을 설정하는 데 유용합니다.)

5.2 Built-in aggregation operators

  • sum: 레이블에 대한 합계 계산
  • avg: 레이블에 대한 평균 계산
  • min: 레이블에 대한 최소값 선택
  • max: 레이블에 대한 최대값 선택
  • stddev: 레이블에 대한 모집단 표준 편차 계산
  • stdvar: 레이블에 대한 모집단 표준 분산 계산
  • count: 벡터의 요소 수 계산
  • topk: 샘플 값에 따라 가장 큰 k개 요소 선택
  • bottomk: 샘플 값에 따라 가장 작은 k개 요소 선택
  • sort: 벡터 요소를 샘플 값에 따라 오름차순으로 정렬하여 반환
  • sort_desc: sort와 동일하지만 내림차순으로 정렬

5.3 Functions

5.4 Probabilistic aggregation

참고