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
입니다. 레이블 식별자는 항상 연산자의 왼쪽에 위치합니다.
- 예를 들어 cluster="namespace"에서 cluster는 레이블 식별자, 연산자는
- 여러 값 유형을 지원하며, 쿼리 입력에서 자동으로 추론됩니다
- 문자열, 기간, 숫자, 바이트
- 문자열 유형은 로그 스트림 선택자에서 사용되는 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 파서보다 성능이 뛰어납니다.