본문으로 건너뛰기

Spring Boot와 ELK를 활용한 서비스 로그 수집 및 모니터링

2025년 3월 6일에 작성되었고, 블로그를 이전하며 옮겨온 포스트입니다.
여기에서 원본을 확인할 수 있습니다.

ELK Stack

정의

ELK Stack은 Elasticsearch, Logstash, Kibana Stack의 줄임말로, 모든 시스템과 애플리케이션에서 로그를 집계, 분석하며 분석된 정보를 시각적으로 나타냄을 도와준다.

작동 방식

  1. App & Log: 어플리케이션 또는 서비스에서 생성된 로그를 Logstash 로 전송한다.
  2. Logstash: 데이터를 수집 후 변환해 Elasticsearch 로 전송한다.
  3. Elasticsearch: 수집된(전송 받은) 데이터 또는 로그를 인덱싱, 분석하고 탐색한다.
  4. Kibana: 분석 결과를 시각화한다.

Spring Boot 프로젝트 세팅

1. 의존성(logstash-logback-encoder) 추가

implementation 'net.logstash.logback:logstash-logback-encoder:7.4'

2. logback-spring.xml 파일 설정

Spring Boot에서 발생한 로그를 logstash가 수집할 수 있도록 로그를 보내주는 logback-spring.xml 설정 파일을 src/main/resources/ 위치에 생성한다.

<configuration>
    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>logstash:5000</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                            "timestamp": "%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}",
                            "level": "%level",
                            "logger": "%logger",
                            "thread": "%thread",
                            "message": "%msg",
                            "stack_trace": "%ex"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="LOGSTASH"/>
    </root>
</configuration>

3. 로그 발생을 위한 테스트 Controller 생성

kibana에서 최종적으로 로그를 확인하기 위해 로그를 발생시킬 수 있는 테스트 Controller를 생성해 준다. 단순히 로그를 발생시키기 위함이므로 간단하게 구성하였다.

// LogController.java

package com.example.demo.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping("/log")
@Slf4j
public class LogController {
    @GetMapping("/")
    public ResponseEntity<?> logTest() {
        log.info("[LogController] 로그 생성 됨");
        return ResponseEntity.status(HttpStatus.OK).body("로그 생성 됨");
    }
}

Spring Boot 프로젝트 Docker Image 생성하기

docker-compose를 이용해 한 번에 서비스들을 실행시킬 수 있도록 Docker Hub에 Spring Boot 프로젝트 Docker Image를 업로드했다.

// Dockerfile

FROM dvmarques/openjdk-17-jdk-alpine-with-timezone
EXPOSE 8080
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Kibana 사용을 위한 기본 세팅

0. 사용된 운영체제

Operation System: Ubuntu 24.04 LTS

1. docker-compose.yml 생성하기

아래와 같이 docker-compose.yml파일을 생성해 준다. 아래 파일에서 사용되는 서비스들은 다음과 같다.

  1. Elasticsearch
  2. Logstash
  3. Kibana
  4. Spring Boot 프로젝트
version: '3'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.11.1
    environment:
      - discovery.type=single-node
    ports:
      - "9200:9200"
    networks:
      - elk
    volumes:
      - esdata:/usr/share/elasticsearch/data

  logstash:
	  image: docker.elastic.co/logstash/logstash:7.12.0
	  ports:
	    - "5044:5044"
	    - "5000:5000"
	  volumes:
	    - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
	  networks:
	    - elk

  kibana:
    image: docker.elastic.co/kibana/kibana:7.11.1
    ports:
      - "5601:5601"
    networks:
      - elk
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - server.host=0.0.0.0

  spring:
    image: yunsol267/elk-stack-prac
    ports:
      - "8080:8080"
    environment:
      - ELASTICSEARCH_HOST=elasticsearch:9200
    depends_on:
      - elasticsearch
    networks:
      - elk

volumes:
  esdata:
    driver: local

networks:
  elk:
    driver: bridge

2. logstash.conf 생성하기

docker-compose.yml 과 동일한 위치에 logstash.conf 파일을 아래와 같이 생성한다.

input {
  beats {
    port => 5044
  }
  
  tcp {
    port => 5000
    codec => json_lines
  }
}

filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:thread}\] %{LOGLEVEL:loglevel} %{DATA:logger} - %{GREEDYDATA:logmessage}" }
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "spring-logs-%{+YYYY.MM.dd}"
  }
  stdout { codec => rubydebug }
}

3. Ubuntu에 Docker 설치하기

docker-compose를 사용하기 위해 아래 명령어를 이용하여 Ubuntu에 docker을 설치해 준다.

sudo snap install docker

4. Docker 이미지 올리기

아래 명령어를 이용하여 1. docker-compose.yml 생성하기 에서 세팅한 도커 이미지를 실행시킨다.

  • -d: 백그라운드로 실행
sudo docker-compose up -d

사용해보기

1. 로그 생성하기

Kibana Dashboard에서 로그를 확인하려면 먼저 로그를 생성해 주어야 한다. 로그는 초반에 Spring Boot 프로젝트에서 만든 API를 이용해 주도록 한다. 접속 주소는 아래와 같다. 필자는 5번 정도 로그를 생성해 주었다.

2. Kibana Dashboard 접속

이제 Kibana를 사용할 모든 준비가 완료되었다. Kibana 대시보드는 http://<IP>:5601/ 주소로 접속할 수 있다. 페이지에 접속하면 아래와 같은 화면이 표시된다.

왼쪽에 메뉴바를 클릭하고, Analytics - Discover 메뉴에 들어가 준다. 그러면 아래와 같은 화면이 표시되는데, Create index pattern 버튼을 클릭한다.

그러면 아래 화면과 같이 index pattern을 생성할 수 있는데 우리가 2. logstash.conf 생성하기 이 단계에서 패턴을 index => "spring-logs-%{+YYYY.MM.dd}" 이렇게 생성했기에 spring-logs-* 를 입력하고, Next step 버튼을 클릭해 준다.

그러면 아래와 같은 화면이 표시될텐데 이는 spring-logs-* 에서 * 부분에 들어가는 항목을 선택해 주는 것이다. 우리는 날짜가 표시되도록 설정했기에 @timestamp 를 클릭하고, 최종적으로 Create index pattern 버튼을 클릭해 준다.

이렇게 하고, 메뉴에서 Analytics - Discover 메뉴에 들어가면, 우리가 발생시켰던 로그들을 확인할 수 있다!

마무리

이렇게 해서 Spring Boot와 ELK를 활용한 서비스 로그 수집 및 모니터링하는 과정을 모두 끝냈다. 로그를 어떻게 수집하고 관리하는지 궁금해서 공부해본 ELK Stack이었지만, 로그 관리나 분석에 상당히 용이해 보이기 때문에 나중에 사이드 프로젝트에도 적용시켜 보고 싶다. 실제로 사이드 프로젝트에 적용하는 적용기는 다음에 기회가 된다면 글을 써 보려고 한다.