actuator프로젝트 사용

0. 프로덕션 준비 기능이란

개발자가 애플리케이션을 개발할 때는 요구사항 개발뿐만 아니라 실제 운영 단계에서 서비스가 문제가 없는지 모니터링하고 지표들을 심어서 감시하는 활동들도 필요하다.

운영 환경에서 서비스할 때 필요한 이런 기능들을 프로덕션 준비 기능이라 한다. 쉽게 이야기해서 프로덕션을 운영에 배포할 때 준비해야 하는 비 기능적 요소들을 뜻한다.

  • 지표(metric), 추적(trace), 감사(auditing)
  • 모니터링

즉, 애플리케이션이 현재 살아있는지, 로그 정보는 정상 설정 되었는지, 커넥션 풀은 얼마나 사용되고 있는지 등을 확인할 수 있어야 한다.

스프링 부트가 제공하는 액추에이터는 이런 프로덕션 준비 기능을 매우 편리하게 사용할 수 있는 다양한 편의 기능들을 제공한다. 더 나아가서 마이크로미터, 프로메테우스, 그라파나 같은 최근 유행하는 모니터링 시스템과 매우 쉽게 연동할 수 있는 기능도 제공한다.

1. 액츄에이터(actuator) 시작

actuator 빌드 설정

implementation 'org.springframework.boot:spring-boot-starter-actuator' //actuator 추가

application.yml - 추가

액츄에이터 기능을 웹에 노출한다.

management:
  endpoints:
    web:
     exposure:
       include: "*"

동작 확인

localhost:8080/actuator

image-20230423150752104

  • 액츄에이터가 제공하는 기능 하나하나를 엔드포인트라 한다. health 는 헬스 정보를, beans 는 스프링 컨테이너에 등록된 빈을 보여준다.
  • 각각의 엔드포인트는 /actuator/{엔드포인트명} 과 같은 형식으로 접근할 수 있다.
    • http://localhost:8080/actuator/health : 애플리케이션 헬스 정보를 보여준다.
    • http://localhost:8080/actuator/beans : 스프링 컨테이너에 등록된 빈을 보여준다.

2. 엔드포인트 설정

엔드포인트를 사용하려면 다음 2가지 과정이 모두 필요하다.

1. 엔드포인트 활성화 : 해당 기능 자체를 사용할지 말지 on , off 를 선택하는 것이다.
 - 엔드포인트는 대부분 기본으로 활성화 되어 있다.( shutdown 제외) 노출이 되어 있지 않을 뿐이다.
1. 엔드포인트 노출 : 활성화된 엔드포인트를 HTTP에 노출할지 아니면 JMX에 노출할지 선택하는 것이다.

application.yml - shutdown 엔드포인트 활성화

management:
  endpoint:
    shutdown:
      enabled: true # Enable shutdown endpoint
  endpoints:
    web:
      exposure:
        include: "*" # Expose all endpoints
  • 특정 엔드포인트를 활성화 하려면 management.endpoint.{엔드포인트명}.enabled=true 를 적용하면 된다.
  • HTTP POST로 http://localhost:8080/actuator/shutdown 를 호출하면 다음 메시지와 함께 실제 서버가 종료되는 것을 확인할 수 있다. {"message": "Shutting down, bye..."}

엔드포인트 노출

management:
 endpoints:
   jmx:
     exposure:
       include: "health,info"
  • jmx 에 health,info 를 노출한다.
management:
 endpoints:
   web:
     exposure:
       include: "*"
         exclude: "env,beans"
  • web 에 모든 엔드포인트를 노출하지만 env , beans 는 제외한다.

3. 다양한 엔드포인트

각각의 엔드포인트를 통해서 개발자는 애플리케이션 내부의 수 많은 기능을 관리하고 모니터링 할 수 있다. 다음은 스프링 부트가 기본으로 제공하는 다양한 엔드포인트 중 자주 사용하는 기능이다.

엔드포인트 목록

  • beans : 스프링 컨테이너에 등록된 스프링 빈을 보여준다.
  • ` conditions` : condition 을 통해서 빈을 등록할 때 평가 조건과 일치하거나 일치하지 않는 이유를 표시한다.
  • configprops : @ConfigurationProperties 를 보여준다.
  • env : Environment 정보를 보여준다.
  • health : 애플리케이션 헬스 정보를 보여준다.
  • httpexchanges : HTTP 호출 응답 정보를 보여준다. HttpExchangeRepository 를 구현한 빈을 별도로 등록해야 한다.
  • info : 애플리케이션 정보를 보여준다.
  • loggers : 애플리케이션 로거 설정을 보여주고 변경도 할 수 있다.
  • metrics : 애플리케이션의 메트릭 정보를 보여준다.
  • mappings : @RequestMapping 정보를 보여준다.
  • threaddump : 쓰레드 덤프를 실행해서 보여준다.
  • shutdown : 애플리케이션을 종료한다. 이 기능은 기본으로 비활성화 되어 있다.

엔드포인트 공식 메뉴얼

4. 헬스 정보

헬스 정보를 사용하면 애플리케이션에 문제가 발생했을 때 문제를 빠르게 인지할 수 있다.

헬스 정보는 단순히 애플리케이션이 요청에 응답을 할 수 있는지 판단하는 것을 넘어서 애플리케이션이 사용하는 데이터베이스가 응답하는지, 디스크 사용량에는 문제가 없는지 같은 다양한 정보들을 포함해서 만들어진다.

헬스 정보를 더 자세히 보려면 다음 옵션을 지정하면 된다.

management:
  endpoint:
    health:
      show-details: always # Show details in health endpoint

image-20230423154045044

show-components 옵션

각 헬스 컴포넌트의 상태 정보만 간략하게 노출한다.

management:
  endpoint:
    health:
#      show-details: always # Show details in health endpoint
      show-components: always # Show components in health endpoint
  endpoints:
    web:
      exposure:
        include: "*" # Expose all endpoints

image-20230423154131162

헬스 이상 상태

헬스 컴포넌트 중에 하나라도 문제가 있으면 전체 상태는 DOWN 이 된다.

{
    "status": "DOWN",
    "components": {
        "db": {
        	"status": "DOWN"
        },
        "diskSpace": {
        	"status": "UP"
        },
        "ping": {
        	"status": "UP"
        }
    }
}
  • 여기서는 db 에 문제가 발생했다. 하나라도 문제가 있으면 DOWN 으로 보기 때문에 이 경우 전체 상태의 status 도 DOWN 이 된다.

헬스 기본 지원 기능 다음 공식 메뉴얼

5. 애플리케이션 정보 (info)

기본으로 제공하는 기능들은 다음과 같다.

  • java : 자바 런타임 정보
  • os : OS 정보
  • env : Environment 에서 info. 로 시작하는 정보
  • build : 빌드 정보, META-INF/build-info.properties 파일이 필요하다.
  • git : git 정보, git.properties 파일이 필요하다.

env , java , os 는 기본으로 비활성화 되어 있다.

java, os 활성화

management:
 info:
   java:
     enabled: true
   os:
     enabled: true

주의!: management.endpoint 하위가 아니다. management 바로 다음에 info가 나온다.

  • 실행해보면 java , os 관련 정보를 확인할 수 있다.

env 활성화

management:
 info:
   env:
     enabled: true
info:
 app:
   name: hello-actuator
   company: yh
  • Environment 에서 info. 로 시작하는 정보를 출력한다.

  • 실행 결과

  • {
        "app":{
            "name":"hello-actuator",
            "company":"yh"
        }
        ...
    }
    

build

빌드 정보를 노출하려면 빌드 시점에 META-INF/buildinfo.properties 파일을 만들어야 한다. gradle을 사용하면 다음 내용을 추가하면 된다.

springBoot {
	buildInfo()
}

이렇게 하고 빌드를 해보면 build 폴더안에 resources/main/META-INF/build-info.properties 파일을 확인할 수 있다.

build.artifact=actuator
build.group=hello
build.name=actuator
build.time=2023-01-01T00\:000\:00.000000Z
build.version=0.0.1-SNAPSHOT
  • build 는 기본으로 활성화 되어 있기 때문에 이 파일만 있으면 바로 확인할 수 있다.

git

git 정보를 노출하려면 git.properties 파일이 필요하다. gradle plugins 에 다음과 같이 추가한다.

plugins {
 ...
 id "com.gorylenko.gradle-git-properties" version "2.4.1" //git info
}

이렇게 하고 빌드를 해보면 build 폴더안에 resources/main/git.properties 파일을 확인할 수 있다.

git 에 대한 더 자세한 정보를 보고 싶다면 다음 옵션을 적용하면 된다.

management:
 info:
   git:
     mode: "full"

info 공식메뉴얼

6. 로거

loggers 엔드포인트를 사용하면 로깅과 관련된 정보를 확인하고, 또 실시간으로 변경할 수도 있다.

LogController 생성

예제를 위한 컨트롤러다.

package hello.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class LogController {

    @GetMapping("/log")
    public String log(){
        log.trace("trace log");
        log.debug("debug log");
        log.info("info log");
        log.warn("warn log");
        log.error("error log");
        return "ok";
    }
}

application.yml 설정

logging:
 level:
   hello.controller: debug

hello.controller 패키지와 그 하위는 debug 레벨을 출력하도록 했다. 이제 앞서 만든 LogController 클래스도 debug 레벨의 영향을 받는다.

로그를 별도로 설정하지 않으면 스프링 부트는 기본으로 INFO 를 사용한다.

결과

DEBUG 53783 --- hello.controller.LogController : debug log
 INFO 53783 --- hello.controller.LogController : info log
 WARN 53783 --- hello.controller.LogController : warn log
ERROR 53783 --- hello.controller.LogController : error log

실행 결과를 보면 기대한 것 처럼 DEBUG 레벨까지 출력되는 것을 확인할 수 있다.

loggers 엔드포인트를 호출

실행 : http://localhost:8080/actuator/loggers

image-20230423174201286

  • 로그를 별도로 설정하지 않으면 스프링 부트는 기본으로 INFO 를 사용한다. 실행 결과를 보면 ROOT 의 configuredLevel 가 INFO 인 것을 확인할 수 있다. 따라서 그 하위도 모두 INFO 레벨이 적용된다.
  • 앞서 우리는 hello.controller 는 DEBUG 로 설정했다. 그래서 해당 부분에서 configuredLevel 이 DEBUG 로 설정된 것을 확인할 수 있다. 그리고 그 하위도 DEBUG 레벨이 적용된다.

더 자세히 조회하기

다음과 같은 패턴을 사용해서 특정 로거 이름을 기준으로 조회할 수 있다.

http://localhost:8080/actuator/loggers/{로거이름}

  • 결과

    • GET http://localhost:8080/actuator/loggers/hello.controller

    • {
       "configuredLevel": "DEBUG",
       "effectiveLevel": "DEBUG"
      }
      

실시간 로그 레벨 변경

서비스 운영중에 문제가 있어서 급하게 DEBUG 나 TRACE 로그를 남겨서 확인해야 확인하고 싶을 때 loggers 엔드포인트를 사용하면 애플리케이션을 다시 시작하지 않고, 실시간으로 로그 레벨을 변경할 수 있다.

POST http://localhost:8080/actuator/loggers/hello.controller

//content/type=application/json
{
 "configuredLevel": "TRACE"
}

GET으로 요청해서 확인해보면 configuredLevel 이 TRACE 로 변경된 것을 확인할 수 있다.

  • GET http://localhost:8080/actuator/loggers/hello.controller

  • {
     "configuredLevel": "TRACE",
     "effectiveLevel": "TRACE"
    }
    

controller 실행

  • http://localhost:8080/log

  • TRACE 53783 --- [nio-8080-exec-6] hello.controller.LogController : trace log
    DEBUG 53783 --- [nio-8080-exec-6] hello.controller.LogController : debug log
     INFO 53783 --- [nio-8080-exec-6] hello.controller.LogController : info log
     WARN 53783 --- [nio-8080-exec-6] hello.controller.LogController : warn log
    ERROR 53783 --- [nio-8080-exec-6] hello.controller.LogController : error log
    
    • 실행 결과를 보면 TRACE 레벨까지 출력되는 것을 확인할 수 있다.

7. HTTP 요청 응답 기록

HTTP 요청과 응답의 과거 기록을 확인하고 싶다면 httpexchanges 엔드포인트를 사용하면 된다.

HttpExchangeRepository 인터페이스의 구현체를 빈으로 등록하면 httpexchanges 엔드포인트를 사용할 수 있다. 스프링 부트는 기본으로 InMemoryHttpExchangeRepository 구현체를 제공한다.

InMemoryHttpExchangeRepository 추가

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class ActuatorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }

    @Bean
    public InMemoryHttpExchangeRepository httpExchangeRepository() {
        return new InMemoryHttpExchangeRepository();
    }
}
  • 이 구현체는 최대 100개의 HTTP 요청을 제공한다. 최대 요청이 넘어가면 과거 요청을 삭제한다. setCapacity() 로 최대 요청수를 변경할 수 있다.

실행

GET http://localhost:8080/actuator/httpexchanges

image-20230423190731183

실행해보면 지금까지 실행한 HTTP 요청과 응답 정보를 확인할 수 있다. 참고로 이 기능은 매우 단순하고 기능에 제한이 많기 때문에 개발 단계에서만 사용하고, 실제 운영 서비스에서는 모니터링 툴이나 핀포인트, Zipkin 같은 다른 기술을 사용하는 것이 좋다.

8. 액츄에이터와 보안

액츄에이터가 제공하는 기능들은 우리 애플리케이션의 내부 정보를 너무 많이 노출한다. 그래서 외부 인터넷 망이 공개된 곳에 액츄에이터의 엔드포인트를 공개하는 것은 보안상 좋은 방안이 아니다.

액츄에이터를 다른 포트에서 실행

예를 들어서 외부 인터넷 망을 통해서 8080 포트에만 접근할 수 있고, 다른 포트는 내부망에서만 접근할 수 있다면 액츄에이터에 다른 포트를 설정하면 된다. 액츄에이터의 기능을 애플리케이션 서버와는 다른 포트에서 실행하려면 다음과 같이 설정하면 된다. 이 경우 기존 8080 포트에서는 액츄에이터를 접근할 수 없다.

액츄에이터 포트 설정 : management.server.port=9292 실행 : http://localhost:9292/actuator

액츄에이터 URL 경로에 인증 설정

포트를 분리하는 것이 어렵고 어쩔 수 없이 외부 인터넷 망을 통해서 접근해야 한다면 /actuator 경로에 서블릿 필터, 스프링 인터셉터 또는 스프링 시큐티리를 통해서 인증된 사용자만 접근 가능하도록 추가 개발이 필요하다.

엔드포인트 경로 변경

management:
 endpoints:
 web:
 base-path: "/manage"

/actuator/{엔드포인트} 대신에 /manage/{엔드포인트} 로 변경된다.

댓글남기기