Grafana

Grafana (시각화 도구 사용)

Grafana와 ClickHouse 공식 플러그인을 사용해 로그와 트레이스를 시각화하는 방법을 살펴봐요.

출처: 문서

본문

Grafana는 ClickHouse에서 옵저버빌리티 데이터를 위한 선호되는 시각화 도구예요. 이는 ClickHouse 공식 Grafana 플러그인을 통해 달성돼요. 여기에서 설치 지침을 따라 할 수 있어요. 플러그인 V4는 새로운 쿼리 빌더 경험에서 로그와 트레이스를 일급 시민으로 만들어요. 이는 SRE가 SQL 쿼리를 직접 작성할 필요를 최소화하고 SQL 기반 옵저버빌리티를 단순화하며, 이 새로운 패러다임의 진전을 이끌어요. 이의 일부로 OpenTelemetry(OTel)를 플러그인의 핵심에 두었어요. 앞으로 몇 년 동안 이것이 SQL 기반 옵저버빌리티의 기반이 되고 데이터가 수집되는 방식이 될 것이라고 믿기 때문이에요.

OpenTelemetry 통합

Grafana에서 ClickHouse 데이터 소스를 구성하면 플러그인을 통해 로그와 트레이스용 기본 데이터베이스와 테이블, 그리고 이 테이블이 OTel 스키마를 따르는지 여부를 지정할 수 있어요. 이를 통해 플러그인은 Grafana에서 올바른 로그와 트레이스 렌더링에 필요한 컬럼을 반환할 수 있어요. 기본 OTel 스키마를 변경했고 자체 컬럼 이름을 사용하고 싶다면, 이 역시 지정할 수 있어요. time(Timestamp), log level(SeverityText), message body(Body) 같은 컬럼에 기본 OTel 컬럼 이름을 사용하면 변경할 필요가 없어요.

HTTP 또는 Native Grafana를 ClickHouse에 HTTP 또는 Native 프로토콜로 연결할 수 있어요. Native는 약간의 성능 이점이 있지만 Grafana 사용자가 발행하는 집계 쿼리에서는 체감하기 어려울 가능성이 높아요. 반대로 HTTP 프로토콜은 프록시하고 검사하기에 보통 더 단순해요.

로그 렌더링이 올바르게 되려면 Logs 구성에 time, log level, message 컬럼이 필요해요. Traces 구성은 조금 더 복잡해요(전체 목록은 여기). 여기서 필요한 컬럼은 전체 트레이스 프로필을 구성하는 후속 쿼리를 추상화할 수 있도록 필요해요. 이 쿼리들은 데이터가 OTel과 유사하게 구조화되어 있다고 가정하므로, 표준 스키마에서 크게 벗어나는 사용자는 이 기능을 활용하려면 뷰를 사용해야 해요. 구성이 끝나면 Grafana Explore로 이동해 로그와 트레이스를 검색할 수 있어요.

로그 (Logs)

Grafana의 로그 요구 사항을 따르면 쿼리 빌더에서 Query Type: Log를 선택하고 Run Query를 클릭할 수 있어요. 쿼리 빌더가 로그를 나열하고 렌더링되도록 하는 쿼리를 구성할 거예요. 예를 들어:

SELECT Timestamp as timestamp, Body as body, SeverityText as level, TraceId as traceID FROM "default"."otel_logs" WHERE ( timestamp >= $__fromTime AND timestamp <= $__toTime ) ORDER BY timestamp DESC LIMIT 1000

쿼리 빌더는 SQL을 직접 작성하지 않아도 쿼리를 수정할 수 있는 간단한 방법을 제공해요. 키워드를 포함한 로그 찾기 등 필터링을 쿼리 빌더에서 수행할 수 있어요. 더 복잡한 쿼리를 작성하려는 사용자는 SQL 에디터로 전환할 수 있어요. 적절한 컬럼이 반환되고 logs가 Query Type으로 선택되면 결과가 로그로 렌더링돼요. 로그 렌더링에 필요한 컬럼은 여기에 나열되어 있어요.

로그에서 트레이스로

로그에 트레이스 ID가 있으면 특정 로그 라인의 트레이스로 이동할 수 있는 이점을 누릴 수 있어요.

트레이스 (Traces)

위의 로그 경험과 유사하게, Grafana가 트레이스를 렌더링하는 데 필요한 컬럼을 충족하면(예: OTel 스키마 사용), 쿼리 빌더가 필요한 쿼리를 자동으로 구성할 수 있어요. Query Type: Traces를 선택하고 Run Query를 클릭하면 다음과 유사한 쿼리가 생성되어 실행돼요(구성된 컬럼에 따라 다름 — 아래는 OTel 사용을 가정):

SELECT "TraceId" as traceID,
  "ServiceName" as serviceName,
  "SpanName" as operationName,
  "Timestamp" as startTime,
  multiply("Duration", 0.000001) as duration
FROM "default"."otel_traces"
WHERE ( Timestamp >= $__fromTime AND Timestamp <= $__toTime )
  AND ( ParentSpanId = '' )
  AND ( Duration > 0 )
  ORDER BY Timestamp DESC, Duration DESC LIMIT 1000

이 쿼리는 Grafana가 기대하는 컬럼 이름을 반환해서 트레이스 테이블을 렌더링해요. duration이나 다른 컬럼으로 필터링을 SQL을 직접 작성하지 않고 수행할 수 있어요. 더 복잡한 쿼리를 작성하려는 사용자는 SQL Editor로 전환할 수 있어요.

트레이스 상세 보기

위에서 보듯 트레이스 ID는 클릭 가능한 링크로 렌더링돼요. 트레이스 ID를 클릭하면 사용자가 View Trace 링크를 통해 관련 스팬을 볼 수 있어요. 이는 다음 쿼리를 발행해(OTel 컬럼 가정) 필요한 구조의 스팬을 가져와서 워터폴로 렌더링해요.

WITH '<trace_id>' AS trace_id,
  (SELECT min(Start) FROM "default"."otel_traces_trace_id_ts"
    WHERE TraceId = trace_id) AS trace_start,
  (SELECT max(End) + 1 FROM "default"."otel_traces_trace_id_ts"
    WHERE TraceId = trace_id) AS trace_end
SELECT "TraceId" AS traceID,
  "SpanId" AS spanID,
  "ParentSpanId" AS parentSpanID,
  "ServiceName" AS serviceName,
  "SpanName" AS operationName,
  "Timestamp" AS startTime,
  multiply("Duration", 0.000001) AS duration,
  arrayMap(key -> map('key', key, 'value',"SpanAttributes"[key]),
  mapKeys("SpanAttributes")) AS tags,
  arrayMap(key -> map('key', key, 'value',"ResourceAttributes"[key]),
  mapKeys("ResourceAttributes")) AS serviceTags
FROM "default"."otel_traces"
WHERE traceID = trace_id
  AND startTime >= trace_start
  AND startTime <= trace_end
LIMIT 1000

위 쿼리가 트레이스 ID 조회를 위해 머티어리얼라이즈드 뷰 otel_traces_trace_id_ts를 사용한다는 점에 유의하세요. 자세한 내용은 쿼리 가속화 - 빠른 조회를 위한 Materialized views 사용을 참고하세요.

트레이스에서 로그로

로그에 트레이스 ID가 있으면 트레이스에서 관련 로그로 이동할 수 있어요. 로그를 보려면 트레이스 ID를 클릭하고 View Logs를 선택해요. 이는 기본 OTel 컬럼을 가정해 다음 쿼리를 발행해요.

SELECT Timestamp AS "timestamp",
  Body AS "body", SeverityText AS "level",
  TraceId AS "traceID" FROM "default"."otel_logs"
WHERE ( traceID = '<trace_id>' )
ORDER BY timestamp ASC LIMIT 1000

대시보드

ClickHouse 데이터 소스를 사용해 Grafana에서 대시보드를 만들 수 있어요. 자세한 내용은 Grafana와 ClickHouse 데이터 소스 문서를 권장해요. 특히 매크로(macros) 개념변수(variables)를 참고하세요. 플러그인은 몇 가지 기본 제공 대시보드를 제공하며, OTel 스펙을 따르는 로깅 및 트레이싱 데이터를 위한 예시 대시보드인 "Simple ClickHouse OTel dashboarding"도 포함돼 있어요. 이는 사용자가 OTel의 기본 컬럼 이름을 따를 것을 요구하며 데이터 소스 구성에서 설치할 수 있어요. 아래에 시각화 구축을 위한 몇 가지 간단한 팁을 제공할게요.

시계열

통계와 함께 라인 차트는 옵저버빌리티 사용 사례에서 가장 흔한 시각화 형태예요. 쿼리가 datetime 이름 time과 숫자 컬럼을 반환하면 ClickHouse 플러그인이 자동으로 라인 차트를 렌더링해요. 예를 들어:

SELECT
 $__timeInterval(Timestamp) as time,
 quantile(0.99)(Duration)/1000000 AS p99
FROM otel_traces
WHERE
 $__timeFilter(Timestamp)
 AND ( Timestamp  >= $__fromTime AND Timestamp <= $__toTime )
GROUP BY time
ORDER BY time ASC
LIMIT 100000

다중 라인 차트

다음 조건이 충족되면 다중 라인 차트가 쿼리에 대해 자동으로 렌더링돼요:

  • 필드 1: time 별칭이 있는 datetime 필드
  • 필드 2: 그룹화할 값. String이어야 함
  • 필드 3+: 메트릭 값

예를 들어:

SELECT
  $__timeInterval(Timestamp) as time,
  ServiceName,
  quantile(0.99)(Duration)/1000000 AS p99
FROM otel_traces
WHERE $__timeFilter(Timestamp)
AND ( Timestamp  >= $__fromTime AND Timestamp <= $__toTime )
GROUP BY ServiceName, time
ORDER BY time ASC
LIMIT 100000

지리 데이터 시각화

앞서 섹션에서 IP 사전을 사용해 지리 좌표로 옵저버빌리티 데이터를 강화하는 방법을 살펴봤어요. latitudelongitude 컬럼이 있다고 가정하면 geohashEncode 함수를 사용해 옵저버빌리티를 시각화할 수 있어요. 이는 Grafana Geo Map 차트와 호환되는 지오 해시를 생성해요. 예시 쿼리와 시각화는 아래와 같아요:

WITH coords AS
        (
        SELECT
                Latitude,
                Longitude,
                geohashEncode(Longitude, Latitude, 4) AS hash
        FROM otel_logs_v2
        WHERE (Longitude != 0) AND (Latitude != 0)
        )
SELECT
        hash,
        count() AS heat,
        round(log10(heat), 2) AS adj_heat
FROM coords
GROUP BY hash

더 알아보기 (Learn more)