Stirling-PDF/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java

264 lines
10 KiB
Java
Raw Normal View History

2023-05-18 00:58:15 +02:00
package stirling.software.SPDF.controller.web;
2023-08-08 20:55:18 +02:00
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Comparator;
2023-05-18 00:58:15 +02:00
import java.util.HashMap;
2023-08-08 20:55:18 +02:00
import java.util.List;
2023-05-18 00:58:15 +02:00
import java.util.Map;
import java.util.Optional;
2023-08-08 20:55:18 +02:00
import java.util.stream.Collectors;
2023-05-18 00:58:15 +02:00
2023-08-08 20:55:18 +02:00
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
2023-05-18 00:58:15 +02:00
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
2023-05-21 18:12:18 +02:00
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.swagger.v3.oas.annotations.Operation;
2023-06-29 22:51:08 +02:00
import io.swagger.v3.oas.annotations.Parameter;
2023-06-25 10:16:32 +02:00
import io.swagger.v3.oas.annotations.tags.Tag;
2023-08-08 20:55:18 +02:00
import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.config.StartupApplicationListener;
2023-05-21 18:12:18 +02:00
2023-05-18 00:58:15 +02:00
@RestController
@RequestMapping("/api/v1")
2023-06-25 10:16:32 +02:00
@Tag(name = "API", description = "Info APIs")
2023-05-18 00:58:15 +02:00
public class MetricsController {
private final MeterRegistry meterRegistry;
2023-08-08 20:55:18 +02:00
private boolean isEndpointEnabled;
@PostConstruct
public void init() {
String isEndpointEnabled = System.getProperty("ENABLE_API_METRICS");
if (isEndpointEnabled == null) {
isEndpointEnabled = System.getenv("ENABLE_API_METRICS");
if (isEndpointEnabled == null) {
isEndpointEnabled = "true";
}
}
this.isEndpointEnabled = "true".equalsIgnoreCase(isEndpointEnabled);
}
2023-05-18 00:58:15 +02:00
public MetricsController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@GetMapping("/status")
@Operation(summary = "Application status and version",
description = "This endpoint returns the status of the application and its version number.")
2023-08-08 20:55:18 +02:00
public ResponseEntity<?> getStatus() {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
2023-05-18 00:58:15 +02:00
Map<String, String> status = new HashMap<>();
status.put("status", "UP");
status.put("version", getClass().getPackage().getImplementationVersion());
2023-08-08 20:55:18 +02:00
return ResponseEntity.ok(status);
2023-05-18 00:58:15 +02:00
}
@GetMapping("/loads")
@Operation(summary = "GET request count",
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
2023-08-08 20:55:18 +02:00
public ResponseEntity<?> getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
try {
2023-05-18 00:58:15 +02:00
2023-06-29 22:51:08 +02:00
double count = 0.0;
2023-05-18 00:58:15 +02:00
for (Meter meter : meterRegistry.getMeters()) {
if (meter.getId().getName().equals("http.requests")) {
String method = meter.getId().getTag("method");
if (method != null && method.equals("GET")) {
2023-06-29 22:51:08 +02:00
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
if(!endpoint.get().startsWith("/")) {
endpoint = Optional.of("/" + endpoint.get());
}
System.out.println("loads " + endpoint.get() + " vs " + meter.getId().getTag("uri"));
if(endpoint.get().equals(meter.getId().getTag("uri"))){
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
} else {
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
2023-05-18 00:58:15 +02:00
}
}
}
2023-08-08 20:55:18 +02:00
return ResponseEntity.ok(count);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@GetMapping("/loads/all")
@Operation(summary = "GET requests count for all endpoints",
description = "This endpoint returns the count of GET requests for each endpoint.")
public ResponseEntity<?> getAllEndpointLoads() {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
try {
Map<String, Double> counts = new HashMap<>();
for (Meter meter : meterRegistry.getMeters()) {
if (meter.getId().getName().equals("http.requests")) {
String method = meter.getId().getTag("method");
if (method != null && method.equals("GET")) {
String uri = meter.getId().getTag("uri");
if (uri != null) {
double currentCount = counts.getOrDefault(uri, 0.0);
if (meter instanceof Counter) {
currentCount += ((Counter) meter).count();
}
counts.put(uri, currentCount);
}
}
}
}
List<EndpointCount> results = counts.entrySet().stream()
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue()))
.sorted(Comparator.comparing(EndpointCount::getCount).reversed())
.collect(Collectors.toList());
return ResponseEntity.ok(results);
2023-05-18 00:58:15 +02:00
} catch (Exception e) {
2023-08-08 20:55:18 +02:00
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
2023-05-18 00:58:15 +02:00
}
}
2023-08-08 20:55:18 +02:00
public class EndpointCount {
private String endpoint;
private double count;
public EndpointCount(String endpoint, double count) {
this.endpoint = endpoint;
this.count = count;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public double getCount() {
return count;
}
public void setCount(double count) {
this.count = count;
}
}
2023-05-18 00:58:15 +02:00
@GetMapping("/requests")
@Operation(summary = "POST request count",
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
2023-08-08 20:55:18 +02:00
public ResponseEntity<?> getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
try {
double count = 0.0;
for (Meter meter : meterRegistry.getMeters()) {
if (meter.getId().getName().equals("http.requests")) {
String method = meter.getId().getTag("method");
if (method != null && method.equals("POST")) {
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
if (!endpoint.get().startsWith("/")) {
endpoint = Optional.of("/" + endpoint.get());
}
if (endpoint.get().equals(meter.getId().getTag("uri"))) {
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
} else {
if (meter instanceof Counter) {
count += ((Counter) meter).count();
}
}
}
}
}
return ResponseEntity.ok(count);
} catch (Exception e) {
return ResponseEntity.ok(-1);
}
}
@GetMapping("/requests/all")
@Operation(summary = "POST requests count for all endpoints",
description = "This endpoint returns the count of POST requests for each endpoint.")
public ResponseEntity<?> getAllPostRequests() {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
2023-05-18 00:58:15 +02:00
try {
2023-08-08 20:55:18 +02:00
Map<String, Double> counts = new HashMap<>();
for (Meter meter : meterRegistry.getMeters()) {
if (meter.getId().getName().equals("http.requests")) {
String method = meter.getId().getTag("method");
if (method != null && method.equals("POST")) {
String uri = meter.getId().getTag("uri");
if (uri != null) {
double currentCount = counts.getOrDefault(uri, 0.0);
if (meter instanceof Counter) {
currentCount += ((Counter) meter).count();
}
counts.put(uri, currentCount);
}
}
}
2023-05-18 00:58:15 +02:00
}
2023-08-08 20:55:18 +02:00
List<EndpointCount> results = counts.entrySet().stream()
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue()))
.sorted(Comparator.comparing(EndpointCount::getCount).reversed())
.collect(Collectors.toList());
return ResponseEntity.ok(results);
2023-05-18 00:58:15 +02:00
} catch (Exception e) {
2023-08-08 20:55:18 +02:00
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
2023-05-18 00:58:15 +02:00
}
}
2023-08-08 20:55:18 +02:00
@GetMapping("/uptime")
public ResponseEntity<?> getUptime() {
if (!isEndpointEnabled) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
}
LocalDateTime now = LocalDateTime.now();
Duration uptime = Duration.between(StartupApplicationListener.startTime, now);
return ResponseEntity.ok(formatDuration(uptime));
}
private String formatDuration(Duration duration) {
long days = duration.toDays();
long hours = duration.toHoursPart();
long minutes = duration.toMinutesPart();
long seconds = duration.toSecondsPart();
return String.format("%dd %dh %dm %ds", days, hours, minutes, seconds);
}
2023-05-18 00:58:15 +02:00
}