이제껏 E와 K를 구현해진 상태에서 뒤늦게 로그를 수집하겠다고 Logstash를 적용해야하는 상황이 펼쳐졌다...
로그스태시 환경 구현하는 방법을 설명보려고 한다.
일단, 기본 배경에는 도커로 elasticsearch와 kibana가 깔려있는 상태
여기서 도커에 logstash를 추가했다.
보면 es를 3개의 노드로, 로그스태시를 추가한 코드로 변경이 되었을 알수있다.
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.3
container_name: es01
environment:
- node.name=es01
- cluster.name=search-cluster
- discovery.seed_hosts=es02,es03
# - discovery.type=single-node
- cluster.initial_master_nodes=es01,es02,es03
- xpack.security.enabled=false
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
ports:
- "9200:9200" # https
- "9300:9300" #tcp
networks:
- es-bridge
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.3
container_name: es02
environment:
- node.name=es02
- cluster.name=search-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- xpack.security.enabled=false
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
ports:
- "9201:9200" # https
- "9301:9300" #tcp
networks:
- es-bridge
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.3
container_name: es03
environment:
- node.name=es03
- cluster.name=search-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- xpack.security.enabled=false
- xpack.security.http.ssl.enabled=false
- xpack.security.transport.ssl.enabled=false
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
ports:
- "9202:9200" # https
- "9302:9300" #tcp
networks:
- es-bridge
logstash:
image: docker.elastic.co/logstash/logstash:7.17.3
container_name: logstash
environment:
- xpack.monitoring.enabled=false
ports:
- 5000:5000
- 9600:9600
volumes:
- ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf # local file mapping
depends_on:
- es01
- es02
- es03
networks:
- es-bridge
kibana:
image: docker.elastic.co/kibana/kibana:7.17.3
container_name: kibana
environment:
SERVER_NAME: kibana
ELASTICSEARCH_HOSTS: http://es01:9200
ports:
- 5601:5601
# Elasticsearch Start Dependency
depends_on:
- es01
networks:
- es-bridge
networks:
es-bridge:
driver: bridge
logstash에 관련된 설정은 대부분 logstash.conf 파일에서 수정을 한다.
수정하는 방법은 일단 내가 알기로는 두가지정도가 있는데,
하나는 도커에서 바로 명령어로 logstash.conf 파일을 열어서 수정할 수 있다.
다른방법으로는 docker에서 세팅을 변경해두는 방법이 있다.<<이 편을 추천함
매번 도커로 여는것 귀찮아서
logstash:
image: docker.elastic.co/logstash/logstash:7.17.3
container_name: logstash
environment:
- xpack.monitoring.enabled=false
ports:
- 5000:5000
- 9600:9600
volumes:
- ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf # local file mapping
depends_on:
- es01
- es02
- es03
networks:
- es-bridge
이렇게 volumes에서 지정해줬다.
프로젝트 폴더안에 pipeline 따로 지정해줬다.
input {
tcp {
port => 5000
codec => json
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:loglevel} %{GREEDYDATA:message}" }
}
date {
match => [ "timestamp", "ISO8601" ]
}
# 이벤트별 태그 추가
if [message] =~ "ReservationEvent" {
mutate { add_tag => ["reservation_event"] }
}
if [message] =~ "PaymentEvent" {
mutate { add_tag => ["payment_event"] }
}
if [message] =~ "CouponEvent" {
mutate { add_tag => ["coupon_event"] }
}
# SQL 관련 테이블 이름으로 쿼리 태그 추가
if [logger_name] == "org.hibernate.SQL" {
if [message] =~ /select/ {
drop {}
}
if [message] =~ /(reservations|reserved_seats|rounds)/ {
mutate { add_tag => ["reservation_query"] }
} else if [message] =~ /payments/ {
mutate { add_tag => ["payment_query"] }
} else if [message] =~ /coupon/ {
mutate { add_tag => ["coupon_query"] }
}
}
}
output {
# 전체 이벤트 로그 전송
if "reservation_event" in [tags] or "payment_event" in [tags] or "coupon_event" in [tags]
or "reservation_query" in [tags] or "payment_query" in [tags] or "coupon_query" in [tags] {
elasticsearch {
hosts => ["http://es01:9200", "http://es02:9200", "http://es03:9200"]
index => "logstash-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
# Reservation 관련 이벤트와 쿼리를 Elasticsearch로 전송
if "reservation_event" in [tags] or "reservation_query" in [tags] {
elasticsearch {
hosts => ["http://es01:9200", "http://es02:9200", "http://es03:9200"]
index => "reservation-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
# Payment 관련 이벤트와 쿼리를 Elasticsearch로 전송
if "payment_event" in [tags] or "payment_query" in [tags] {
elasticsearch {
hosts => ["http://es01:9200", "http://es02:9200", "http://es03:9200"]
index => "payment-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
# Coupon 관련 이벤트와 쿼리를 Elasticsearch로 전송
if "coupon_event" in [tags] or "coupon_query" in [tags] {
elasticsearch {
hosts => ["http://es01:9200", "http://es02:9200", "http://es03:9200"]
index => "coupon-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
}
logstash.conf 파일내용이다.
log수집은 예매, 결제, 쿠폰 세가지 관련해서 수집하기로 결정했다.
logback파일은 Spring Boot에서 애플리케이션 로깅을 설정하는 데 사용되는 Logback의 설정 파일이다. 애플리케이션에서 발생하는 로그 메시지를 기록하고 저장하거나 출력하는 역할을 한다.
[역할]
로그 레벨 설정
로그를 어떤 수준(레벨)에서 기록할지 설정한다.
로그 레벨: TRACE > DEBUG > INFO > WARN > ERROR
로그 출력 대상 지정 (Appender 설정)
로그를 파일, 콘솔, 데이터베이스, 또는 외부 시스템(예: Elasticsearch)에 출력할 수 있다.
Appender를 사용해 로그를 어디로 출력할지 정의한다.
로그 포맷 지정
로그 메시지의 출력 형식을 정의한다.
%d: 날짜/시간
%level: 로그 레벨
%logger: 클래스 이름
%msg: 로그 메시지
%n: 줄바꿈
로그 필터링
특정 조건에 따라 로그를 필터링할 수 있다.
환경별 로그 설정
Spring Boot에서 logback-spring.xml은 프로파일(spring.profiles.active)을 지원한다.
<springProfile name="dev">
<logger name="com.example" level="DEBUG"/>
</springProfile>
<springProfile name="prod">
<logger name="com.example" level="INFO"/>
</springProfile>
로그 압축 및 백업
로그 파일의 크기가 커지면 자동으로 백업하고 새 파일을 생성할 수 있다.
Spring Boot와의 통합
logback-spring.xml 파일은 Spring Boot가 로깅 설정을 초기화할 때 사용된다.
application.properties나 application.yml에 정의된 Spring Boot 로깅 설정과도 연동됩니다.
예: logging.level 속성을 통해 로그 레벨 제어 가능.
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<property resource="application.properties"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 로컬 파일에 로그 저장 설정 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern> ${LOGSTASH_FILE_PATH} </fileNamePattern>
<maxHistory>14</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n%xThrowable{5}</pattern>
</encoder>
</appender>
<!-- logstash setting -->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination> ${LOGSTASH_DESTINATION} </destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<!-- 예약 관련 로그를 Logstash로 전송 -->
<!-- additivity를 false로 하면 해당 name에 해당하는 패키지의 로그가 root로 전파되지 않음. 즉, 콘솔에 안나옴 -->
<!-- false로 해놓고 콘솔에도 출력하고 싶으면 appender-ref ref="CONSOLE" 추가해주면 됨 -->
<logger name="com.sparta.projectblue.aop.LogstashAspect" level="DEBUG">
<appender-ref ref="LOGSTASH" />
<appender-ref ref="CONSOLE" />
</logger>
<logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
<appender-ref ref="LOGSTASH" />
</logger>
<!-- 전체 애플리케이션 로깅 설정 -->
<root level="INFO">
<appender-ref ref="CONSOLE" /> <!-- INFO레벨 이상 로그를 CONSOLE에 출력 -->
<appender-ref ref="FILE" /> <!-- INFO레벨 이상 로그를 File에 기록 -->
</root>
</configuration>