- Spring Boot Actuator - 2. 주요 Endpoint2025년 09월 21일
- 알쓸개잡
- 작성자
- 2025.09.21.:22
반응형Spring Boot Actuator는 기본적으로 여러 Endpoint를 제공한다. Actuator의 강점은 단순히 "ON/OFF" 수준의 헬스체크를 넘어 애플리케이션 내부 상태를 입체적으로 보여주는 다양한 Endpoint를 제공한다.
이번 포스팅에서는 Spring Boot Actuator를 통해서 실무에서 자주 사용되는 Endpoint에 대해서 살펴보고자 한다.
우선 Spring Boot Actuator에서 제공하는 Endpoint 목록은 공식문서를 통해 확인해 볼 수 있다.
https://docs.spring.io/spring-boot/reference/actuator/endpoints.html
이번 포스팅에서는 다음의 Endpoint를 살펴보도록 하겠다.
- /actuator/health
- /actuator/info
- /actuator/env
- /actuator/loggers
- /actuator/beans, /actuator/mappings
- /actuator/metrics
이전 포스팅에서도 언급했듯이 Spring Boot Actuator는 기본적으로 health만 노출한다. (Spring Boot 3.2 기준)
나머지 Endpoint에 대해서는 management.endpoints.web[jmx].exposure.include 에 노출하고자 하는 Endpoint를 추가해 줘야 한다.management: endpoints: web: exposure: include: health, info, metrics, beans, mappings, ...
actuator 관련 설정 파악하기
본론으로 들어가기에 앞서 actuator 관련 설정 항목에 대한 정보를 손쉽게 얻는 방법을 소개하고자 한다.
spring-boot-starter-actuator 의존성을 추가하면 spring-boot-actuator, spring-boot-actuator-autoconfigure의존성이 따라오는데 각 의존성의 META-INF/spring-configuration-metadata.json 파일을 참조하면 손쉽게 설정에 대한 내용을 파악할 수 있다. 또한
예로 Actuator에서 기본 제공하는 Endpoint 시작은 왜 /actuator일까? base-path 설정을 확인해 보면 알 수 있다.
spring-configuration-metadata.json 파일을 보면 다음과 같은 항목이 있다.
{ "name": "management.endpoints.web.base-path", "type": "java.lang.String", "description": "Base path for Web endpoints. Relative to the servlet context path (server.servlet.context-path) or WebFlux base path (spring.webflux.base-path) when the management server is sharing the main server port. Relative to the management server base path (management.server.base-path) when a separate management server port (management.server.port) is configured.", "sourceType": "org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties", "defaultValue": "\/actuator" }
management.endpoints.web.base-path는 Web 모드의 endpoints 들의 기본 context path를 설정하는 항목임을 알 수 있다.
디폴트 값은 "/actuator"라고 명시되어 있다. 또한 해당 설정 항목은 org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties 클래스에서 주입받아 사용됨을 확인할 수 있다.
코드는 다음과 같다.
@ConfigurationProperties("management.endpoints.web") public class WebEndpointProperties { private final Exposure exposure = new Exposure(); /** * Base path for Web endpoints. Relative to the servlet context path * (server.servlet.context-path) or WebFlux base path (spring.webflux.base-path) when * the management server is sharing the main server port. Relative to the management * server base path (management.server.base-path) when a separate management server * port (management.server.port) is configured. */ private String basePath = "/actuator"; ... ... }
위 코드를 봐도 management.endpoints.web.base-path 설정 기본값은 /actuator 임을 확인할 수 있다.
Actuator에서 기본적으로 노출되는 Endpoint는 health 인 것은 어떻게 확인할 수 있을까?
spring-configuration-metadata.json 파일을 보면 다음과 같은 항목이 있다.
{ "name": "management.endpoints.web.exposure.include", "type": "java.util.Set<java.lang.String>", "description": "Endpoint IDs that should be included or '*' for all.", "sourceType": "org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties$Exposure", "defaultValue": [ "health" ] }
management.endpoints.web.exposure.include 설정은 포함되어야 하는 Endpint ID 목록을 설정하는 항목임을 알 수 있다.
디폴트는 "health" 임을 확인할 수 있다.
코드 상으로 따라가기는 좀 어렵지만 여차저차해서 org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure Enum 클래스를 보면 다음과 같다.
public enum EndpointExposure { /** * Exposed over a JMX endpoint. */ JMX("health"), /** * Exposed over a web endpoint. */ WEB("health"), /** * Exposed on Cloud Foundry over `/cloudfoundryapplication`. * @since 2.6.4 * @deprecated since 3.4.0 for removal in 4.0.0 in favor of using * {@link EndpointExposure#WEB} */ @Deprecated(since = "3.4.0", forRemoval = true) CLOUD_FOUNDRY("*"); private final String[] defaultIncludes; EndpointExposure(String... defaultIncludes) { this.defaultIncludes = defaultIncludes; } /** * Return the default set of include patterns. * @return the default includes */ public String[] getDefaultIncludes() { return this.defaultIncludes; } }
JMX, WEB 노출 타입 모두 기본 값은 health 임을 알 수 있다. (Spring Boot 3.2 기준)
/actuator/health
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/health.html
health Endpoint는 애플리케이션의 상태에 대한 상세한 정보를 제공한다.
GET http://localhost:8080/actuator/health
{ "status": "UP" }
기본 호출 결과는 단순하다. "UP" 또는 "DOWN"과 같은 요약 상태만 반환한다. 하지만 DB, Redis, Kafka와 같은 의존성 라이브러리가 포함되어 있으면 자동으로 해당 서비스에 대한 HealthIndicator가 활성화된다.
management.endpoint.health.show-details와 management.health.<name>.enabled 설정을 통해서 해당 서비스에 대한 health 정보를 노출시킬 수 있다.
management: endpoints: web: exposure: include: health endpoint: health: show-details: always health: redis: enabled: true mongo: enabled: true spring: data: redis: host: localhost port: 6379 mongodb: host: localhost port: 27017
Actuator 자동 구성은 spring.data.redis.host[port] 정보를 통해서 redis에 대한 HealthIndicator를 활성화한다.
또한 spring.data.mongodb.host[port] 정보를 통해서 mongodb에 대한 HealthIndicator를 활성화한다.
다음은 redis, mongodb를 활성화했을 때 호출되는 health 정보다.
{ # 애플리케이션 상태 "status": "UP", "components": { "diskSpace": { "status": "UP", ... }, # mongodb 상태 "mongo": { "status": "UP", "details": { "maxWireVersion": 17 } }, "ping": { "status": "UP" }, # redis 상태 "redis": { "status": "UP", "details": { "version": "7.2.4" } }, "ssl": { "status": "UP", "details": { "validChains": [], "invalidChains": [] } } } }
/actuator/info
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/info.html
info Endpoint는 애플리케이션에 대한 일반 정보를 제공한다.
info Endpoint를 호출하기 위해서는 다음과 같은 설정이 필요하다.
management: endpoints: web: exposure: include: health, info info: # java 버전 java: enabled: true # OS 정보 os: enabled: true # 환경변수 및 info 설정 정보 env: enabled: true # 애플리케이션 process 정보 process: enabled: true # 아래 정보는 management.info.env.enabled가 true인 경우 표시된다. info: app: name: demo-app version: "1.0.0" description: Spring Boot Actuator demo application
GET http://localhost:8080/actuator/info
{ "app": { "name": "demo-app", "version": "1.0.0", "description": "Spring Boot Actuator demo application" }, "java": { "version": "17.0.14", "vendor": { "name": "Eclipse Adoptium", "version": "Temurin-17.0.14+7" }, "runtime": { "name": "OpenJDK Runtime Environment", "version": "17.0.14+7" }, "jvm": { "name": "OpenJDK 64-Bit Server VM", "vendor": "Eclipse Adoptium", "version": "17.0.14+7" } }, "os": { "name": "Mac OS X", "version": "15.6.1", "arch": "aarch64" }, "process": { "pid": 5836, "parentPid": 28236, "owner": "..." "cpus": 10, "memory": { "heap": { "committed": 142606336, "used": 53277184, "init": 1073741824, "max": 17179869184 }, "nonHeap": { "committed": 77987840, "used": 76130272, "init": 2555904, "max": -1 }, "garbageCollectors": [ { "name": "G1 Young Generation", "collectionCount": 7 }, { "name": "G1 Old Generation", "collectionCount": 0 } ] } } }
/actuator/loggers
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/loggers.html
애플리케이션의 로거 및 해당 레벨 설정에 대한 접근을 제공한다.
전체 목록 또는 개별 로거의 구성을 확인할 수 있으며 이는 명시적으로 구성된 로깅 레벨과 로깅 프레임워크가 부여한 유효 로깅 레벨로 구성된다.
loggers Endpoint를 활성화하고 노출하기 위해서는 다음 설정이 필요하다.
management: endpoints: web: exposure: # 노출을 위한 설정 include: health, info, loggers endpoint: loggers: # 개발환경에서 read-write를 지정했으나 운영환경에서는 권장하지 않음 access: read-write
이외에도 다음과 같은 설정이 있다.
management.endpoint.loggers.cache.time-to-live
- 읽기 응답 캐시 TTL (기본값 : 미지정)
전체 로거 조회
GET http://localhost:8080/actuator/loggers
애플리케이션 모든 logger에 대한 로그레벨이 출력된다.
{ "levels": [ "OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" ], "loggers": { "ROOT": { "configuredLevel": "INFO", "effectiveLevel": "INFO" }, "_org": { "effectiveLevel": "INFO" }, "_org.springframework": { "effectiveLevel": "INFO" }, "_org.springframework.web": { "effectiveLevel": "INFO" }, "_org.springframework.web.servlet": { "effectiveLevel": "INFO" }, ... ... ... ... "reactor.util.Loggers": { "effectiveLevel": "INFO" } }, "groups": { "web": { "members": [ "org.springframework.core.codec", "org.springframework.http", "org.springframework.web", "org.springframework.boot.actuate.endpoint.web", "org.springframework.boot.web.servlet.ServletContextInitializerBeans" ] }, "sql": { "members": [ "org.springframework.jdbc.core", "org.hibernate.SQL", "org.jooq.tools.LoggerListener" ] } } }
개별 로거 조회
GET http://localhost:8080/actuator/loggers/reactor.util.Loggers
{"effectiveLevel":"INFO"}
런타임 로그 레벨 변경
런타임에 지정된 logger의 로그 레벨 변경이 가능하다.
management.endpoint.loggers.access 가 read-only의 경우에는 POST 호출을 할 수 없다. (405 Method Not Allowed)
POST http://localhost:8080/actuator/loggers/reactor.util.Loggers
body payload
{ "configuredLevel": "DEBUG" }
GET http://localhost:8080/actuator/loggers/reactor.util.Loggers 호출 결과
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}
여기서 configuredLevel은 사용자가 직접 지정한 로그 레벨을 의미한다.
effectiveLevel은 실제로 적용된 최종 로그 레벨을 의미한다. 해당 로거의 configuredLevel이 있으면 우선 적용되고 없으면 상위 패키지 로거의 configuredLevel을 따라간다. 모든 패키지에 configuredLevel이 없으면 최종적으로 root 로거의 configuredLevel을 따라간다. root 로거의 디폴트 configuredLevel은 INFO 인 듯하다.
하지만 위에서 reactor.util.Loggers의 configuredLevel을 DEBUG로 변경함으로써 reactor.util.Loggers 로거의 effectiveLevel이 DEBUG로 변경됨을 확인할 수 있다.
/actuator/env
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/env.html
env Endpoint는 애플리케이션이 사용하고 있는 모든 속성 및 환경 변수 정보를 응답한다.
env Endpoint 관련된 설정은 다음과 같다.
management: endpoints: web: exposure: # env Endpoint 추가 include: env endpoint: env: access: unrestricted show-values: always info: app: # 매우 민감한 정보 password: test-password name: demo-app version: "1.0.0" description: Spring Boot Actuator demo application
management.endpoint.env.access는 엔드포인트 단위의 접근 권한 수준을 지정한다.
값은 다음과 같다.
- none : 접근을 허용하지 않는다.
- read-only : 설정을 읽기만 지원한다.
- unrestricted : 읽기 및 수정을 지원한다.
management.endpoint.env.access 설정은 디폴트로 management.endpoints.access.default를 따른다. (unrestricted)
보통 운영환경에서는 read-only로 제한하는 것을 권장한다.management.endpoint.env.show-values는 설정 값 노출여부를 결정한다.
- never: 키만 노출되고 값은 숨겨진다. (******)
- when-authorized: 권한이 있는 사용자인 경우에만 값이 노출된다. Spring Security와 연동하여 인증/인가된 사용자에게만 표시됨.
- always: 무조건 값을 노출한다. 인증 비밀번호 및 access key와 같은 민감한 정보가 노출되므로 운영환경에서는 매우 위험하다.
show-values 설정은 값의 노출 여부가 전체적으로 적용되므로 세밀한 제어를 위해서는 SanitizingFunction 빈을 직접 등록해서 확장하는 방법이 있다.
GET http://localhost:8080/actuator/env
{ "activeProfiles": [], "defaultProfiles": [ "default" ], "propertySources": [ { "name": "server.ports", "properties": { "local.server.port": { "value": 8080 } } }, { "name": "servletContextInitParams", "properties": {} }, { "name": "systemProperties", "properties": { ... } }, { "name": "systemEnvironment", "properties": { ... } }, { "name": "Config resource 'class path resource [application.yml]' via location 'optional:classpath:/'", "properties": { ... "info.app.name": { "value": "demo-app", "origin": "class path resource [application.yml] - 39:13" }, "info.app.version": { "value": "1.0.0", "origin": "class path resource [application.yml] - 40:16" }, "info.app.description": { "value": "Spring Boot Actuator demo application", "origin": "class path resource [application.yml] - 41:20" }, //민감정보 "info.app.password": { "value": "test-password", "origin": "class path resource [application.yml] - 42:17" } } }, { "name": "applicationInfo", "properties": { "spring.application.pid": { "value": 4450 } } }, { "name": "Management Server", "properties": { "local.management.port": { "value": "8080" } } } ] }
지정된 profile, 시스템속성, 시스템 환경변수, application.yml 정보들을 확인할 수 있다.
info.app.password와 같이 비밀번호 값을 갖는 민감한 속성도 값이 그대로 노출되는 것을 확인할 수 있다.
show-values를 never로 지정하면 "******"와 같이 마스킹 처리(sanitize)는 되겠지만 모든 속성이 마스킹 처리된다.
custom sanitizing
위와 같이 민감한 설정 정보의 경우 마스킹 처리가 필요하다.(sanitize)
이때 필요한 것이 SanitizingFunction이다. 마스킹 처리가 필요한 속성에 대해서 SanitizingFunction을 통해서 처리할 수 있다.
@Configuration public class EnvSanitizerConfig { @Bean public SanitizingFunction sanitizingFunction() { return (data -> { if ( data.getKey().contains( "password" ) ) { return data.withSanitizedValue(); } return data; }); } }
SanitizingFunction은 SanitizableData를 파라미터로 받아서 SanitizableData을 리턴하는 함수형 인터페이스다.
원하는 마스킹 동작을 SanitizingFunction 빈으로 정의하면 env 처리 시 우리가 작성한 빈이 동작한다.
SanitizableData 에는 현재 속성의 key와 value를 모두 가지고 있다. 해당 속성이 sanitize 처리가 필요한 경우 withSanitizedValue()를 호출하여 리턴하면 된다.
app.password 속성이 민감한 정보를 가지고 있다고 했을 때 단순히 키에 'password'를 포함하면 data.withSanitizedValue()를 리턴하여 마스킹 처리를 하도록 하였다.
호출 결과를 보면 다음과 같이 password가 포함된 키 값은 마스킹 처리된 된 것을 확인할 수 있다.
{ "activeProfiles": [], "defaultProfiles": [ "default" ], "propertySources": [ ... ... { "name": "Config resource 'class path resource [application.yml]' via location 'optional:classpath:/'", "properties": { ... ... //민감정보 "info.app.password": { "value": "******", "origin": "class path resource [application.yml] - 42:17" } } }, ... ... ] }
마지막으로 /actuator/env/{property key}로 개별 속성 조회를 위한 호출이 가능하다.
/actuator/beans, /actuator/mappings
beans Endpoint
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/beans.html
beans Endpoint는 애플리케이션의 스프링 컨테이너에 등록된 모든 빈과 의존 관계를 보여준다.
관련 설정은 다음과 같다.
management: endpoints: web: exposure: include: beans endpoint: beans: access: read_only cache: time-to-live: 6000ms
management.endpoints.web.exposure.include에 beans를 추가함으로써 WEB 모드에서 노출을 허용한다.
management.endpoint.beans.access는 접근 수준을 제어한다.
- unrestricted : 모든 사용자 접근 가능
- none : 엔드포인트 접근을 허용하지 않음
- read_only : 읽기 전용으로만 허용
unrestricted와 read_only는 호출 결과가 동일한데 beans Endpoint는 읽기 전용이라 차이가 없는 게 아닐까 싶다.
마지막으로 management.endpoint.beans.cache.time-to-live 설정은 캐싱 시간을 설정한다.
GET http://localhost:8080/actuator/beans
{ "contexts": { "application": { "beans": { "applicationTaskExecutor": { "aliases": [ "bootstrapExecutor" ], "scope": "singleton", "type": "org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor", "resource": "class path resource [org/springframework/boot/autoconfigure/task/TaskExecutorConfigurations$TaskExecutorConfiguration.class]", "dependencies": [ "org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$TaskExecutorConfiguration", "threadPoolTaskExecutorBuilder" ] }, ... ... } } } }
mappings Endpoint
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/mappings.html
mappings Endpoint는 Spring MVC (혹은 WebFlux) 애플리케이션의 모든 요청 매핑 정보를 노출하는 엔드포인트다. 컨트롤러 메서드, 경로, HTTP 메서드, 핸들러 어댑터, 필터/인터셉터 등을 확인할 수 있다.
관련 설정은 다음과 같다.
management: endpoints: web: exposure: include: mappings endpoint: mappings: access: read_only cache: time-to-live: 6000ms
management.endpoints.web.exposure.include에 mappings 엔트포인트를 추가하여 WEB 모드에서 노출시킨다.
management.endpoint.mappings.access, management.endpoint.mappings.cache.time-to-live 설정은 beans와 동일하다.
확인을 위해 간단한 Filter 클래스와 컨트롤러를 추가하겠다.
@Component @Slf4j public class SimpleLoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { log.info(">>> request: {}, {}", request.getMethod(), request.getRequestURI()); filterChain.doFilter(request, response); log.info("<<< response: status={}", response.getStatus()); } }
요청/응답에 대해서 간단히 로그를 찍는 필터 클래스를 정의하였다.
@RestController public class HelloController { @GetMapping(path = "/hello") public String hello() { return "Hello World"; } }
/hello 호출 시 "Hello World"를 응답하는 컨트롤러를 정의하였다.
GET http://localhost:8080/actuator/mappings
{ "contexts": { "application": { "mappings": { "dispatcherServlets": { "dispatcherServlet": [ ... ... { "predicate": "{GET [/actuator/mappings], produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}", "handler": "Actuator web endpoint 'mappings'", "details": { "handlerMethod": { "className": "org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler", "name": "handle", "descriptor": "(Ljakarta/servlet/http/HttpServletRequest;Ljava/util/Map;)Ljava/lang/Object;" }, "requestMappingConditions": { "consumes": [], "headers": [], "methods": [ "GET" ], "params": [], "patterns": [ "/actuator/mappings" ], "produces": [ { "mediaType": "application/vnd.spring-boot.actuator.v3+json", "negated": false }, { "mediaType": "application/vnd.spring-boot.actuator.v2+json", "negated": false }, { "mediaType": "application/json", "negated": false } ] } } }, ... ... { "predicate": "{GET [/hello]}", "handler": "org.example.spring.actuator.example.controller.HelloController#hello()", "details": { "handlerMethod": { "className": "org.example.spring.actuator.example.controller.HelloController", "name": "hello", "descriptor": "()Ljava/lang/String;" }, "requestMappingConditions": { "consumes": [], "headers": [], "methods": [ "GET" ], "params": [], "patterns": [ "/hello" ], "produces": [] } } }, ... ... ] }, "servletFilters": [ ... ... { "servletNameMappings": [], "urlPatternMappings": [ "/*" ], "name": "simpleLoggingFilter", "className": "org.example.spring.actuator.example.filter.SimpleLoggingFilter" }, ... ... ], "servlets": [ { "mappings": [ "/" ], "name": "dispatcherServlet", "className": "org.springframework.web.servlet.DispatcherServlet" } ] } } } }
Actuator Endpoint에 대한 정보들과 필터들에 대한 정보를 확인할 수 있다.
/actuator/metrics
참고링크 : https://docs.spring.io/spring-boot/api/rest/actuator/metrics.html
https://docs.spring.io/spring-boot/reference/actuator/metrics.html
metrics Endpoint는 애플리케이션이 기록한 metrics를 진단하기 위한 애플리케이션 접근을 제공한다. 이 Endpoint 목적은 현재 등록된 metrics를 표시하여 사용자가 어떤 metrics가 사용 가능한지, 현재 값이 무엇인지, 특정 작업을 트리거할 때 특정 값에 변화가 발생하는지 확인할 수 있도록 하는 것이다. 수집한 metrics를 통해 애플리케이션을 진단하려면 외부 metric 백엔드를 사용해야 한다.
활성화를 위한 설정은 다음과 같다.
management: endpoints: web: exposure: include: metrics endpoint: metrics: access: read_only cache: time-to-live: 6000ms
GET http://localhost:8080/actuator/metrics
{ "names": [ "application.ready.time", "application.started.time", "disk.free", "disk.total", "executor.active", "executor.completed", "executor.pool.core", "executor.pool.max", "executor.pool.size", "executor.queue.remaining", "executor.queued", "http.server.requests.active", "jvm.buffer.count", "jvm.buffer.memory.used", "jvm.buffer.total.capacity", "jvm.classes.loaded", "jvm.classes.unloaded", "jvm.compilation.time", "jvm.gc.live.data.size", "jvm.gc.max.data.size", "jvm.gc.memory.allocated", "jvm.gc.memory.promoted", "jvm.gc.overhead", "jvm.gc.pause", "jvm.info", "jvm.memory.committed", "jvm.memory.max", "jvm.memory.usage.after.gc", "jvm.memory.used", "jvm.threads.daemon", "jvm.threads.live", "jvm.threads.peak", "jvm.threads.started", "jvm.threads.states", "logback.events", "mongodb.driver.pool.checkedout", "mongodb.driver.pool.checkoutfailed", "mongodb.driver.pool.size", "mongodb.driver.pool.waitqueuesize", "process.cpu.time", "process.cpu.usage", "process.files.max", "process.files.open", "process.start.time", "process.uptime", "system.cpu.count", "system.cpu.usage", "system.load.average.1m", "tomcat.sessions.active.current", "tomcat.sessions.active.max", "tomcat.sessions.alive.max", "tomcat.sessions.created", "tomcat.sessions.expired", "tomcat.sessions.rejected" ] }
GET http://localhost:8080/actuator/metrics/<matric-name>
지정된 metric-name에 해당하는 정보를 출력한다.
다음은 jvm.memory.used(JVM 메모리 사용량)에 대한 metric 정보를 확인한다.
GET http://localhost:8080/actuator/metrics/jvm.memory.used
{ "name": "jvm.memory.used", "description": "The amount of used memory", "baseUnit": "bytes", "measurements": [ { "statistic": "VALUE", "value": 155870768 } ], "availableTags": [ { "tag": "area", "values": [ "heap", "nonheap" ] }, { "tag": "id", "values": [ "G1 Survivor Space", "Compressed Class Space", "Metaspace", "CodeCache", "G1 Old Gen", "G1 Eden Space" ] } ] }
JVM 메모리 사용 정보를 출력한다. availableTags를 통해서 지정된 태그에 해당하는 정보만 출력할 수 있다. tag는 어떤 상황에서 수집된 것인가를 알려주는 메타데이터 역할을 한다. 위 응답에서는 tag를 지정해서 영역별, 세그먼트 별로 세분화가 가능하다.
tag로 지정된 것은 태그명이고 values는 해당 tag에 지정할 수 있는 값을 의미한다.
다음은 JVM 메모리 사용량 중에 heap 사용량을 요청하는 엔드포인트다.
GET http://localhost:8080/actuator/metrics/jvm.memory.used?tag=area:heap
{ "name": "jvm.memory.used", "description": "The amount of used memory", "baseUnit": "bytes", "measurements": [ { "statistic": "VALUE", "value": 30753280 } ], "availableTags": [ { "tag": "id", "values": [ "G1 Survivor Space", "G1 Old Gen", "G1 Eden Space" ] } ] }
커스텀 metric 등록
애플리케이션 내의 필요한 지표를 사용자 정의하여 추가할 수 있다.
다음은 /hello, /failed-hello를 호출한 개수 지표를 metric으로 추가하고 success_count, failed_count를 type이름의 태그의 값으로 지정한 예를 보여준다.
package org.example.spring.actuator.example.metric; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import org.springframework.stereotype.Component; @Component public class HelloCallCount { private final MeterRegistry meterRegistry; public HelloCallCount( MeterRegistry meterRegistry ) { this.meterRegistry = meterRegistry; } public void addCounter(String type) { // MeterRegistry에 hello.callCount metric을 등록 meterRegistry.counter( "hello.callCount", Tags.of( "type", type ) ) .increment(); } }
Spring Boot가 MeterRegistry 빈을 자동으로 등록한다. (기본은 SimpleMeterRegistry, 운영 환경에서는 모니터링 시스템에 맞는 MeterRegistry를 보통 사용한다.)
HelloCallCount 클래스를 보면 MeterRegistry 인스턴스를 주입받고 addCounter()를 호출하는 순간에 hello.callCount 이름의 metric을 등록한다. (MeterRegistry에 등록) 태그 이름은 'type'이고 값은 동적으로 전달되는 type 파라미터 값이 되겠다.
Actuator Metrics Endpoint를 호출 시 MeterRegistry에 등록된 모든 Meter를 수집하여 /actuator/metrics 엔드포인트에 노출한다.
package org.example.spring.actuator.example.controller; import org.example.spring.actuator.example.metric.HelloCallCount; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { private final HelloCallCount helloCallCount; public HelloController(HelloCallCount helloCallCount) { this.helloCallCount = helloCallCount; } @GetMapping(path = "/hello") public String hello() { helloCallCount.addCounter( "success_count" ); return "Hello World"; } @GetMapping(path = "/failed-hello") public String failedHello() { helloCallCount.addCounter( "failed_count" ); return "Failed Hello World"; } }
/hello를 호출하면 type 태그의 success_count에 통계가 증가하고 /failed-hello를 호출하면 type태그의 failed_count에 통계가 증가한다.
GET http://localhost:8080/actuator/metrics를 호출하면 다음과 같이 hello.callCount metric이 추가된 것을 확인할 수 있다.
단, /actuator/metrics 호출 전에 /hello 혹은 /failed-hello가 호출되어야 생성된다. /actuator/metrics 호출 전에 /hello나 /failed-hello가 한 번도 호출되지 않았다면 helloCallCount.addCounter()가 호출되지 않았으므로 hello.callCount metric이 등록되지 않는다. 따라서 /actuator/metrics 호출 결과에 hello.callCount는 노출되지 않을 것이다. 또한 이 상태에서 /actuator/metrics/hello.callCount를 조회하면 404 응답 코드가 발생한다.
다음과 같이 /hello 2회, /failed-hello를 1회 호출했을 때 결과를 살펴보자.
GET http://localhost:8080/hello GET http://localhost:8080/hello GET http://localhost:8080/failed-hello
이후
GET http://localhost:8080/actuator/metrics/hello.callCount 호출 결과는 다음과 같다.
{ "name": "hello.callCount", "measurements": [ { "statistic": "COUNT", "value": 3 } ], "availableTags": [ { "tag": "type", "values": [ "success_count", "failed_count" ] } ] }
총 호출 횟수는 3회로 응답한다.
type 태그의 값으로 success_count, failed_count가 생성되었음을 확인할 수 있다.
GET http://localhost:8080/actuator/metrics/hello.callCount?tag=type:success_count
{ "name": "hello.callCount", "measurements": [ { "statistic": "COUNT", "value": 2 } ], "availableTags": [] }
success_count는 2로써 /hello 가 2번 호출되었다는 것을 확인할 수 있다.
GET http://localhost:8080/actuator/metrics/hello.callCount?tag=type:failed_count
{ "name": "hello.callCount", "measurements": [ { "statistic": "COUNT", "value": 1 } ], "availableTags": [] }
failed_count는 1로써 /failed-hello가 1번 호출되었다는 것을 확인할 수 있다.
https://docs.spring.io/spring-boot/reference/actuator/metrics.html는 metrics 엔드포인트와 연동 가능한 모니터링 시스템과 연동 방법에 대해서, 그리고 지원되는 메트릭에 대해서 정보를 제공한다.
끝.
반응형'스프링부트' 카테고리의 다른 글
Spring Boot Actuator - 4. Endpoint 커스텀 (0) 2025.09.24 Spring Boot Actuator - 3. Actuator 보안 (0) 2025.09.23 Spring Boot Actuator - 1. 시작하기 (0) 2025.09.17 Spring Boot JSON 처리를 위한 자동 구성 및 설정 (0) 2025.01.04 외부 설정 파일 로딩하기 (0) 2024.08.18 다음글이전글이전 글이 없습니다.댓글