로그 파일 남기기

개발을 하면서 늘 로그도 편하게 확인할 수 있으면 좋겠다는 생각을 하였다.

하지만 어떻게 하는지 몰라서 그냥 IDE 터미널 로그만 보았었는데

최근 인프라 관련 편의성 설정들을 해보면서 로그도 어떻게 파일로 따로 저장할 수 있을거란 생각이 들었다.

이번 글에서는 스프링부트 애플리케이션의 로그를 저장하는 방법을 정리해두려 한다.


써보기

사실 로그는 거의 모든 애플리케이션에서 남기는거라 스프링에서 기본 로깅 라이브러리를 제공한다.

스프링부트에서 로깅을 할 때 쓰는 @Slf4j 는 다들 한번씩 써본 애노테이션일거라 생각한다.

우리가 그동안 쓰던 Slf4j는 인터페이스이고, 구현체로 Logback, Log4j 등이 있다.

이번 글에서 사용할 Logback 라이브러리는 스프링부트의 기본 로깅 라이브러리이므로 따로 의존성을 추가할 필요는 없다.

(Log4j는 따로 추가해야한다는것 같기는 하다.)

순서는 아래와 같다.

  1. logback-spring.xml 파일 작성
  2. 결과 확인

1. logback-spring.xml 파일 작성

logback 라이브러리로 로그 파일을 남기려면 아래 두 가지 방법 중 하나로 설정을 추가 해줘야한다.

  • yml 파일 설정
  • xml 파일 설정

xml 파일은 몬가 구닥다리 느낌이 나서 최대한 yml 파일로 해보고 싶었지만 세세한 설정은 xml 파일로 하는게 나은듯하다.

yml 파일로 설정하려면 yml 파일이 길어지는것 같고 길이도 비슷한것 같아서 xml 파일로 설정하였다.

logback에서 읽는 xml 설정 파일의 기본 값은 logback-spirng.xml 인데 따로 추가 설정을 해주면 파일명을 변경할 수 있다.

로그는 기본적으로 아래와 같은 형식으로 출력하고 저장한다.

[날짜] [쓰레드 이름] [로그 레벨] [로그 발생 지점] [로그 메시지]
ex) 2024-06-18 13:24:59 [http-nio-8080-exec-9] ERROR cohttp://m.example.dream.TestController - [error] hi2 error

logback-spring.xml

<configuration>
    <!-- 콘솔창(IDE 터미널 혹은 CLI 등)에 띄울 로그 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 모든 로그 저장용 파일 설정 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 로그 파일명 -->
        <file>logs/application.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 로그 파일을 일별로 롤오버 -->
            <fileNamePattern>logs/application.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 로그를 30일간 저장하고 그 이상은 덮어씌움 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- error 로그 저장용 파일 설정 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- error 로그 파일명 -->
        <file>logs/error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 로그 파일을 일별로 롤오버 -->
            <fileNamePattern>logs/error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 로그를 30일간 저장하고 그 이상은 덮어씌움 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 루트 로거 - info 레벨 이상의 로그 저장 -->
    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
</configuration>

 

<rollPolicy/> 에서는 롤링 정책에 따라 롤 오버 시의 로그 파일 이름을 지정한다.

롤 오버 시 logs/error.2024-06-18.log 이런 식으로 저장한다.

본인은 모든 로그를 저장하는 파일과 에러 로그를 저장하는 파일을 따로 두고 싶었다.

그래서 모든 로그는 application.log에, 에러 로그는 error.log에 저장하도록 설정하였다.


2. 결과 확인

애플리케이션을 실행하면 아래 사진처럼 logs 폴더를 만들고 그 아래에 로그 파일을 생성한다.

2-1. 모든 로그

원하는대로 INFO 레벨 이상의 로그를 남긴다.

2-2. 에러 로그

원하는대로 ERROR 로그만 남긴다.


EC2 에서 jar 파일로 배포할때는?

로컬에서 IDE로 실행할 때는 프로젝트 루트 디렉토리에 logs 폴더를 만들고 그 아래에 저장되었다.

이렇게 설정해두면 EC2에서 jar 파일로 빌드하면 로그 파일이 어디에 생성될까?

 

궁금해서 실험해보았더니 아래처럼 jar 파일이 있는 디렉토리에 logs 폴더가 생성되어 있다.

기본적으로 jar 파일로 실행할때는 jar 파일이 있는 디렉토리가 루트 디렉토리라고 생각해도 될것 같다.

 

Alert rules 설정

이전 글에서는 디스코드 웹 훅을 만들고 그라파나와 연동을 해보았다.

이번 글에서는 그라파나에서 Alert rules에 장애 조건을 설정하고,

장애 발생 시 연동한 디스코드로 경고 메시지를 보내는 설정을 해볼것이다.


구현하기

이번 글에서는 간단히 특정 상황 발생 시 디스코드로 경고 메시지를 발송하는 정도로 구현할 것이다.

기본적으로 그라파나는 프로메테우스 서버에서 받은 데이터를 이용하므로 프로메테우스 서버는 항상 켜져있어야 한다.

순서는 아래와 같다.

  1. 그라파나의 Alert rules 설정
  2. 결과 확인

1. 그라파나의 Alert rules 설정

다음은 그라파나에서 경고 메시지를 보낼 조건을 설정한다.

우리의 그라파나 서버는 프로메테우스에서 받은 데이터를 토대로 하므로 애플리케이션 상태에 따른 조건을 설정할 수 있다.

프로메테우스 설정을 원하는대로 설정하여 여러 애플리케이션 서버나 DB 서버의 알림 설정을 할 수 있다.

본인은 prometheus.yml 파일을 간단히 아래처럼 설정하였다.

# prometheus.yml
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

# Here it's Prometheus itself.
scrape_configs:
  - job_name: "spring-actuator"
    metrics_path: '/actuator/prometheus'
    scrape_interval: 15s
    static_configs:
      - targets: [ 'localhost:8080' ]

 

Alerting 탭에서 Alert rules 페이지로 이동하여 새로운 규칙을 추가한다.

1-1. 규칙 이름

규칙 이름을 설정한다.

1-2. 경고 메시지 발송 조건 설정

경고 메시지 발송 조건을 설정한다.

  • 최상단의 Query 측에서 프로메테우스(혹은 다른 DataSource)에서 받은 데이터로 쿼리를 작성할 수 있다.
  • 아래쪽 Expressions로 Query 결과를 이용한 표현식을 통해 조건을 설정할 수 있다.

필요하다면 Query, Expressions를 추가할 수도 있다.

본인은 Query 결과를 이용하여 Expressions에서 조건을 설정해보았다.

 

아래 사진의 promQL은 내려가있는 인스턴스가 있는지 확인하는 쿼리이다.

여기서 up은 인스턴스의 활성화 여부이며, 0은 비활성화 상태이고 1은 활성화된 상태임을 뜻한다.

count는 괄호 안의 조건에 맞는 결과의 갯수를 반환한다.

count(up == 0)에서 비활성화 된 인스턴스가 없으면 no data를 반환하므로 OR vector(0) 을 추가하여 0을 반환하도록 한다.

쿼리 값(A 값)이 0보다 크면 경고 메시지를 발송하도록 설정하였다.

1-3. 서비스 상태 확인 간격 및 메시지 발송 시간 설정

Evaluation behavior은 서비스의 상태 확인에 관련된 세부 설정이다.

여기서 서비스 상태를 얼마 간격으로 다시 확인하는지, 장애 발견 후 얼마 뒤에 메시지를 발송할 지 설정한다.

본인은 아래처럼 설정하였다.

ㄴFolder

디렉토리를 설정할 수 있다.

본인은 rules 라는 디렉토리를 만들었다.

 

ㄴEvaluation group

Evaluation group에서 해당 그룹은 얼마 간격으로 서비스 상태를 다시 확인하는지 설정할 수 있다.

본인은 테스트의 용이성을 위해 아래처럼 10초 간격으로 상태를 다시 확인하는 그룹을 만들고 설정하였다.

ㄴPending peorid

Pending peorid에서 장애 발생 후 얼마 뒤에 메시지를 보낼지 설정한다.

이 또한 테스트 용이성을 위해 10초 간격으로 설정하였다.

1-4. 장애 발생 시 메시지를 전송할 경로 설정

연동한 디스코드 웹 훅 경로로 메시지를 보내도록 Contact point를 지정한다.

1-5. 경고 메시지 내용 설정

아래처럼 경고 메시지 내용을 설정할 수 있다.

Add custom annotation 으로 원하는 내용을 추가할 수도 있다.

본인은 job 이름과 스프링부트 애플리케이션 상태를 확인할 수 있는 패널 경로를 넣어주었다.

 

여기까지 설정 했으면 우상단의 저장 버튼을 누르면 Alert rule이 추가되고, 아래처럼 추가된 Alert rule을 확인할 수 있다.


2. 결과 확인

알림 설정이 제대로 동작하는지 확인해보기 위해 애플리케이션을 종료해보았다.

아래처럼 디스코드로 설정한 경고 메시지가 잘 전달됨을 확인할 수 있다.

 

참고자료

 

[과제] prometheus와 grafana를 이용한 MySQL 모니터링 구축

prometheus와 grafana를 이용한 DB 모니터링 구축하기서버 1: DB 서버DB 설치프로메테우스 exporter 설치 (node exporter, db exporter)서버 2: 모니터링용 서버프로메테우스 설치그라파나 설치서버 1에는 2개 이상

velog.io

 

Grafana Alert 적용하기

Grafana를 프로젝트에 적용하고 모니터링을 완성한 후 장애가 발생했을 때 email로 받아보면 좋겠다는 생각을 하게 되었습니다. Grafana Alert 기능을 사용하면 장애 발생 시 email로 받아볼 수 있음을

velog.io

 

서비스 장애 알림

스프링부트 액추에이터, 프로메테우스, 그라파나를 이용하여 메트릭을 수집 및 시각화하였다.

이렇게 메트릭을 수집하면 비즈니스적인 인사이트를 얻을 수도 있지만, 특정 메트릭의 이상 수치 또한 파악할 수 있다.

만약, 이상 수치 또는 비정상적인 응답 값을 보일 때 경고 메시지를 보내도록 알림 설정을 하면 좀 더 빠르게 대처할 수 있을 것이다.

 

경고 메시지를 전송하도록 설정할 수 있는 방법은 Alert manager, 그라파나 등 여러가지가 있다.

이 중 그라파나가 제공하는 알림 기능을 이용해 디스코드로 경고 메시지를 보내도록 설정해보려 한다.

사실 프로메테우스의 Alert manager로 알림 설정을 해보려 했지만 실패했다.

그 대안으로 선택한게 그라파나이고, 이번 글에서는 디스코드 웹 훅을 만들고 그라파나와 연동을 해볼것이다.


사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • Spring Boot Actuator, Prometheus, Grafana, Discord

구현하기

순서는 아래와 같다.

  1. 디스코드 웹 훅 생성
  2. 그라파나와 디스코드 연동
  3. 디스코드 연동 확인

1. 디스코드 웹 훅 생성

디스코드와 연동하려면 디스코드의 웹 훅을 만들어둬야 한다.

웹 훅을 만들려면 디스코드 서버 권한이 있어야 하기 때문에 본인은 연습용으로 디스코드 서버를 하나 만들었다.

1-1. 채널 설정창으로 이동

권한이 있는 상태에서 아래처럼 알람을 설정하고자 하는 채널의 톱니 모양 버튼을 누른다.

