-
이코에코(Eco²) Observability #6: Log-Trace 연동 및 Kibana 검색 구조이코에코(Eco²)/Observability 2025. 12. 19. 03:10

개요
분산 시스템에서 로그와 트레이스를 연결하는 것은 디버깅의 핵심입니다.
이 문서에서는 Kibana에서
trace.id로 로그를 검색할 수 있도록 구성한 과정과 현재 구현 상태를 다룹니다.
현재 클러스터 상태
Trace 커버리지 통계

전체 로그 1,750,699 trace.id 있는 로그 125,398 커버리지 7.16% 서비스별 trace.id 분포
istio-proxy 125,179 99.8% chat-api 40 0.03% scan-api 34 0.03% ext-authz 11 0.01% auth-api 10 0.01% image-api 4 - location-api 2 - my-api 1 - istio-proxy (EnvoyFilter)가 대부분의 trace를 생성. 앱 로그는 요청 처리 시에만 trace.id 포함.
현재 구현 구조
Trace 생성 흐름

컴포넌트별 trace.id 지원
컴포넌트 trace.id 소스 구현 방식 상태 Istio Gateway %TRACE_ID%EnvoyFilter ✅ istio-proxy (Sidecar) %TRACE_ID%EnvoyFilter ✅ ext-authz (Go gRPC) gRPC metadata 수동 추출 ✅ Python APIs OTEL SDK 자동 계측 ✅ 시스템 로그 N/A 미지원 ❌
실제 로그 예시
1. istio-proxy 로그 (EnvoyFilter)
{ "@timestamp": "2025-12-18T18:05:28.383Z", "service.name": "istio-proxy", "trace.id": "c8fd3e757ca339685a7309846a5821b6", "http.request.method": "GET", "url.path": "/healthz/ready", "http.response.status_code": 200 }2. ext-authz 로그 (gRPC metadata 추출)
{ "@timestamp": "2025-12-18T12:02:06.845Z", "service.name": "ext-authz", "trace.id": "a593d6809fe6f036728dc73cfd170b0e", "span.id": "3e491beac3443f3c", "msg": "Authorization denied", "event.outcome": "failure" }3. Python App 로그 (OTEL SDK)
{ "@timestamp": "2025-12-18T09:31:11.811+00:00", "service.name": "auth-api", "trace.id": "5fdc8e113b2618f6006a00c89347d78a", "span.id": "44ea44a93a45564f", "log.level": "warning", "message": "HTTP 401 UNAUTHORIZED: Missing refresh token" }
핵심 구현 상세
1. EnvoyFilter (Istio Access Log)
workloads/istio/base/envoy-filter-access-log.yaml:apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: enable-access-log namespace: istio-system spec: configPatches: - applyTo: NETWORK_FILTER match: context: ANY listener: filterChain: filter: name: envoy.filters.network.http_connection_manager patch: operation: MERGE value: typed_config: '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager access_log: - name: envoy.access_loggers.file typed_config: '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog path: /dev/stdout log_format: json_format: # ✅ %TRACE_ID% - 헤더 없어도 Envoy가 자동 생성 trace.id: '%TRACE_ID%' span.id: '%REQ(X-B3-SPANID)%' http.request.method: '%REQ(:METHOD)%' url.path: '%REQ(:PATH)%' http.response.status_code: '%RESPONSE_CODE%'%TRACE_ID% vs %REQ(X-B3-TRACEID)% 비교
변수 값 보장 설명 %REQ(X-B3-TRACEID)%❌ 클라이언트가 보낸 헤더만 %TRACE_ID%✅ Envoy가 항상 자동 생성 2. Index Template (ECS 호환)
subobjects: false로 dot notation 필드명 유지:{ "index_patterns": ["logs-*"], "template": { "mappings": { "subobjects": false, "properties": { "trace.id": { "type": "keyword" }, "span.id": { "type": "keyword" }, "log.level": { "type": "keyword" }, "service.name": { "type": "keyword" } } } } }3. Fluent Bit 설정
[OUTPUT] Name es Match kube.* Replace_Dots Off # ✅ ECS dot notation 유지 ...
Kibana 검색 가이드
검색 쿼리 예시
# 특정 trace의 모든 로그 (cross-service) trace.id:5fdc8e113b2618f6006a00c89347d78a # 특정 서비스의 에러 로그 service.name:auth-api AND log.level:error # istio-proxy 401 에러 service.name:istio-proxy AND http.response.status_code:401 # 앱 로그만 (시스템 제외) trace.id:* AND service.name:(auth-api OR scan-api OR chat-api)Jaeger ↔ Kibana 연동 워크플로우

실제 사용
- Jaeger:
https://jaeger.dev.growbin.app/trace/{trace_id} - Kibana:
https://kibana.dev.growbin.app/app/discover→trace.id:{trace_id}
ECS 필드 매핑 현황
앱 로그 필드 (Python OTEL)
필드 타입 소스 예시 trace.idkeyword OTEL SDK 5fdc8e113b2618f6...span.idkeyword OTEL SDK 44ea44a93a45564fservice.namekeyword App 코드 auth-apiservice.versionkeyword App 코드 1.0.7log.levelkeyword App 코드 info,warning,errormessagetext App 코드 로그 메시지 Istio 로그 필드 (EnvoyFilter)
필드 타입 소스 예시 trace.idkeyword %TRACE_ID%c8fd3e757ca33968...span.idkeyword %REQ(X-B3-SPANID)%B3 헤더 또는 빈값 http.request.methodkeyword %REQ(:METHOD)%GET,POSTurl.pathkeyword %REQ(:PATH)%/api/v1/auth/refreshhttp.response.status_codeinteger %RESPONSE_CODE%200,401,500시스템 로그 필드 (Lua 자동 생성)
필드 타입 소스 예시 service.namekeyword K8s 라벨 calico-node,argocd-serverservice.environmentkeyword namespace kube-system,argocdkubernetes.namespacekeyword K8s 메타 kube-systemkubernetes.pod.namekeyword K8s 메타 calico-node-xv9c8
Trace Propagation 아키텍처
┌─────────────────────────────────────────────────────────────────────────┐ │ Trace ID Propagation │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ [Client Request] │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Istio Ingress │ ◀── trace.id 생성 (%TRACE_ID%) │ │ │ Gateway │ → ES에 access log 전송 │ │ └────────┬─────────┘ │ │ │ gRPC + B3 메타데이터 │ │ ▼ │ │ ┌──────────────────┐ │ │ │ ext-authz │ ◀── gRPC metadata에서 trace.id 추출 │ │ │ (Go gRPC) │ → ES에 auth log 전송 │ │ └────────┬─────────┘ │ │ │ 인증 결과 │ │ ▼ │ │ ┌──────────────────┐ │ │ │ App Sidecar │ ◀── B3 헤더 전파 │ │ │ (istio-proxy) │ → ES에 access log 전송 │ │ └────────┬─────────┘ │ │ │ HTTP + B3 헤더 │ │ ▼ │ │ ┌──────────────────┐ │ │ │ App (Python) │ ◀── OTEL SDK가 B3 헤더 읽음 │ │ │ + OTEL SDK │ → ES에 app log 전송 (동일 trace.id) │ │ └──────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘
트러블슈팅
Issue 1: trace.id로 검색 안됨
증상:
Kibana: trace.id:xxx → No results원인: Fluent Bit
Merge_Log_Key설정으로 필드가 중첩됨해결: Nest lift 필터 추가
[FILTER] Name nest Match kube.* Operation lift Nested_under log_processedIssue 2: ECS dot notation이 object로 변환됨
증상:
// 의도: "trace.id": "abc" // 실제: "trace": { "id": "abc" }해결:
- Index Template:
subobjects: false - Fluent Bit:
Replace_Dots Off
Issue 3: ext-authz 거부 시 trace.id 없음
증상: 401 에러에 trace.id가 없어서 추적 불가
해결: gRPC metadata에서 B3 헤더 추출if md, ok := metadata.FromIncomingContext(ctx); ok { if vals := md.Get("x-b3-traceid"); len(vals) > 0 { trace.TraceID = vals[0] } }
OpenTelemetry 커버리지 요약
OTEL이 커버하는 범위
Python APIs OTEL SDK 자동 계측 ✅ ✅ Istio Sidecar Envoy 내장 tracing ✅ ✅ Istio Gateway Envoy 내장 tracing ✅ ✅ OTEL이 커버하지 않는 범위
ext-authz (Go gRPC) SDK 미적용 gRPC metadata 수동 추출 시스템 로그 (calico 등) 지원 안함 N/A (trace 불필요)
Reference
결론
trace.id 커버리지 7.16% (주로 istio-proxy) ECS 필드명 ✅ dot notation 유지 Cross-service 검색 ✅ 단일 인덱스로 가능 ext-authz trace ✅ gRPC metadata 추출 Jaeger ↔ Kibana 연동 ✅ trace.id로 검색 Service
'이코에코(Eco²) > Observability' 카테고리의 다른 글
이코에코(Eco²) Observability #5: 인덱스 전략 및 라이프사이클 관리 (0) 2025.12.19 이코에코(Eco²) Observability #4: 분산 트레이싱 통합 (0) 2025.12.19 이코에코(Eco²) Observability #3: 도메인별 ECS 구조화 로깅 (0) 2025.12.19 이코에코(Eco²) Observability #2: 로깅 정책 수립 (0) 2025.12.19 이코에코(Eco²) Observability #1: EFK 파이프라인 구축 (0) 2025.12.19 - Jaeger: