멋사 부트캠프

[멋사 부트캠프] Day09 - 예외처리 및 로그분석(ELK)

sagecode 2025. 6. 28. 14:20

서버 개발시 오류분석, 디버깅을 할 때 콘솔에 찍힌 로그나 단순 텍스트 파일에 저장된 로그 파일을 분석하기엔 너무 가독성이 좋지 않고 어렵다.

 

  • 로그가 너무 길어서 원하는 내용을 찾기 어렵다
  • 시간대별, 기능별로 분석하기 어렵다
  • 서버가 여러 개일 경우, 로그가 분산돼 있어 추적이 어렵다

이런 문제들을 해결하기 위해 등장한 것이 로그 수집, 분석, 시각화 도구이다. 그중에서도 가장 많이 사용되는 조합이 바로 ELK스택이다.

ELK란?

Elasticsearch: 로그 데이터를 저장하고 검색하는 강력한 엔진
Logstash: 로그 데이터를 수집하고 필요한 정보를 추출하는 파이프라인 도구
Kibana: 저장된 로그를 보기 좋게 시각화해주는 도구

 

ELK 작동순서

Spring Boot 애플리케이션
   ↓ 로그파일 생성 (logback.xml에서 지정된 app.log)
Logstash
   ↓ 로그파일 수집 및 가공 (필터 처리, 예: AOP_LOG 구분)
Elasticsearch
   ↓ 정제된 로그 저장 (인덱스에 문서로 저장됨)
Kibana
   ↓ Elasticsearch에 저장된 로그를 조회, 시각화

각 구성요소의 역할

1. Logstash: 로그 수집기

  • input → 로그 파일을 읽음 (app.log)
  • filter → grok으로 패턴 추출하고, "AOP_LOG" / "OAuth2_LOG" 여부에 따라 필드 추가
  • output → Elasticsearch에 spring-logs-YYYY.MM.dd 인덱스로 로그 전송

2. Elasticsearch: 로그 저장소이자 검색엔진

  • Logstash에서 넘겨받은 로그 데이터를 JSON 형태로 저장
  • 내부적으로 샤드(Shard) 구조로 데이터를 분산 처리
  • 각 로그는 "문서(document)", 문서는 "인덱스(index)"에 저장됨

3. Kibana: 시각화 도구

  • Elasticsearch에 쿼리 보내서 로그 검색
  • 시간별, 로그타입별 필터 적용
  • 대시보드 구성해서 로그 흐름 모니터링 가능

순서를 요약해보았다. 이제 하나하나 어떤 코드가 작동하는지 알아보자.

 

LogStash

logback-spring.xml

<configuration>
    <!--    로그 파일이 저장될 경로 변수-->
    <property
            name="LOG_PATH"
            value="logs"
    />
    <!-- 파일 로그 출력 패턴: 색상 X (ELK 연동용) -->
    <property
            name="FILE_PATTERN"
            value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-3level] %logger{5} - %msg%n"
    />
    
    <appender
            name="FILE"
            class="ch.qos.logback.core.rolling.RollingFileAppender">  <!-- RollingFileAppender: 로그를 파일로 남김, 일자별로 파일 자동 분할 -->
        <file>${LOG_PATH}/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>10</maxHistory>  <!-- : 10일치까지만 파일 보관(자동 삭제) -->
        </rollingPolicy>
        <encoder>
            <Pattern>${FILE_PATTERN}</Pattern>
        </encoder>
    </appender>

<LOG_PATH 변수 정의, 로그 출력 형식 정의>

  • 실제 저장 경로: logs/app.log

예시 로그 : 2025-06-28 12:34:56.123 [main] [INFO] MyClass - 로그 메시지

 

<파일 로그 Appender 설정>

  • RollingFileAppender : 로그 파일을 하루 단위로 분할함
  • 오늘은 app.log, 내일은 app-2025-06-29.log처럼 분할 (파일 생성)
  • 최대 10일치만 보관 (10일 지나면 자동 삭제)

 

<logger
        name="org.boot.backend5project"
        level="DEBUG"
        additive="false" >
    <appender-ref ref="STDOUT"/>
</logger>

<root level="INFO">
    <appender-ref ref="ASYNC"/> <!-- 콘솔(터미널) 로그 비동기 처리 -->
    <appender-ref ref="FILE"/>  <!-- 파일 로그(ELK 연동) -->
</root>

 

<패키지별 레벨 조정, 전체 로그 전송 설정 (root)>

  • 특정 패키지에 대해 로그 레벨 DEBUG로 조정
  • 전체 로그 INFO 이상만 처리
  • 콘솔(ASYNC) + 파일(FILE) 둘 다 동시에 기록됨

logstash.conf

input {
    file {
      path => "/logs/app.log"
      start_position => "beginning"
      sincedb_path => "/dev/null"
      type => "backend3"
    }
}

input 태그 안에 어떤 로그를 읽어 올지 디렉토리 경로를 작성한다.

여러 서버(backend1, 2, 3)의 로그를 각각 따로 수집할 수도 있어서 확장 가능하다.

 

filter {
#아래 규칙에서 자동으로 키워드로 형성되어 키바나에서 확인 가능
  grok {
    match => {
      "message" => "%{TIMESTAMP_ISO8601:timestamp}
      \[%{DATA:thread}\] \[%{LOGLEVEL:level}\s*\] %{JAVACLASS:logger} - %{GREEDYDATA:log}"
    }
  }

   # 로그가 AOP 로그인지 식별
   if "AOP_LOG" in [message] {
     mutate {
       add_field => { "log_type" => "aop" }
     }
   }
   else if "OAuth2_LOG" in [message]{
     mutate {
       add_field => { "log_type" => "OAuth2" }
     }
   }

  date {
    match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"]
    timezone => "Asia/Seoul"
    target => "@timestamp"
  }
}

(1) grok - 로그 패턴 파싱

  • 로그 메시지에서 시간, 쓰레드, 레벨, 클래스명, 실제 로그 메시지를 정규식으로 추출

(2) mutate - 특정 로그 태깅

  • 로그 메시지 안에 "AOP_LOG" 또는 "OAuth2_LOG"가 포함되면, 해당 태그(log_type)를 부여

(3) date - 타임스탬프 변환

  • grok에서 추출한 timestamp 값을 Logstash의 표준 시간 필드 @timestamp로 변환
output {
   # log 전용이고 검색 엔진이랑은 상관없은 검색엔진은 logstash 안씀
   #엘라스틱서치에서 해당 이름의 인덱스가 없으면 자동 생성함
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "spring-logs-%{+YYYY.MM.dd}"
  }
  stdout { codec => rubydebug } # 디버깅용
}

파싱한 로그를 엘라스틱서치로 내보낸다.

 

ElasticSearch

Elasticsearch는 분산형 RESTful 검색 및 분석 엔진으로, JSON 기반의 구조화된 데이터를 저장하고, 초고속 검색·분석 기능을 제공해주는 시스템이다.

 

ELK에서의 역할

  • Logstash가 보낸 로그 데이터를 문서(Document) 형태로 저장
  • Kibana에서 쿼리(Query) 를 통해 해당 로그를 실시간으로 조회·분석

엘라스틱 서치는 index라는 테이블 단위로 logstash에서 적용한 단위로 로그를 저장한다.

이런식으로 localhost:9200/_cat/indices?v에 접속하게 되면 index목록이 나온다.

 

Kibana

Kibana는 Elasticsearch에 저장된 로그를 조회하고, 시각화할 수 있도록 도와주는 도구이다. 개발자가 콘솔에 찍힌 로그를 눈으로 추적하지 않아도, 원하는 로그를 검색하고 시간 흐름에 따라 시각적으로 확인할 수 있게 해준다.

 

인덱스 패턴 등록

처음 Kibana를 실행하면, 로그를 보기 위해 **Index Pattern**을 등록해야 합니다.

1. 브라우저에서 `http://localhost:5601` 접속
2. 좌측 메뉴 → Stack Management → Index Patterns
3. `spring-logs-*` 입력 후, @timestamp 필드를 시간 필드로 선택
4. Create 완료!

 

5. Kibana Index Pattern 설정

6. Discover 메뉴에서 로그 확인

좌측 필드에서 level: INFO 클릭하면 자동으로 필터가 추가됨

하게 되면 아래 스크린샷같이 뜬다.

 

 

결론은 ELK는 Spring Boot 애플리케이션에서 발생한 로그를 logback으로 파일로 남기고, 이를 Logstash가 수집 및 가공하여 Elasticsearch에 저장한 후, Kibana에서 시각화하여 개발자가 시간별, 유형별 로그를 효율적으로 분석할 수 있도록 구성한 로그 모니터링 시스템이다.