레이블 이해하기
레이블은 Loki의 중요한 부분입니다. 레이블을 통해 Loki는 로그 메시지를 로그 스트림으로 구성하고 그룹화할 수 있습니다. 각 로그 스트림은 Loki에 저장되고 쿼리되려면 하나 이상의 레이블을 가져야 합니다.
이 항목에서는 레이블과 Loki로 로그를 전송할 때 레이블 선택이 중요한 이유에 대해 알아봅니다.
참고: 레이블은 로그 소스를 설명하는 낮은 카디널리티 값을 저장하기 위한 것입니다. 로그에서 높은 카디널리티 데이터를 자주 검색하는 경우 구조화된 메타데이터를 사용해야 합니다.
레이블 이해하기
Loki에서는 각 로그 라인의 내용이 인덱싱되지 않습니다. 대신 로그 항목은 레이블로 인덱싱된 스트림으로 그룹화됩니다.
"레이블은 키-값 쌍이며, 예를 들어 다음은 모두 레이블입니다:"
deployment_environment = development
cloud_region = us-west-1
namespace = grafana-server
위의 모든 레이블을 공유하는 로그 메시지 집합을 로그 스트림이라고 합니다. Loki가 검색을 수행할 때 먼저 선택한 스트림의 모든 메시지를 찾은 다음 스트림의 로그를 반복하여 쿼리를 수행합니다.
레이블링은 쿼리에 영향을 미치며, 이는 대시보드에도 영향을 미칩니다. Loki에 로그 수집을 시작하기 전에 레이블링 전략에 대해 시간을 들여 생각하는 것이 좋습니다.
모든 사용자를 위한 기본 레이블
Loki는 수집 시 로그 메시지를 파싱하거나 처리하지 않습니다. 그러나 로그를 수집하는 데 사용하는 클라이언트에 따라 일부 레이블이 로그에 자동으로 적용될 수 있습니다.
service_name
Loki는 로그를 수집하는 동안 기본 service_name
레이블을 자동으로 채우려고 시도합니다. 서비스 이름 레이블은 다음 Grafana 및 Grafana Cloud 기능에서 로그를 찾고 탐색하는 데 사용됩니다.
- 로그 드릴다운
- Grafana Cloud Application Observability
참고: 이미 service_name
을 적용하고 있는 경우 Loki는 해당 값을 사용합니다.
Loki는 다음 레이블을 이 순서대로 찾아 service_name
레이블을 만들려고 시도합니다.
service_name
service
app
application
name
app_kubernetes_io_name
container
container_name
component
workload
job
목록과 일치하는 레이블이 없으면 unknown_service
값이 적용됩니다.
limits_config
블록의 discover_service_name
에 레이블 목록을 제공하여 이 목록을 변경할 수 있습니다. Grafana Cloud를 사용하는 경우 지원팀에 문의하여 이 설정을 구성하십시오.
OpenTelemetry를 위한 기본 레이블
Grafana Alloy 또는 OpenTelemetry Collector를 Loki 클라이언트로 사용하는 경우 Loki는 일부 OTel 리소스 속성을 레이블로 자동 할당합니다. 리소스 속성은 일반적으로 로그의 소스를 식별하므로 Loki의 인덱스 레이블에 잘 매핑됩니다.
기본적으로 다음 리소스 속성은 점(.
)을 밑줄(_
)로 바꿔 레이블로 저장되며, 나머지 속성은 각 로그 항목과 함께 구조화된 메타데이터로 저장됩니다.
cloud.availability_zone
cloud.region
container.name
deployment.environment.name
k8s.cluster.name
k8s.container.name
k8s.cronjob.name
k8s.daemonset.name
k8s.deployment.name
k8s.job.name
k8s.namespace.name
k8s.pod.name
k8s.replicaset.name
k8s.statefulset.name
service.instance.id
service.name
service.namespace
참고: Loki는 기본적으로 15개의 인덱스 레이블 제한이 있으므로 일부 리소스 속성만 레이블로 저장하는 것을 권장합니다. 기본 구성은 15개 이상의 리소스 속성을 선택하지만 일부는 상호 배타적입니다.
팁: Grafana Cloud Logs의 경우 현재 OpenTelemetry 지침을 참조하십시오.
레이블로 저장할 기본 리소스 속성 목록은 배포자의 otlp_config
아래 default_resource_attributes_as_index_labels
를 사용하여 구성할 수 있습니다. limits_config.otlp_config
를 사용하여 전역 제한을 설정할 수 있습니다. Grafana Cloud를 사용하는 경우 지원팀에 문의하여 이 설정을 구성하십시오.
주의: 높은 카디널리티 가능성 때문에 k8s.pod.name
및 service.instance.id
는 더 이상 기본 레이블로 권장되지 않습니다. 그러나 기본 레이블에서 이러한 리소스 속성을 제거하면 기존 사용자에게 주요 변경 사항이 되므로 아직 기본 레이블에서 더 이상 사용되지 않습니다. Grafana Loki를 처음 사용하는 경우 Alloy 또는 OpenTelemetry Collector 구성을 수정하여 k8s.pod.name
및 service.instance.id
를 인덱스 레이블에서 구조화된 메타데이터로 변환하는 것이 좋습니다. 샘플 구성은 기본 레이블 제거를 참조하십시오.
레이블링은 반복적입니다
작은 레이블 세트로 시작하는 것이 좋습니다. Grafana Alloy 또는 OpenTelemetry Collector 또는 Kubernetes Monitoring Helm 차트에서 할당한 기본 레이블을 수락하면 요구 사항을 충족할 수 있지만 시간이 지남에 따라 레이블링 전략을 수정해야 할 수도 있습니다.
첫 번째 레이블 세트가 작동하는 방식을 이해하고 해당 레이블을 적용하고 쿼리하는 방법을 이해하면 쿼리 패턴을 충족하지 못할 수 있습니다. 레이블을 수정하거나 변경하고 쿼리를 다시 테스트해야 할 수도 있습니다.
비즈니스 요구에 맞는 올바른 레이블을 결정하려면 여러 차례의 테스트가 필요할 수 있습니다. 비즈니스 요구 사항을 충족하도록 Loki 환경을 계속 조정함에 따라 이는 예상되어야 합니다.
낮은 카디널리티 레이블 생성
카디널리티는 생성하는 로그 스트림 수에 영향을 미치는 고유한 레이블과 값의 조합을 나타냅니다. 높은 카디널리티로 인해 Loki는 거대한 인덱스를 구축하고 수천 개의 작은 청크를 개체 저장소로 플러시합니다. 레이블의 카디널리티가 높으면 Loki의 성능이 매우 저하됩니다. 고려하지 않으면 높은 카디널리티는 Loki의 성능과 비용 효율성을 크게 저하시킵니다.
높은 카디널리티는 타임스탬프 또는 ip_address와 같이 제한되지 않거나 큰 가능한 값 집합을 가진 레이블을 사용하거나 값이 작고 유한한 집합이 있더라도 너무 많은 레이블을 적용하여 발생할 수 있습니다.
높은 카디널리티는 상당한 성능 저하를 유발할 수 있습니다. 제한된 값을 가진 더 적은 수의 레이블을 선호하십시오.
사용자 정의 레이블 생성
팁: Grafana Alloy 또는 Kubernetes Monitoring Helm 차트와 같은 많은 로그 수집기는 자동으로 적절한 레이블을 할당하므로 자체 레이블링 전략을 만들 필요가 없습니다. 대부분의 사용 사례에서는 기본 레이블을 그냥 수락하면 됩니다.
일반적으로 레이블은 다음과 같이 로그의 소스를 설명합니다.
- 애플리케이션의 네임스페이스 또는 추가 논리적 그룹화
- 로그가 생성된 클러스터 및/또는 지역
- 디스크의 소스 로그 파일의 파일 이름
- 환경에 개별적으로 명명된 시스템 또는 가상 머신이 있는 경우 로그가 생성된 호스트 이름. 임시 시스템 또는 가상 머신이 있는 환경이 있는 경우 호스트 이름은 구조화된 메타데이터에 저장해야 합니다.
로그에 위의 예제 레이블이 있는 경우 LogQL에서 다음과 같이 쿼리할 수 있습니다.
{namespace="mynamespace", cluster="cluster123" filename="/var/log/myapp.log"}
인덱스 기반 로그 애그리게이터와 달리 Loki는 로그 내용에서 검색하려는 모든 필드에 대해 레이블을 만들 필요가 없습니다. 레이블은 로그 스트림을 구성하고 식별하는 데만 필요합니다. Loki는 매우 병렬화된 방식으로 로그 스트림을 반복하여 주어진 문자열을 검색하여 검색을 수행합니다.
Loki가 검색을 수행하는 방법에 대한 자세한 내용은 쿼리 섹션을 참조하십시오.
이는 로그 메시지 내의 다음과 같은 항목에 대해 레이블을 추가할 필요가 없음을 의미합니다.
- 로그 수준
- 로그 메시지
- 예외 이름
즉, 경우에 따라 로그 스트림을 더 좁히는 데 도움이 되는 몇 가지 추가 레이블을 추가할 수 있습니다. 사용자 정의 레이블을 추가할 때는 다음 원칙을 따르십시오.
- 더 적은 수의 레이블을 사용하고 최대 10-15개의 레이블을 목표로 하십시오. 레이블이 적을수록 인덱스가 작아져 성능이 향상됩니다.
- 레이블을 가능한 한 구체적으로 지정하십시오. Loki가 검색해야 할 양이 적을수록 결과가 더 빨리 반환됩니다.
- 무한한 값이 아닌 장기적인 값을 가진 레이블을 만드십시오. 좋은 레이블이 되려면 시간이 지남에 따라 안정적인 값 집합을 가진 것이 좋습니다. 단 하나의 레이블 값만 변경되어도 새 스트림이 생성됩니다.
- 사용자가 실제로 쿼리할 용어를 기반으로 레이블을 만드십시오.
- 매우 구체적인 검색(예: 사용자 ID 또는 고객 ID) 또는 거의 사용되지 않는 검색(아마도 1년에 한 번 수행되는 검색)에 대한 레이블을 만들지 마십시오.
레이블 형식
Loki는 Prometheus (opens in a new tab)와 동일한 레이블 명명 제한을 적용합니다.
- ASCII 문자와 숫자, 밑줄 및 콜론을 포함할 수 있습니다. 정규식
[a-zA-Z_:][a-zA-Z0-9_:]*
과 일치해야 합니다. - 레이블에서 지원되지 않는 문자는 밑줄로 변환해야 합니다. 예를 들어 레이블
app.kubernetes.io/name
은app_kubernetes_io_name
으로 작성해야 합니다. - 그러나 레이블 이름을 이중 밑줄로 시작하고 끝내지 마십시오. 이 명명 규칙은 레이블 브라우저, 쿼리 빌더 및 자동 완성에서 기본적으로 숨겨져 사용자의 혼동을 피하기 위해 내부 레이블(예:
__stream_shard__
)에 사용됩니다.
Loki에서는 로그 메시지의 내용에 따라 레이블을 추가할 필요가 없습니다.
레이블 및 수집 순서
Loki는 순서가 맞지 않는 로그 항목 수집을 지원합니다. 순서가 맞지 않는 쓰기는 기본적으로 전역적으로 활성화되어 있지만 클러스터 또는 테넌트별로 비활성화/활성화할 수 있습니다. 순서가 맞지 않는 로그 항목을 수집할 계획이라면 레이블 선택이 중요합니다. 스트림을 분리하여 별도로 수집할 수 있도록 레이블을 사용하는 방법을 찾는 것이 좋습니다.
주어진 로그 스트림(주어진 레이블 이름 및 값 집합으로 식별됨)의 항목은 기본 2시간 시간 창 내에서 순서대로 수집되어야 합니다. 주어진 로그 스트림에 대해 너무 오래된 항목을 보내려고 하면 Loki는 too far behind
오류로 응답합니다.
수집 지연 및 전송이 다른 시스템의 경우 레이블을 사용하여 별도의 스트림을 만듭니다. 대신에:
{environment="production"}
로그 스트림을 다음과 같이 분리할 수 있습니다.
{environment="production", app="slow_app"}
{environment="production", app="fast_app"}
이제 "fast_app"과 "slow_app"은 다른 스트림으로 로그를 전송하여 각각 수집 순서를 유지할 수 있습니다.
Loki 레이블 예제
로그에 레이블이 추가되는 방식은 Loki에 로그를 보내는 데 사용하는 클라이언트에서 구성됩니다. 특정 구성은 각 클라이언트마다 다릅니다.
Alloy 예제
Grafana Labs는 Grafana Alloy를 사용하여 Loki에 로그를 보내는 것을 권장합니다. 다음은 구성 예제입니다.
local.file_match "tmplogs" {
path_targets = [
{"__path__" = "/tmp/alloy-logs/*.log"},
]
}
loki.source.file "local_files" {
targets = local.file_match.tmplogs.targets
forward_to = [loki.process.add_new_label.receiver]
}
loki.process "add_new_label" {
// Extract the value of "level" from the log line and add it to the extracted map as "extracted_level"
// You could also use "level" = "", which would extract the value of "level" and add it to the extracted map as "level"
// but to make it explicit for this example, we will use a different name.
//
// The extracted map will be covered in more detail in the next section.
stage.logfmt {
mapping = {
"extracted_level" = "level",
}
}
// Add the value of "extracted_level" from the extracted map as a "level" label
stage.labels {
values = {
"level" = "extracted_level",
}
}
forward_to = [loki.relabel.add_static_label.receiver]
}
loki.relabel "add_static_label" {
forward_to = [loki.write.local_loki.receiver]
rule {
target_label = "os"
replacement = constants.os
}
}
loki.write "local_loki" {
endpoint {
url = "http://localhost:3100/loki/api/v1/push"
}
}
Promtail 예제
다음은 Loki에 로그를 보내기 위한 Promtail 구성 예제입니다.
scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: syslog
__path__: /var/log/syslog
이 구성은 하나의 파일을 추적하고 job=syslog
라는 하나의 레이블을 할당합니다. 이렇게 하면 Loki에 하나의 스트림이 생성됩니다.
다음과 같이 쿼리할 수 있습니다.
{job="syslog"}
이제 예제를 조금 확장해 보겠습니다.
scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: syslog
__path__: /var/log/syslog
- job_name: apache
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: apache
__path__: /var/log/apache.log
이제 두 개의 파일을 추적합니다. 각 파일은 하나의 값으로 하나의 레이블만 받으므로 Loki는 이제 두 개의 스트림을 저장합니다.
다음과 같은 몇 가지 방법으로 이러한 스트림을 쿼리할 수 있습니다.
{job="apache"} <- job 레이블이 apache인 로그 표시
{job="syslog"} <- job 레이블이 syslog인 로그 표시
{job=~"apache|syslog"} <- job이 apache 또는 syslog인 로그 표시
마지막 예제에서는 정규식 레이블 매처를 사용하여 두 가지 가능한 값 중 하나를 가진 job
레이블을 사용하는 로그 스트림을 보았습니다. 이제 추가 레이블을 어떻게 사용할 수 있는지 고려해 보십시오.
scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: syslog
env: dev
__path__: /var/log/syslog
- job_name: apache
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: apache
env: dev
__path__: /var/log/apache.log
이제 정규식 대신 다음을 수행할 수 있습니다.
{env="dev"} <- env=dev인 모든 로그를 반환하며, 이 경우 두 로그 스트림이 모두 포함됩니다.
이제 레이블의 강력함을 이해하기 시작했을 것입니다. 단일 레이블을 사용하여 많은 스트림을 쿼리할 수 있습니다. 여러 다른 레이블을 결합하여 매우 유연한 로그 쿼리를 만들 수 있습니다.
레이블은 Loki 로그 데이터의 인덱스입니다. 청크로 별도로 저장되는 압축된 로그 콘텐츠를 찾는 데 사용됩니다. 레이블과 값의 모든 고유한 조합은 스트림을 정의하며 스트림에 대한 로그는 일괄 처리되고 압축되어 청크로 저장됩니다.
Loki가 효율적이고 비용 효율적이려면 레이블을 책임감 있게 사용해야 합니다. 다음 섹션에서는 이에 대해 자세히 알아보겠습니다.
카디널리티 예제
이전 두 예제에서는 단일 값을 가진 정적으로 정의된 레이블을 사용하지만 동적으로 레이블을 정의하는 방법이 있습니다. Apache 로그와 이러한 로그 라인을 구문 분석하는 데 사용할 수 있는 거대한 정규식을 사용하여 살펴보겠습니다.
11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
- job_name: system
pipeline_stages:
- regex:
expression: "^(?P<ip>\\S+) (?P<identd>\\S+) (?P<user>\\S+) \\[(?P<timestamp>[\\w:/]+\\s[+\\-]\\d{4})\\] \\\"(?P<action>\\S+)\\s?(?P<path>\\S+)?\\s?(?P<protocol>\\S+)?\\\" (?P<status_code>\\d{3}|-) (?P<size>\\d+|-)\\s?\\\"?(?P<referer>[^\\\"]*)\\\"?\\s?\\\"?(?P<useragent>[^\\\"]*)?\\\"?$"
- labels:
action:
status_code:
static_configs:
- targets:
- localhost
labels:
job: apache
env: dev
__path__: /var/log/apache.log
이 정규식은 로그 라인의 모든 구성 요소와 일치하고 각 구성 요소의 값을 캡처 그룹으로 추출합니다. 파이프라인 코드 내에서 이 데이터는 해당 로그 라인을 처리하는 동안 여러 용도로 사용할 수 있도록 임시 데이터 구조에 배치됩니다(이 시점에서 임시 데이터는 삭제됨). 이에 대한 자세한 내용은 Promtail 파이프라인 문서에서 확인할 수 있습니다.
해당 정규식에서 캡처 그룹 중 두 개를 사용하여 로그 라인의 내용에 따라 두 개의 레이블을 동적으로 설정합니다.
action
(예:action="GET"
,action="POST"
)status_code
(예:status_code="200"
,status_code="400"
)
이제 몇 가지 예제 라인을 살펴보겠습니다.
11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
Loki에서는 다음 스트림이 생성됩니다.
{job="apache",env="dev",action="GET",status_code="200"} 11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="POST",status_code="200"} 11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="GET",status_code="400"} 11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="POST",status_code="400"} 11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
이 네 개의 로그 라인은 네 개의 별도 스트림이 되고 네 개의 별도 청크를 채우기 시작합니다.
해당 레이블/값 조합과 일치하는 추가 로그 라인은 기존 스트림에 추가됩니다. 다른 고유한 레이블 조합이 들어오면(예: status_code="500"
) 또 다른 새 스트림이 생성됩니다.
이제 ip
에 대한 레이블을 설정했다고 상상해 보십시오. 사용자의 모든 요청이 고유한 스트림이 될 뿐만 아니라 동일한 사용자의 다른 작업 또는 status_code를 가진 모든 요청이 자체 스트림을 갖게 됩니다.
빠른 계산을 해보면, 일반적인 작업이 4개(GET, PUT, POST, DELETE)이고 일반적인 상태 코드가 4개(더 있을 수 있음)라고 하면 16개의 스트림과 16개의 별도 청크가 됩니다. 이제 ip
에 레이블을 사용하면 모든 사용자로 곱하십시오. 수천 또는 수만 개의 스트림을 빠르게 가질 수 있습니다.
원본: https://grafana.com/docs/loki/latest/get-started/labels/ (opens in a new tab)