728x90
Elasticsearch — 저장 & 검색 엔진
- 모든 로그가 최종적으로 저장되는 곳.
- 검색 엔진 기반이라 대량 로그를 빠르게 조회할 수 있음
- Kibana가 시각화할 때도 결국 Elasticsearch에서 데이터를 가져감
- 핵심 역할: 로그 데이터베이스(검색 특화 DB)
Logstash — 로그 파이프라인(수집/변환/적재)
- 애플리케이션, 서버, DB, 파일 등 여러 소스에서 로그를 수집
- 수집한 로그를 필터링하거나 JSON 형태로 가공(transform) 하고 Elasticsearch로 보내줌
- ‘가공기 → 적재기’ 역할
- 핵심 역할:데이터 수집기 + 변환기
Kibana — 시각화 & 분석 UI
- Elasticsearch에 저장된 데이터를 대시보드 형태로 보여주는 UI
- 오류 추적, 서비스 분석, 로그 검색 등을 쉽게 해주는 툴
- 개발자/운영자가 직접 쓰는 부분
- Logstash: 로그를 모아서 가공해서 ES로 보냄
- Elasticsearch: 로그를 저장하고 검색함
- Kibana: 로그를 보여주고 시각화함
1. Docker Compose 설정
- docker-compose.yml 생성
- Elasticsearch·Kibana·Logstash 3개 컨테이너 구성
- Elastic 보안 기능 끔(xpack.security.enabled=false) → 로컬 테스트 목적
- Elasticsearch JVM 메모리 1GB로 고정함
- Kibana가 Elasticsearch와 연결되도록 hosts 설정
- Logstash는 pipeline 디렉토리를 마운트하도록 설정
- elk 네트워크를 bridge 타입으로 생성
2. docker-compose.yml 구성 저장함
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
container_name: elasticsearch-local
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
networks:
- elk
kibana:
image: docker.elastic.co/kibana/kibana:8.15.0
container_name: kibana-local
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch-local:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- elk
logstash:
image: docker.elastic.co/logstash/logstash:8.15.0
container_name: logstash-local
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "6000:6000"
depends_on:
- elasticsearch
networks:
- elk
networks:
elk:
driver: bridge
# 구동
docker-compose up -d


정상적으로 올라오면:
- Elasticsearch: http://localhost:9200
더보기
Elasticsearch 상태 확인:
curl http://localhost:9200
정상이라면 이런 응답:
{
"name" : "elasticsearch-local",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "...",
"tagline" : "You Know, for Search"
}
- Kibana 접속: 브라우저에서 👉 http://localhost:5601
테스트용 로그 넣기: 키바나에서 Index를 보려면 데이터를 넣어야 함
curl -X POST "localhost:9200/local-app-logs-test/_doc" \
-H 'Content-Type: application/json' \
-d '{
"level": "ERROR",
"message": "Test log from curl",
"@timestamp": "2025-12-09T10:00:00Z",
"env": "LOCAL"
}'


3. Logstash pipeline 구성함
- document/logstash/pipeline 디렉토리 생성
- input 플러그인에서 TCP 6000 포트로 JSON 로그 수신하도록 설정
- output 플러그인에서 Elasticsearch로 로그 저장
- stdout 출력을 rubydebug 포맷으로 설정하여 디버깅 편하게 함
4. Logstash 파이프라인 파일 저장
input {
tcp {
port => 6000
codec => json_lines
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch-local:9200"]
index => "local-app-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
경로: document/logstash/pipeline/logstash
5. 스프링 Boot에서 로컬 Logback 설정 사용
- application.yml에서 logback-local.xml 설정을 읽도록 지정
- 로컬 실행 시 Logstash로 로그를 전송할 수 있게 별도 profile 사용
application.yml
logging:
config: classpath:logback-local.xml
6. Logback에서 Logstash TCP Appender 구성
- 콘솔 출력용 appender 유지
- LogstashTcpSocketAppender 추가
- 127.0.0.1:6000 으로 로그 전송
- JSON 포맷으로 로그를 구성하는 provider 리스트 설정
- timestamp, level, thread, loggerName, message, MDC(rId, ctxtId 등) 포함되도록 설정
- stackTrace도 JSON 형태로 저장
7. logback-local.xml 저장
<configuration>
<!-- 기존 콘솔 로거 유지 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss} [rId=%-32X{rId}][ctxtId=%-32X{ctxtId}] %-5.40thread
%highlight(%-5level){FATAL=red blink, ERROR=red, WARN=yellow, INFO=green, DEBUG=blue, TRACE=cyan}
%cyan(%-40.40logger{36}.%method:%line){magenta} %msg%n
</pattern>
</encoder>
</appender>
<!-- Logstash로 전달 (로컬 전용) -->
<appender name="LOCAL_ELASTIC" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>127.0.0.1:6000</destination>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp fieldName="@timestamp"/>
<logLevel fieldName="log.level"/>
<threadName fieldName="thread"/>
<loggerName fieldName="logger"/>
<message fieldName="message"/>
<pattern>
<pattern>{"env":"LOCAL"}</pattern>
</pattern>
<mdc/>
<stackTrace fieldName="error.stacktrace"/>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="LOCAL_ELASTIC"/>
</root>
</configuration>
8. 로그가 실제로 Elasticsearch에 저장됨
- Logstash가 TCP로 받은 JSON 로그를 Elastic 인덱스(local-app-logs-YYYY.MM.dd)에 저장함
- Kibana Discover에서 수집된 로그 확인 가능함
- MDC에 포함된 값(rId, ctxtId 등)도 그대로 JSON 필드로 표시됨
실제 저장된 로그 예시
docker logs -f logstash-local
"logger_name" => "jdbc.audit",
"requestURI" => "POST /api/user/list",
"rId" => "a473569d21de45e8b49df490d89adf23",
"uId" => "39ABCD5DA688AC31",
"@version" => "1",
"message" => "9. Connection.getMetaData() returned com.mysql.cj.jdbc.DatabaseMetaDataUsingInfoSchema@21ff9f94",
"env" => "LOCAL",
"ctxtId" => "a473569d21de45e8b49df490d89adf23",
"cId" => "53FC2846C7F5BAC9",
"@timestamp" => 2025-12-08T06:36:16.234Z,
"level" => "INFO",
"thread_name" => "http-nio-8080-exec-10"
}
{
"logger_name" => "{}....controller",
"requestURI" => "POST /api/user/list",
"rId" => "a473569d21de45e8b49df490d89adf23",
"uId" => "39ABCD5DA688AC31",
"@version" => "1",
"message" => "{\"list\":[...],\"result\":\"20000\"}",
"env" => "LOCAL",
"ctxtId" => "a473569d21de45e8b49df490d89adf23",
"cId" => "53FC2846C7F5BAC9",
"@timestamp" => 2025-12-08T06:36:16.277Z,
"level" => "DEBUG",
"thread_name" => "http-nio-8080-exec-10"
}


728x90
