Skip to content

Commit c727773

Browse files
committed
feat: #WB-3251, expose ent version as metrics
1 parent ab17df6 commit c727773

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

infra/src/main/java/org/entcore/infra/Starter.java

+16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.vertx.core.DeploymentOptions;
2828
import io.vertx.core.eventbus.MessageConsumer;
2929
import io.vertx.core.json.JsonArray;
30+
import io.vertx.core.metrics.MetricsOptions;
3031
import io.vertx.core.shareddata.AsyncMap;
3132
import io.vertx.core.shareddata.LocalMap;
3233
import org.entcore.common.email.EmailFactory;
@@ -37,6 +38,7 @@
3738
import org.entcore.infra.controllers.*;
3839
import org.entcore.infra.cron.HardBounceTask;
3940
import org.entcore.infra.cron.MonitoringEventsChecker;
41+
import org.entcore.infra.metrics.MicrometerInfraMetricsRecorder;
4042
import org.entcore.infra.services.EventStoreService;
4143
import org.entcore.infra.services.impl.ClamAvService;
4244
import org.entcore.infra.services.impl.ExecCommandWorker;
@@ -225,6 +227,20 @@ public void start() {
225227
);
226228
vertx.setPeriodic(checkMonitoringEvents.getLong("period", 300000L), monitoringEventsChecker);
227229
}
230+
final boolean metricsActivated;
231+
if(config.getJsonObject("metricsOptions") == null) {
232+
final String metricsOptions = (String) vertx.sharedData().getLocalMap("server").get("metricsOptions");
233+
if(metricsOptions == null){
234+
metricsActivated = false;
235+
}else{
236+
metricsActivated = new MetricsOptions(new JsonObject(metricsOptions)).isEnabled();
237+
}
238+
} else {
239+
metricsActivated = new MetricsOptions(config.getJsonObject("metricsOptions")).isEnabled();
240+
}
241+
if(metricsActivated) {
242+
new MicrometerInfraMetricsRecorder(vertx);
243+
}
228244
}
229245

230246
private void loadInvalidEmails() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.entcore.infra.metrics;
2+
3+
public interface InfraMetricsRecorder {
4+
class NoopInfraMetricsRecorder implements InfraMetricsRecorder {
5+
public static final InfraMetricsRecorder instance = new NoopInfraMetricsRecorder();
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.entcore.infra.metrics;
2+
3+
import io.micrometer.core.instrument.Gauge;
4+
import io.micrometer.core.instrument.MeterRegistry;
5+
import io.vertx.core.Vertx;
6+
import io.vertx.core.logging.Logger;
7+
import io.vertx.core.logging.LoggerFactory;
8+
import io.vertx.core.shareddata.LocalMap;
9+
import io.vertx.micrometer.backends.BackendRegistries;
10+
import org.apache.commons.lang3.StringUtils;
11+
12+
import java.util.concurrent.atomic.AtomicLong;
13+
14+
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
15+
16+
/**
17+
* Supplies the metric 'ent.version' that contains a codified version of the ENT.
18+
* It takes the value of "ent-version" from the configuration and then applies the following transformation :
19+
* - only numbers, hyphens and dots are preserved
20+
* - each group of digits between hyphens and dots are grouped together, right-padded with 0 if needed
21+
* - the groups are "concatenated" together and parsed to a long to get the exposed metric.
22+
* The metric is tagged with the version as specified in the configuration.
23+
*/
24+
public class MicrometerInfraMetricsRecorder implements InfraMetricsRecorder {
25+
private static final Logger log = LoggerFactory.getLogger(MicrometerInfraMetricsRecorder.class);
26+
private static final int VERSION_PADDING = 2;
27+
public MicrometerInfraMetricsRecorder(final Vertx vertx) {
28+
final MeterRegistry registry = BackendRegistries.getDefaultNow();
29+
if(registry == null) {
30+
throw new IllegalStateException("micrometer.registries.empty");
31+
}
32+
String literalVersion;
33+
final AtomicLong version = new AtomicLong();
34+
try {
35+
literalVersion = getLiteralVersion(vertx);
36+
version.set(getEntVersion(literalVersion));
37+
} catch (Exception e) {
38+
log.error("An error occurred while creating the metrics to expose ent version");
39+
literalVersion = "error";
40+
version.set(-1);
41+
}
42+
Gauge.builder("ent.version", version::get)
43+
.tag("ent-version", literalVersion).register(registry);
44+
}
45+
46+
private String getLiteralVersion(Vertx vertx) {
47+
String entVersion = vertx.getOrCreateContext().config().getString("ent-version");
48+
if(org.apache.commons.lang3.StringUtils.isEmpty(entVersion)) {
49+
final LocalMap<Object, Object> localMap = vertx.sharedData().getLocalMap("server");
50+
entVersion = (String)localMap.get("ent-version");
51+
}
52+
return StringUtils.isEmpty(entVersion) ? "na" : entVersion;
53+
}
54+
55+
private Long getEntVersion(final String entVersion) {
56+
final String cleanVersion = entVersion
57+
.replaceAll("[^\\d-\\.]","")
58+
.replaceAll("-", ".")
59+
.replaceAll("\\.{2,}", "");
60+
final String[] parts = cleanVersion.split("\\.");
61+
long version = 0;
62+
for(int i = 0; i < parts.length ; i++) {
63+
final String part = parts[i].trim();
64+
if(isNotEmpty(part)) {
65+
version += (long) (Integer.parseInt(part) * Math.pow(10, VERSION_PADDING * (parts.length - (i + 1))));
66+
}
67+
}
68+
return version;
69+
}
70+
}

0 commit comments

Comments
 (0)