Spring Boot Actuator: Production-ready Features
Opened this issue · 5 comments
- Spring Boot 에는 운영 환경 모니터링을 위한 여러 가지 기능이 있음
- HTTP 엔드포인트 or JMX 를 사용하여 애플리케이션을 관리하고 모니터링 가능 함
- Auditing, health, metrics 수집 또한 자동으로 적용 됨
1. Enabling Production-ready Features
spring-boot-actuator
모듈이 모든 운영 환경 기능을 제공한다- 가장 쉬운 방법은 spring-boot-starter-actuator ‘Starter’ 를 추가해라
Definition of Actuator
- 액츄에이터는 물건을 움직이거나 제어를 위한 기계 장치(제조 용어)
- 액츄에이터는 작은 변화로 많은 움직임(motion)을 생성할 수 있다.
dependencies {
compile("org.springframework.boot:spring-boot-starter-actuator")
}
2. Endpoints
-
액츄에이터 엔드포인트를 사용하면 애플리케이션을 모니터링하고 상호작용 가능하다
-
Spring Boot 에는 built-in 엔드포인트가 여러개 포함되어 있고, 사용자가 직접 추가도 가능하다
- 예를 들어,
health
엔드포인트는 애플리케이션의 기본 health 정보를 제공한다
- 예를 들어,
-
개별 엔드포인트는 비활성화 가능하다
- application context 에 엔드포인트 Bean 이 존재하는지 안하는지로 제어한다.
-
원격 접근 할려면 JMX or HTTP 로 노출(expose) 해야 한다
- 대개 HTTP를 쓴다
/actuator
과 함께 엔드포인트가 URL 에 매핑된다- 예를 들어, health 엔드포인트는
/actuator/health
- 예를 들어, health 엔드포인트는
-
사용 가능한 technology-agnostic endpoints
ID | Description |
---|---|
auditevents | Exposes audit events information for the current application. Requires an AuditEventRepository bean. |
beans | Displays a complete list of all the Spring beans in your application. |
caches | Exposes available caches. |
conditions | Shows the conditions that were evaluated on configuration and auto-configuration classes and the reasons why they did or did not match. |
configprops | Displays a collated list of all @ConfigurationProperties. |
env | Exposes properties from Spring’s ConfigurableEnvironment. |
flyway | Shows any Flyway database migrations that have been applied. Requires one or more Flyway beans. |
health | Shows application health information. |
httptrace | Displays HTTP trace information (by default, the last 100 HTTP request-response exchanges). Requires an HttpTraceRepository bean. |
info | Displays arbitrary application info. |
integrationgraph | Shows the Spring Integration graph. Requires a dependency on spring-integration-core. |
loggers | Shows and modifies the configuration of loggers in the application. |
liquibase | Shows any Liquibase database migrations that have been applied. Requires one or more Liquibase beans. |
metrics | Shows ‘metrics’ information for the current application. |
mappings | Displays a collated list of all @RequestMapping paths. |
scheduledtasks | Displays the scheduled tasks in your application. |
sessions | Allows retrieval and deletion of user sessions from a Spring Session-backed session store. Requires a Servlet-based web application using Spring Session. |
shutdown | Lets the application be gracefully shutdown. Disabled by default. |
threaddump | Performs a thread dump. |
- 웹 애플리케이션(Spring MVC, Spring WebFlux, or Jersey)인 경우 추가되는 엔드포인트
ID | Description |
---|---|
heapdump | Returns an hprof heap dump file. |
jolokia | Exposes JMX beans over HTTP (when Jolokia is on the classpath, not available for WebFlux). Requires a dependency on jolokia-core. |
logfile | Returns the contents of the logfile (if logging.file.name or logging.file.path properties have been set). Supports the use of the HTTP Range header to retrieve part of the log file’s content. |
prometheus | Exposes metrics in a format that can be scraped by a Prometheus server. Requires a dependency on micrometer-registry-prometheus. |
- 엔드포인트 요청 및 응답 형식은 다음 문서 참고
2.1. Enabling Endpoints
- 기본적으로
shutdown
을 제외한 모든 엔드포인트는 활성화 management.endpoint.<id>.enabled
로 컨트롤 가능shutdown
엔드포인트 활성화 하기
management.endpoint.shutdown.enabled=true
- 엔드포인트 활성화를 사전동의 없이(opt-out) 하는것보다 사전 동의를 받게끔(opt-in)으로 할려면
management.endpoints.enabled-by-default
를false
로 해라.- 개별적인 엔드포인트를
enabled
해라
- 개별적인 엔드포인트를
- 다음 예제는
info
엔드포인트를 enabled 하고 다른 모든 엔드포인트들을 disables 한다.
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
diasbled 엔드포인트는 애플리케이션 컨텍스트에서 완전히 제거된다. 기술적인 변화로 expose 를 원한다면, include and exclude properties 를 대신 써라
2.2 Exposing Endpoints
- 엔드포인트는 민감한 정보를 포함할 수 있으므로, expose 시기를 신중하게 고려해라
- 다음은 built-in 엔드포인트의 기본 exposure 테이블이다
ID | JMX | Web |
---|---|---|
auditevents | Yes | No |
beans | Yes | No |
caches | Yes | No |
conditions | Yes | No |
configprops | Yes | No |
env | Yes | No |
flyway | Yes | No |
health | Yes | Yes |
heapdump | N/A | No |
httptrace | Yes | No |
info | Yes | Yes |
integrationgraph | Yes | No |
jolokia | N/A | No |
logfile | N/A | No |
loggers | Yes | No |
liquibase | Yes | No |
metrics | Yes | No |
mappings | Yes | No |
prometheus | N/A | No |
scheduledtasks | Yes | No |
sessions | Yes | No |
shutdown | Yes | No |
threaddump | Yes | No |
- expose 엔드포인트를 바꾸고 싶다면, include and exclude properties 를 써라
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude | |
management.endpoints.jmx.exposure.include | * |
management.endpoints.web.exposure.exclude | |
management.endpoints.web.exposure.include | info, health |
include
는 expose 를 원하는 엔드포인트의 IDs 목록이다.exclude
는 반대로 expose 를 원하지 않는 엔드포인트의 IDs 목록이다.exclude
가include
보다 우선순위가 높다- 예를 들어, JMX 엔드포인트 expose 는 모두 중지하고,
health
와info
엔드포인트만 expose 하고 싶다면?
management.endpoints.jmx.exposure.include=health,info
*
로 모든 엔드포인트 선택 가능- 예를 들어,
env
와beans
을 제외한 모든 것을 HTTP 를 통해 expose 하고 싶다면?
- 예를 들어,
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
*
는 YAML 에서 특별한 의미가 있으므로, 따옴표를 추가 해야 함
management:
endpoints:
web:
exposure:
include: "*"
엔드포인트가 public 하게 expose 되어 있다면 엔드포인트 보안이 필요하다
엔드포인트에 대한 별도 전략이 필요하면
EndpointFilter
bean 을 등록 해라
2.3. Securing HTTP Endpoints
- 다른 민감한 URL 과 마찬가지로 HTTP 엔드포인트도 보호해야 한다
- Spring Security 가 있다면, content-negotiation strategy 으로 기본적으로 보호된다
- 예를 들어, 특정 role 을 가진 사용자만 HTTP 엔드포인트에 커스텀 보안을 적용하려는 경우, Spring Security 와 함께
RequestMatcher
를 제공한다 - 일반적인 Spring Security 구성은 다음과 유사하다
@Configuration(proxyBeanMethods = false)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
http.httpBasic();
}
}
- 위 코드는
EndpointRequest.toAnyEndpoint()
는 모든 엔드포인트를 말하고,ENDPOINT_ADMIN
role 을 가졌는지 검사 - 방화벽 뒤에서 애플리케이션을 배포하는 경우, 인증 없이 모든 엔드포인트에 접근할 수 있다.
management.endpoints.web.exposure.include=*
- 추가적으로 미인증 접근에 대해서 엔드포인트 접근을 허용하기 위해선
@Configuration(proxyBeanMethods = false)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
requests.anyRequest().permitAll());
}
}
2.4. Configuring Endpoints
- 엔드포인트는 파라미터 없는 읽기 작업은 자동으로 캐싱한다
cache.time-to-live
로 응답 캐시 시간을 설정 가능- 다음 예제는 10초 캐싱
management.endpoint.beans.cache.time-to-live=10s
management.endpoint.<name>
는 고유하게 식별하는데 사용된다.
인증된 HTTP 요청 시,Principal
이 엔드포인트 입력에 사용되므로, 캐시 되지 않는다
2.5. Hypermedia for Actuator Web Endpoints
- 모든 엔드포인트의 "discovery page" 링크가 추가된다.
- 기본적으로
/actuator
에서 이용 가능
- 기본적으로
- 커스텀 management context path 가 구성되면 "discovery page" 가 자동으로
/actuator
에서 root management context 로 이동한다.- context path 가
/management
이면, discovery page 는/management
에서 이용 가능 - context path 가
/
면 다른 매핑과의 충돌 방지를 위해 disabled 된다.
- context path 가
2.6. CORS Support
- Cross-origin resource sharing (CORS) 는 W3C 스펙으로, cross-domain 요청이 승인 되는지 유연하게 지정할 수 있다
- Spring MVC or Spring WebFlux 의 액츄에이터에서는 이러한 시나리오를 구성할 수 있는 웹 엔드포인트가 있다
- CORS 는 기본적으로 disabled 다.
management.endpoints.web.cors.allowed-origins
로 활성화 가능. - 다음 구성은 example.com 도메인에서 GET 및 POST 호출을 허용합니다.
management.endpoints.web.cors.allowed-origins=https://example.com
management.endpoints.web.cors.allowed-methods=GET,POST
2.7. Implementing Custom Endpoints
- @bean 과 @endpoint 을 함께 붙히고, @ReadOperation, @WriteOperation, or @DeleteOperation 중에 하나 있으면, JMX 나 웹 HTTP 로 expose 된다
- @JmxEndpoint or @WebEndpoint 로 JMX or Web 으로만 expose 가능
- @EndpointWebExtension and @EndpointJmxExtension 으로 더 확장 가능 하다.
- web-framework-specific 기능에 접근해야 하면, Spring @controller and @RestController 엔드포인트를 구현하면 된다.
2.7.1. Receiving Input
- 엔드포인트 조작은 파라미터를 입력받아서 한다
- 웹으로 expose 할때, URL 쿼리 파라미터 및 JSON 본문으로 전달 함
- JMX 로 expose 할때에는, MBean 파라미터로 조작
- 기본적으로 파라미터가 필수로 요구되는데,
@org.springframework.lang.Nullable
로 선택적으로 만들 수 있다 - JSON 요청 바디
{
"name": "test",
"counter": 42
}
메소드 구조는 단순한 타입(int, String 등)만 가능. 커스텀타입으로
name
과counter
프로퍼티를 사용할 수 없다.
매핑된 input 파라미터를 조작하려면 엔드포인트 구현체를-parameters
로 컴파일 해야 한다 (Kotlin 은-java-parameters
) Gradle, Maven 에서spring-boot-starter-parent
를 쓰고 있다면 자동으로 사용된다
Input type conversion
- 엔드포인트의 operation 메소드로 전달된 파라미터는 필요한 경우 자동으로 필수 타입(required type)으로 바뀐다.
- operation 메소드가 호출 전에, JMX or HTTP 요청을 통해 입력된 파라미터는 ApplicationConversionService as well as any Converter or GenericConverter beans qualified with @EndpointConverter 를 통해 필수 타입으로 바뀜
2.7.2. Custom Web Endpoints
- @endpoint, @WebEndpoint, or @EndpointWebExtension 은 Jersey, Spring MVC, or Spring WebFlux 를 사용해서 HTTP 로 자동으로 expose 된다
Web Endpoint Request Predicates
- web-exposed endpoint 에서 각 요청의 predicate 는 자동으로 생성 된다
Path
- predicate 는 엔드포인트 ID 와 엔드포인트의 base path 기준으로 결정된다
- 기본 base path 는
/actuator
이다 - 예를 들어 ID
sessions
인 경우, predicate 의 path 는/actuator/sessions
이다
- 기본 base path 는
@Selector
와 파라미터 조합으로 커스터마이징 가능- 모든 path 엘리먼트를 챕켜 하려면
@Selector(Match=ALL_REMAINING)
- 마지막 파라미터를
String[]
타입으로 넣을 수 있음
- 모든 path 엘리먼트를 챕켜 하려면
HTTP method
Operation | HTTP method |
---|---|
@ReadOperation | GET |
@WriteOperation | POST |
@DeleteOperation | DELETE |
Consumes
- @WriteOperation (HTTP POST) 를 붙히면, predicate 는
application/vnd.spring-boot.actuator.v2+json, application/json
이다. - 다른 모든 operations 는 empty 로 consume 한다
Produces
- @DeleteOperation, @ReadOperation, and @WriteOperation 로 predicate 는 produces 가 판별한다
- 사용 안하면, 자동으로 결정한다
- operation 메소드 가 void 를 응답하면, produce 는 empty 가 된다.
- org.springframework.core.io.Resource 를 응답하면,
application/octet-stream
이다 - 다른 모든 operations 는
application/vnd.spring-boot.actuator.v2+json, application/json
이다
Web Endpoint Response Status
- 엔드포인트 operation 의 기본 응답 status 는 operation type (read, write, or delete) 에 따라 다르다
- @ReadOperation 응답시, 응답 status 은 200 (OK) 이다. 응답 값이 없으면, 404 (Not Found)
- @WriteOperation or @DeleteOperation 응답시, 200 (OK) 이다. 응답 값이 없으면, 204 (No Content)
- 필수 파라미터 없이 호출, 필수 타입으로 변환 할수 없는 파라미터 등의 operation method 는 400 (Bad Request)
Web Endpoint Range Requests
- Spring MVC or Spring Web Flux 에서 org.springframework.core.io.Resource 가 range 요청 지원 함
Jersy 에서는 Range 요청 안 됨
Web Endpoint Security
- web-specific endpoint 조작은 현재 java.security.Principal 나 org.springframework.boot.actuate.endpoint.SecurityContext 로 가능하다
- 전자는 전형적으로 @nullable 를 주입받아 인증된 사용자, 미인증 사용자가 다르게 행동한다
- 후자는 isUserInRole(String) 메소드에서 권한 체크하는데 쓰인다
2.7.3. Servlet endpoints
- Servlet 의 @ServletEndpoint that also implements Supplier 도 구현을 통해 엔드포인트 expose 가능
- Servlet 엔드포인트는 서블릿 컨테이너와 깊이 연관되는걸 제공하지만, portability 을 포기한다
- 기존의 서블릿을 expose 한다
- 새 엔드포인트를 원하면 @endpoint and @WebEndpoint 로 헤리
2.7.4. Controller endpoints
- @ControllerEndpoint and @RestControllerEndpoint 은 Spring MVC or Spring WebFlux 에서만 expose 되는 엔드포인트를 구현할 수 있다
- @RequestMapping and @GetMapping 처럼 Spring MVC and Spring WebFlux 에서 쓰는 애너테이션을 쓰면 매핑되고, 엔드포인트 ID 는 path 의 prefix 로 사용 됨
- 컨트롤러 엔드포인트는 Spring’s web frameworks와 깊이 연관되는걸 제공하지만, portability 을 포기한다
- @endpoint and @WebEndpoint 사용 가능
2.8. Health Information
- 실행중인 애플리케이션 health 정보 확인 가능
- production 시스템이 다운되면 모니터링 하다가 알림 하는데 사용하기 좋다
health
엔드포인트로 expose 된다management.endpoint.health.show-details
와management.endpoint.health.show-components
로 구성 가능
Name | Description |
---|---|
never | Details are never shown. |
when-authorized | Details are only shown to authorized users. Authorized roles can be configured using management.endpoint.health.roles. |
always | Details are shown to all users. |
- 기본값은
never
- 사용자는 하나 이상의 엔드포인트 role 이 있다면 인증되었다고 간주된다
- 엔드포인트에 구성된 role이 없다면(default) 모든 사용자는 인증되었다고 간주된다
management.endpoint.health.roles
로 구성 가능
always
를 사용하여 secured 애플리케이션을 가졌다면, 인증사용자와 미인증사용자 둘다 health 엔드포인트에 접근 가능해야만 한다(must)
- Health 정보는
HealthContributorRegistry
에서 수집 한다. (기본적으로 HealthContributor 객체)- 직접 작성도 가능
HealthContributor
는HealthIndicator
orCompositeHealthContributor
로 될 수 있다.HealthIndicator
는Status
를 포함하는 실제 health 정보를 제공CompositeHealthContributor
는 다른HealthContributors
와 혼합을 제공
- 기본적으로 최종 health 시스템은
StatusAggregator
(HealthIndicator 에서 status 를 정렬한) 에서 유래한다.- 정렬된 목록에서 첫번째 status 는 전체 health status 다
HealthIndicator
응답이 없다면 UNKNOWN status 가 사용된다
HealthContributorRegistry
는 런타임으로 health indicator 를 등록 및 해제할때 쓴다
2.8.1. Auto-configured HealthIndicators
- 자동 구성되는
HealthIndicators
Name | Description |
---|---|
CassandraHealthIndicator | Checks that a Cassandra database is up. |
CouchbaseHealthIndicator | Checks that a Couchbase cluster is up. |
DiskSpaceHealthIndicator | Checks for low disk space. |
ElasticSearchRestHealthContributorAutoConfiguration | Checks that an Elasticsearch cluster is up. |
HazelcastHealthIndicator | Checks that a Hazelcast server is up. |
InfluxDbHealthIndicator | Checks that an InfluxDB server is up. |
JmsHealthIndicator | Checks that a JMS broker is up. |
LdapHealthIndicator | Checks that an LDAP server is up. |
MailHealthIndicator | Checks that a mail server is up. |
MongoHealthIndicator | Checks that a Mongo database is up. |
Neo4jHealthIndicator | Checks that a Neo4j database is up. |
PingHealthIndicator | Always responds with UP. |
RabbitHealthIndicator | Checks that a Rabbit server is up. |
RedisHealthIndicator | Checks that a Redis server is up. |
SolrHealthIndicator | Checks that a Solr server is up. |
management.health.defaults.enabled
로 모두 diable 할 수 있음
2.8.2. Writing Custom HealthIndicators
HealthIndicator
인터페이스 구현해서 커스터마이징 해라health()
메소드와Health
응답 반환을 제공해라Health
응답은 status 를 포함해야 하고, 선택적으로 세부 정보도 넣을 수 있다
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
}
주어진
HealthIndicator
ID 는 HealthIndicator suffix 를 뺀 bean 이다. 위의 경우my
- Spring Boot 는 이미 정의된
Status
타입 말고도 사용자 정의 가능함StatusAggregator
를 구현하거나,management.endpoint.health.status.order
를 설정해라
- 예를 들어, FATAL Status 를 가진
HealthIndicator
구현체가 있을때, severity 우선순위 대로 적으면 된다
management.endpoint.health.status.order=fatal,down,out-of-service,unknown,up
- 전체 health 의 응답 HTTP status 코드를 반영한다. (ex UP 은 200, OUT_OF_SERVICE and DOWN 는 503)
- 사용자 정의 가능함. FATAL 을 503 으로 설정
management.endpoint.health.status.http-mapping.fatal=503
더 많이 조절해야 하면, HttpCodeStatusMapper Bean 을 정의해라
- 내장된 기본 status 매핑
Status | Mapping |
---|---|
DOWN | SERVICE_UNAVAILABLE (503) |
OUT_OF_SERVICE | SERVICE_UNAVAILABLE (503) |
UP | No mapping by default, so http status is 200 |
UNKNOWN | No mapping by default, so http status is 200 |
2.8.3. Reactive Health Indicators
- Spring WebFlux 에서 ReactiveHealthContributor 은 non-blocking 으로 health 접근 가능
ReactiveHealthContributorRegistry
(기본적으로 HealthContributor and ReactiveHealthContributor 객체) 에서 컨텐츠 수집 함
- reactive API 를 하지 않는 일반적인
HealthContributors
는 스케쥴러로 실행 함
ReactiveHealthContributorRegistry
로 health indicator를 실시간으로 등록, 안등록
ReactiveHealthIndicator
인터페이스 구현 가능. 다음은ReactiveHealthIndicator
구현체를 보여줌
@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {
@Override
public Mono<Health> health() {
return doHealthCheck() //perform some specific health check that returns a Mono<Health>
.onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build()));
}
}
오류를 자동으로 처리하려면
AbstractReactiveHealthIndicator
를 확장해라
2.8.4. Auto-configured ReactiveHealthIndicators
- 자동구성되는
ReactiveHealthIndicators
Name | Description |
---|---|
CassandraReactiveHealthIndicator | Checks that a Cassandra database is up. |
CouchbaseReactiveHealthIndicator | Checks that a Couchbase cluster is up. |
MongoReactiveHealthIndicator | Checks that a Mongo database is up. |
RedisReactiveHealthIndicator | Checks that a Redis server is up. |
필요한 경우, reactive indicator 는 regular 로 대체된다. 명시적으로 처리 되지 않은
HealthIndicator
은 자동 래핑된다
2.8.5. Health Groups
- health indicators 를 그룹핑 할 수 있다
- Kubernetes 에 배포할때에는 “liveness” and “readiness” probes health 세트가 필요할 수 있다
- Health indicator 그룹을 만들려면
management.endpoint.health.group.<name>
를 써라- include or exclude 설정 가능
management.endpoint.health.group.custom.include=db
localhost:8080/actuator/health/custom
에서 확인 해봐라- 기본 그룹은 StatusAggregator and HttpCodeStatusMapper 설정을 상속 받음
- show-details and roles 로 재정의도 가능함
management.endpoint.health.group.custom.show-details=when-authorized
management.endpoint.health.group.custom.roles=admin
management.endpoint.health.group.custom.status.order=fatal,up
management.endpoint.health.group.custom.status.http-mapping.fatal=500
커스텀 StatusAggregator or HttpCodeStatusMapper 를 그룹으로 등록해야 하면,
@Qualifier("groupname")
를 써라
2.9. Application Information
ApplicationContext
에 정의된 모든InfoContributor
빈에서 수집된 다양한 정보를 expose 한다- 여러가지 자동구성된것도 있고, 직접 작성도 가능
2.9.1. Auto-configured InfoContributors
- 적절하게 알아서 자동구성
Name | Description |
---|---|
EnvironmentInfoContributor | Exposes any key from the Environment under the info key. |
GitInfoContributor | Exposes git information if a git.properties file is available. |
BuildInfoContributor | Exposes build information if a META-INF/build-info.properties file is available. |
management.info.defaults.enabled 로 모두 비활성 가능
2.9.2. Custom Application Information
info.*
으로 설정 가능info
아래 모든Environment
properties 가 자동으로 expose 된다.
info.app.encoding=UTF-8
info.app.java.source=1.8
info.app.java.target=1.8
이렇게 hardcoding 말고, 빌드시 주입 가능
info.app.encoding=@project.build.sourceEncoding@
info.app.java.source=@java.version@
info.app.java.target=@java.version@
2.9.3. Git Commit Information
- 빌드 될때
git
소스 코드 레파지터리에 대한 상태도 게시한다 GitProperties
빈이 사용 가능하면 git.branch, git.commit.id, and git.commit.time 가 expose 된다
git.properties
파일이 사용 가능하면GitProperties
빈은 자동구성 됨
- 전체 git 정보 표시를 원하면 이렇게 해라
management.info.git.mode=full
2.9.4. Build Information
BuildProperties
빈이 사용 가능하면,info
엔드포인트가 빌드 정보를 게시한다.META-INF/build-info.properties
파일이 classpath 에 있어야 한다
Gradle, Maven 플러그인으로 지원
2.9.5. Writing Custom InfoContributors
InfoContributor
인터페이스를 구현하면 커스텀 가능
import java.util.Collections;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class ExampleInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("example",
Collections.singletonMap("key", "value"));
}
}
- 응답은?
{
"example": {
"key" : "value"
}
}
3. Monitoring and Management over HTTP
- 웹 애플리케이션을 개발하면, 스프링 부트 Actuator 는 모든 활성화된 엔드포인트를 HTTP 로 expose 한다
- 기본 컨벤션은 엔드포인트 id 와
/actuator
prefix 를 사용하는 URL path 다.- 예를 들어
health
는/actuator/health
로 expose 한다
- 예를 들어
Actuator 는 기본적으로 Spring MVC, Spring WebFlux, and Jersey 를 지원한다.
3.1. Customizing the Management Endpoint Paths
- 때로는 커스텀 prefix 를 management 엔드포인트로 쓰는것이 유용하다.
- 예를 들어, 애플리케이션이 다른 목적으로
actuator
를 사용중이라면,management.endpoints.web.base-path
로 management 엔드포인트 prefix 를 바꿀 수 있다.
- 예를 들어, 애플리케이션이 다른 목적으로
management.endpoints.web.base-path=/manage
- 위에서는
/actuator/{id}
to/manage/{id}
(for example,/manage/info
). 로 바뀐다
management 포트가 다른 HTTP 포트로 구성되어 expose 안되었을 경우,
management.endpoints.web.base-path
는server.servlet.context-path
와 관련된다. 만약management.server.port
가 구성되면,management.endpoints.web.base-path
는management.server.servlet.context-path
와 관련된다.
- 엔드포인트를 다른 path 로 맵 하고 싶을때는
management.endpoints.web.path-mapping
를 써라 - 다음은
/actuator/health
to/healthcheck
로 리맵하는 예제다
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck
3.2. Customizing the Management Server Port
- 기본 HTTP port 로 management 엔드포인트를 expose 하는것은 cloud-based 배포에서는 현명한 선택이다
- 그러나 자체 데이터 센터에서 애플리케이션을 실행한다면, 다른 HTTP 포트를 사용하는 것이 좋다
management.server.port
로 바꿀수 있다
management.server.port=8081
Cloud Foundry 에서는 8080 port 에서 HTTP 와 TCP 라우팅을 요청을 받습니다.
3.3. Configuring Management-specific SSL
- 커스텀 포트로 구성했을때 management 서버는
management.server.ssl.*
를 이용해 SSL 로 구성할 수 있다. - 예를 들어, 메인 애플리케이션은 HTTPS 를 쓰지만, management 서버는 HTTP 를 쓰도록 핟다.
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:store.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=false
- 그렇지 않으면, 메인 서버와 management 서버 둘다 SSL 을 사용할 수 있다. (다른 key stores)
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:main.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=true
management.server.ssl.key-store=classpath:management.jks
management.server.ssl.key-password=secret
3.4. Customizing the Management Server Address
management.server.address
로 management 엔드포인트가 사용 가능한 adress 를 커스텀 가능- internal or ops-facing(?) 네트워트만 listen 하고 싶거나
localhost
만 listen 하고 싶을때 유용하다.
메인 서버 포트와 달라야만 다른 address 에서 listen 가능하다
- 다음 예제에서는 원격 management 연결을 허용하지 않는다
management.server.port=8081
management.server.address=127.0.0.1
3.5. Disabling HTTP Endpoints
- HTTP 로 엔드포인트를 expose 하고 싶지 않다면, management port 를 -1 로 해라
management.server.port=-1
management.endpoints.web.exposure.exclude
를 써도 된다
management.endpoints.web.exposure.exclude=*
4. Monitoring and Management over JMX
- Java Management Extensions (JMX) 은 애플리케이션을 관리하고 모니터를 하는 표준 메커니즘을 제공한다.
- 기본적으로 이 기능은 활성화 되어 있지 않고, spring.jmx.enabled to true 해야만 켤수 있다
- 스프링부트에서는 기본적으로 management 엔드포인트를 JMX MBeans 으로 expose 한다.
4.1. Customizing MBean Names
- MBean 은 일반적으로
id
엔드포인트로 생성 된다.- 예를 들어
health
엔드포인트는org.springframework.boot:type=Endpoint,name=Health
로 expose 된다
- 예를 들어
- 애플리케이션에 둘 이상의
ApplicationContext
가 있다면 충돌날 수 있다.- MBean 이 항상 유니크 하도록 spring.jmx.unique-names property to true 하면 된다
- JVX 도메인을 커스터마이징 하여 엔드포인트 노출 가능하다.
spring.jmx.unique-names=true
management.endpoints.jmx.domain=com.example.myapp
4.2. Disabling JMX Endpoints
- JMX 엔드포인트를 expose 원하지 않는다면 management.endpoints.jmx.exposure.exclude property to * 로 설정 해라
management.endpoints.jmx.exposure.exclude=*
4.3. Using Jolokia for JMX over HTTP
- Jolokia 는 JMX beans 에 접근 대체 방법을 제공하는 JMX-HTTP 브리지다.
org.jolokia:jolokia-core
를 추가해라
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
- 그런다음
management.endpoints.web.exposure.include
에 jolokia or * 을 넣으면, Jolokia 엔드포인트가 expose 된다- management HTTP 서버에서
/actuator/jolokia
로 접근 가능
- management HTTP 서버에서
4.3.1. Customizing Jolokia
- 전통적으로 서블릿 파라미터를 통해 세팅 가능하다
- 스프링부트에서는
management.endpoint.jolokia.config.
로 설정 가능하다
management.endpoint.jolokia.config.debug=true
4.3.2. Disabling Jolokia
- Jolokia 를 쓰지만 스프링부트에서 안 쓸려면
management.endpoint.jolokia.enabled=false
5. Loggers
- Spring Boot Actuator 는 런타임시 애플리케이션 로그 레벨을 보고 설정 가능한 기능이 포함되어 있다
- 로그 레벨
- TRACE
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
- OFF
- null
- null indicates 은 명시적인 구성이 없음을 말함
5.1. Configure a Logger
- 주어진 로거를 구성하기 위해 resource’s URI 에 POST 해라
{
"configuredLevel": "DEBUG"
}
로거 레벨을 "reset" 하기 위해(기본 구성을 사용하려고),
configuredLevel
을null
로 할 수 있다.
6. Metrics
- Spring Boot Actuator 는 많은 모니터링 시스템과 애플리케이션 메트릭인 Micrometer를 자동구성과 의존성 관리를제공한다.
6.1. Getting started
- 스프링부트는 혼합된
MeterRegistry
를 자동구성하고, classpath 에서 알맞은 registry 도 추가 함micrometer-registry-{system}
가 있으면 됨
- 대부분의 registries 는 공통 기능을 공유한다
- 예를 들어, Micrometer registry 구현체가 classpath에 있어도 disable 가능하다
- Datadog disable
management.metrics.export.datadog.enabled=false
- 스프링부트는 명시적으로 설정하지 않는 한, 자동구성된 registries 를 글로벌 스태틱 registry 인
Metrics
에 추가한다.- 명시적으로 등록 안할려면?
management.metrics.use-global-registry=false
- meters 가 registry 에 등록되기 전에(공통 태그 등) 추가로 구성하고 싶다면
MeterRegistryCustomizer
빈을 등록가능하다.
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("region", "us-east-1");
}
- generic type 으로, 부분적인 registry 구현체를 커스터마이징 가능
@Bean
MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
return registry -> registry.config().namingConvention(MY_CUSTOM_CONVENTION);
}
- 컴포넌트의
MeterRegistry
에 주입 가능하고, metrics 을 등록할 수 있다
@Component
public class SampleBean {
private final Counter counter;
public SampleBean(MeterRegistry registry) {
this.counter = registry.counter("received.messages");
}
public void handleMessage(String message) {
this.counter.increment();
// handle message implementation
}
}
- 스프링부트는 설정과 애너테이션으로 bulit-in instrumentation (i.e. MeterBinder implementations) 을 구성한다.
6.2. Supported monitoring systems
6.2.1. AppOptics
- 기본적으로 AppOptics registry 는
api.appoptics.com/v1/measurements
로 메트릭을 주기적으로 push 한다.- API token 은 필수다
management.metrics.export.appoptics.api-token=YOUR_TOKEN
6.2.5. Elastic
- 기본적으로 메트릭은 로컬머신에서 실행중인
Elastic
으로 export 된다. - 사용할 Elastic 서버는 다음과 같이 사용한다.
management.metrics.export.elastic.host=https://elastic.example.com:8086
6.2.13. Prometheus
- Prometheus 는 개별 앱 인스턴스의 메트릭을 poll 할것으로 기대한다.
- Spring Boot 는
/actuator/prometheus
액츄에이터 엔드포인트를 제공하고, Prometheus 가 scrape(긁어) 해갈수 있다
엔드포인트는 기본적으로 사용할 수 없기 때문에, expose 시켜야 한다
prometheus.yml
에scrape_config
을 추가한 예제이다.
scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['HOST:PORT']
- ephemeral(수명이 짧은) 혹은 배치 잡에서 Prometheus Pushgateway 를 통해 Prometheus 로 메트릭을 expose 할 수 있다.
- Prometheus Pushgateway 사용하려면 디펜던시 추가 필요
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>
- classpath에 위 디펜던시가 있다면
PrometheusPushGatewayManager
를 자동구성 함management.metrics.export.prometheus.pushgateway
로도 설정 가능
6.2.15. Simple
- Micrometer 는 다른 registry가 구성되어 있지 않다면, 간단한 in-memory 로 자동구성 한다. 이를 통해 어떤 메트릭이 수집되는지 확인 가능하다
- 사용가능한 다른 backend 가 있다면 득시 disable 된다
- 명시적인 비활성
management.metrics.export.simple.enabled=false
6.3. Supported Metrics
- JVM metrics, report utilization of:
- Various memory and buffer pools
- Statistics related to garbage collection
*Threads utilization - Number of classes loaded/unloaded
- CPU metrics
- File descriptor metrics
- Kafka consumer metrics
- Log4j2 metrics: record the number of events logged to Log4j2 at each level
- Logback metrics: record the number of events logged to Logback at each level
- Uptime metrics: report a gauge for uptime and a fixed gauge representing the application’s absolute start time
- Tomcat metrics (server.tomcat.mbeanregistry.enabled must be set to true for all Tomcat metrics to be registered)
- Spring Integration metrics
6.3.1. Spring MVC Metrics
- 자동구성으로 Spring MVC 가 처리하는 요청을 계측가능하다
management.metrics.web.server.request.autotime.enabled
가true
이면 모든 요청을 계측.false
이면@Timed
붙은 것만 계측
@RestController
@Timed
public class MyController {
@GetMapping("/api/people")
@Timed(extraTags = { "region", "us-east-1" })
@Timed(value = "all.people", longTask = true)
public List<Person> listPeople() { ... }
}
-
컨트롤러로 들어오는 모든 요청의 timings 을 활성화
-
개별적인 엔드포인트 활성화.
-
long task 일 경우
longTask = true
붙힘- Long task timers 는 별도의 메트릭 이름이 필요하고, short 태스크 타이머도 쌓일 수 있음
-
기본적으로 메트릭 이름은
http.server.requests
로 생성 됨management.metrics.web.server.request.metric-name
로 커스텀 가능
-
기본적인 Spring MVC-related 메트릭 정보는 다음의 표처럼 tag 됨
Tag | Description |
---|---|
exception | Simple class name of any exception that was thrown while handling the request. |
method | Request’s method (for example, GET or POST) |
outcome | Request’s outcome based on the status code of the response. 1xx is INFORMATIONAL, 2xx is SUCCESS, 3xx is REDIRECTION, 4xx CLIENT_ERROR, and 5xx is SERVER_ERROR |
status | Response’s HTTP status code (for example, 200 or 500) |
uri | Request’s URI template prior to variable substitution, if possible (for example, /api/person/{id}) |
WebMvcTagsProvider
구현해서 커스터마이징 가능
6.3.2. Spring WebFlux Metrics
- 자동구성으로 WebFlux 컨트롤러나 functional 핸들러를 통한 모든 요청을 계측 가능하다
- 기본적으로 메트릭 이름은
http.server.requests
로 생성 됨management.metrics.web.server.request.metric-name
로 커스텀 가능
- 기본적인 WebFlux-related 메트릭 정보는 다음의 표처럼 tag 됨
Tag | Description |
---|---|
exception | Simple class name of any exception that was thrown while handling the request. |
method | Request’s method (for example, GET or POST) |
outcome | Request’s outcome based on the status code of the response. 1xx is INFORMATIONAL, 2xx is SUCCESS, 3xx is REDIRECTION, 4xx CLIENT_ERROR, and 5xx is SERVER_ERROR |
status | Response’s HTTP status code (for example, 200 or 500) |
uri | Request’s URI template prior to variable substitution, if possible (for example, /api/person/{id}) |
WebFluxTagsProvider
구현해서 커스터마이징 가능
6.3.3. Jersey Server Metrics
- 생략
6.3.4. HTTP Client Metrics
- Spring Boot Actuator 는
RestTemplate
와WebClient
의 계측도 관리한다- 이를 위해 자동구성된 빌더를 inject 하고 객체를 만들어야 한다
- RestTemplateBuilder for RestTemplate
- WebClient.Builder for WebClient
MetricsRestTemplateCustomizer
나MetricsWebClientCustomizer
로 수동으로 커스터마이징 가능
- 이를 위해 자동구성된 빌더를 inject 하고 객체를 만들어야 한다
- 기본적으로 메트릭 이름은
http.server.requests
로 생성 됨management.metrics.web.server.request.metric-name
로 커스텀 가능
- 기본적인 메트릭 정보는 다음의 표처럼 tag 됨
Tag | Description |
---|---|
clientName | Host portion of the URI |
method | Request’s method (for example, GET or POST) |
outcome | Request’s outcome based on the status code of the response. 1xx is INFORMATIONAL, 2xx is SUCCESS, 3xx is REDIRECTION, 4xx CLIENT_ERROR, and 5xx is SERVER_ERROR, UNKNOWN otherwise |
status | Response’s HTTP status code if available (for example, 200 or 500), or IO_ERROR in case of I/O issues, CLIENT_ERROR otherwise |
uri | Request’s URI template prior to variable substitution, if possible (for example, /api/person/{id}) |
- 태그 커스터마이징을 하기 위해선
RestTemplateExchangeTagsProvider
나WebClientExchangeTagsProvider
를 구현면 됨- 또한 편리한 static functions 가
RestTemplateExchangeTags
와WebClientExchangeTags
에 있음
- 또한 편리한 static functions 가
6.3.5. Cache Metrics
- 자동구성으로 startup 시
cache
prefix 붙은 사용가능한 모든Cache
를 계측 가능하다 - 캐시 계측은 기본 메트릭 세트로 표준화 되었음
- 추가적인 캐시 라이브리리들
- Caffeine
- EhCache 2
- Hazelcast
- Any compliant JCache (JSR-107) implementation
- 메트릭은 태그는
CacheManager
에 있는 cacheName 으로 된다
오로지 startup 시에 이용가능한 캐시만 bound 된다. on-the-fly 혹은 startup 이후 프로그래밍적으로 만들려면, 명시적으로 등록해라.
CacheMetricsRegistrar
bean 은 프로세스를 보다 쉽게 해준다
6.3.6. DataSource Metrics
- 자동구성으로 시
jdbc.connections
prefix 붙은 사용가능한 모든DataSource
를 계측 가능하다 - Data source 계측으로 currently active, idle, maximum allowed, and minimum allowed connections in the pool 을 알 수 있다
- 메트릭은
DataSource
의 bean 이름 기반으로 태그 된다
기본적으로 스프링부트가 제공하는 모든 data sources 의 메타데이터를 제공한다. 별도로 추가하려면
DataSourcePoolMetadataProvider
bean 을 만들어라.DataSourcePoolMetadataProvidersConfiguration
에 예제 있음
- Hikari-specific metrics 은
hikaricp
prefix 로 expose 된다. 각 메트릭은 풀 이름으로 태그 된다. (spring.datasource.name
로 조절 가능)
6.3.7. Hibernate Metrics
- 자동구성으로 이용가능한 Hibernate
EntityManagerFactory
객체를hibernate
란 이름으로 계측 된다 - 메트릭은
EntityManagerFactory
bean 이름으로 태그된다 - 표준 JPA 설정을 enable 해야 한다.
hibernate.generate_statistics
- 다음 예제처럼 자동구성된
EntityManagerFactory
를 활성화 한다
spring.jpa.properties.hibernate.generate_statistics=true
6.3.8. RabbitMQ Metrics
- 자동구성으로 이용가능한 모든 RabbitMQ 커넥션 팩토리를
rabbitmq
란 이름으로 계측가능하다
6.4. Registering custom metrics
- 커스텀 메트릭을 등록하려면
MeterRegistry
를 컨포넌트로 주입하라
class Dictionary {
private final List<String> words = new CopyOnWriteArrayList<>();
Dictionary(MeterRegistry registry) {
registry.gaugeCollectionSize("dictionary.size", Tags.empty(), this.words);
}
// …
}
- 반복적으로 메트릭을 계측하려면
MeterBinder
구현체를 캡슐화 한다- 기본적으로 모든
MeterBinder
beans 은 자동으로 Spring-managedMeterRegistry
에 바인드 된다
- 기본적으로 모든
6.5. Customizing individual metrics
- 특정
Meter
객체를 커스텀해야 한다면,io.micrometer.core.instrument.config.MeterFilter
객체를 이용해라- 기본적으로 모든
MeterFilter
beans 은 자동으로MeterRegistry.Config
마이크로미터에 적용된다
- 기본적으로 모든
- 예를들어
com.example
로 시작하는 모든 meter IDs 의mytag.region
태그 이름을mytag.area
로 바꾸려면 다음과 같이 해라
@Bean
public MeterFilter renameRegionTagMeterFilter() {
return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
}
6.5.1. Common tags
- Common 태그는 일반적으로 운영 환경의 dimensional drill-down 에 사용된다. (host, instance, region, stack, etc.)
- Common 태그는 모든 meters 에 적용되며 다음과 같이 구성 가능하다
management.metrics.tags.region=us-east-1
management.metrics.tags.stack=prod
- 위 설정은 모든 meter로
region
과stack
태그를us-east-1
와prod
에 추가한다.
Graphite 를 사용할때에는 common 태그의 순서가 중요하다. 이 방법으로는 common 태그의 순서를 보장하지 못하므로, Graphite 사용자는
MeterFilter
를 정의해서 쓰는게 낫다
6.5.2. Per-meter properties
MeterFilter
beans 이외에도 properties 를 사용해서 per-meter 제한된 커스텀이 가능하다- Per-meter 커스텀은 주어진 이름으로 시작하는 모든 meter IDs 에 적용된다
- 예를 들어 다음은
example.remote
로 시작하는 ID 를 disable 한다
- 예를 들어 다음은
management.metrics.enable.example.remote=false
Table 1. Per-meter customizations
Property | Description |
---|---|
management.metrics.enable | Whether to deny meters from emitting any metrics. |
management.metrics.distribution.percentiles-histogram | Whether to publish a histogram suitable for computing aggregable (across dimension) percentile approximations. |
management.metrics.distribution.minimum-expected-value, management.metrics.distribution.maximum-expected-value | Publish less histogram buckets by clamping the range of expected values. |
management.metrics.distribution.percentiles | Publish percentile values computed in your application |
management.metrics.distribution.sla | Publish a cumulative histogram with buckets defined by your SLAs. |
percentiles-histogram
percentiles
sla
개념에 대한 자세한 것은 "Histograms and percentiles" section 참고
6.6. Metrics endpoint
- Spring Boot 는 수집한 메트릭을 검사하는
metrics
엔드포엔트를 제공한다- 기본적으로 이용못하지만 expose 해야만 한다.
/actuator/metrics
에 가보면 이용가능한 meter 이름 목록이 있다- 특정 meter 에 대한 정보를 디릴 다운 가능하다.
- e.g.
/actuator/metrics/jvm.memory.max
여기에서 사용하는 이름은 코드와 일치해야 한다. Prometheus 에서는
jvm.memory.max
는jvm_memory_max
로 나타내므로, 엔드포인트에서 meter 를 검사할때jvm.memory.max
를 사용 해야 한다
- 또한
tag=KEY:VALUE
쿼리 파라미터를 URL 끝에 추가할 수 있다.- e.g.
/actuator/metrics/jvm.memory.max?tag=area:nonheap
- e.g.
reported 된 측정치는 미터 이름, 태그와 일치하는 모든 통계의 합(sum) 이다. 따라서 위 응답의 "Value" 는 "Code Cache", "Compressed Class Space", and "Metaspace" areas of the heap 의 합이다. 메타스페이스의 최대 크기를 알고 싶다면
tag=id:Metaspace
를 추가해라. i.e./actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace
7. Auditing
- Spring Security 가 실행되면 Spring Boot Actuator 는 이벤트를 publish 하는 유연한 audit 프레임워크를 갖는다.
- by default, “authentication success”, “failure” and “access denied” exceptions
- 이는 인증 실패를 기반으로 잠금 정책(lock-out policy) 구현하는데 유용하다
AuditEventRepository
로 구성하여 활성화 가능- Spring Boot 는
InMemoryAuditEventRepository
제공한다InMemoryAuditEventRepository
는 기능이 제한적이라 개발 환경에서만 써라- 프로덕션 환경에서는
AuditEventRepository
를 직접 만들어라
7.1. Custom Auditing
- publish 된 보안 이벤트를 커스텀 하기 위해
AbstractAuthenticationAuditListener
AbstractAuthorizationAuditListener
구현해라 - 자체적인 비지니스 이벤트 audit 사용도 가능하다
AuditEventRepository
빈 직접 주입AuditApplicationEvent
ApplicationEventPublisher
구현 (by implementing ApplicationEventPublisherAware)
8. HTTP Tracing
- HttpTraceRepository 타입을 HTTP 추적(Tracing) 가능
- 편의상 스프링부트가
InMemoryHttpTraceRepository
제공하는데 마지막 100개의 요청-응답을 추적가능하다InMemoryHttpTraceRepository
는 개발환경에서만 쓰고, 프로덕션에서는 Zipkin, Spring Cloud Sleuth 추천한다
- 혹은
HttpTraceRepository
를 직접 만들어라 httptrace
엔드포인트에서HttpTraceRepository
에 저장된 request-response exchanges 정보를 얻을 수 있다
8.1. Custom HTTP tracing
- 각 추적을 include 하려면
management.trace.http.include
를 이용해라 - 부가적인 커스텀을 하려면
HttpExchangeTracer
를 구현해라
9. Process Monitoring
- 스프링부트에서 프로세스 모니터링을 위한 파일을 생성하는 두가지 클래스가 있음
ApplicationPidFileWriter
는 애플리케이션 PID 를 포함하는 파일 만듦 (기본적으로application.pid
란 파일)WebServerPortFileWriter
실행중인 웹서버 포트를 포함하는 파일을 만듦 (기본적으로application.port
란 파일)
9.1. Extending Configuration
META-INF/spring.factories
파일에서 리스너 활성화 가능
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.ApplicationPidFileWriter,\
org.springframework.boot.web.context.WebServerPortFileWriter
9.2. Programmatically
pringApplication.addListeners(…)
로Writer
객체를 전달해서 리스너 주입 가능- 이 메소드를 사용하면 파일 이름과 path 커스텀 가능
10. Cloud Foundry Support
- 생략