Skip to content

Commit

Permalink
Merge pull request #617 from swisspost/feature/issue615_provide_metrics
Browse files Browse the repository at this point in the history
#615 Made MonitoringHandler optional and added the same metrics with micrometer
  • Loading branch information
mcweba authored Dec 9, 2024
2 parents 5fb534c + 06e4ed9 commit 20aa5fe
Show file tree
Hide file tree
Showing 25 changed files with 615 additions and 141 deletions.
26 changes: 25 additions & 1 deletion gateleen-expansion/README_expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,28 @@ For more information about the StorageExpand feature see the [vertx-rest-storage
This allows you to create one octet-stream containing each json resource in the given collection (see expand feature).
Basically it works exactly the same way as the default expand feature works, except that it does not set an eTag for the request.

> <font color="orange">Attention: </font> No eTag header is created / returned when this feature is used!
> <font color="orange">Attention: </font> No eTag header is created / returned when this feature is used!
### Micrometer metrics
The expansion feature is monitored with micrometer. The following metrics are available:
* gateleen_expand_requests_total
* gateleen_storage_expand_requests_total

For `expand_requests_total` additional tags are provided to specify the expand level.

Example metrics:

```
# HELP gateleen_expand_requests_total
# TYPE gateleen_expand_requests_total counter
gateleen_expand_requests_total{level="1",} 23677.0
gateleen_expand_requests_total{level="2",} 2350.0
gateleen_expand_requests_total{level="3",} 77.0
gateleen_expand_requests_total{level="4",} 0.0
gateleen_expand_requests_total{level="0",} 0.0
# HELP gateleen_storage_expand_requests_total
# TYPE gateleen_storage_expand_requests_total counter
gateleen_storage_expand_requests_total 37.0
```

To enable the metrics, set a `MeterRegistry` instance by calling `setMeterRegistry(MeterRegistry meterRegistry)` method in `ExpansionHandler` class.
4 changes: 4 additions & 0 deletions gateleen-expansion/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<groupId>org.swisspush</groupId>
<artifactId>rest-storage</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>

<!-- TEST dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.swisspush.gateleen.expansion;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
Expand Down Expand Up @@ -27,10 +29,7 @@
import org.swisspush.gateleen.routing.RuleFeaturesProvider;
import org.swisspush.gateleen.routing.RuleProvider;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import static org.swisspush.gateleen.core.util.StatusCode.INTERNAL_SERVER_ERROR;
Expand Down Expand Up @@ -89,6 +88,10 @@ public class ExpansionHandler implements RuleChangesObserver {
private static final int DECREMENT_BY_ONE = 1;
private static final int MAX_RECURSION_LEVEL = 0;

private static final String EXPAND_REQUEST_METRIC = "gateleen.expand.requests";
private static final String STORAGE_EXPAND_REQUEST_METRIC = "gateleen.storage.expand.requests";
private static final String LEVEL = "level";

public static final String MAX_EXPANSION_LEVEL_SOFT_PROPERTY = "max.expansion.level.soft";
public static final String MAX_EXPANSION_LEVEL_HARD_PROPERTY = "max.expansion.level.hard";
public static final String MAX_SUBREQUEST_PROPERTY = "max.expansion.subrequests";
Expand Down Expand Up @@ -123,6 +126,9 @@ public class ExpansionHandler implements RuleChangesObserver {

private RuleFeaturesProvider ruleFeaturesProvider = new RuleFeaturesProvider(new ArrayList<>());

private final Map<Integer, Counter> counterMap = new HashMap<>();
private Counter storageExpandCounter;

/**
* Creates a new instance of the ExpansionHandler.
*
Expand Down Expand Up @@ -176,6 +182,26 @@ public int getMaxSubRequestCount() {
return maxSubRequestCount;
}

public void setMeterRegistry(MeterRegistry meterRegistry) {
counterMap.clear();
if(meterRegistry != null) {
counterMap.put(0, Counter.builder(EXPAND_REQUEST_METRIC).tag(LEVEL, "0").register(meterRegistry));
counterMap.put(1, Counter.builder(EXPAND_REQUEST_METRIC).tag(LEVEL, "1").register(meterRegistry));
counterMap.put(2, Counter.builder(EXPAND_REQUEST_METRIC).tag(LEVEL, "2").register(meterRegistry));
counterMap.put(3, Counter.builder(EXPAND_REQUEST_METRIC).tag(LEVEL, "3").register(meterRegistry));
counterMap.put(4, Counter.builder(EXPAND_REQUEST_METRIC).tag(LEVEL, "4").register(meterRegistry));

storageExpandCounter = Counter.builder(STORAGE_EXPAND_REQUEST_METRIC).register(meterRegistry);
}
}

private void incrementExpandReqCount(int level) {
Counter counter = counterMap.get(level);
if(counter != null) {
counter.increment();
}
}

/**
* Initialize the lists which defines, when which parameter
* is removed (if any).
Expand Down Expand Up @@ -363,6 +389,8 @@ private void handleExpansionRequest(final HttpServerRequest req, final Recursive
log.debug("constructed uri for request: {}", targetUri);

Integer finalExpandLevel = expandLevel;
incrementExpandReqCount(finalExpandLevel);

httpClient.request(HttpMethod.GET, targetUri).onComplete(asyncReqResult -> {
if (asyncReqResult.failed()) {
log.warn("Failed request to {}: {}", targetUri, asyncReqResult.cause());
Expand Down Expand Up @@ -505,6 +533,11 @@ private void makeStorageExpandRequest(final String targetUri, final List subReso
Logger log = RequestLoggerFactory.getLogger(ExpansionHandler.class, req);
HttpMethod reqMethod = HttpMethod.POST;
String reqUri = targetUri + "?storageExpand=true";

if(storageExpandCounter != null) {
storageExpandCounter.increment();
}

httpClient.request(reqMethod, reqUri).onComplete(asyncResult -> {
if (asyncResult.failed()) {
log.warn("Failed request to {}", reqUri, asyncResult.cause());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public class ExpansionHandlerTest {
public void setUp() {
vertx = Vertx.vertx();
httpClient = Mockito.mock(HttpClient.class);
// Mockito.when(httpClient.request(any(HttpMethod.class), anyString(), Matchers.<Handler<HttpClientResponse>>any())).thenReturn(Mockito.mock(HttpClientRequest.class));
storage = new MockResourceStorage();
}

Expand Down
22 changes: 20 additions & 2 deletions gateleen-hook/README_hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ PUT http://myserver:7012/gateleen/everything/_hooks/listeners/http/myexample
"destination": "/gateleen/example/thePosition",
"filter": "/gateleen/everything/.*/position.*",
"headers": [
{ "header":"X-Expire-After", "value":"3600", mode:"complete"}
{ "header":"X-Expire-After", "value":"3600", "mode":"complete"}
],
"headersFilter": "x-foo: (A|B)"
}
Expand Down Expand Up @@ -294,4 +294,22 @@ The response contains the matching routes, or an empty list if no match is found
{
"routes": []
}
```
```

## Micrometer metrics
The hook feature is monitored with micrometer. The following metrics are available:
* gateleen_listener_count
* gateleen_routes_count

Example metrics:

```
# HELP gateleen_listener_count Amount of listener hooks currently registered
# TYPE gateleen_listener_count gauge
gateleen_listener_count 577.0
# HELP gateleen_routes_count Amount of route hooks currently registered
# TYPE gateleen_routes_count gauge
gateleen_routes_count 15.0
```

To enable the metrics, set a `MeterRegistry` instance by calling `setMeterRegistry(MeterRegistry meterRegistry)` method in `HookHandler` class.
4 changes: 4 additions & 0 deletions gateleen-hook/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
<artifactId>gateleen-queue</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>

<!-- TEST dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.ValidationMessage;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
Expand Down Expand Up @@ -59,6 +61,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -150,6 +153,10 @@ public class HookHandler implements LoggableResource {
private final String normalizedRouteBase;
private final String normalizedListenerBase;

private final AtomicLong listenerCount = new AtomicLong(0);
private final AtomicLong routesCount = new AtomicLong(0);
private MeterRegistry meterRegistry;

/**
* Creates a new HookHandler.
*
Expand All @@ -162,7 +169,7 @@ public class HookHandler implements LoggableResource {
* @param hookRootUri hookRootUri
*/
public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage storage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri) {
this(vertx, selfClient, storage, loggingResourceManager, logAppenderRepository, monitoringHandler, userProfilePath, hookRootUri,
new QueueClient(vertx, monitoringHandler));
Expand All @@ -182,14 +189,14 @@ public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage sto
* @param requestQueue requestQueue
*/
public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage storage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue) {
this(vertx, selfClient, storage, loggingResourceManager, logAppenderRepository, monitoringHandler, userProfilePath, hookRootUri,
requestQueue, false);
}

public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage storage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue, boolean listableRoutes) {
this(vertx, selfClient, storage, loggingResourceManager, logAppenderRepository, monitoringHandler, userProfilePath, hookRootUri,
requestQueue, false, null);
Expand All @@ -210,23 +217,23 @@ public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage sto
* @param reducedPropagationManager reducedPropagationManager
*/
public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage storage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue, boolean listableRoutes,
@Nullable ReducedPropagationManager reducedPropagationManager) {
this(vertx, selfClient, storage, loggingResourceManager, logAppenderRepository, monitoringHandler, userProfilePath, hookRootUri,
requestQueue, listableRoutes, reducedPropagationManager, null, storage);
}

public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage userProfileStorage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue, boolean listableRoutes,
ReducedPropagationManager reducedPropagationManager, @Nullable Handler doneHandler, ResourceStorage hookStorage) {
this(vertx, selfClient, userProfileStorage, loggingResourceManager, logAppenderRepository, monitoringHandler, userProfilePath, hookRootUri,
requestQueue, listableRoutes, reducedPropagationManager, doneHandler, hookStorage, Router.DEFAULT_ROUTER_MULTIPLIER);
}

