Post

ELK Stack으로 로그 수집, 시각화 시스템 구축하기

ELK Stack으로 로그 수집, 시각화 시스템 구축하기

로그 수집의 이유


로그의 중요성

컴퓨터 과학에서 로그(log)는 컴퓨터나 장비의 운영 정보를 시간 순서대로 기록한 정보를 말한다.

현대의 소프트웨어는 함수 호출, 오류, HTTP 요청, 데이터베이스 트랜잭션 등 다양한 데이터를 로그로 기록하게 된다.

그렇다면 로그가 중요한 이유는 무엇일까?

  • 운영하다가 장애가 발생했는지 로그를 통해 확인
  • 장애 발생시 문제 해결을 위한 힌트 제공
  • CS(고객 문의)가 들어와 서비스에서 처리된 데이터 확인
  • 개인정보를 다루는 서비스나 금융 관련 서비스에서는 법적으로 로그 기록을 강제

로그가 중요한 이유는 이처럼 장애 상황에 대응할 수 있는 강력한 힌트를 주고, 고객들의 문의 상황에 빠른 대응을 할 수 있도록 정보를 주기 때문이다.

Image

로그 수집의 중요성

만약 아래와 같이 단일 서버를 운영한다면 장애 상황이 발생해 로그를 확인해야한다고 할 때 바로 직접 서버로 접속해 로그 파일을 추적해 볼 수 있을 것이다.

단일 서버일 때에는 이러한 과정이 별로 불편하다고 느끼지 않을 수 있다.

Image

그렇지만 아래와 같이 분산 서버를 구축해 서버가 3대로 늘었다고 가정하면, 같은 방식으로 로그 파일을 추적하는 데에는 3배 이상의 시간이 소요될 것이다.

여기서 서버의 개수가 더 늘어난다면 이러한 방식으로 로그 파일을 추적하는 것은 불가능에 가까워질 것이다.

Image

이 때 각 서버에서의 로그들을 적절하게 수집하고 가공하여서, 모두 모아 시각화해서 제공한다면 편리하게 로그를 조회하고 문제 상황에 빠르게 대응할 수 있을 것이다.

Image

ELK Stack으로 로그 수집, 시각화 시스템 구축하기


ELK Stack

Image

ELK는 이처럼 세가지 기술로 구성된다.

  • Elasticsearch (로그 저장 및 검색)
  • Logstash (로그 수집)
  • Kibana (로그 시각화)

이 세가지 기술은 각자의 독립된 기술이기 때문에 필요에 따라 다른 용도로도 사용이 가능하다.

그렇지만 로그 수집에서는 이렇게 세가지 기술이 합쳐졌을 때, 호환이 좋고 용이하기 때문에 같이 구축하는 것이 일반적이고 세가지 기술을 같이 쓰기 때문에 Stack 이라고 부른다.

또한 ELK는 Elastic이라는 회사에서 제공하는 오픈소스이기 때문에 누구나 무료로 이용이 가능하다.

Logback

ELK 스택을 통해서 로깅 시스템을 구축하기 전에 Logback을 통해서 로그의 형식을 지정해주고 파일로 남길 수 있도록 하였다.

Logback은 로깅 라이브러리로 Slf4j(Simple Logging Façade for Java)의 구현체이다.

Image

기본적으로 resources폴더에 logback.xml 파일을 두는 것을 통해서 적용이 가능하고,

profiles에 따라서 logback-{profiles}.xml로 여러 파일을 두고 각 환경에 맞게 사용하는 것이 관례이다.

여기서는 logback.xml 한가지 파일만 두었다.

logback.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<configuration>
    <property name="LOG_FILE" value="application.log"/>

    <!-- 콘솔 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 파일 출력 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>application.%d{yyyy-MM-dd_HH-mm}.log.gz</fileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- Logger 설정 -->
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

logback.xml은 다음과 같이 작성해주었다. 콘솔로 출력하는 방식과, 파일로 출력하는 방식을 지정해주었다.

각 태그들의 역할을 간단하게 본다면 다음과 같다.

  • <configuration>: 최상단 태그
  • <property>: 재사용 가능한 전역 변수 설정
  • <appender>: 로그 출력 방식 정의

Appender들의 역할은 다음과 같다.

  • ConsoleAppender: 콘솔에서 로그 출력
  • RollingFileAppender: 로그 파일을 자동으로 롤링하여 저장

RollingFileAppender를 통해서 매분 기록되는 로그들이 파일로 저장되고, 최대 5개까지 저장되는 것을 확인할 수 있다. 여기서는 눈으로 로그 저장을 확인하고자 분마다 기록하였지만 보통은 하루마다 파일을 만드는 것이 관례라고 한다.

Image

Logstash & Elasticsearch

다음으로는 본격적으로 Logstash와 Elasticsearch를 구축해보았다.

먼저 Logstash와 Elasticsearch의 실행에는 도커를 사용하였다.

Elasticsearch 실행 command

1
docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e "xpack.security.http.ssl.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:8.10.0

Logstash 실행 command

1
docker run -d --name logstash -p 5044:5044 -p 9600:9600 -v ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf docker.elastic.co/logstash/logstash:8.10.0

또한 logstash의 의존성을 추가해주고 logback.xml에 Logstash Appender를 추가해주었다.

logback.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<configuration>
    <property name="LOG_FILE" value="application.log"/>

    <!-- Logstash로 전송할 Appender -->
    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>localhost:5044</destination>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
    </appender>

    <!-- 콘솔 출력 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 파일 출력 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>application.%d{yyyy-MM-dd_HH-mm}.log.gz</fileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- Logger 설정 -->
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
        <appender-ref ref="LOGSTASH" />
    </root>
</configuration>

LogstashTcpSocketAppender를 통해서 로그들이 Logstash로 전송되게 된다.

다음으로는 logstash.conf 파일을 프로젝트의 root 디렉토리에 추가해주었다.

이를 통해서 logstash와 elasticsearch가 서로 연동이 가능하도록 설정해주었다.

logstash.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
input {
    tcp {
        port => 5044
        codec => json
    }
}

output {
    elasticsearch {
        hosts => ["<http://elasticsearch:9200>"]
        index => "application-logs-%{+YYYY.MM.dd}"
    }
}

또한 logstash와 elasticsearch가 문제없이 통신할 수 있도록 도커를 통해서 네트워크를 만들어주었다.

도커 컨테이너간 통신을 위한 네트워크 생성

1
2
3
docker network create elastic-network
docker network connect elastic-network elasticsearch
docker network connect elastic-network logstash

Elasticsearch Multi-head라는 크롬 확장프로그램을 통해서 Elasticsearch에 수집된 로그들을 확인할 수 있었다. 또한 URL에 직접 쿼리를 작성하여 로그를 확인할 수도 있다.

Image

Image

Kibana

마지막으로 Kibana를 구축해주었다. Kibana 또한 도커를 통해 실행하였다.

kibana 실행 도커 command

1
docker run -d --name kibana --network elastic-network -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://elasticsearch:9200" kibana:8.10.1

실행 후에 http://localhost:5601로 접속하면 Kibana의 화면을 확인할 수 있다.

Kibana에서 데이터를 조회할 수 있는 뷰를 만들어주면 아래와 같이 로그를 확인할 수 있다.

Image

또한 아래처럼 KQL(Kibana Query Language)을 활용해 쿼리를 작성해 원하는 데이터만 선별하여 조회할 수도 있다.

Image

그리고 필요한 경우 아래와 같이 대시보드를 구성해 정보들을 모니터링 가능하도록 구축할 수도 있다.

Image

This post is licensed under CC BY 4.0 by the author.