1-2. 웹 후크 만들기

채널 설정 창에서 연동 탭으로 이동하면 웹 후크 만들기 버튼이 보인다.

1-3. 웹 후크 URL 복사

만들기 버튼으로 들어가면 자동으로 해당 채널에 웹 훅을 생성해준다.

이제 여기서 복사한 웹 후크 URL를 그라파나와 연동한다.

 


2. 그라파나와 디스코드 연동

1에서 만든 디스코드 웹 훅을 그라파나와 연동할것이다.

2-1. Contact point 추가 페이지로 이동

그라파나의 기본 포트인 localhost:3000으로 접속하고 Alerting 탭에서 Contact point 페이지로 이동하면 아래와 같다.

여기서 Add contact point 버튼을 눌러서 Contact point 추가 페이지로 이동한다.

2-2. 새로운 Contact point 추가

Contact point 이름을 설정해주고, Integration에서 디스코드를 선택한다.

Webhook URL 에 1-3에서 복사한 웹 훅 URL을 넣어준다.

바로 저장을 해도 되지만 Test를 눌러서 원하는대로 연동이 되는지 확인할 수도 있다.


3. 디스코드 연동 확인

3-1. 테스트 연동 메시지 확인

연동이 되었다면 테스트를 눌렀을 때 아래처럼 메시지가 잘 온다

3-2. Contact point 등록 확인

저장 후 Contact points 페이지로 이동하면 우리가 추가한 디스코드 웹 훅이 등록되었음을 확인할 수 있다.

 

문제 발생

Spring Rest Docs + Swagger를 써보려고 하였다.

어느정도 설정이 다 끝나서 기분 좋게 마무리 하려고 배포 환경에서 실행하는것 처럼 jar 파일로 실행해보았다.

하지만 jar 파일로 빌드 후 java -jar 명령어로 실행하니 아래처럼 Swagger UI에서 openapi3.yaml을 읽지 못하였다.

분명 IDE에서는 몇번을 해봐도 잘 되는데 jar 파일로 실행해보면 openapi3.yaml 파일을 읽지 못하는 현상이 발생하였다.


문제 해결

jar 파일로 패키징 시 static 파일을 jar 파일에 추가해주지 않아서 발생한 문제였다.

jar 파일로 패키징하면 static 경로의 파일들은 jar 파일 내의 /BOOT-INF/classes/static 경로에서 읽는다.

IDE로 실행할 때는 static 파일을 읽을 수 있었지만, jar 파일로 패키징 할 때 openapi3.yaml 파일을 넣어준 적이 없다.

 

그래서 아래처럼 jar 파일을 만드는 단계인 bootJar 단계에서 openapi3.yaml 파일을 함께 패키징 하도록 설정하였다.

또한 openapi3.yaml 파일이 생성되는 단계인 copyOasToSwagger 다음에 실행되게 하였다.

// build.gradle.kts
tasks {
    bootJar {
        dependsOn("copyOasToSwagger")
        from("build/api-spec") {
            into ("BOOT-INF/classes/static/swagger-ui")
        }
    }
}

 

또한 swagger-initializer.js 의 url 경로를 아래처럼 수정해주었다.

