Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Health Check endpoints #792

Merged
merged 15 commits into from
Jul 11, 2023
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ tasks.withType(JavaExec) {
}

group = "org.assimbly.gateway"
version = '4.0.2'
version = '4.0.3'

description = ""

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gateway",
"version": "4.0.2",
"version": "4.0.3",
"private": true,
"description": "A message gateway based on Apache camel",
"license": "Apache License 2.0",
Expand Down Expand Up @@ -132,7 +132,7 @@
"eslint": "8.9.0",
"eslint-config-prettier": "8.4.0",
"eslint-webpack-plugin": "3.1.1",
"folder-hash": "4.0.2",
"folder-hash": "4.0.3",
"generator-jhipster": "7.7.0",
"husky": "7.0.4",
"jest": "27.5.1",
Expand Down
6 changes: 3 additions & 3 deletions scripts/version/versioned_files.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"applicationName": "gateway",
"oldVersion": "4.0.2",
"newVersion": "4.0.2",
"oldVersion": "4.0.3",
"newVersion": "4.0.3",
"resources": [
{
"path": "/package.json"
Expand All @@ -13,4 +13,4 @@
"path": "/src/main/resources/config/application.yml"
}
]
}
}
24 changes: 24 additions & 0 deletions src/main/java/org/assimbly/gateway/service/HealthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.assimbly.gateway.service;

/**
* Service Interface for managing Integration.
*/
public interface HealthService {

/**
* Convert double size to long Kb
*
* @param var1 the value to convert
* @return Kb
*/
long convertSizeToKb(double var1);

/**
* Invoke system method
*
* @param methodName to invoke
* @return object with method call response
*/
Object invokeMethod(String methodName);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.assimbly.gateway.service.impl;

import org.assimbly.gateway.service.HealthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;

/**
* Service Implementation for managing Integration.
*/
@Service
@Transactional
public class HealthServiceImpl implements HealthService {

private final Logger log = LoggerFactory.getLogger(getClass());

private final OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();

public HealthServiceImpl() {
//
}

/**
* Convert double size to long Kb
*
* @param size the value to convert
* @return Kb
*/
@Override
public long convertSizeToKb(double size) {
return (long) (size / 1024);
}

/**
* Invoke system method
*
* @param methodName to invoke
* @return object with method call response
*/
@Override
public Object invokeMethod(String methodName) {
try {
Class<?> unixOS = Class.forName("com.sun.management.UnixOperatingSystemMXBean");

if (unixOS.isInstance(operatingSystemMXBean))
return unixOS.getMethod(methodName).invoke(operatingSystemMXBean);

} catch (Throwable ignored) { }

return "Unknown";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.assimbly.gateway.service.response;

import java.util.HashMap;
import java.util.Map;

public class BackendResponse {

private Map<String, Object> jvm = new HashMap<>();
private Map<String, Long> memory = new HashMap<>();
private Map<String, Integer> threads = new HashMap<>();

public Map<String, Long> getMemory() {
return memory;
}
public void setMemory(Map<String, Long> memory) {
this.memory = memory;
}
public void addMemory(String key, Long value) {
this.memory.put(key, value);
}

public Map<String, Integer> getThreads() {
return threads;
}
public void setThreads(Map<String, Integer> threads) {
this.threads = threads;
}
public void addThread(String key, Integer value) {
this.threads.put(key, value);
}

public Map<String, Object> getJvm() {
return jvm;
}
public void setJvm(Map<String, Object> jvm) {
this.jvm = jvm;
}
public void addJvm(String key, Object value) {
this.jvm.put(key, value);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.assimbly.gateway.web.rest.broker;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Parameter;
import org.assimbly.brokerrest.ManagedBrokerRuntime;
import org.assimbly.gateway.service.HealthService;
import org.assimbly.util.rest.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
* REST controller for getting the {@link AuditEvent}s.
*/
@RestController
@RequestMapping("/health")
public class HealthBrokerResource {

protected Logger log = LoggerFactory.getLogger(getClass());

public HealthBrokerResource(HealthService healthService) { }

@Autowired
private ManagedBrokerRuntime managedBroker;

private boolean plainResponse;

@GetMapping(
path = "/broker",
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE}
)
public ResponseEntity<String> getBrokerStats(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType) throws Exception {

plainResponse = true;
long connectorId = 1;

try {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectMapper mapper = new ObjectMapper();

Map<String, Object> statsMap = managedBroker.getStats("classic");

mapper.writeValue(out, statsMap);

return ResponseUtil.createSuccessResponse(connectorId, mediaType, "/health/broker", out.toString(StandardCharsets.UTF_8), plainResponse);
} catch (Exception e) {
log.error("Get broker failed",e);
return ResponseUtil.createFailureResponse(connectorId, mediaType,"/health/broker",e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.assimbly.gateway.web.rest.integration;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Parameter;
import org.assimbly.gateway.service.HealthService;
import org.assimbly.gateway.service.response.BackendResponse;
import org.assimbly.integration.Integration;
import org.assimbly.integrationrest.IntegrationRuntime;
import org.assimbly.util.rest.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.lang.management.ThreadMXBean;
import java.nio.charset.StandardCharsets;

/**
* REST controller for getting the {@link AuditEvent}s.
*/
@RestController
@RequestMapping("/health")
public class HealthIntegrationResource {

protected Logger log = LoggerFactory.getLogger(getClass());

private final HealthService healthService;

public HealthIntegrationResource(HealthService healthService) {
this.healthService = healthService;
}

@Autowired
private IntegrationRuntime integrationRuntime;

private Integration integration;

private boolean plainResponse;

@GetMapping(
path = "/jvm",
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE}
)
public ResponseEntity<String> getJvmStats(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType) throws Exception {

plainResponse = true;
long connectorId = 1;

try {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectMapper mapper = new ObjectMapper();
final BackendResponse backendResponse = new BackendResponse();
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

MemoryUsage mem = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();

backendResponse.addMemory("current", healthService.convertSizeToKb(mem.getUsed()));
backendResponse.addMemory("max", healthService.convertSizeToKb(mem.getMax()));
backendResponse.addMemory("committed", healthService.convertSizeToKb(mem.getCommitted()));
backendResponse.addMemory("cached", healthService.convertSizeToKb(mem.getCommitted() - mem.getUsed()));
backendResponse.addMemory("currentUsedPercentage", (mem.getUsed() * 100 / mem.getMax()));

backendResponse.addThread("threadCount", threadMXBean.getThreadCount());
backendResponse.addThread("peakThreadCount", threadMXBean.getPeakThreadCount());

backendResponse.addJvm("openFileDescriptors", healthService.invokeMethod("getOpenFileDescriptorCount"));
backendResponse.addJvm("maxFileDescriptors", healthService.invokeMethod("getMaxFileDescriptorCount"));

mapper.writeValue(out, backendResponse);
return org.assimbly.util.rest.ResponseUtil.createSuccessResponse(connectorId, mediaType, "/health/jvm", out.toString(StandardCharsets.UTF_8), plainResponse);
} catch (Exception e) {
log.error("Get jvm failed",e);
return ResponseUtil.createFailureResponse(connectorId, mediaType,"/health/jvm",e.getMessage());
}
}

@GetMapping(
path = "/flow",
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE}
)
public ResponseEntity<String> getFlowStats(@Parameter(hidden = true) @RequestHeader("Accept") String mediaType) throws Exception {

plainResponse = true;
long connectorId = 1;
integration = integrationRuntime.getIntegration();

try {
String stats = integration.getStats(mediaType);
if(stats.startsWith("Error")||stats.startsWith("Warning")) {plainResponse = false;}
return org.assimbly.util.rest.ResponseUtil.createSuccessResponse(connectorId, mediaType, "/health/flow", stats, plainResponse);
} catch (Exception e) {
log.error("Get flow failed",e);
return ResponseUtil.createFailureResponse(connectorId, mediaType,"/health/flow",e.getMessage());
}
}
}
2 changes: 1 addition & 1 deletion src/main/resources/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ jhipster:

application:
info:
version: 4.0.2
version: 4.0.3
documentation:
url: https://github.com/assimbly/gateway/wiki
camel-url: https://camel.apache.org/components/latest
Expand Down