You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2020/03/17 10:28:51 UTC
[sling-whiteboard] branch master updated: metrics-osgi: add a JSON
writer for metrics
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
The following commit(s) were added to refs/heads/master by this push:
new d4c51d6 metrics-osgi: add a JSON writer for metrics
d4c51d6 is described below
commit d4c51d69a93f00a67493a1108762b5f435baa79b
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Tue Mar 17 11:28:27 2020 +0100
metrics-osgi: add a JSON writer for metrics
---
osgi-metrics/consumers/bnd.bnd | 1 +
osgi-metrics/consumers/pom.xml | 13 +++
.../impl/json/JsonWritingMetricsListener.java | 95 ++++++++++++++++++++++
.../impl/json/JsonWritingMetricsListenerTest.java | 77 ++++++++++++++++++
4 files changed, 186 insertions(+)
diff --git a/osgi-metrics/consumers/bnd.bnd b/osgi-metrics/consumers/bnd.bnd
new file mode 100644
index 0000000..0be6687
--- /dev/null
+++ b/osgi-metrics/consumers/bnd.bnd
@@ -0,0 +1 @@
+Conditional-Package: org.apache.felix.utils.json
\ No newline at end of file
diff --git a/osgi-metrics/consumers/pom.xml b/osgi-metrics/consumers/pom.xml
index 21e90a5..8f47241 100644
--- a/osgi-metrics/consumers/pom.xml
+++ b/osgi-metrics/consumers/pom.xml
@@ -85,6 +85,19 @@
<version>0.1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ <version>1.11.4</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>3.3.3</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/osgi-metrics/consumers/src/main/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListener.java b/osgi-metrics/consumers/src/main/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListener.java
new file mode 100644
index 0000000..75f8e19
--- /dev/null
+++ b/osgi-metrics/consumers/src/main/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListener.java
@@ -0,0 +1,95 @@
+/*
+ * 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.sling.metrics.osgi.consumers.impl.json;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.felix.utils.json.JSONWriter;
+import org.apache.sling.metrics.osgi.BundleStartDuration;
+import org.apache.sling.metrics.osgi.ServiceRestartCounter;
+import org.apache.sling.metrics.osgi.StartupMetrics;
+import org.apache.sling.metrics.osgi.StartupMetricsListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+public class JsonWritingMetricsListener implements StartupMetricsListener {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private BundleContext ctx;
+
+ @Activate
+ protected void activate(BundleContext ctx) {
+ this.ctx = ctx;
+ }
+
+ @Override
+ public void onStartupComplete(StartupMetrics metrics) {
+
+ File metricsFile = ctx.getDataFile("startup-metrics-" + System.currentTimeMillis() + ".json");
+ if ( metricsFile == null ) {
+ logger.warn("Unable to get data file in the bundle area, startup metrics will not be written");
+ return;
+ }
+
+ try {
+ try ( FileWriter fw = new FileWriter(metricsFile)) {
+ JSONWriter w = new JSONWriter(fw);
+ w.object();
+ // application metrics
+ w.key("application");
+ w.object();
+ w.key("startTimeMillis").value(metrics.getJvmStartup().toEpochMilli());
+ w.key("startDurationMillis").value(metrics.getStartupTime().toMillis());
+ w.endObject();
+
+ // bundle metrics
+ w.key("bundles");
+ w.array();
+ for ( BundleStartDuration bsd : metrics.getBundleStartDurations() ) {
+ w.object();
+ w.key("symbolicName").value(bsd.getSymbolicName());
+ w.key("startTimeMillis").value(bsd.getStartingAt().toEpochMilli());
+ w.key("startDurationMillis").value(bsd.getStartedAfter().toMillis());
+ w.endObject();
+ }
+ w.endArray();
+
+ // service metrics
+ w.key("services");
+ w.array();
+ for ( ServiceRestartCounter src : metrics.getServiceRestarts() ) {
+ w.object();
+ w.key("identifier").value(src.getServiceIdentifier());
+ w.key("restarts").value(src.getServiceRestarts());
+ w.endObject();
+ }
+ w.endArray();
+
+ w.endObject();
+ }
+ } catch (IOException e) {
+ logger.warn("Failed wrting startup metrics", e);
+ }
+ }
+}
diff --git a/osgi-metrics/consumers/src/test/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListenerTest.java b/osgi-metrics/consumers/src/test/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListenerTest.java
new file mode 100644
index 0000000..c117585
--- /dev/null
+++ b/osgi-metrics/consumers/src/test/java/org/apache/sling/metrics/osgi/consumers/impl/json/JsonWritingMetricsListenerTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.sling.metrics.osgi.consumers.impl.json;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+
+import org.apache.felix.utils.json.JSONParser;
+import org.apache.sling.metrics.osgi.BundleStartDuration;
+import org.apache.sling.metrics.osgi.ServiceRestartCounter;
+import org.apache.sling.metrics.osgi.StartupMetrics;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+
+public class JsonWritingMetricsListenerTest {
+
+ @Rule
+ public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Test
+ public void metricsArePersisted() throws IOException {
+ // bridge the mock bundle context with the temporary folder
+ BundleContext mockBundleContext = mock(BundleContext.class);
+ when(mockBundleContext.getDataFile(Mockito.anyString())).thenAnswer( i -> tmp.newFile(i.getArgument(0, String.class)));
+
+ JsonWritingMetricsListener listener = new JsonWritingMetricsListener();
+ listener.activate(mockBundleContext);
+
+ StartupMetrics metrics = StartupMetrics.Builder
+ .withJvmStartup(Instant.now())
+ .withStartupTime(Duration.ofMillis(50))
+ .withBundleStartDurations(Arrays.asList(new BundleStartDuration("foo", Instant.now(), Duration.ofMillis(5))))
+ .withServiceRestarts(Arrays.asList(new ServiceRestartCounter("some.service", 1)))
+ .build();
+
+ listener.onStartupComplete(metrics);
+
+ File[] files = tmp.getRoot().listFiles();
+
+ assertThat("Bundle data area should hold one file", files.length, equalTo(1));
+
+ File metricsFile = files[0];
+ try ( FileInputStream fis = new FileInputStream(metricsFile)) {
+ JSONParser p = new JSONParser(fis);
+ assertThat(p.getParsed().keySet(), hasItem("application"));
+ assertThat(p.getParsed().keySet(), hasItem("bundles"));
+ assertThat(p.getParsed().keySet(), hasItem("services"));
+ }
+ }
+}