... 생략
window.ui = SwaggerUIBundle({
  url: "/swagger-ui/openapi3.yaml", 
  dom_id: '#swagger-ui',
... 생략

 

task 실행 목록을 보면 원하는 순서대로 동작함을 알 수 있다.

 

Swagger UI 도 잘 동작한다.

그라파나로 애플리케이션 상태 확인

이전 글에서 로컬에 프로메테우스 및 그라파나를 설치해보고 적용까지 해보았다.

공유 대시보드 중에는 스프링부트 애플리케이션 상태를 확인할 수 있는 대시보드가 있다.

임의로 몇 가지 장애 상황을 만들어보고 이 대시보드로 애플리케이션 상태를 확인해보았다.

장애 상황은 아래와 같이 설정했다.

  1. JVM 메모리 고갈
  2. 커넥션 풀 고갈
  3. error 로그 급증

사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • Spring Boot Actuator, Prometheus, Grafana

1. memory 고갈

의도적으로 List에 문자열을 채워 애플리케이션의 힙 메모리를 가득 채워보았다.

예시 코드는 아래와 같다.

해당 엔드포인트를 여러번 호출하면서 그래프 추이를 살펴보았다.

TrafficController

private List<String> list = new ArrayList<>();

@GetMapping("/jvm")
public String jvm() {
    log.info("[jvm]");
    for (int i = 0; i < 1000000; i++) {
        list.add("hi" + i);
    }
    return "jvm success";
}

 

로컬에서 한거라 메모리를 다 채우기 힘들어서 도중에 멈췄지만 아래와 같이 메모리 사용량을 그래프로 확인할 수 있다.


2. Connection pool 고갈

커넥션 풀 고갈을 위해 의도적으로 커넥션을 열고 close() 해주지 않았다.

예시 코드는 아래와 같다.

해당 엔드포인트를 여러번 호출하면서 그래프 추이를 살펴보았다.

TrafficController

@Autowired
DataSource dataSource;

@GetMapping("/jdbc")
public String jdbc() throws SQLException {
    log.info("jdbc");
    Connection conn = dataSource.getConnection();
    // conn.close(); // 커넥션을 닫지 않아본다.
    return "ok";
}

2-1. 정상 상태

Hikari CP 커넥션 풀 기본 설정인 10개 중 8개를 사용해보니 아래와 같은 그래프를 확인할 수 있었다.

2-2. 커넥션 풀 고갈

커넥션 풀을 10개를 다 쓰고 추가로 커넥션 풀이 필요한 요청을 하면 그 요청은 이전 커넥션 풀이 반환될 때 까지 대기상태가 된다.

일정 시간 대기하다가 여전히 사용 가능한 커넥션 풀이 없다면 그 요청은 Timeout이 된다.

요청이 Timeout이 되어 반려되면 아래와 같이 Connection Timeout Count가 올라간다.


3. error 로그 급증

에러 로그를 급증시켜보았다.

예시 코드는 아래와 같다.

해당 엔드포인트를 여러번 호출하면서 그래프 추이를 살펴보았다.

TrafficController

@GetMapping("/error-log")
public String errorLog() {
    log.error("error log");
    return "error";
}

 

아래처럼 에러로그가 증가하는 그래프를 확인할 수 있었다.

 

Grafana

그라파나는 수집한 메트릭을 시각화해주는 오픈소스 라이브러리이다.

이전 글에서 스프링부트 액추에이터가 제공하는 메트릭을 프로메테우스로 수집하고 각종 연산을 할 수 있었다.

프로메테우스에서도 간단한 시각화를 지원하지만 여러 지표들을 시각화하기에는 불편함이 많다.

그라파나는 데이터 시각화에 초점을 둔 라이브러리라고 할 수 있다.

 

아래 사진은 스프링 액추에이터, 프로메테우스, 그라파나를 이용한 모니터링 과정의 대략적인 흐름이다.

액추에이터가 메트릭을 제공하고 프로메테우스는 마이크로미터 구현체가 변환한 데이터를 수집하고 그라파나로 시각화한다.


사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • Spring Boot Actuator, Prometheus, Grafana

써보기

프로메테우스를 설치 과정은 이전 글을 참고한다.

이번 글에서는 프로메테우스 서버까지 띄운 상태라고 생각하고 그라파나를 사용해볼 것이다.

보안 설정도 해야하겠지만 우선은 써보는데에 목적을 갖고 가장 간단한 방식으로 구현하려 한다.

순서는 아래와 같다.

  1. 로컬에 그라파나 설치
  2. 로컬에서 그라파나 접속
  3. 그라파나 Data Sources 설정
  4. 그라파나 대시보드 생성
  5. 결과 확인

 

1. 로컬에 그라파나 설치

원하는 버전을 설치해도 되지만 본인은 그라파나 최신 버전을 설치하였다.

압축 파일을 압축 해제하고 bin 폴더의 grafana-server.exe 파일을 실행한다.


2. 로컬에서 그라파나 접속

그라파나의 기본 포트번호는 3000번이다.

localhost:3000으로 접속하면 아래와 같은 화면이 나온다.

ID: admin / PW: admin 으로 접속한다.

 

접속하면 비밀번호를 변경하라고 나오는데 스킵해도 된다.


3. 그라파나 Data Sources 설정

3-1. Data Sources 페이지로 이동

아래처럼 좌상단의 햄버거 버튼을 누르고 Connections 탭의 Data Sources 설정에 들어간다.

처음 접속하면 Data Sources가 아무것도 없을테니 아래처럼 Add data source 버튼을 눌러서 추가해준다.

3-2. Data Source 추가

우리는 프로메테우스를 시각화할 예정이므로 프로메테우스를 선택한다.

 

이름은 원하는대로 설정해도 되고 프로메테우스 서버 URL을 아래처럼 http://localhost:9090으로 설정해주자.

이전 글에서도 언급했지만 프로메테우스 서버의 기본 포트번호는 9090이다.

 

프로메테우스 서버가 잘 떠있다면 아래처럼 Save & test 버튼 클릭 시 성공했다는 팝업창이 뜰것이다.


4. 그라파나 대시보드 생성

그라파나에서는 잘 만들어둔 대시보드를 공유한다.

우선은 만들어진 공유 대시보드를 사용해보자.

4-1. 공유 대시보드 검색

위 링크에 들어가면 아래처럼 검색창이 나온다.

여기에 spring을 치면 인기순으로 나오는 공유 대시보드가 나온다.

이런 식으로 잘 만들어진 공유 대시보드를 이용할 수 있으니 하나만 예시로 적용해보겠다.

첫번째에 있는 마이크로미터에서 제공하는 JVM 시각화 대시보드를 이용해보자.

4-2. 공유 대시보드 ID 복사

아래 사진처럼 공유 대시보드의 ID를 복사한다.

4-3. 대시보드 생성

 

우리는 공유 대시보드를 이용할 것이므로 import dashboard 버튼을 클릭한다.

 

복사해둔 공유 대시보드 ID를 입력하고 Load 버튼을 누른다.

 

Data Source를 우리가 추가한 프로메테우스로 선택해주고 Import 버튼을 클릭한다.


5. 결과 확인

Import 버튼을 누르면 바로 생성한 대시보드로 이동한다.

아래 사진처럼 공유 대시보드의 템플릿으로 잘 생성되었다.

Data Source는 우리가 설정한 프로메테우스 서버를 이용하므로 우리 애플리케이션의 상태를 확인할 수 있다.

 

대시보드 탭으로 이동하면 생성된 대시보드를 확인할 수 있다.

 

Prometheus

위 그림은 프로메테우스 공식 홈페이지에서 프로메테우스의 동작 흐름을 나타낸 그림이다.

프로메테우스는 메트릭을 수집하여 저장 및 연산하고 간단한 시각화를 지원하는 오픈소스 라이브러리이다.

이전 글에서 본 것 처럼 스프링부트 액추에이터에서 애플리케이션 정보와 메트릭 정보를 제공한다.

프로메테우스는 액추에이터에서 제공하는 정보를 이용하여 저장 및 간단히 시각화해서 볼 수 있다.

이 글에서는 로컬에서 스프링부트 액추에이터 및 프로메테우스를 이용하여 메트릭을 활용하는 법을 정리해두려 한다.

 

액추에이터에서 제공하는 정보를 이용하려면 모니터링 툴에 맞는 데이터 양식으로 변환해야한다.

아래 그림은 어떻게 액추에이터의 데이터가 모니터링 툴에 맞는 양식으로 변환되는지 표현한다.

간단히 표현하자면 마이크로미터라는 라이브러리에서 표준 측정 방식을 정해두고

마이크로미터 구현체가 각각의 모니터링 툴에 맞는 양식으로 변환해주는 형식이다.


사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • Spring Boot Actuator, Prometheus

써보기

로컬에서 프로메테우스를 설치하고 사용해볼 것이다.

순서는 아래와 같다.

  1. 스프링부트 액추에이터 및 프로메테우스 의존성 추가
  2. 로컬에 프로메테우스 설치
  3. 프로메테우스 설정
  4. 로컬에서 프로메테우스 접속
  5. 프로메테우스 써보기

1. 의존성 추가

우선 아래처럼 스프링부트 액추에이터와 프로메테우스의 의존성을 추가해준다.

// build.gradle.kts
// 모니터링
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation ("io.micrometer:micrometer-registry-prometheus")

 

의존성을 추가해주면 "/actuator/prometheus" 경로로 들어가면 아래와 같은 JSON 결과 값을 확인할 수 있다.

잘 보면 "/actuator/metrics" 에서 본 데이터들이 형식만 다르게 나와있는걸 알 수 있다.

위에서 그림으로 언급한 마이크로미터 구현체가 프로메테우스에 맞는 데이터 형식으로 변환한것이다.

 

2. 로컬에 프로메테우스 설치

본인 환경은 윈도우이므로 윈도우 기준으로 설명하겠다.

로컬에서는 맥에서도 실행 방법만 exe 파일 실행이 아닐 뿐 다르진 않을 것이다.

프로메테우스 공식 홈페이지에서 최신 버전을 다운 받는다.

굳이 최신일 필요는 없지만 공부용이니까 본인은 최신 버전으로 다운 받았다.


3. 프로메테우스 설정

3-1. prometheus.yml 설정

아래 두가지 파일만 생각하면 된다.

우선 우리 애플리케이션에서 메트릭 정보를 받아올 수 있도록 prometheus.yml 파일을 설정해야한다.

vsCode 혹은 IntelliJ 같은로 띄워서 설정해주자.

 

아래 yml 파일에서 추가라는 주석이 달린 아래 부분을 넣어주면 된다.

targets 에는 설정한 액추에이터가 띄워진 서버 URL을 입력해주면 된다.

기본은 8080포트일테지만 이전 글에서 언급했던 것 처럼 원하는 포트번호로 수정할 수도 있다.

scrape_interval 로 메트릭 정보 수집 주기를 정할 수 있다.

본인은 15초로 설정하였다.

// prometheus.yml
... 생략
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
      
  #추가
  - job_name: "spring-actuator"
    metrics_path: '/actuator/prometheus'
    scrape_interval: 15s     // 15초에 한번씩 actuator 정보 수집
    static_configs:
      - targets: [ 'localhost:8080' ]  // 메트릭을 수집할 서버 도메인
... 생략

3-2. prometheus.exe 실행

프로메테우스를 실행하면 아래처럼 서버 실행 창이 뜬다.


4. 프로메테우스 접속

프로메테우스의 기본 포트인 9090으로 접속한다.

localhost:9090으로 접속하면 아래와 같은 창을 확인할 수 있다.


5. 프로메테우스 쿼리 써보기

5-1. 프로메테우스 쿼리 사용

아래처럼 promQL 이라는 프로메테우스 전용 쿼리를 사용할 수 있다.

본인은 간단한 Count 쿼리 조회만 해봤지만 promQL을 이용한 다양한 연산이 가능하니 프로메테우스 공식 홈페이지를 참고해보자.

3-1에서 설정한 scrape_interval 대로 15초당 한번씩 "/actuator/prometheus" 경로로 요청을 한다.

5-2. 프로메테우스 쿼리 그래프 확인

아래처럼 쿼리 결과를 간단한 그래프로 시각화하여 볼 수도 있다.

Spring Boot Actuator

서비스 배포도 해보고 배포 자동화까지 해보았다.

이제 서비스가 원활하게 돌아가는지 확인할 수 있도록 모니터링을 적용해보려 한다.

Spring Boot Actuator에서는 CPU 사용율, 커넥션풀과 같은 애플리케이션 정보와 HTTP 요청 횟수 같은 메트릭 정보를 제공한다.

이 글에서는 Spring Boot Actuator로 메트릭을 확인하는 방법을 적어두려 한다.


사용 기술

  • Spring Boot 3.2.4 / gradle-kotlin
  • Java 17
  • Spring Boot Actuator

써보기

최종적으로는 스프링부트 애플리케이션에 의존성을 추가하고 로컬에서 프로메테우스와 그라파나를 설치하고 사용해볼 것이다.

이번 글에서는 스프링부트 액추에이터를 써보기까지만 한다.

순서는 아래와 같다.

  1. 스프링부트 액추에이터 의존성 추가
  2. 엔드포인트 활성화 및 노출
  3. 액추에이터가 제공하는 데이터 확인

1. 의존성 추가

아래처럼 스프링부트 액추에이터의 의존성을 추가해준다.

// build.gradle.kts
// 모니터링
implementation("org.springframework.boot:spring-boot-starter-actuator")

 

의존성을 추가해주면 "/actuator" 경로로 들어가면 아래와 같은 JSON 결과 값을 확인할 수 있다.


2. 엔드포인트 활성화 / 노출

스프링부트 액추에이터의 메트릭을 이용하려면 기본적으로 아래 두가지를 해줘야한다.

  • 엔드포인트 활성화
  • 엔드포인트 노출 

스프링부트 액추에이터 의존성을 추가하면 기본적인 엔드포인트들은 활성화가 된다.

이제 스프링부트 액추에이터가 제공하는 메트릭을 활용할 수 있게 엔드포인트 활성화와 노출을 해보자.

아래처럼 application.yml을 설정 해준다.

// application.yml
... 생략
server:
  tomcat:
    mbeanregistry:
      enabled: true         // tomcat 관련 정보를 노출
management:
  endpoint:
    health:
      show-details: always  // health 엔드포인트 상세 정보 출력
  endpoints:
    web:
      exposure:
        include: "*"        // 엔드포인트 노출
... 생략

 

management.endpoints.web.exposure.include: "*" 옵션으로 엔드포인트를 노출하면

아래처럼 애플리케이션 정보와 메트릭 지표를 확인할 수 있다.


3. 액추에이터가 제공하는 데이터 확인

3-1. 애플리케이션 정보 확인

3-2. 메트릭 지표 확인


Spring Boot Actuator와 보안

이렇게 많은 메트릭을 퍼블릭하게 열어두면 악용의 소지가 있다.

따라서 아래처럼 application.yml 파일에 메트릭을 확인할 포트 번호를 지정할 수 있다.

서비스 중인 애플리케이션 서버의 포트와 다른 포트를 이용하여 Nginx 등으로 내부망에서만 접근 가능하도록 하거나

같은 포트를 사용한다면 필터나 스프링 시큐리티 등을 이용하여 권한이 있는 사용자만 접근하도록 한다.

// application.yml
management:
  server:
    port: 9090         // 액추에이터 포트 번호 지정
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: "*"

 

 

참고자료

 

스프링 부트 - 핵심 원리와 활용 | 김영한 - 인프런

김영한 | 실무에 필요한 스프링 부트는 이 강의 하나로 모두 정리해드립니다., 백엔드 개발자를 위한 스프링 부트 끝판왕! 실무에 필요한 내용을 모두 담았습니다.  [임베딩 영상] 김영한의 스

www.inflearn.com

 

+ Recent posts