DBILITY

spring boot actuator + embedded mongodb 본문

java/spring cloud

spring boot actuator + embedded mongodb

DBILITY 2019. 9. 4. 17:38
반응형

Spring Starter Project로 생성시 spring-boot 버전은 2.1.8.RELEASE.
Actuator는 App 운영시 모니터링 및 매트릭 수집의 역할을 한다.
대표적으로 다음과 같은 endpoint가 있으며 기본적으로 shutdown을 제외하고 모두 활성화되어 있다.

 path  Description 
 /beans  초기화된 모든 spring bean 목록 
 /env  설정가능한 환경속성 목록으로 환경변수 및 설정파일의 속성을 포함 
 /health  상태정보 
 /info  사용자 임의 정보 
 /logger  로거설정정보 표시,수정 
 /metrics  메트릭 정보표시( 메모리사용량, 실행중인 쓰레드 수 REST Method Response Time 등 )
 /httptrace  http trace정보( last 100 http request) 

application.properties에 설정을 통해 endpoint 노출,비노출을 설정가능하며 기본적으로 health,info경로만 노출되어 있다.
endpoint 목록은 https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html 확인가능하다.
다음은 beans,env,logger를 제외하고 모두 노출하는 설정이다.

management.endpoints.web.exposure.exclude=beans,env,logger
management.endpoints.web.exposure.include=*

actuator를 적용하기 위해선 pom에 spring-boot-starter-actuator dependancy를 추가한다.
/info 경로에 git 커밋정보 노출을 위해 build 섹션 plugins에 git-commit-id-plugin 아래와 같이 추가해야 한다.
build시 classpath 최상위에 git.properties가 생성된다.

<plugin>
	<groupId>pl.project13.maven</groupId>
	<artifactId>git-commit-id-plugin</artifactId>
	<configuration>
		<failOnNoGitDirectory>false</failOnNoGitDirectory>
	</configuration>
</plugin>

/actuator/info 요청시 {"git":{"commit":{"time":"2019-09-04T09:27:24Z","id":"c1495f5"},"branch":"master"}} 와 같은 정보가 포함되게 된다.

App 빌드정보 노출을 원할 경우 다음과 같이 spring-boot-maven-plugin을 수정해 META-INF/build-info.properties가 자동생성 되도록 한다.

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<executions>
		<execution>
			<goals>
				<goal>build-info</goal>
				<goal>repackage</goal>
			</goals>
			<configuration>
				<additionalProperties>
					<java.target>${maven.compiler.target}</java.target>
					<time>${maven.build.timestamp}</time>
				</additionalProperties>
			</configuration>
		</execution>
	</executions>
</plugin>

/actuator/info 요청시 {"build":{"version":"0.0.1-SNAPSHOT","java":{"target":"1.8"},"artifact":"spring-restful","name":"spring-restful","group":"com.dbility.cloud","time":"2019-09-04T12:48:42Z"}}와 같은 정보가 포함되게 된다.

/health api는 디스크사용량, 메일서비스, JMS, 데이터소스, 몽고디비나 카산드라 같은 NoSQL을 모니터링한다.
기본은 STATUS:UP만 제공된다.
상세정보를 확인하려면, application.properties에 다음과 같이 추가하며. 선택 값은 [always,never,when-authorized]가 있다.

management.endpoint.health.show-details=always

/actuator/health 요청시 {"status":"UP","details":{"diskSpace":{"status":"UP","details":{"total":208274305024,"free":36507033600,"threshold":10485760}}}} 와 같이 디스크 정보가 포함된다.

embeded 몽고디비의 health정보 확인을 위해 다음과 같이 dependency를 추가한다. 몽고디비 사용법은 따로 학습이 필요하다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
	<groupId>de.flapdoodle.embed</groupId>
	<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>

 

/actuator/health 요청시 {status":"UP","details":{"diskSpace":{"status":"UP","details":{"total":208274305024,"free":36195037184,"threshold":10485760}},"mongo":{"status":"UP","details":{"version":"3.5.5"}}}} 와 같이 몽고디비정보가 포함된다.

/metrics api 호출시 다음과 같이 항목명만 출력이 된다.

{
    "names": [
        "jvm.memory.max",
        "jvm.threads.states",
        "jvm.gc.memory.promoted",
        "jvm.memory.used",
        "jvm.gc.max.data.size",
        "jvm.gc.pause",
        "jvm.memory.committed",
        "system.cpu.count",
        "logback.events",
        "http.server.requests",
        "tomcat.global.sent",
        "jvm.buffer.memory.used",
        "tomcat.sessions.created",
        "jvm.threads.daemon",
        "system.cpu.usage",
        "jvm.gc.memory.allocated",
        "tomcat.global.request.max",
        "tomcat.global.request",
        "tomcat.sessions.expired",
        "jvm.threads.live",
        "jvm.threads.peak",
        "tomcat.global.received",
        "process.uptime",
        "tomcat.sessions.rejected",
        "process.cpu.usage",
        "tomcat.threads.config.max",
        "jvm.classes.loaded",
        "jvm.classes.unloaded",
        "tomcat.global.error",
        "tomcat.sessions.active.current",
        "tomcat.sessions.alive.max",
        "jvm.gc.live.data.size",
        "tomcat.threads.current",
        "jvm.buffer.count",
        "jvm.buffer.total.capacity",
        "tomcat.sessions.active.max",
        "tomcat.threads.busy",
        "process.start.time"
    ]
}

/actuator/metrics/{항목} 형태로 호출해 봤다.
다음은 jvm.memory.max 추가하여 /actuator/metrics/jvm.memory.max를 호출한 결과.

{
    "name": "jvm.memory.max",
    "description": "The maximum amount of memory in bytes that can be used for memory management",
    "baseUnit": "bytes",
    "measurements": [
        {
            "statistic": "VALUE",
            "value": 5.447876607E9
        }
    ],
    "availableTags": [
        {
            "tag": "area",
            "values": [
                "heap",
                "nonheap"
            ]
        },
        {
            "tag": "id",
            "values": [
                "Compressed Class Space",
                "PS Survivor Space",
                "PS Old Gen",
                "Metaspace",
                "PS Eden Space",
                "Code Cache"
            ]
        }
    ]
}

사용자 정의용으로 MeterRegistry를 제공한다.
이전 글의 EmpController에 사용할 EmpService를 생성하고, 각 Api 호출에 따라 services.emp.post, service.emp.delete를 metrics에 제공해 본다.
맞는지는 모르겠으나, metrics조회시 동작한다.

Emp.java

package com.dbility.cloud.spring.model;

import java.util.Date;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.Data;

@Document(collection = "emp")
@Data
public class Emp {

	@Id
	private String id; //ObjectId
	private String empno;
	private String ename;
	private String job;
	private Long mgr;
	private Date hiredate;
	private double sal;
	private Long deptno;
}

EmpCounterService.java

package com.dbility.cloud.spring.service;

public interface EmpCounterService {

	public void CountNewEmp() throws Exception;
	public void CountDeleteEmp() throws Exception;
}

EmpCounterServiceImpl.java

package com.dbility.cloud.spring.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dbility.cloud.spring.service.EmpCounterService;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;

@Service("EmpCounterService")
public class EmpCounterServiceImpl implements EmpCounterService {

	private final MeterRegistry registry;

	@Autowired
	public EmpCounterServiceImpl(MeterRegistry registry) {
		this.registry=registry;
		this.registry.counter("services.emp.post", Tags.empty());
		this.registry.counter("services.emp.delete", Tags.empty());
	}

	@Override
	public void CountNewEmp() throws Exception {
		registry.counter("services.emp.post", Tags.empty()).increment();
	}

	@Override
	public void CountDeleteEmp() throws Exception {
		registry.counter("services.emp.delete", Tags.empty()).increment();
	}

}

EmpController.java

package com.dbility.cloud.spring.controller;

import java.util.List;

import javax.annotation.Resource;

import org.bson.codecs.ObjectIdGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.dbility.cloud.spring.data.EmpRepository;
import com.dbility.cloud.spring.model.Emp;
import com.dbility.cloud.spring.service.EmpCounterService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping(value = "/emp")
public class EmpController {

	@Autowired
	private EmpRepository repository;

	@Resource(name="EmpCounterService")
	private EmpCounterService empCounterService;

	@GetMapping
	public List<emp> findAll() throws Exception {
		List<emp> emps = repository.findAll();
		log.debug("GET ALL --> {}", emps);
		return emps;
	}

	@GetMapping(value = "/{id}")
	public List<emp> findById(@RequestParam String id) throws Exception {
		log.debug("GET param --> {}", id);
		List<emp> emps = repository.findByEmpno(id);
		log.debug("GET result--> {}", emps);
		return emps;
	}

	@PostMapping
	public Emp add(@RequestBody Emp emp) throws Exception {
		emp.setId(new ObjectIdGenerator().generate().toString());
		repository.save(emp);
		empCounterService.CountNewEmp();
		log.debug("POST --> {}", emp);

		return emp;
	}

	@DeleteMapping
	public void delete(Emp emp) throws Exception {
		repository.delete(emp);
		empCounterService.CountDeleteEmp();
		log.debug("DELETE --> {}", emp);
	}

	@PutMapping
	public void update(@RequestBody Emp emp) throws Exception {
		repository.save(emp);
		log.debug("PUT --> {}", emp);
	}

}

swagger-ui에서 PUT 5회, DELETE 2회 실행 후 metrics를 조회하면 다음과 같은 결과가 출력된다.

{
    "name": "services.emp.post",
    "description": null,
    "baseUnit": null,
    "measurements": [
        {
            "statistic": "COUNT",
            "value": 5.0
        }
    ],
    "availableTags": [
    ]
}
{
    "name": "services.emp.delete",
    "description": null,
    "baseUnit": null,
    "measurements": [
        {
            "statistic": "COUNT",
            "value": 2.0
        }
    ],
    "availableTags": [
    ]
}

 

반응형
Comments