LogQL: 로그 쿼리 언어
LogQL은 Grafana Loki의 PromQL에서 영감을 받은 쿼리 언어입니다. 쿼리는 로그 소스를 집계하기 위해 분산된 grep
처럼 작동합니다. LogQL은 필터링을 위해 레이블과 연산자를 사용합니다.
LogQL 쿼리에는 두 가지 유형이 있습니다.
이진 연산자
산술 연산자
Loki에는 다음과 같은 이진 산술 연산자가 있습니다.
+
(덧셈)-
(뺄셈)*
(곱셈)/
(나눗셈)%
(나머지)^
(거듭제곱)
이진 산술 연산자는 두 개의 리터럴(스칼라), 리터럴과 벡터, 그리고 두 개의 벡터 사이에 정의됩니다.
두 리터럴 사이에서는 동작이 명확합니다. 두 스칼라 피연산자에 연산자를 적용한 결과인 다른 리터럴로 평가됩니다 (1 + 1 = 2
).
벡터와 리터럴 사이에서는 연산자가 벡터의 모든 데이터 샘플 값에 적용됩니다. 예를 들어 시계열 벡터에 2를 곱하면 결과는 원래 벡터의 모든 샘플 값에 2를 곱한 또 다른 벡터가 됩니다.
두 벡터 사이에서는 이진 산술 연산자가 왼쪽 벡터의 각 항목과 오른쪽 벡터의 일치하는 요소에 적용됩니다. 결과는 그룹화 레이블이 출력 레이블 세트가 되는 결과 벡터로 전파됩니다. 오른쪽 벡터에서 일치하는 항목을 찾을 수 없는 항목은 결과에 포함되지 않습니다.
산술 연산자를 연결할 때는 연산자 순서에 특히 주의하세요.
산술 예제
간단한 쿼리로 상태 확인을 구현합니다.
1 + 1
로그 스트림 항목의 비율을 두 배로 늘립니다.
sum(rate({app="foo"}[1m])) * 2
foo
앱의 경고 로그 대 오류 로그 비율을 가져옵니다.
sum(rate({app="foo", level="warn"}[1m])) / sum(rate({app="foo", level="error"}[1m]))
논리 및 집합 연산자
이러한 논리/집합 이진 연산자는 두 벡터 사이에서만 정의됩니다.
and
(교집합)or
(합집합)unless
(차집합)
vector1 and vector2
는 정확히 일치하는 레이블 세트를 가진 vector2
의 요소가 있는 vector1
의 요소로 구성된 벡터를 반환합니다. 다른 요소는 삭제됩니다.
vector1 or vector2
는 vector1
의 모든 원래 요소(레이블 세트 + 값)와 vector1
에 일치하는 레이블 세트가 없는 vector2
의 모든 요소를 포함하는 벡터를 반환합니다.
vector1 unless vector2
는 vector2
에 정확히 일치하는 레이블 세트를 가진 요소가 없는 vector1
의 요소로 구성된 벡터를 반환합니다. 두 벡터의 모든 일치하는 요소는 삭제됩니다.
이진 연산자 예제
이 예제 쿼리는 이러한 쿼리의 교집합을 반환하며, 실질적으로 rate({app="bar"})
와 같습니다.
rate({app=~"foo|bar"}[1m]) and rate({app="bar"}[1m])
비교 연산자
==
(같음)!=
(같지 않음)>
(보다 큼)>=
(크거나 같음)<
(보다 작음)<=
(작거나 같음)
비교 연산자는 스칼라/스칼라, 벡터/스칼라, 벡터/벡터 값 쌍 사이에 정의됩니다. 기본적으로 필터링합니다. 연산자 뒤에 bool
을 제공하여 동작을 수정할 수 있으며, 이 경우 필터링하는 대신 값에 대해 0 또는 1을 반환합니다.
두 스칼라 사이에서 이러한 연산자는 비교 결과에 따라 0(거짓) 또는 1(참)인 다른 스칼라를 반환합니다. bool
수정자는 제공해서는 안 됩니다.
1 >= 1
은 "1"
과 같습니다.
벡터와 스칼라 사이에서 이러한 연산자는 벡터의 모든 데이터 샘플 값에 적용되며, 비교 결과가 거짓인 벡터 요소는 결과 벡터에서 삭제됩니다. bool
수정자가 제공되면 삭제될 벡터 요소는 값 0을 갖고 유지될 벡터 요소는 값 1을 갖습니다.
지난 1분 동안 최소 10개의 라인을 기록한 스트림을 필터링합니다.
count_over_time({foo="bar"}[1m]) > 10
10개 미만/이상의 라인을 기록한 스트림에 값 0/1을 첨부합니다.
count_over_time({foo="bar"}[1m]) > bool 10
두 벡터 사이에서 이러한 연산자는 기본적으로 필터 역할을 하며 일치하는 항목에 적용됩니다. 표현식이 참이 아니거나 표현식의 다른 쪽에서 일치 항목을 찾지 못하는 벡터 요소는 결과에서 삭제되고, 다른 요소는 결과 벡터로 전파됩니다. bool
수정자가 제공되면 삭제될 벡터 요소는 값 0을 갖고 유지될 벡터 요소는 값 1을 가지며, 그룹화 레이블은 다시 출력 레이블 세트가 됩니다.
app=bar
에 해당하는 것보다 지난 1분 동안 더 높은 카운트를 가진 app=foo
와 일치하는 스트림을 반환합니다(앱 레이블 제외).
sum without(app) (count_over_time({app="foo"}[1m])) > sum without(app) (count_over_time({app="bar"}[1m]))
위와 동일하지만, 비교를 통과하면 벡터 값은 1
로 설정되고, 실패하거나 필터링될 경우 0
으로 설정됩니다.
sum without(app) (count_over_time({app="foo"}[1m])) > bool sum without(app) (count_over_time({app="bar"}[1m]))
패턴 매치 필터 연산자
|>
(라인 매치 패턴)!>
(라인 매치 제외 패턴)
패턴 필터는 효율성을 향상시킬 뿐만 아니라 LogQL 쿼리 작성 프로세스를 단순화합니다. 복잡한 정규식 패턴의 필요성을 제거함으로써 사용자는 보다 직관적인 구문을 사용하여 쿼리를 생성하여 인지 부하와 오류 가능성을 줄일 수 있습니다.
패턴 구문 내에서 <_>
는 임의의 텍스트를 나타내는 와일드카드로 사용됩니다. 이를 통해 쿼리는 지정된 패턴이 발생하는 로그 라인(예: 정적 콘텐츠가 포함되고 중간에 가변 콘텐츠가 있는 로그 라인)과 일치할 수 있습니다.
라인 매치 패턴 예제:
{service_name=`distributor`} |> `<_> caller=http.go:194 level=debug <_> msg="POST /push.v1.PusherService/Push <_>`
라인 매치 제외 패턴 예제:
{service_name=`distributor`} !> `<_> caller=http.go:194 level=debug <_> msg="POST /push.v1.PusherService/Push <_>`
예를 들어, 위의 예제 쿼리는 distributor
서비스의 다음 로그 라인과 각각 일치하거나 일치하지 않습니다.
ts=2024-04-05T08:40:13.585911094Z caller=http.go:194 level=debug traceID=23e54a271db607cc orgID=3648 msg="POST /push.v1.PusherService/Push (200) 12.684035ms"
연산자 순서
연산자를 연결하거나 결합할 때는 연산자 우선순위를 고려해야 합니다. 일반적으로 동일한 우선순위 수준의 연산자는 왼쪽 결합성을 갖는 일반적인 수학적 규칙 (opens in a new tab)을 따릅니다.
자세한 내용은 Golang 언어 문서 (opens in a new tab)에서 확인할 수 있습니다.
1 + 2 / 3
은 1 + ( 2 / 3 )
와 같습니다.
2 * 3 % 2
는 (2 * 3) % 2
로 평가됩니다.
on
및 ignoring
키워드
ignoring
키워드는 일치하는 동안 지정된 레이블을 무시하도록 합니다. 구문:
<vector expr> <bin-op> ignoring(<labels>) <vector expr>
이 예는 지난 1분 동안 총 카운트가 foo
앱의 평균 값을 초과하는 머신을 반환합니다.
max by(machine) (count_over_time({app="foo"}[1m])) > bool ignoring(machine) avg(count_over_time({app="foo"}[1m]))
on
키워드는 고려되는 레이블 집합을 지정된 목록으로 줄입니다. 구문:
<vector expr> <bin-op> on(<labels>) <vector expr>
이 예는 foo
앱에서 지난 1분 동안의 모든 머신 총 카운트 비율을 반환합니다.
sum by(machine) (count_over_time({app="foo"}[1m])) / on() sum(count_over_time({app="foo"}[1m]))
다대일 및 일대다 벡터 일치
다대일 및 일대다 일치는 "일(one)" 측의 각 벡터 요소가 "다(many)" 측의 여러 요소와 일치할 수 있을 때 발생합니다. group_left
또는 group_right
수정자를 사용하여 일치를 명시적으로 요청해야 하며, 여기서 left
또는 right
는 카디널리티가 더 높은 벡터를 결정합니다. 구문:
<vector expr> <bin-op> ignoring(<labels>) group_left(<labels>) <vector expr>
<vector expr> <bin-op> ignoring(<labels>) group_right(<labels>) <vector expr>
<vector expr> <bin-op> on(<labels>) group_left(<labels>) <vector expr>
<vector expr> <bin-op> on(<labels>) group_right(<labels>) <vector expr>
group
수정자와 함께 제공된 레이블 목록에는 결과 메트릭에 포함된 "일" 측의 추가 레이블이 포함됩니다. 레이블은 on
및 group_x
에 의해 지정된 목록 중 하나에만 나타나야 합니다. 결과 벡터의 모든 시계열은 고유하게 식별 가능해야 합니다. 그룹화 수정자는 비교 및 산술에만 사용할 수 있습니다. 기본적으로 시스템은 and
, unless
, or
연산을 오른쪽 벡터의 모든 항목과 일치시킵니다.
다음 예는 app
및 status
별로 분할된 요청 비율을 총 요청의 백분율로 반환합니다.
sum by (app, status) ( rate( {job="http-server"} | json [5m] ) ) / on (app) group_left sum by (app) ( rate( {job="http-server"} | json [5m] ) )
이 버전은 group_left(<labels>)
를 사용하여 오른쪽에서 <labels>
를 결과에 포함하고 사용자, 조직 및 네임스페이스별로 버려진 이벤트 비용을 반환합니다.
sum by (user, namespace) ( rate( {job="events"} | logfmt | discarded="true" [5m] ) ) * on (user) group_left(organization) max_over_time( {job="cost-calculator"} | logfmt | unwrap cost [5m] ) by (user, organization)
주석
LogQL 쿼리는 #
문자를 사용하여 주석을 달 수 있습니다.
{app="foo"} # 이 뒤에 오는 모든 것은 쿼리에서 해석되지 않습니다.
여러 줄 LogQL 쿼리의 경우 쿼리 파서는 #
을 사용하여 전체 또는 부분 라인을 제외할 수 있습니다.
{app="foo"}
| json # 이 라인은 무시됩니다.
| bar="baz" # 이것은 bar = "baz"인지 확인합니다.
파이프라인 오류
파이프라인 처리 오류는 다음과 같은 여러 가지 이유로 발생할 수 있습니다.
- 숫자 레이블 필터가 레이블 값을 숫자로 변환하지 못할 수 있습니다.
- 레이블에 대한 메트릭 변환이 실패할 수 있습니다.
- 로그 라인이 유효한 json 문서가 아닙니다.
- 기타...
이러한 오류가 발생하면 Loki는 해당 로그 라인을 필터링하지 않습니다. 대신 __error__
라는 새 시스템 레이블과 함께 파이프라인의 다음 단계로 전달됩니다. 오류를 필터링하는 유일한 방법은 레이블 필터 표현식을 사용하는 것입니다. __error__
레이블은 언어를 통해 이름을 바꿀 수 없습니다.
예를 들어 json 오류를 제거하려면:
{cluster="ops-tools1",container="ingress-nginx"} | json | __error__ != "JSONParserErr"
또는 __error__ = ""
와 같은 캐치-올 매처를 사용하여 모든 오류를 제거하거나 __error__ != ""
를 사용하여 오류만 표시할 수도 있습니다.
필터는 이 오류를 생성한 단계 뒤에 배치해야 합니다. 즉, unwrap 표현식에서 오류를 제거해야 하는 경우 unwrap 뒤에 배치해야 합니다.
quantile_over_time( 0.99, {container="ingress-nginx",service="hosted-grafana"} | json | unwrap response_latency_seconds | __error__=""[1m] ) by (cluster)
메트릭 쿼리에는 오류가 포함될 수 없습니다. 실행 중에 오류가 발견되면 Loki는 오류와 적절한 상태 코드를 반환합니다.
함수
Loki는 데이터에 대한 작업을 수행하는 함수를 지원합니다.
label_replace()
v
의 각 시계열에 대해,
label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)
는 정규식 regex
를 레이블 src_label
과 일치시킵니다. 일치하면 시계열은 dst_label
레이블이 replacement
의 확장으로 대체된 상태로 반환됩니다.
$1
은 첫 번째 일치하는 하위 그룹으로, $2
는 두 번째 등으로 대체됩니다. 정규식이 일치하지 않으면 시계열은 변경되지 않은 상태로 반환됩니다.
이 예는 각 시계열에 foo
레이블과 값 a
가 추가된 벡터를 반환합니다.
label_replace(rate({job="api-server",service="a:c"} |= "err" [1m]), "foo", "$1", "service", "(.*):.*")