public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage userProfileStorage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue, boolean listableRoutes,
ReducedPropagationManager reducedPropagationManager, @Nullable Handler doneHandler, ResourceStorage hookStorage,
int routeMultiplier) {
Expand Down Expand Up @@ -256,7 +263,7 @@ public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage use
* parallel operation.
*/
public HookHandler(Vertx vertx, HttpClient selfClient, final ResourceStorage userProfileStorage,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, MonitoringHandler monitoringHandler,
LoggingResourceManager loggingResourceManager, LogAppenderRepository logAppenderRepository, @Nullable MonitoringHandler monitoringHandler,
String userProfilePath, String hookRootUri, RequestQueue requestQueue, boolean listableRoutes,
ReducedPropagationManager reducedPropagationManager, @Nullable Handler doneHandler, ResourceStorage hookStorage,
int routeMultiplier, @Nonnull QueueSplitter queueSplitter) {
Expand Down Expand Up @@ -317,6 +324,16 @@ public void handle(Void aVoid) {
initMethods.forEach(handlerConsumer -> handlerConsumer.accept(readyHandler));
}

public void setMeterRegistry(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
if(meterRegistry != null) {
Gauge.builder("gateleen.listener.count", listenerCount, AtomicLong::get)
.description("Amount of listener hooks currently registered").register(meterRegistry);
Gauge.builder("gateleen.routes.count", routesCount, AtomicLong::get)
.description("Amount of route hooks currently registered").register(meterRegistry);
}
}

@Override
public void enableResourceLogging(boolean resourceLoggingEnabled) {
this.logHookConfigurationResourceChanges = resourceLoggingEnabled;
Expand Down Expand Up @@ -361,8 +378,15 @@ private void registerCleanupHandler(Handler<Void> readyHandler) {
routeRepository.removeRoute(key);
}
}
monitoringHandler.updateListenerCount(listenerRepository.size());
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
if(meterRegistry != null) {
listenerCount.set(listenerRepository.size());
routesCount.set(routeRepository.getRoutes().size());
}

if(monitoringHandler != null) {
monitoringHandler.updateListenerCount(listenerRepository.size());
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
}
log.trace("done");
});

Expand Down Expand Up @@ -1352,7 +1376,12 @@ private void unregisterRoute(String requestUrl) {
log.debug("Unregister route {}", routedUrl);

routeRepository.removeRoute(routedUrl);
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
if(meterRegistry != null) {
routesCount.set(routeRepository.getRoutes().size());
}
if(monitoringHandler != null) {
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
}
}

/**
Expand All @@ -1367,7 +1396,12 @@ private void unregisterListener(String requestUrl) {

routeRepository.removeRoute(hookRootUri + LISTENER_HOOK_TARGET_PATH + getListenerUrlSegment(requestUrl));
listenerRepository.removeListener(listenerId);
monitoringHandler.updateListenerCount(listenerRepository.size());
if(meterRegistry != null) {
listenerCount.set(listenerRepository.size());
}
if(monitoringHandler != null) {
monitoringHandler.updateListenerCount(listenerRepository.size());
}
}

/**
Expand Down Expand Up @@ -1491,7 +1525,12 @@ private void registerListener(Buffer buffer) {

// create and add a new listener (or update an already existing listener)
listenerRepository.addListener(new Listener(listenerId, getMonitoredUrlSegment(requestUrl), target, hook));
monitoringHandler.updateListenerCount(listenerRepository.size());
if(meterRegistry != null) {
listenerCount.set(listenerRepository.size());
}
if(monitoringHandler != null) {
monitoringHandler.updateListenerCount(listenerRepository.size());
}
}

/**
Expand Down Expand Up @@ -1672,7 +1711,12 @@ private void registerRoute(Buffer buffer) {
existingRoute.getRule().setHeaderFunction(hook.getHeaderFunction());
existingRoute.getHook().setExpirationTime(hook.getExpirationTime().orElse(null));
}
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
if(meterRegistry != null) {
routesCount.set(routeRepository.getRoutes().size());
}
if(monitoringHandler != null) {
monitoringHandler.updateRoutesCount(routeRepository.getRoutes().size());
}
}

/**
Expand Down Expand Up @@ -1721,8 +1765,10 @@ private boolean headersFilterPatternEquals(Pattern headersFilterPatternLeft, Pat
* @return Route
*/
private Route createRoute(String urlPattern, HttpHook hook, String hookDisplayText) {
return new Route(vertx, userProfileStorage, loggingResourceManager, logAppenderRepository, monitoringHandler,
Route route = new Route(vertx, userProfileStorage, loggingResourceManager, logAppenderRepository, monitoringHandler,
userProfilePath, hook, urlPattern, selfClient, hookDisplayText);
route.setMeterRegistry(meterRegistry);
return route;
}

/**
Expand Down
Loading

0 comments on commit 20aa5fe

Please sign in to comment.