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

FDP-94: Add monitoring and small fixes #9

Merged
merged 12 commits into from
Dec 7, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import java.time.Duration


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ComponentScan(basePackages = ["org.gxf.soapbridge"])
@EmbeddedKafka(topics = ["requests", "responses"])
class EndToEndTest(
@LocalServerPort private val soapPort: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import org.gxf.soapbridge.application.services.ConnectionCacheService;
import org.gxf.soapbridge.application.services.SigningService;
import org.gxf.soapbridge.configuration.properties.SoapConfigurationProperties;
import org.gxf.soapbridge.kafka.senders.ProxyRequestKafkaSender;
import org.gxf.soapbridge.monitoring.MonitoringService;
import org.gxf.soapbridge.soap.clients.Connection;
import org.gxf.soapbridge.soap.exceptions.ConnectionNotFoundInCacheException;
import org.gxf.soapbridge.soap.exceptions.ProxyServerException;
Expand Down Expand Up @@ -57,16 +59,20 @@ public class SoapEndpoint implements HttpRequestHandler {
/** Map of time-outs for specific functions. */
private final Map<String, Integer> customTimeOutsMap;

private final MonitoringService monitoringService;

public SoapEndpoint(
final ConnectionCacheService connectionCacheService,
final SoapConfigurationProperties soapConfiguration,
final ProxyRequestKafkaSender proxyRequestsSender,
final SigningService signingService) {
final ConnectionCacheService connectionCacheService,
final SoapConfigurationProperties soapConfiguration,
final ProxyRequestKafkaSender proxyRequestsSender,
final SigningService signingService,
MonitoringService monitoringService) {
this.connectionCacheService = connectionCacheService;
this.soapConfiguration = soapConfiguration;
this.proxyRequestsSender = proxyRequestsSender;
this.signingService = signingService;
customTimeOutsMap = soapConfiguration.getCustomTimeouts();
this.monitoringService = monitoringService;
}

/** Handles incoming SOAP requests. */
Expand All @@ -75,6 +81,7 @@ public void handleRequest(
@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response)
throws ServletException, IOException {

Instant startTime = Instant.now();
// For debugging, print all headers and parameters.
LOGGER.debug("Start of SoapEndpoint.handleRequest()");
logHeaderValues(request);
Expand All @@ -89,6 +96,7 @@ public void handleRequest(
final String soapPayload = readSoapPayload(request);
if (soapPayload == null) {
LOGGER.error("Unable to read SOAP request, returning 500.");
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);
createErrorResponse(response);
return;
}
Expand All @@ -102,6 +110,7 @@ public void handleRequest(
}
if (organisationName == null) {
LOGGER.error("Unable to find client certificate, returning 500.");
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);
createErrorResponse(response);
return;
}
Expand All @@ -121,6 +130,7 @@ public void handleRequest(
requestMessage.setSignature(signature);
} catch (final ProxyServerException e) {
LOGGER.error("Unable to sign message or set security key", e);
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);
createErrorResponse(response);
connectionCacheService.removeConnection(connectionId);
return;
Expand All @@ -142,12 +152,14 @@ public void handleRequest(
final boolean responseReceived = newConnection.waitForResponseReceived(timeout);
if (!responseReceived) {
LOGGER.error("No response received within the specified timeout of {} seconds", timeout);
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);
createErrorResponse(response);
connectionCacheService.removeConnection(connectionId);
return;
}
} catch (final InterruptedException e) {
LOGGER.error("Error while waiting for response", e);
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogelijk is het nuttiger om errors te tellen. Eventueel naast het meten van de duratie.

createErrorResponse(response);
connectionCacheService.removeConnection(connectionId);
Thread.currentThread().interrupt();
Expand All @@ -157,10 +169,12 @@ public void handleRequest(
final String soap = readResponse(connectionId);
if (soap == null) {
LOGGER.error("Unable to read SOAP response: null");
monitoringService.recordConnectionTime(startTime, request.getContextPath(), false);
createErrorResponse(response);
} else {
LOGGER.debug("Request handled, trying to send response...");
createSuccessFulResponse(response, soap);
monitoringService.recordConnectionTime(startTime, request.getContextPath(), true);
}

LOGGER.debug(
Expand Down
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is dit voldoende om ook bijv. fail-rates uit te halen? Of moeten we wat counters toeveoegen?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is het überhaupt nodig om fouten te timen? Kunnen we niet gerichter timeouts, technische exceptions etc. 'counten'?

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.gxf.soapbridge.monitoring

import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
import org.springframework.stereotype.Service
import java.time.Duration
import java.time.Instant

@Service
class MonitoringService(
private val registry: MeterRegistry
) {

companion object {
private const val METRIC_PREFIX = "gxf.soap.bridge"
}

fun recordConnectionTime(startTime: Instant, context: String, successful: Boolean) {
sanderv marked this conversation as resolved.
Show resolved Hide resolved
val duration = Duration.between(startTime, Instant.now())

Timer
.builder("${METRIC_PREFIX}.connection.timer")
.description("Counts the successful requests to the Maki API")
sanderv marked this conversation as resolved.
Show resolved Hide resolved
.tag("context", context)
.tag("successful", successful.toString())
.register(registry)
.record(duration)
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.spring.gradle.dependencymanagement.internal.dsl.StandardDependencyMana
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("org.springframework.boot") version "3.1.5" apply false
id("org.springframework.boot") version "3.1.6" apply false
id("io.spring.dependency-management") version "1.1.3" apply false
kotlin("jvm") version "1.9.10" apply false
kotlin("plugin.spring") version "1.9.10" apply false
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading