Spring Boot Actuator предлагает вам набор конечных точек для мониторинга вашего приложения, но иногда вам может потребоваться создать пользовательскую конечную точку для получения определенных показателей.
Есть 2 способа сделать пользовательскую конечную точку:
- пользовательская конечная точка с помощью @Endpoint,
- конечная точка контроллера с помощью @RestControllerEndpoint мы увидим только вторую.
В нашем примере мы не создаем пользовательскую конечную точку для нашего приложения, а для мониторинга нашего сервера Jira, размещенного извне. Действительно, нам нужно знать, работает ли он вверх или вниз и сколько времени он тратит на получение ответа.
Вам понадобятся следующие зависимости:
dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation "org.springframework.boot:spring-boot-starter-web" implementation "org.springframework.boot:spring-boot-starter-security" implementation 'org.springframework.boot:spring-boot-starter-tomcat' implementation group: 'com.konghq', name: 'unirest-java', version: '3.11.06' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.11.3' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.5.0' implementation group: 'org.springdoc', name: 'springdoc-openapi-data-rest', version: '1.5.0' }
Здесь, наше приложение.файл yml со свойствами подключения к серверу actuator и jira
management: endpoints: web: exposure: include: '*' base-path: "/management" security: enabled: false endpoint: health: show-details: always app: config: jira: host: "https://myjiraserver" user: "jiraUser" password: "jirapwd" api-path: "/rest/api/2"
Мы сопоставили свойства jira с классом конфигурации java.
@Component @ConfigurationProperties("app.config.jira") @Validated public class JiraConfig { @NotEmpty protected String host; @NotEmpty protected String user; @NotEmpty protected String password; @NotEmpty protected String apiPath; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getApiPath() { return apiPath; } public void setApiPath(String apiPath) { this.apiPath = apiPath; } }
Затем, вот служба, которая вызывает конечную точку jira и указывает время отклика.
@Service public class JiraConnectorService { private static final Logger logger = LoggerFactory.getLogger(JiraConnectorService.class); public static final String HEADER_ACCEPT = "accept"; public static final String HEADER_APP_JSON = "application/json"; public static final String JIRA_MYSELF_ENDPOINT = "/myself"; private JiraConfig jiraConfig; @Autowired public void setJiraConfig(JiraConfig jiraConfig) { this.jiraConfig = jiraConfig; } public ResponseTimeData getResponseTime() throws UnirestException { logger.info("Get responseTime info"); String mySelfEndPointUrl = jiraConfig.getHost() + jiraConfig.getApiPath() + JIRA_MYSELF_ENDPOINT; logger.info("Call {}", mySelfEndPointUrl); ResponseTimeData data = new ResponseTimeData(); long start = System.currentTimeMillis(); HttpResponsejsonResponse = Unirest.get(mySelfEndPointUrl) .basicAuth(jiraConfig.getUser(), jiraConfig.getPassword()) .header(HEADER_ACCEPT, HEADER_APP_JSON) .asJson(); data.setTime(System.currentTimeMillis() - start); data.setHttpStatusCode(jsonResponse.getStatus()); data.setMessage(jsonResponse.getStatusText()); logger.info("Call {} successfull", mySelfEndPointUrl); return data; } }
Модель данных
public class ResponseTimeData { private long time; private int httpStatusCode; private String message; public long getTime() { return time; } public void setTime(long time) { this.time = time; } public int getHttpStatusCode() { return httpStatusCode; } public void setHttpStatusCode(int httpStatusCode) { this.httpStatusCode = httpStatusCode; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
public class HealthDtl { protected String status; private int httpStatusCode; private String message; private Long responseTimeMs; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public int getHttpStatusCode() { return httpStatusCode; } public void setHttpStatusCode(int httpStatusCode) { this.httpStatusCode = httpStatusCode; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Long getResponseTimeMs() { return responseTimeMs; } public void setResponseTimeMs(Long responseTimeMs) { this.responseTimeMs = responseTimeMs; } }
А теперь пользовательская конечная точка rest!
@Component @RestControllerEndpoint(id = "jira") public class RestJiraEndPoint { private static final Logger logger = LoggerFactory.getLogger(RestJiraEndPoint.class); private final JiraConnectorService jiraConnectorService; public RestJiraEndPoint(JiraConnectorService jiraConnectorService, MessageSource messageSource){ this.jiraConnectorService = jiraConnectorService; } @GetMapping("/healthDtl") @ResponseBody public ResponseEntityhealthDtl() { logger.info("/jira/healthDtl endpoint called"); HealthDtl health = new HealthDtl(); ResponseTimeData data = new ResponseTimeData(); try { data = jiraConnectorService.getResponseTime(); if(data.getHttpStatusCode() == HttpStatus.OK.value()) health.setStatus("UP"); else health.setStatus("DOWN"); health.setMessage(data.getMessage()); health.setResponseTimeMs(data.getTime()); } catch (UnirestException e) { logger.error(e.getLocalizedMessage(), e); health.setStatus("DOWN"); health.setMessage(e.getMessage()); } health.setHttpStatusCode(data.getHttpStatusCode()); return new ResponseEntity<>(health, HttpStatus.OK); } }
Теперь у вас есть новая конечная точка привода/управление/jira/healthDtl, которая отвечает:
{ "status":"UP", "httpStatusCode":200, "message":"", "responseTimeMs":369 }
Я добавлю новый пост о том, как выполнить модульное тестирование этой пользовательской конечной точки привода.
Оригинал: “https://dev.to/mbarre/how-to-create-a-custom-actuator-endpoint-to-monitor-jira-228o”