refactoring reporter structure to make it easier to be pluggable
diff --git a/geronimo-microprofile-reporter/pom.xml b/geronimo-microprofile-reporter/pom.xml
index 7db4665..fe6028e 100644
--- a/geronimo-microprofile-reporter/pom.xml
+++ b/geronimo-microprofile-reporter/pom.xml
@@ -66,6 +66,12 @@
<version>4.12</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.meecrowave</groupId>
+ <artifactId>meecrowave-junit</artifactId>
+ <version>${meecrowave.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck1.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck1.java
deleted file mode 100644
index 9c12b18..0000000
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck1.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (C) 2006-2019 Talend Inc. - www.talend.com
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.geronimo.microprofile.reporter.storage;
-
-import javax.enterprise.context.Dependent;
-
-import org.eclipse.microprofile.health.Health;
-import org.eclipse.microprofile.health.HealthCheck;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-
-@Health
-@Dependent
-public class FakeCheck1 implements HealthCheck {
- @Override
- public HealthCheckResponse call() {
- return HealthCheckResponse.named("check1").up().build();
- }
-}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck2.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck2.java
deleted file mode 100644
index 2bab8bb..0000000
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/FakeCheck2.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (C) 2006-2019 Talend Inc. - www.talend.com
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.geronimo.microprofile.reporter.storage;
-
-import javax.enterprise.context.Dependent;
-
-import org.eclipse.microprofile.health.Health;
-import org.eclipse.microprofile.health.HealthCheck;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
-
-@Health
-@Dependent
-public class FakeCheck2 implements HealthCheck {
- @Override
- public HealthCheckResponse call() {
- final HealthCheckResponseBuilder named = HealthCheckResponse.named("check_2");
- if (System.currentTimeMillis() % 2 == 0) {
- return named.up().withData("foo", "bar").withData("another", "dummy").build();
- }
- return named.down().withData("foo", "bar").withData("another", "dummy").build();
- }
-}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/MicroprofileDatabase.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/MicroprofileDatabase.java
deleted file mode 100644
index cf67677..0000000
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/MicroprofileDatabase.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.geronimo.microprofile.reporter.storage;
-
-import static java.lang.Thread.NORM_PRIORITY;
-import static java.util.Optional.ofNullable;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.eclipse.microprofile.metrics.MetricRegistry.Type.BASE;
-import static org.eclipse.microprofile.metrics.MetricRegistry.Type.VENDOR;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.stream.Stream;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.Destroyed;
-import javax.enterprise.context.Initialized;
-import javax.enterprise.event.Observes;
-import javax.inject.Inject;
-import javax.servlet.ServletContext;
-
-import org.apache.geronimo.microprofile.opentracing.common.impl.FinishedSpan;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-import org.eclipse.microprofile.metrics.Metered;
-import org.eclipse.microprofile.metrics.MetricRegistry;
-import org.eclipse.microprofile.metrics.Snapshot;
-import org.eclipse.microprofile.metrics.annotation.RegistryType;
-
-import io.opentracing.Span;
-
-// TODO: make span dependency optional and composable (events?)
-@ApplicationScoped
-public class MicroprofileDatabase {
-
- @Inject
- @ConfigProperty(name = "geronimo.microprofile.reporter.metrics.pollingInterval", defaultValue = "5000")
- private Long pollingInterval;
-
- @Inject
- @RegistryType(type = BASE)
- private MetricRegistry baseRegistry;
-
- @Inject
- @RegistryType(type = VENDOR)
- private MetricRegistry vendorRegistry;
-
- @Inject
- private MetricRegistry applicationRegistry;
-
- @Inject
- private HealthRegistry healthRegistry;
-
- private ScheduledExecutorService scheduler;
-
- private ScheduledFuture<?> pollFuture;
-
- private Map<String, MetricRegistry> metrics;
-
- private final InMemoryDatabase<Span> spanDatabase = new InMemoryDatabase<>("none");
- private final Map<String, InMemoryDatabase<Long>> counters = new HashMap<>();
- private final Map<String, InMemoryDatabase<Double>> gauges = new HashMap<>();
- private final Map<String, InMemoryDatabase<Snapshot>> histograms = new HashMap<>();
- private final Map<String, InMemoryDatabase<MeterSnapshot>> meters = new HashMap<>();
- private final Map<String, InMemoryDatabase<TimerSnapshot>> timers = new HashMap<>();
- private final Map<String, InMemoryDatabase<CheckSnapshot>> checks = new HashMap<>();
-
- public InMemoryDatabase<Span> getSpans() {
- return spanDatabase;
- }
-
- public Map<String, InMemoryDatabase<Long>> getCounters() {
- return counters;
- }
-
- public Map<String, InMemoryDatabase<Double>> getGauges() {
- return gauges;
- }
-
- public Map<String, InMemoryDatabase<Snapshot>> getHistograms() {
- return histograms;
- }
-
- public Map<String, InMemoryDatabase<MeterSnapshot>> getMeters() {
- return meters;
- }
-
- public Map<String, InMemoryDatabase<TimerSnapshot>> getTimers() {
- return timers;
- }
-
- public Map<String, InMemoryDatabase<CheckSnapshot>> getChecks() {
- return checks;
- }
-
- private void poll() {
- metrics.forEach(this::updateMetrics);
-
- healthRegistry.doCheck().forEach(this::updateHealthCheck);
- }
-
- private void updateHealthCheck(final HealthCheckResponse healthCheckResponse) {
- final String name = healthCheckResponse.getName();
- InMemoryDatabase<CheckSnapshot> db = checks.get(name);
- if (db == null) {
- db = new InMemoryDatabase<>("check");
- final InMemoryDatabase<CheckSnapshot> existing = checks.putIfAbsent(name, db);
- if (existing != null) {
- db = existing;
- }
- }
- db.add(new CheckSnapshot(
- healthCheckResponse.getName(),
- ofNullable(healthCheckResponse.getState()).orElse(HealthCheckResponse.State.DOWN).name(),
- healthCheckResponse.getData().map(HashMap::new).orElseGet(HashMap::new)));
- }
-
- private void updateMetrics(final String type, final MetricRegistry registry) {
- registry.getCounters().forEach((name, counter) -> {
- final String virtualName = getMetricStorageName(type, name);
- final long count = counter.getCount();
- getDb(counters, virtualName, registry, name).add(count);
- });
-
- registry.getGauges().forEach((name, gauge) -> {
- final String virtualName = getMetricStorageName(type, name);
- final Object value = gauge.getValue();
- if (Number.class.isInstance(value)) {
- try {
- getDb(gauges, virtualName, registry, name).add(Number.class.cast(value).doubleValue());
- } catch (final NullPointerException | NumberFormatException nfe) {
- // ignore, we can't do much if the value is not a double
- }
- } // else ignore, will not be able to do anything of it anyway
- });
-
- registry.getHistograms().forEach((name, histogram) -> {
- final String virtualName = getMetricStorageName(type, name);
- final Snapshot snapshot = histogram.getSnapshot();
- getDb(histograms, virtualName, registry, name).add(snapshot);
- });
-
- registry.getMeters().forEach((name, meter) -> {
- final String virtualName = getMetricStorageName(type, name);
- final MeterSnapshot snapshot = new MeterSnapshot(meter);
- getDb(meters, virtualName, registry, name).add(snapshot);
- });
-
- registry.getTimers().forEach((name, timer) -> {
- final String virtualName = getMetricStorageName(type, name);
- final TimerSnapshot snapshot = new TimerSnapshot(new MeterSnapshot(timer), timer.getSnapshot());
- getDb(timers, virtualName, registry, name).add(snapshot);
- });
- }
-
- // alternatively we can decorate the registries and register/unregister following the registry lifecycle
- // shouldnt be worth it for now
- private <T> InMemoryDatabase<T> getDb(final Map<String, InMemoryDatabase<T>> registry,
- final String virtualName, final MetricRegistry source,
- final String key) {
- InMemoryDatabase<T> db = registry.get(virtualName);
- if (db == null) {
- db = new InMemoryDatabase<>(ofNullable(source.getMetadata().get(key).getUnit()).orElse(""));
- final InMemoryDatabase<T> existing = registry.putIfAbsent(virtualName, db);
- if (existing != null) {
- db = existing;
- }
- }
- return db;
- }
-
- private String getMetricStorageName(final String type, final String name) {
- return type + "#" + name;
- }
-
- private String name(final Object start) {
- if (ServletContext.class.isInstance(start)) {
- final ServletContext context = ServletContext.class.cast(start);
- try {
- return "[web=" + context.getVirtualServerName() + '/' + context.getContextPath() + "]";
- } catch (final Error | Exception e) { // no getVirtualServerName() for this context
- return "[web=" + context.getContextPath() + "]";
- }
- }
- return start.toString();
- }
-
- void onSpan(@Observes final FinishedSpan span) {
- final Span value = span.getSpan();
- if (value.getClass().getName().equals("org.apache.geronimo.microprofile.opentracing.common.impl.SpanImpl")) {
- spanDatabase.add(value);
- } // else we will not be able to read the metadata
- }
-
- void onStart(@Observes @Initialized(ApplicationScoped.class) final Object start) {
- metrics = new HashMap<>(3);
- metrics.put("vendor", vendorRegistry);
- metrics.put("base", baseRegistry);
- metrics.put("application", applicationRegistry);
-
- final ClassLoader appLoader = Thread.currentThread().getContextClassLoader();
- scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
- final Thread thread = new Thread(r, "geronimo-microprofile-reporter-poller-" + name(start));
- thread.setContextClassLoader(appLoader);
- if (thread.isDaemon()) {
- thread.setDaemon(false);
- }
- if (thread.getPriority() != NORM_PRIORITY) {
- thread.setPriority(NORM_PRIORITY);
- }
- return thread;
- });
- pollFuture = scheduler.scheduleAtFixedRate(this::poll, pollingInterval, pollingInterval, MILLISECONDS);
- }
-
- void onStop(@Observes @Destroyed(ApplicationScoped.class) final Object stop) {
- if (pollFuture != null) {
- pollFuture.cancel(true);
- pollFuture = null;
- }
- if (scheduler != null) {
- scheduler.shutdownNow();
- try {
- scheduler.awaitTermination(10, SECONDS);
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- scheduler = null;
- }
- Stream.of(counters, gauges, histograms, meters, timers).forEach(Map::clear);
- }
-
- public static class TimerSnapshot {
- private final MeterSnapshot meter;
- private final Snapshot histogram;
-
- private TimerSnapshot(final MeterSnapshot meter, final Snapshot histogram) {
- this.meter = meter;
- this.histogram = histogram;
- }
- }
-
- public static class MeterSnapshot {
- private final long count;
- private final double rateMean;
- private final double rate1;
- private final double rate5;
- private final double rate15;
-
- private MeterSnapshot(final Metered meter) {
- this(meter.getCount(), meter.getMeanRate(), meter.getOneMinuteRate(), meter.getFiveMinuteRate(), meter.getFifteenMinuteRate());
- }
-
- private MeterSnapshot(final long count, final double rateMean,
- final double rate1, final double rate5, final double rate15) {
- this.count = count;
- this.rateMean = rateMean;
- this.rate1 = rate1;
- this.rate5 = rate5;
- this.rate15 = rate15;
- }
- }
-
- public static class CheckSnapshot {
- private final String name;
- private final String state;
- private final Map<String, Object> data;
-
- private CheckSnapshot(final String name, final String state, final Map<String, Object> data) {
- this.name = name;
- this.state = state;
- this.data = data;
- }
- }
-}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/InMemoryDatabase.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/InMemoryDatabase.java
similarity index 97%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/InMemoryDatabase.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/InMemoryDatabase.java
index 7b3d86c..d1b5213 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/InMemoryDatabase.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/InMemoryDatabase.java
@@ -14,12 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.data;
import static java.util.stream.Collectors.toMap;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
@@ -67,7 +66,7 @@
}
}
- void add(final T value) {
+ public void add(final T value) {
ensureUpToDate();
final long now = System.currentTimeMillis();
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/MicroprofileDatabase.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/MicroprofileDatabase.java
new file mode 100644
index 0000000..b4bc8da
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/data/MicroprofileDatabase.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.data;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Destroyed;
+import javax.enterprise.event.Observes;
+
+import org.apache.geronimo.microprofile.reporter.storage.plugins.health.CheckSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.MeterSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.SnapshotStat;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.TimerSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.tracing.SpanEntry;
+
+@ApplicationScoped
+public class MicroprofileDatabase {
+ private final InMemoryDatabase<SpanEntry> spanDatabase = new InMemoryDatabase<>("none");
+ private final Map<String, InMemoryDatabase<Long>> counters = new HashMap<>();
+ private final Map<String, InMemoryDatabase<Double>> gauges = new HashMap<>();
+ private final Map<String, InMemoryDatabase<SnapshotStat>> histograms = new HashMap<>();
+ private final Map<String, InMemoryDatabase<MeterSnapshot>> meters = new HashMap<>();
+ private final Map<String, InMemoryDatabase<TimerSnapshot>> timers = new HashMap<>();
+ private final Map<String, InMemoryDatabase<CheckSnapshot>> checks = new HashMap<>();
+
+ public InMemoryDatabase<SpanEntry> getSpans() {
+ return spanDatabase;
+ }
+
+ public Map<String, InMemoryDatabase<Long>> getCounters() {
+ return counters;
+ }
+
+ public Map<String, InMemoryDatabase<Double>> getGauges() {
+ return gauges;
+ }
+
+ public Map<String, InMemoryDatabase<SnapshotStat>> getHistograms() {
+ return histograms;
+ }
+
+ public Map<String, InMemoryDatabase<MeterSnapshot>> getMeters() {
+ return meters;
+ }
+
+ public Map<String, InMemoryDatabase<TimerSnapshot>> getTimers() {
+ return timers;
+ }
+
+ public Map<String, InMemoryDatabase<CheckSnapshot>> getChecks() {
+ return checks;
+ }
+
+ void onStop(@Observes @Destroyed(ApplicationScoped.class) final Object stop) {
+ Stream.of(counters, gauges, histograms, meters, timers).forEach(Map::clear);
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/Html.java
similarity index 95%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/Html.java
index 8ed2414..b4e7523 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/Html.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.front;
import static java.util.Collections.unmodifiableMap;
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HtmlWriter.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/HtmlWriter.java
similarity index 96%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HtmlWriter.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/HtmlWriter.java
index 2efc598..11040be 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HtmlWriter.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/HtmlWriter.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.front;
import static java.util.stream.Collectors.joining;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
@@ -43,6 +43,8 @@
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
+import org.apache.geronimo.microprofile.reporter.storage.templating.TemplatingEngine;
+
@Provider
@Dependent
@Produces(TEXT_HTML)
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/ReporterEndpoints.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/ReporterEndpoints.java
similarity index 81%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/ReporterEndpoints.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/ReporterEndpoints.java
index 984adba..c6ac0ad 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/ReporterEndpoints.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/front/ReporterEndpoints.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.front;
import static java.util.Arrays.asList;
import static java.util.Comparator.comparing;
@@ -28,6 +28,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@@ -40,14 +41,19 @@
import javax.ws.rs.BadRequestException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-import org.eclipse.microprofile.metrics.Snapshot;
-
-import io.opentracing.Span;
+import org.apache.geronimo.microprofile.reporter.storage.data.InMemoryDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.data.MicroprofileDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.health.CheckSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.health.HealthService;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.MeterSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.SnapshotStat;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.metrics.TimerSnapshot;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.tracing.SpanEntry;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.tracing.TracingExtension;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
@Path("geronimo/microprofile/reporter")
@ApplicationScoped
@@ -59,19 +65,21 @@
private MicroprofileDatabase database;
@Inject
- private SpanMapper spanMapper;
+ private HealthService health;
@Inject
- private HealthRegistry healthRegistry;
+ private TracingExtension tracing;
+
+ @Inject
+ @ConfigProperty(name = "geronimo.microprofile.reporter.resources.chartjs",
+ defaultValue = "/META-INF/resources/webjars/chart.js/2.7.3/dist/Chart.bundle.min.js")
+ private String chartJsResource;
private String chartJs;
+ private List<String> tiles;
@PostConstruct
private void init() {
- // we load chart.js like that to enable to override it easily and respect our relative path properly
- final String chartJsResource = System.getProperty( // don't use mp-config, it is optional
- "geronimo.microprofile.reporter.chartjs.resources",
- "/META-INF/resources/webjars/chart.js/2.7.3/dist/Chart.bundle.min.js");
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
chartJs = (chartJsResource.startsWith("/") ?
Stream.of(chartJsResource, chartJsResource.substring(1)) : Stream.of(chartJsResource, '/' + chartJsResource))
@@ -92,6 +100,14 @@
.findFirst()
.orElseThrow(() -> new IllegalStateException("No " + chartJsResource + " found, did you add org.webjars.bower:chart.js:2.7.3 to your classpath?"));
+ tiles = new ArrayList<>(7);
+ if (tracing.isActive()) {
+ tiles.add("Spans");
+ }
+ tiles.addAll(asList("Counters", "Gauges", "Histograms", "Meters", "Timers"));
+ if (health.isActive()) {
+ tiles.add("Health Checks");
+ }
}
@GET
@@ -100,7 +116,7 @@
.with("view", "index.html")
.with("colors", COLORS)
.with("title", "Home")
- .with("tiles", asList("Spans", "Counters", "Gauges", "Histograms", "Meters", "Timers", "Health Checks"));
+ .with("tiles", tiles);
}
@GET
@@ -177,7 +193,7 @@
@GET
@Path("histogram")
public Html getHistogram(@QueryParam("histogram") final String name) {
- final InMemoryDatabase<Snapshot> db = database.getHistograms().get(name);
+ final InMemoryDatabase<SnapshotStat> db = database.getHistograms().get(name);
return new Html("main.html")
.with("view", "histogram.html")
.with("colors", COLORS)
@@ -201,7 +217,7 @@
@GET
@Path("meter")
public Html getMeter(@QueryParam("meter") final String name) {
- final InMemoryDatabase<MicroprofileDatabase.MeterSnapshot> db = database.getMeters().get(name);
+ final InMemoryDatabase<MeterSnapshot> db = database.getMeters().get(name);
return new Html("main.html")
.with("view", "meter.html")
.with("colors", COLORS)
@@ -225,7 +241,7 @@
@GET
@Path("timer")
public Html getTimer(@QueryParam("timer") final String name) {
- final InMemoryDatabase<MicroprofileDatabase.TimerSnapshot> db = database.getTimers().get(name);
+ final InMemoryDatabase<TimerSnapshot> db = database.getTimers().get(name);
return new Html("main.html")
.with("view", "timer.html")
.with("colors", COLORS)
@@ -239,7 +255,7 @@
@GET
@Path("spans")
public Html getSpans() {
- final InMemoryDatabase<Span> db = database.getSpans();
+ final InMemoryDatabase<SpanEntry> db = database.getSpans();
return new Html("main.html")
.with("view", "spans.html")
.with("colors", COLORS)
@@ -247,15 +263,15 @@
.with("spans", db == null ?
null :
db.snapshot().stream()
- .map(it -> new Point<>(it.getTimestamp(), spanMapper.map(it.getValue())))
+ .map(it -> new Point<>(it.getTimestamp(), it.getValue()))
.collect(toList()));
}
@GET
@Path("span")
public Html getSpan(@QueryParam("spanId") final String id) {
- final SpanMapper.SpanEntry value = database.getSpans().snapshot().stream()
- .map(it -> spanMapper.map(it.getValue()))
+ final SpanEntry value = database.getSpans().snapshot().stream()
+ .map(InMemoryDatabase.Value::getValue)
.filter(it -> it.getSpanId().equals(id))
.findFirst()
.orElseThrow(() -> new BadRequestException("No matching span"));
@@ -279,7 +295,7 @@
@GET
@Path("check")
public Html getHealth(@QueryParam("check") final String name) {
- final InMemoryDatabase<MicroprofileDatabase.CheckSnapshot> db = database.getChecks().get(name);
+ final InMemoryDatabase<CheckSnapshot> db = database.getChecks().get(name);
return new Html("main.html")
.with("view", "health.html")
.with("colors", COLORS)
@@ -292,7 +308,7 @@
@GET
@Path("health-check-detail")
public Html getHealthCheckDetail(@QueryParam("check") final String name) {
- final InMemoryDatabase.Value<MicroprofileDatabase.CheckSnapshot> last = ofNullable(database.getChecks().get(name))
+ final InMemoryDatabase.Value<CheckSnapshot> last = ofNullable(database.getChecks().get(name))
.map(InMemoryDatabase::snapshot)
.map(it -> it.isEmpty() ? null : it.getLast())
.orElse(null); // todo: orElseGet -> call them all and filter per name?
@@ -309,17 +325,16 @@
@GET
@Path("health-application")
public Html getApplicationHealth() {
- final List<HealthCheckResponse> checks = healthRegistry.doCheck()
- .sorted(comparing(HealthCheckResponse::getName))
- .collect(toList());
- final boolean stateOk = checks.stream()
- .noneMatch(it -> it.getState().equals(HealthCheckResponse.State.DOWN));
+ final List<CheckSnapshot> checks = health.doCheck()
+ .sorted(comparing(CheckSnapshot::getName))
+ .collect(toList());
return new Html("main.html")
.with("view", "health-application.html")
.with("colors", COLORS)
.with("title", "Application Health")
- .with("globalStateOk", stateOk)
- .with("globalStateKo", !stateOk)
+ .with("globalState", checks.stream()
+ .filter(it -> it.getState().equals("DOWN")).findAny()
+ .map(CheckSnapshot::getState).orElse("UP"))
.with("checks", checks);
}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Poller.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Poller.java
new file mode 100644
index 0000000..6d74c99
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Poller.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2006-2019 Talend Inc. - www.talend.com
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins;
+
+import static java.lang.Thread.NORM_PRIORITY;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Destroyed;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Event;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+@ApplicationScoped
+public class Poller {
+ private static final Tick TICK = new Tick();
+
+ private ScheduledExecutorService scheduler;
+
+ private ScheduledFuture<?> pollFuture;
+
+ @Inject
+ private Event<Tick> tickEvent;
+
+ void onStart(@Observes @Initialized(ApplicationScoped.class) final Object start,
+ @ConfigProperty(name = "geronimo.microprofile.reporter.polling.interval", defaultValue = "5000") final Long pollingInterval) {
+ if (pollingInterval <= 0) {
+ return;
+ }
+
+ final ClassLoader appLoader = Thread.currentThread().getContextClassLoader();
+ scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
+ final Thread thread = new Thread(r, "geronimo-microprofile-reporter-poller-" + name(start));
+ thread.setContextClassLoader(appLoader);
+ if (thread.isDaemon()) {
+ thread.setDaemon(false);
+ }
+ if (thread.getPriority() != NORM_PRIORITY) {
+ thread.setPriority(NORM_PRIORITY);
+ }
+ return thread;
+ });
+ pollFuture = scheduler.scheduleAtFixedRate(() -> tickEvent.fire(TICK), pollingInterval, pollingInterval, MILLISECONDS);
+ }
+
+ void onStop(@Observes @Destroyed(ApplicationScoped.class) final Object stop) {
+ if (pollFuture != null) {
+ pollFuture.cancel(true);
+ pollFuture = null;
+ }
+ if (scheduler != null) {
+ scheduler.shutdownNow();
+ try {
+ scheduler.awaitTermination(10, SECONDS);
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ scheduler = null;
+ }
+ }
+
+ private String name(final Object start) {
+ if (ServletContext.class.isInstance(start)) {
+ final ServletContext context = ServletContext.class.cast(start);
+ try {
+ return "[web=" + context.getVirtualServerName() + '/' + context.getContextPath() + "]";
+ } catch (final Error | Exception e) { // no getVirtualServerName() for this context
+ return "[web=" + context.getContextPath() + "]";
+ }
+ }
+ return start.toString();
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Tick.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Tick.java
new file mode 100644
index 0000000..0d938bf
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/Tick.java
@@ -0,0 +1,18 @@
+/**
+ * Copyright (C) 2006-2019 Talend Inc. - www.talend.com
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins;
+
+public class Tick {}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/CheckSnapshot.java
similarity index 63%
copy from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java
copy to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/CheckSnapshot.java
index 8ed2414..fde661c 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/Html.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/CheckSnapshot.java
@@ -14,34 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
-import static java.util.Collections.unmodifiableMap;
-
-import java.util.HashMap;
import java.util.Map;
-public class Html {
+public class CheckSnapshot {
private final String name;
- private final Map<String, Object> data = new HashMap<>();
+ private final String state;
+ private final Map<String, Object> data;
- public Html(final String name) {
+ CheckSnapshot(final String name, final String state, final Map<String, Object> data) {
this.name = name;
+ this.state = state;
+ this.data = data;
}
- public Html with(final String name, final Object data) {
- if (data == null) {
- return this;
- }
- this.data.put(name, data);
- return this;
- }
-
- String getName() {
+ public String getName() {
return name;
}
- Map<String, Object> getData() {
- return unmodifiableMap(data);
+ public String getState() {
+ return state;
+ }
+
+ public Map<String, Object> getData() {
+ return data;
}
}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthDataExtractor.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthDataExtractor.java
new file mode 100644
index 0000000..b4a9e05
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthDataExtractor.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
+
+import static java.util.Optional.ofNullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.enterprise.inject.Vetoed;
+
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+
+@Vetoed
+class HealthDataExtractor {
+ private final List<HealthCheck> checks = new ArrayList<>();
+
+ Stream<CheckSnapshot> doCheck() {
+ return checks.stream().map(check -> {
+ try {
+ return check.call();
+ } catch (final RuntimeException re) {
+ return HealthCheckResponse.named(check.getClass().getName())
+ .down()
+ .withData("exceptionMessage", re.getMessage())
+ .build();
+ }
+ }).map(healthCheckResponse -> new CheckSnapshot(
+ healthCheckResponse.getName(),
+ ofNullable(healthCheckResponse.getState()).orElse(HealthCheckResponse.State.DOWN).name(),
+ healthCheckResponse.getData().map(HashMap::new).orElseGet(HashMap::new)));
+ }
+
+ void register(final Object check) {
+ checks.add(HealthCheck.class.cast(check));
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HealthRegistry.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthRegistry.java
similarity index 63%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HealthRegistry.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthRegistry.java
index 0b97764..eab7110 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/HealthRegistry.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthRegistry.java
@@ -14,59 +14,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
-
-import static java.util.stream.Collectors.toList;
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
-import java.util.stream.Stream;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessBean;
-import org.eclipse.microprofile.health.Health;
-import org.eclipse.microprofile.health.HealthCheck;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-
public class HealthRegistry implements Extension {
private static final Annotation[] NO_ANNOTATION = new Annotation[0];
private final Collection<Bean<?>> beans = new ArrayList<>();
private final Collection<CreationalContext<?>> contexts = new ArrayList<>();
- private final List<HealthCheck> checks = new ArrayList<>();
- public Stream<HealthCheckResponse> doCheck() {
- return checks.stream().map(check -> invoke(check));
- }
+ private Class<? extends Annotation> annotationMarker;
+ private Class<?> apiType;
- private HealthCheckResponse invoke(final HealthCheck check) {
+ void onStart(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
- return check.call();
- } catch (final RuntimeException re) {
- return HealthCheckResponse.named(check.getClass().getName())
- .down()
- .withData("exceptionMessage", re.getMessage())
- .build();
+ annotationMarker = (Class<? extends Annotation>) loader.loadClass("org.eclipse.microprofile.health.Health");
+ apiType = loader.loadClass("org.eclipse.microprofile.health.HealthCheck");
+ } catch (final ClassNotFoundException e) {
+ // no-op
}
}
+ public Class<?> getApiType() {
+ return apiType;
+ }
+
void findChecks(@Observes final ProcessBean<?> bean) {
- if (bean.getAnnotated().isAnnotationPresent(Health.class) && bean.getBean().getTypes().contains(HealthCheck.class)) {
+ if (bean.getAnnotated().isAnnotationPresent(annotationMarker) && bean.getBean().getTypes().contains(apiType)) {
beans.add(bean.getBean());
}
}
void start(@Observes final AfterDeploymentValidation afterDeploymentValidation, final BeanManager beanManager) {
- checks.addAll(beans.stream().map(it -> lookup(it, beanManager)).collect(toList()));
+ if (beans.isEmpty()) {
+ return;
+ }
+ final HealthService healthService = HealthService.class.cast(
+ beanManager.getReference(beanManager.resolve(beanManager.getBeans(HealthService.class)),
+ HealthService.class, beanManager.createCreationalContext(null)));
+ beans.stream().map(it -> lookup(it, beanManager)).forEach(healthService::register);
}
void stop(@Observes final BeforeShutdown beforeShutdown) {
@@ -83,14 +83,14 @@
}
}
- private HealthCheck lookup(final Bean<?> bean, final BeanManager manager) {
+ private Object lookup(final Bean<?> bean, final BeanManager manager) {
final Class<?> beanClass = bean.getBeanClass();
final Bean<?> resolvedBean = manager.resolve(manager.getBeans(
- beanClass != null ? beanClass : HealthCheck.class, bean.getQualifiers().toArray(NO_ANNOTATION)));
+ beanClass != null ? beanClass : apiType, bean.getQualifiers().toArray(NO_ANNOTATION)));
final CreationalContext<Object> creationalContext = manager.createCreationalContext(null);
if (!manager.isNormalScope(resolvedBean.getScope())) {
contexts.add(creationalContext);
}
- return HealthCheck.class.cast(manager.getReference(resolvedBean, HealthCheck.class, creationalContext));
+ return manager.getReference(resolvedBean, apiType, creationalContext);
}
}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthService.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthService.java
new file mode 100644
index 0000000..a93db8b
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthService.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
+
+import java.util.stream.Stream;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+
+import org.apache.geronimo.microprofile.reporter.storage.data.InMemoryDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.data.MicroprofileDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.Tick;
+
+// cdi indirection to not require health check api and impl to be present
+@ApplicationScoped
+public class HealthService {
+ private final HealthDataExtractor extractor = new HealthDataExtractor();
+
+ @Inject
+ private HealthRegistry registry;
+
+ @Inject
+ private MicroprofileDatabase database;
+
+ public boolean isActive() {
+ return registry.getApiType() != null;
+ }
+
+ void register(final Object check) {
+ extractor.register(check);
+ }
+
+ public Stream<CheckSnapshot> doCheck() {
+ return extractor.doCheck();
+ }
+
+ public void onTick(@Observes final Tick tick) {
+ if (isActive()) {
+ doCheck().forEach(this::updateHealthCheck);
+ }
+ }
+
+ private void updateHealthCheck(final CheckSnapshot healthCheckResponse) {
+ final String name = healthCheckResponse.getName();
+ InMemoryDatabase<CheckSnapshot> db = database.getChecks().get(name);
+ if (db == null) {
+ db = new InMemoryDatabase<>("check");
+ final InMemoryDatabase<CheckSnapshot> existing = database.getChecks().putIfAbsent(name, db);
+ if (existing != null) {
+ db = existing;
+ }
+ }
+ db.add(healthCheckResponse);
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MeterSnapshot.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MeterSnapshot.java
new file mode 100644
index 0000000..47da990
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MeterSnapshot.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2006-2019 Talend Inc. - www.talend.com
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.metrics;
+
+public class MeterSnapshot {
+ private final long count;
+ private final double rateMean;
+ private final double rate1;
+ private final double rate5;
+ private final double rate15;
+
+ MeterSnapshot(final long count, final double rateMean,
+ final double rate1, final double rate5, final double rate15) {
+ this.count = count;
+ this.rateMean = rateMean;
+ this.rate1 = rate1;
+ this.rate5 = rate5;
+ this.rate15 = rate15;
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MetricsService.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MetricsService.java
new file mode 100644
index 0000000..124c2c9
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/MetricsService.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.metrics;
+
+import static java.util.Optional.ofNullable;
+import static org.eclipse.microprofile.metrics.MetricRegistry.Type.BASE;
+import static org.eclipse.microprofile.metrics.MetricRegistry.Type.VENDOR;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+
+import org.apache.geronimo.microprofile.reporter.storage.data.InMemoryDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.data.MicroprofileDatabase;
+import org.apache.geronimo.microprofile.reporter.storage.plugins.Tick;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Snapshot;
+import org.eclipse.microprofile.metrics.annotation.RegistryType;
+
+@ApplicationScoped
+public class MetricsService {
+ @Inject
+ private MicroprofileDatabase database;
+
+ @Inject
+ @RegistryType(type = BASE)
+ private MetricRegistry baseRegistry;
+
+ @Inject
+ @RegistryType(type = VENDOR)
+ private MetricRegistry vendorRegistry;
+
+ @Inject
+ private MetricRegistry applicationRegistry;
+
+ private Map<String, MetricRegistry> metricsIndex;
+
+ private void updateMetrics(final String type, final MetricRegistry registry) {
+ registry.getCounters().forEach((name, counter) -> {
+ final String virtualName = getMetricStorageName(type, name);
+ final long count = counter.getCount();
+ getDb(database.getCounters(), virtualName, registry, name).add(count);
+ });
+
+ registry.getGauges().forEach((name, gauge) -> {
+ final String virtualName = getMetricStorageName(type, name);
+ final Object value = gauge.getValue();
+ if (Number.class.isInstance(value)) {
+ try {
+ getDb(database.getGauges(), virtualName, registry, name).add(Number.class.cast(value).doubleValue());
+ } catch (final NullPointerException | NumberFormatException nfe) {
+ // ignore, we can't do much if the value is not a double
+ }
+ } // else ignore, will not be able to do anything of it anyway
+ });
+
+ registry.getHistograms().forEach((name, histogram) -> {
+ final String virtualName = getMetricStorageName(type, name);
+ final Snapshot snapshot = histogram.getSnapshot();
+ getDb(database.getHistograms(), virtualName, registry, name)
+ .add(new SnapshotStat(snapshot.size(), snapshot.getMedian(), snapshot.getMean(), snapshot.getMin(), snapshot.getMax(), snapshot.getStdDev(),
+ snapshot.get75thPercentile(), snapshot.get95thPercentile(), snapshot.get98thPercentile(), snapshot.get99thPercentile(), snapshot.get999thPercentile()));
+ });
+
+ registry.getMeters().forEach((name, meter) -> {
+ final String virtualName = getMetricStorageName(type, name);
+ final MeterSnapshot snapshot = new MeterSnapshot(
+ meter.getCount(), meter.getMeanRate(), meter.getOneMinuteRate(), meter.getFiveMinuteRate(), meter.getFifteenMinuteRate());
+ getDb(database.getMeters(), virtualName, registry, name).add(snapshot);
+ });
+
+ registry.getTimers().forEach((name, timer) -> {
+ final String virtualName = getMetricStorageName(type, name);
+ final Snapshot snapshot = timer.getSnapshot();
+ final TimerSnapshot timerSnapshot = new TimerSnapshot(new MeterSnapshot(
+ timer.getCount(), timer.getMeanRate(), timer.getOneMinuteRate(), timer.getFiveMinuteRate(), timer.getFifteenMinuteRate()),
+ new SnapshotStat(snapshot.size(), snapshot.getMedian(), snapshot.getMean(), snapshot.getMin(), snapshot.getMax(), snapshot.getStdDev(),
+ snapshot.get75thPercentile(), snapshot.get95thPercentile(), snapshot.get98thPercentile(), snapshot.get99thPercentile(), snapshot.get999thPercentile()));
+ getDb(database.getTimers(), virtualName, registry, name).add(timerSnapshot);
+ });
+ }
+
+ // alternatively we can decorate the registries and register/unregister following the registry lifecycle
+ // shouldnt be worth it for now
+ private <T> InMemoryDatabase<T> getDb(final Map<String, InMemoryDatabase<T>> registry,
+ final String virtualName, final MetricRegistry source,
+ final String key) {
+ InMemoryDatabase<T> db = registry.get(virtualName);
+ if (db == null) {
+ db = new InMemoryDatabase<>(ofNullable(source.getMetadata().get(key).getUnit()).orElse(""));
+ final InMemoryDatabase<T> existing = registry.putIfAbsent(virtualName, db);
+ if (existing != null) {
+ db = existing;
+ }
+ }
+ return db;
+ }
+
+ private String getMetricStorageName(final String type, final String name) {
+ return type + "#" + name;
+ }
+
+ @PostConstruct
+ private void init() {
+ metricsIndex = new HashMap<>(3);
+ metricsIndex.put("vendor", vendorRegistry);
+ metricsIndex.put("base", baseRegistry);
+ metricsIndex.put("application", applicationRegistry);
+ }
+
+ void onTick(@Observes final Tick tick) {
+ metricsIndex.forEach(this::updateMetrics);
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/SnapshotStat.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/SnapshotStat.java
new file mode 100644
index 0000000..4f12976
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/SnapshotStat.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.metrics;
+
+public class SnapshotStat {
+
+ private final int size;
+
+ private final double median;
+
+ private final double mean;
+
+ private final double min;
+
+ private final double max;
+
+ private final double stdDev;
+
+ private final double pc75;
+
+ private final double pc95;
+
+ private final double pc98;
+
+ private final double pc99;
+
+ private final double pc999;
+
+ SnapshotStat(final int size, final double median, final double mean,
+ final double min, final double max, final double stdDev,
+ final double pc75, final double pc95, final double pc98,
+ final double pc99, final double pc999) {
+ this.size = size;
+ this.median = median;
+ this.mean = mean;
+ this.min = min;
+ this.max = max;
+ this.stdDev = stdDev;
+ this.pc75 = pc75;
+ this.pc95 = pc95;
+ this.pc98 = pc98;
+ this.pc99 = pc99;
+ this.pc999 = pc999;
+ }
+
+ public double get75thPercentile() {
+ return pc75;
+ }
+
+ public double get95thPercentile() {
+ return pc95;
+ }
+
+ public double get98thPercentile() {
+ return pc98;
+ }
+
+ public double get99thPercentile() {
+ return pc99;
+ }
+
+ public double get999thPercentile() {
+ return pc999;
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/TimerSnapshot.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/TimerSnapshot.java
new file mode 100644
index 0000000..3f40b19
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/metrics/TimerSnapshot.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.metrics;
+
+public class TimerSnapshot {
+ private final MeterSnapshot meter;
+ private final SnapshotStat histogram;
+
+ TimerSnapshot(final MeterSnapshot meter, final SnapshotStat histogram) {
+ this.meter = meter;
+ this.histogram = histogram;
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanEntry.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanEntry.java
new file mode 100644
index 0000000..bebeea8
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanEntry.java
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.tracing;
+
+import java.util.Collection;
+import java.util.Map;
+
+public class SpanEntry {
+ private final String spanId;
+ private final String traceId;
+ private final String parentId;
+ private final String name;
+ private final long timestamp;
+ private final long duration;
+ private final String kind;
+ private final Map<String, Object> tags;
+ private final Collection<LogEntry> getLogs;
+
+ SpanEntry(final String spanId, final String traceId, final String parentId, final String name,
+ final long timestamp, final long duration, final String kind, final Map<String, Object> tags,
+ final Collection<LogEntry> getLogs) {
+ this.spanId = spanId;
+ this.traceId = traceId;
+ this.parentId = parentId;
+ this.name = name;
+ this.timestamp = timestamp;
+ this.duration = duration;
+ this.kind = kind;
+ this.tags = tags;
+ this.getLogs = getLogs;
+ }
+
+ public String getSpanId() {
+ return spanId;
+ }
+
+ public String getTraceId() {
+ return traceId;
+ }
+
+ public String getParentId() {
+ return parentId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public String getKind() {
+ return kind;
+ }
+
+ public Map<String, Object> getTags() {
+ return tags;
+ }
+
+ public Collection<LogEntry> getGetLogs() {
+ return getLogs;
+ }
+
+ public static class LogEntry {
+
+ private final long timestampMicros;
+
+ private final Map<String, Object> fields;
+
+ LogEntry(final long timestampMicros, final Map<String, Object> fields) {
+ this.timestampMicros = timestampMicros;
+ this.fields = fields;
+ }
+
+ public long getTimestampMicros() {
+ return timestampMicros;
+ }
+
+ public Map<String, Object> getFields() {
+ return fields;
+ }
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/SpanMapper.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanMapper.java
similarity index 63%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/SpanMapper.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanMapper.java
index 9d525d9..03daf7a 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/SpanMapper.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/SpanMapper.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.plugins.tracing;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toList;
@@ -78,10 +78,10 @@
return null;
}
try {
- final Collection<LogEntry> logs = ofNullable((Collection<?>) getLogs.invoke(span))
+ final Collection<SpanEntry.LogEntry> logs = ofNullable((Collection<?>) getLogs.invoke(span))
.map(it -> it.stream().map(log -> {
try {
- return new LogEntry(Long.class.cast(logGetTimestampMicros.invoke(log)), Map.class.cast(logGetFields.invoke(log)));
+ return new SpanEntry.LogEntry(Long.class.cast(logGetTimestampMicros.invoke(log)), Map.class.cast(logGetFields.invoke(log)));
} catch (final IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (final InvocationTargetException e) {
@@ -108,86 +108,4 @@
private static String stringify(final Object value) {
return value == null ? null : String.valueOf(value);
}
-
- public static class LogEntry {
-
- private final long timestampMicros;
-
- private final Map<String, Object> fields;
-
- private LogEntry(final long timestampMicros, final Map<String, Object> fields) {
- this.timestampMicros = timestampMicros;
- this.fields = fields;
- }
-
- public long getTimestampMicros() {
- return timestampMicros;
- }
-
- public Map<String, Object> getFields() {
- return fields;
- }
- }
-
- public static class SpanEntry {
- private final String spanId;
- private final String traceId;
- private final String parentId;
- private final String name;
- private final long timestamp;
- private final long duration;
- private final String kind;
- private final Map<String, Object> tags;
- private final Collection<LogEntry> getLogs;
-
- private SpanEntry(final String spanId, final String traceId, final String parentId, final String name,
- final long timestamp, final long duration, final String kind, final Map<String, Object> tags,
- final Collection<LogEntry> getLogs) {
- this.spanId = spanId;
- this.traceId = traceId;
- this.parentId = parentId;
- this.name = name;
- this.timestamp = timestamp;
- this.duration = duration;
- this.kind = kind;
- this.tags = tags;
- this.getLogs = getLogs;
- }
-
- public String getSpanId() {
- return spanId;
- }
-
- public String getTraceId() {
- return traceId;
- }
-
- public String getParentId() {
- return parentId;
- }
-
- public String getName() {
- return name;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public long getDuration() {
- return duration;
- }
-
- public String getKind() {
- return kind;
- }
-
- public Map<String, Object> getTags() {
- return tags;
- }
-
- public Collection<LogEntry> getGetLogs() {
- return getLogs;
- }
- }
}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingExtension.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingExtension.java
new file mode 100644
index 0000000..d741727
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingExtension.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.tracing;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AfterDeploymentValidation;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+
+import org.apache.geronimo.microprofile.reporter.storage.data.MicroprofileDatabase;
+
+public class TracingExtension implements Extension {
+ private boolean active;
+ private Class<?> finishedSpan;
+ private TracingService service;
+
+ public boolean isActive() {
+ return active;
+ }
+
+ void onStart(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ try {
+ loader.loadClass("io.opentracing.Span");
+ finishedSpan = loader.loadClass("org.apache.geronimo.microprofile.opentracing.common.impl.FinishedSpan");
+ active = true;
+ } catch (final ClassNotFoundException e) {
+ // no-op
+ }
+ }
+
+ void addObserver(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
+ if (active) {
+ // like that to avoid to require tracing in the app
+ afterBeanDiscovery.addObserverMethod()
+ .observedType(finishedSpan)
+ .notifyWith(e -> service.onSpan(e.getEvent()));
+ }
+ }
+
+ void createService(@Observes final AfterDeploymentValidation afterDeploymentValidation, final BeanManager manager) {
+ if (active) {
+ service = new TracingService(lookup(manager, MicroprofileDatabase.class), lookup(manager, SpanMapper.class));
+ }
+ }
+
+ // only lookup normal bean so ignore cc
+ private <T> T lookup(final BeanManager beanManager, final Class<T> type) {
+ final Bean<?> bean = beanManager.resolve(beanManager.getBeans(type));
+ return type.cast(beanManager.getReference(bean, type, beanManager.createCreationalContext(null)));
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingService.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingService.java
new file mode 100644
index 0000000..873f5dd
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/plugins/tracing/TracingService.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.tracing;
+
+import javax.enterprise.inject.Vetoed;
+
+import org.apache.geronimo.microprofile.opentracing.common.impl.FinishedSpan;
+import org.apache.geronimo.microprofile.reporter.storage.data.MicroprofileDatabase;
+
+import io.opentracing.Span;
+
+@Vetoed
+class TracingService {
+ private final MicroprofileDatabase database;
+ private final SpanMapper mapper;
+
+ TracingService(final MicroprofileDatabase database, final SpanMapper mapper) {
+ this.database = database;
+ this.mapper = mapper;
+ }
+
+ void onSpan(final Object event) {
+ final FinishedSpan finishedSpan = FinishedSpan.class.cast(event);
+ final Span value = finishedSpan.getSpan();
+ if (!value.getClass().getName().equals("org.apache.geronimo.microprofile.opentracing.common.impl.SpanImpl")) {
+ return;
+ }
+ final SpanEntry mapped = mapper.map(value);
+ if (mapped == null) {
+ return;
+ }
+ database.getSpans().add(mapped);
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplateHelper.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplateHelper.java
similarity index 99%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplateHelper.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplateHelper.java
index 4eb8849..10b32df 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplateHelper.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplateHelper.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.templating;
import static java.util.stream.Collectors.joining;
diff --git a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplatingEngine.java b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplatingEngine.java
similarity index 99%
rename from geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplatingEngine.java
rename to geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplatingEngine.java
index 142e6ee..6a9c1da 100644
--- a/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/TemplatingEngine.java
+++ b/geronimo-microprofile-reporter/src/main/java/org/apache/geronimo/microprofile/reporter/storage/templating/TemplatingEngine.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geronimo.microprofile.reporter.storage;
+package org.apache.geronimo.microprofile.reporter.storage.templating;
import static java.util.Locale.ROOT;
import static java.util.stream.Collectors.joining;
@@ -365,7 +365,7 @@
return registry;
}
- void clean() {
+ public void clean() {
templates.clear();
}
diff --git a/geronimo-microprofile-reporter/src/main/resources/META-INF/beans.xml b/geronimo-microprofile-reporter/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..70dd4a9
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+ bean-discovery-mode="all"
+ version="2.0">
+ <trim/>
+</beans>
diff --git a/geronimo-microprofile-reporter/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/geronimo-microprofile-reporter/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index d0ef3e1..9b0ba85 100644
--- a/geronimo-microprofile-reporter/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/geronimo-microprofile-reporter/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -1 +1,2 @@
-org.apache.geronimo.microprofile.reporter.storage.HealthRegistry
+org.apache.geronimo.microprofile.reporter.storage.plugins.health.HealthRegistry
+org.apache.geronimo.microprofile.reporter.storage.plugins.tracing.TracingExtension
diff --git a/geronimo-microprofile-reporter/src/main/resources/geronimo/microprofile/reporter/health-application.html b/geronimo-microprofile-reporter/src/main/resources/geronimo/microprofile/reporter/health-application.html
index cc93320..9d1db9b 100644
--- a/geronimo-microprofile-reporter/src/main/resources/geronimo/microprofile/reporter/health-application.html
+++ b/geronimo-microprofile-reporter/src/main/resources/geronimo/microprofile/reporter/health-application.html
@@ -18,7 +18,9 @@
<div>
<h2>Overall State</h2>
- <div class="health-check-state @if($globalStateOk,inline:green)@if($globalStateKo,inline:red)"></div>
+ <div class="health-check-state health-check-@lowercase($globalState)">
+ <span>$globalState</span>
+ </div>
<h2>Checks</h2>
<table>
@@ -26,7 +28,7 @@
<tr><th>Name</th><th>State</th><th>Data</th></tr>
</thead>
<tbody>
- @each($checks,incline:<tr><td>$$value.name</td><td>$$value.state</td><td>$$value.data</td></tr>)
+ @each($checks,inline:<tr><td>$$value.name</td><td>$$value.state</td><td>$$value.data</td></tr>)
</tbody>
</table>
</div>
diff --git a/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/html/TemplatingEngineTest.java b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/html/TemplatingEngineTest.java
index d61aaa8..5f1e0e6 100644
--- a/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/html/TemplatingEngineTest.java
+++ b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/html/TemplatingEngineTest.java
@@ -24,7 +24,7 @@
import java.util.Map;
import java.util.function.Function;
-import org.apache.geronimo.microprofile.reporter.storage.TemplatingEngine;
+import org.apache.geronimo.microprofile.reporter.storage.templating.TemplatingEngine;
import org.junit.Test;
public class TemplatingEngineTest {
diff --git a/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check1.java b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check1.java
new file mode 100644
index 0000000..dd77f2c
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check1.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.eclipse.microprofile.health.Health;
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+
+@Health
+@ApplicationScoped
+public class Check1 implements HealthCheck {
+ @Override
+ public HealthCheckResponse call() {
+ return HealthCheckResponse.named("check1").up().build();
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check2.java b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check2.java
new file mode 100644
index 0000000..d6bd2ff
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/Check2.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.eclipse.microprofile.health.Health;
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+
+@Health
+@ApplicationScoped
+public class Check2 implements HealthCheck {
+ @Override
+ public HealthCheckResponse call() {
+ return HealthCheckResponse.named("check2").down().withData("failure", "oops for test").build();
+ }
+}
diff --git a/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthServiceTest.java b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthServiceTest.java
new file mode 100644
index 0000000..2b0fd6d
--- /dev/null
+++ b/geronimo-microprofile-reporter/src/test/java/org/apache/geronimo/microprofile/reporter/storage/plugins/health/HealthServiceTest.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.reporter.storage.plugins.health;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.inject.Inject;
+
+import org.apache.meecrowave.junit.InjectRule;
+import org.apache.meecrowave.junit.MeecrowaveRule;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class HealthServiceTest {
+ @ClassRule
+ public static final MeecrowaveRule SERVER = new MeecrowaveRule();
+
+ @Rule
+ public final InjectRule injector = new InjectRule(this);
+
+ @Inject
+ private HealthService service;
+
+ @Test
+ public void ensureHealthChecksWereRegistered() {
+ assertEquals(2, service.doCheck().count());
+ }
+}
diff --git a/geronimo-microprofile-site/src/main/jbake/content/reporter.adoc b/geronimo-microprofile-site/src/main/jbake/content/reporter.adoc
index 8d40572..082da85 100644
--- a/geronimo-microprofile-site/src/main/jbake/content/reporter.adoc
+++ b/geronimo-microprofile-site/src/main/jbake/content/reporter.adoc
@@ -2,11 +2,14 @@
:jbake-date: 2019-01-07
:icons: font
-Apache Geronimo Microprofile Reporter allows to visualize spans (OpenTracing) and Metrics
+Apache Geronimo Microprofile Reporter allows to visualize spans (OpenTracing), the health of your application and Metrics
in a small webapp.
IMPORTANT: this is for test and demo purposes, this is not yet intended to be deployed in production.
+Also note that part of the UI are designed to be auto activated when relevant, typically, if you don't have Microprofile
+Health, the associated UI will not be active.
+
== Dependencies
[source,xml]