본문 바로가기
도서/프로그래밍

애플리케이션 설정과 검사 - 처음부터 제대로 배우는 스프링 부트 [04]

by 신발사야지 2024. 2. 20.

CHAPTER 5 애플리케이션 설정과 검사

디버깅은 개발자로 입문할 때부터 배워서 개발자로 일하는 동안 개선하고 확장해야 할 기본 기량

이와 같이 중요함에도, 코드 디버깅은 애플리케이션 내 동작을 구축, 식별, 분리하는 한 단계에 불과합니다. 동적이고 분산된 애플리케이션이 많아지면 종종 다음 작업을 수행해야 합니다.

  • 애플리케이션의 동적 설정과 재설정
  • 현재 설정과 출처의 확인과 결정
  • 애필리케이션 환경과 헬스 지표의 검사와 모니터링
  • 실행 중인 애플리케이션의 로깅 수준을 일시적으로 조정해 오류 원인 식별

이 장에서는 스프링 부트에 내장된 설정 기능, 자동 설정 리포트와 함께 스프링 액추에이터로 애플리케이션 환경 설정을 유연하게 동적으로 생성, 식별, 수정하는 방법을 다룹니다.

5.1 애플리케이션 설정

많은 설정이 있고 유용하나, 이 장에서는 몇 가지 시나리오만 살펴보겠습니다.

  • 명령 줄 인수
  • OS 환경 변수
  • 패키징된 애플리케이션 jar 안에 있는 애플리케이션 속성(application.properties와 YAML파일)

5.1.1 @Value

설정을 코드에 녹이는 가장 간단한 접근방식, 패턴 매칭과 SpEL(스프링 표현 언어)을 기반으로 구축되어 간단하고 강력

@Value("${greeting-name: Mirage}") // Mirage 는 properties에 값이 없을 경우 사용할 기본값
private String name;

5.1.2 @ConfigurationProperties

@Value 가 유연하지만 단점이 있기 때문에, 스프링 개발팀에서는 @ConfigurationProperties 를 만들었습니다. 불일치시 경고해줌

package com.thehecklers.sburrestdemo;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "greeting")
public class Greeting {
    private String name;
    private String coffee;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCoffee() {
        return coffee;
    }

    public void setCoffee(String coffee) {
        this.coffee = coffee;
    }
}

5.2 자동 설정 리포트

application.properties 파일에 debug=ture 추가

Positive matches : 현재 활성화된 AutoConfiguration 목록
Negative matches : 현재 비활성화된 AutoConfiguration 목록
Exclusions : 예외처리 한 AutoConfiguration 목록
Unconditional classes : conditional 조건이 없는 AutoConfiguration 목록 (활성화된 것으로 보면 됨)

출처:

https://luvstudy.tistory.com/258

[파란하늘의 지식창고:티스토리]

Negative matches:
-----------------

   AopAutoConfiguration.AspectJAutoProxyingConfiguration.JdkDynamicAutoProxyConfiguration:
      Did not match:
         - @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition)

5.3 액추에이터

의존성 추가

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

GET 호출 해보면

GET <http://localhost:8080/actuator>

HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v3+json
Transfer-Encoding: chunked
Date: Tue, 20 Feb 2024 11:10:16 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "_links": {
    "self": {
      "href": "<http://localhost:8080/actuator>",
      "templated": false
    },
    "health": {
      "href": "<http://localhost:8080/actuator/health>",
      "templated": false
    },
    "health-path": {
      "href": "<http://localhost:8080/actuator/health/{*path}>",
      "templated": true
    }
  }
}
Response file saved.
> 2024-02-20T201016.200.json

보안상 문제가 될 수 있기 때문에 조심해야 한다.

다음과 같은 내용을 application.properties 에 추가한다

management.endpoints.web.exposure.include=env, info, health

만약 엔드포인트를 많이 노출하면 실행시 다음과 같은 log가 찍힘

EndpointLinksResolver      : Exposing 13 endpoint(s) beneath base path '/actuator'
GET <http://localhost:8080/actuator>

HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v3+json
Transfer-Encoding: chunked
Date: Tue, 20 Feb 2024 11:14:40 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "_links": {
    "self": {
      "href": "<http://localhost:8080/actuator>",
      "templated": false
    },
    "beans": { => 생성한 모든 스프링 빈
      "href": "<http://localhost:8080/actuator/beans>",
      "templated": false
    },
    "caches-cache": {
      "href": "<http://localhost:8080/actuator/caches/{cache}>",
      "templated": true
    },
    "caches": {
      "href": "<http://localhost:8080/actuator/caches>",
      "templated": false
    },
    "health": { => health 정보
      "href": "<http://localhost:8080/actuator/health>",
      "templated": false
    },
    "health-path": {
      "href": "<http://localhost:8080/actuator/health/{*path}>",
      "templated": true
    },
    "info": {
      "href": "<http://localhost:8080/actuator/info>",
      "templated": false
    },
    "conditions": {
      "href": "<http://localhost:8080/actuator/conditions>",
      "templated": false
    },
    "configprops": {
      "href": "<http://localhost:8080/actuator/configprops>",
      "templated": false
    },
    "configprops-prefix": {
      "href": "<http://localhost:8080/actuator/configprops/{prefix}>",
      "templated": true
    },
    "env": { => 애플리케이션이 작동하는 환경의 무수한 측면 확인
      "href": "<http://localhost:8080/actuator/env>",
      "templated": false
    },
    "env-toMatch": {
      "href": "<http://localhost:8080/actuator/env/{toMatch}>",
      "templated": true
    },
    "loggers": { => 모든 컴포넌트의 로깅 수준
      "href": "<http://localhost:8080/actuator/loggers>",
      "templated": false
    },
    "loggers-name": {
      "href": "<http://localhost:8080/actuator/loggers/{name}>",
      "templated": true
    },
    "heapdump": { => 트러블 슈팅과 분석을 위해 힙 덤프 시작
      "href": "<http://localhost:8080/actuator/heapdump>",
      "templated": false
    },
    "threaddump": {=> 트러블 슈팅과 분석을 위해 쓰레 덤프 시작
      "href": "<http://localhost:8080/actuator/threaddump>",
      "templated": false
    },
    "metrics-requiredMetricName": {
      "href": "<http://localhost:8080/actuator/metrics/{requiredMetricName}>",
      "templated": true
    },
    "metrics": { => 애플리케이션에서 현재 캡처 중인 메트릭스
      "href": "<http://localhost:8080/actuator/metrics>",
      "templated": false
    },
    "scheduledtasks": {
      "href": "<http://localhost:8080/actuator/scheduledtasks>",
      "templated": false
    },
    "mappings": { => 모든 엔드포인트 매핑과 세부 지원 정보
      "href": "<http://localhost:8080/actuator/mappings>",
      "templated": false
    }
  }
}

health check 를 위해 프로퍼티에 다음 항목을 추가 후 재실행

management.endpoint.health.show-details=always

액추에이터로 health 엔드 포인트를 조회해보면

GET <http://localhost:8080/actuator/health>

HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v3+json
Transfer-Encoding: chunked
Date: Tue, 20 Feb 2024 11:19:04 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "H2",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 511987150848,
        "free": 388745297920,
        "threshold": 10485760,
        "path": "\\\\IdeaProjects\\\\SpringBootUpAndRunning-Spring-Boot-3\\\\java\\\\sbur-rest-demo\\\\.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

코드 뿐만 아니라 명령줄 인수등으로 값이 오버라이딩 될 수 있는데

액추에이터를 사용하면 데이터 기반으로 오류를 잡아내기 훨씬 간단해진다.

액추에이터는 실행 중인 스프링 부트 로깅 수준을 변경하는 것도 가능

기본값으로는 info 를 하고 있다가 문제 발생시 로깅 레벨을 Trace 로 올리는 것이 가능

5.4 마치며

  • 애플리케이션을 동적으로 설정 및 재설정
  • 현재 설정과 해당 출처를 결정/확인
  • 애플리케이션 환경과 health 지표 검사, 모니터링
  • 실시간으로 애플리케이션 로깅 수준을 일시적으로 조정해 근본원인 식별