You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sk...@apache.org on 2022/09/09 16:43:00 UTC
[ignite-3] branch main updated: IGNITE-17444 Introduced MetricExporter interface and service loading. Fixes #1027
This is an automated email from the ASF dual-hosted git repository.
sk0x50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new d9d230453b IGNITE-17444 Introduced MetricExporter interface and service loading. Fixes #1027
d9d230453b is described below
commit d9d230453b4c410937a021cdfad3d86199b99961
Author: Kirill Gusakov <kg...@gmail.com>
AuthorDate: Fri Sep 9 19:42:46 2022 +0300
IGNITE-17444 Introduced MetricExporter interface and service loading. Fixes #1027
Signed-off-by: Slava Koptilin <sl...@gmail.com>
---
.../exporters/MetricExportersLoadingTest.java | 74 ++++++++++++++
.../metrics/exporters/TestMetricsSource.java | 61 ++++++++++++
.../metrics/exporters/TestPullMetricExporter.java | 98 +++++++++++++++++++
.../metrics/exporters/TestPushMetricExporter.java | 69 +++++++++++++
...gnite.internal.metrics.exporters.MetricExporter | 17 ++++
.../ignite/internal/metrics/MetricManager.java | 40 +++++++-
.../ignite/internal/metrics/MetricProvider.java | 47 +++++++++
.../metrics/exporters/BasicMetricExporter.java | 52 ++++++++++
.../internal/metrics/exporters/MetricExporter.java | 56 +++++++++++
.../metrics/exporters/PushMetricExporter.java | 107 +++++++++++++++++++++
10 files changed, 619 insertions(+), 2 deletions(-)
diff --git a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/MetricExportersLoadingTest.java b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/MetricExportersLoadingTest.java
new file mode 100644
index 0000000000..5fb4593da4
--- /dev/null
+++ b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/MetricExportersLoadingTest.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.ignite.internal.metrics.exporters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.concurrent.locks.LockSupport;
+import org.apache.ignite.internal.metrics.MetricManager;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Integration test for metrics' exporters loading.
+ */
+public class MetricExportersLoadingTest {
+ @Test
+ public void test() throws Exception {
+ MetricManager metricManager = new MetricManager();
+
+ TestMetricsSource src = new TestMetricsSource("TestMetricsSource");
+
+ metricManager.registerSource(src);
+
+ metricManager.enable(src.name());
+
+ try (OutputStream pullOutputStream = new ByteArrayOutputStream();
+ OutputStream pushOutputStream = new ByteArrayOutputStream()) {
+ TestPullMetricExporter.setOutputStream(pullOutputStream);
+
+ TestPushMetricExporter.setOutputStream(pushOutputStream);
+
+ assertEquals(0, pullOutputStream.toString().length());
+
+ assertEquals(0, pushOutputStream.toString().length());
+
+ metricManager.start();
+
+ src.inc();
+
+ waitForOutput(pushOutputStream, "TestMetricsSource:\nmetric:1");
+ assertTrue(pushOutputStream.toString().contains("TestMetricsSource:\nmetric:1"));
+
+ TestPullMetricExporter.requestMetrics();
+
+ waitForOutput(pullOutputStream, "TestMetricsSource:\nmetric:1");
+ assertTrue(pullOutputStream.toString().contains("TestMetricsSource:\nmetric:1"));
+
+ metricManager.stop();
+ }
+ }
+
+ private void waitForOutput(OutputStream outputStream, String content) {
+ while (!outputStream.toString().contains(content)) {
+ LockSupport.parkNanos(100_000_000);
+ }
+ }
+}
diff --git a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestMetricsSource.java b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestMetricsSource.java
new file mode 100644
index 0000000000..1c6d4e1737
--- /dev/null
+++ b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestMetricsSource.java
@@ -0,0 +1,61 @@
+/*
+ * 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.ignite.internal.metrics.exporters;
+
+import org.apache.ignite.internal.metrics.AbstractMetricSource;
+import org.apache.ignite.internal.metrics.AtomicIntMetric;
+import org.apache.ignite.internal.metrics.MetricSetBuilder;
+import org.apache.ignite.internal.metrics.ThreadPoolMetricTest;
+import org.apache.ignite.internal.metrics.exporters.TestMetricsSource.Holder;
+
+/**
+ * Metric source for {@link ThreadPoolMetricTest}.
+ */
+public class TestMetricsSource extends AbstractMetricSource<Holder> {
+ private AtomicIntMetric atomicIntMetric;
+
+ /**
+ * Constructor.
+ *
+ * @param name Name.
+ */
+ public TestMetricsSource(String name) {
+ super(name);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Holder createHolder() {
+ return new Holder();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void init(MetricSetBuilder bldr, Holder holder) {
+ atomicIntMetric = bldr.atomicInt("metric", "Metric");
+ }
+
+ public void inc() {
+ atomicIntMetric.increment();
+ }
+
+ /**
+ * Holder class.
+ */
+ protected static class Holder implements AbstractMetricSource.Holder<Holder> {
+ // No-op.
+ }
+}
diff --git a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
new file mode 100644
index 0000000000..0029fe06ed
--- /dev/null
+++ b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPullMetricExporter.java
@@ -0,0 +1,98 @@
+/*
+ * 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.ignite.internal.metrics.exporters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.apache.ignite.internal.metrics.Metric;
+import org.apache.ignite.internal.metrics.MetricSet;
+
+/**
+ * Simple pull exporter, which simulate the pull principe throw primitive wait/notify API
+ * instead of the complex TCP/IP etc. endpoints.
+ */
+public class TestPullMetricExporter extends BasicMetricExporter {
+ private static OutputStream outputStream;
+
+ private static final Object obj = new Object();
+
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+
+ public static void setOutputStream(OutputStream outputStream) {
+ TestPullMetricExporter.outputStream = outputStream;
+ }
+
+ /**
+ * Simulate metric request.
+ */
+ public static void requestMetrics() {
+ synchronized (obj) {
+ obj.notify();
+ }
+ }
+
+ @Override
+ public void start() {
+ executorService.execute(() -> {
+ while (true) {
+ waitForRequest();
+
+ var report = new StringBuilder();
+
+ for (MetricSet metricSet : metrics().get1().values()) {
+ report.append(metricSet.name()).append(":\n");
+
+ for (Metric metric : metricSet) {
+ report.append(metric.name())
+ .append(":")
+ .append(metric.getValueAsString())
+ .append("\n");
+ }
+
+ report.append("\n");
+ }
+
+ try {
+ outputStream.write(report.toString().getBytes(StandardCharsets.UTF_8));
+
+ outputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void stop() {
+ executorService.shutdown();
+ }
+
+ private void waitForRequest() {
+ synchronized (obj) {
+ try {
+ obj.wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.java
new file mode 100644
index 0000000000..ac4d7675d0
--- /dev/null
+++ b/modules/metrics/src/integrationTest/java/org/apache/ignite/internal/metrics/exporters/TestPushMetricExporter.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.ignite.internal.metrics.exporters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import org.apache.ignite.internal.metrics.Metric;
+import org.apache.ignite.internal.metrics.MetricSet;
+
+/**
+ * Test push metrics exporter.
+ */
+public class TestPushMetricExporter extends PushMetricExporter {
+ private static OutputStream outputStream;
+
+ public TestPushMetricExporter() {
+ setPeriod(100);
+ }
+
+ public static void setOutputStream(OutputStream outputStream) {
+ TestPushMetricExporter.outputStream = outputStream;
+ }
+
+ @Override
+ public void report() {
+ var report = new StringBuilder();
+
+ for (MetricSet metricSet : metrics().get1().values()) {
+ report.append(metricSet.name()).append(":\n");
+
+ for (Metric metric : metricSet) {
+ report.append(metric.name())
+ .append(":")
+ .append(metric.getValueAsString())
+ .append("\n");
+ }
+
+ report.append("\n");
+ }
+
+ write(report.toString());
+ }
+
+ private void write(String report) {
+ try {
+ outputStream.write(report.getBytes(StandardCharsets.UTF_8));
+
+ outputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/modules/metrics/src/integrationTest/resources/META-INF/services/org.apache.ignite.internal.metrics.exporters.MetricExporter b/modules/metrics/src/integrationTest/resources/META-INF/services/org.apache.ignite.internal.metrics.exporters.MetricExporter
new file mode 100644
index 0000000000..165247eaaa
--- /dev/null
+++ b/modules/metrics/src/integrationTest/resources/META-INF/services/org.apache.ignite.internal.metrics.exporters.MetricExporter
@@ -0,0 +1,17 @@
+# 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.
+#
+org.apache.ignite.internal.metrics.exporters.TestPullMetricExporter
+org.apache.ignite.internal.metrics.exporters.TestPushMetricExporter
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
index 91cc669441..b4da6e8aa9 100644
--- a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricManager.java
@@ -17,11 +17,18 @@
package org.apache.ignite.internal.metrics;
+import static java.util.stream.Collectors.toUnmodifiableList;
+
+import java.util.List;
import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
import org.apache.ignite.internal.manager.IgniteComponent;
+import org.apache.ignite.internal.metrics.exporters.MetricExporter;
import org.apache.ignite.lang.IgniteBiTuple;
import org.jetbrains.annotations.NotNull;
+
/**
* Metric manager.
*/
@@ -31,6 +38,9 @@ public class MetricManager implements IgniteComponent {
*/
private final MetricRegistry registry;
+ /** Metrics' exporters. */
+ private List<MetricExporter> metricExporters;
+
/**
* Constructor.
*/
@@ -40,12 +50,23 @@ public class MetricManager implements IgniteComponent {
/** {@inheritDoc} */
@Override public void start() {
- // No-op.
+ // TODO: IGNITE-17358 not all exporters should be started, it must be defined by configuration
+ metricExporters = loadExporters();
+
+ MetricProvider metricsProvider = new MetricProvider(registry);
+
+ for (MetricExporter metricExporter : metricExporters) {
+ metricExporter.init(metricsProvider);
+
+ metricExporter.start();
+ }
}
/** {@inheritDoc} */
@Override public void stop() throws Exception {
- // No-op.
+ for (MetricExporter metricExporter : metricExporters) {
+ metricExporter.stop();
+ }
}
/**
@@ -95,6 +116,21 @@ public class MetricManager implements IgniteComponent {
return registry.enable(srcName);
}
+ /**
+ * Load exporters by {@link ServiceLoader} mechanism.
+ *
+ * @return list of loaded exporters.
+ */
+ private List<MetricExporter> loadExporters() {
+ var clsLdr = Thread.currentThread().getContextClassLoader();
+
+ return ServiceLoader
+ .load(MetricExporter.class, clsLdr)
+ .stream()
+ .map(Provider::get)
+ .collect(toUnmodifiableList());
+ }
+
/**
* Disable metric source. See {@link MetricRegistry#disable(MetricSource)}.
*
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricProvider.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricProvider.java
new file mode 100644
index 0000000000..ca4ae3f901
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricProvider.java
@@ -0,0 +1,47 @@
+/*
+ * 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.ignite.internal.metrics;
+
+import java.util.Map;
+import org.apache.ignite.lang.IgniteBiTuple;
+
+/**
+ * Read-only metrics registry.
+ */
+public class MetricProvider {
+ /** Metrics registry. */
+ private MetricRegistry metricRegistry;
+
+ /**
+ * Constructor.
+ *
+ * @param metricRegistry Metrics registry.
+ */
+ public MetricProvider(MetricRegistry metricRegistry) {
+ this.metricRegistry = metricRegistry;
+ }
+
+ /**
+ * Returns a map of (metricSetName -> metricSet) pairs with available metrics from {@link MetricRegistry}.
+ *
+ * @return map of metrics
+ */
+ public IgniteBiTuple<Map<String, MetricSet>, Long> metrics() {
+ return metricRegistry.metricSnapshot();
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
new file mode 100644
index 0000000000..10aa93d311
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/BasicMetricExporter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ignite.internal.metrics.exporters;
+
+import java.util.Map;
+import org.apache.ignite.internal.metrics.MetricProvider;
+import org.apache.ignite.internal.metrics.MetricSet;
+import org.apache.ignite.lang.IgniteBiTuple;
+
+/**
+ * Base class for new metrics exporters implementations.
+ */
+public abstract class BasicMetricExporter implements MetricExporter {
+ /** Metrics provider. */
+ private MetricProvider metricsProvider;
+
+ /** {@inheritDoc} */
+ @Override
+ public final void init(MetricProvider metricProvider) {
+ this.metricsProvider = metricProvider;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final String name() {
+ return getClass().getCanonicalName();
+ }
+
+ /**
+ * Returns a map of (metricSetName -> metricSet) pairs with available metrics.
+ *
+ * @return map of metrics
+ */
+ protected final IgniteBiTuple<Map<String, MetricSet>, Long> metrics() {
+ return metricsProvider.metrics();
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
new file mode 100644
index 0000000000..cb7c38dd3d
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/MetricExporter.java
@@ -0,0 +1,56 @@
+/*
+ * 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.ignite.internal.metrics.exporters;
+
+import org.apache.ignite.internal.metrics.MetricProvider;
+
+/**
+ * Interface for metric exporters to external recipients.
+ * Exporters can be one of the two type: push and pull exporters.
+ *
+ * <p>Push exporters push metrics to the external endpoint periodically.
+ * Push exporters should implement {@link PushMetricExporter} according to its documentation.
+ *
+ * <p>Pull exporters is the endpoint by itself (HTTP, JMX and etc.), which response with the metric data for request.
+ * Pull exporters should extend {@link BasicMetricExporter}.
+ */
+public interface MetricExporter {
+ /**
+ * Initialize metric exporter with the provider of available metrics.
+ *
+ * @param metricProvider Metrics provider
+ */
+ void init(MetricProvider metricProvider);
+
+ /**
+ * Start metrics exporter. Here all needed listeners, schedulers etc. should be started.
+ */
+ void start();
+
+ /**
+ * Stop and cleanup work for current exporter must be implemented here.
+ */
+ void stop();
+
+ /**
+ * Returns the name of exporter. Name must be unique.
+ *
+ * @return Name of the exporter.
+ */
+ String name();
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
new file mode 100644
index 0000000000..6f8cdc649b
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/exporters/PushMetricExporter.java
@@ -0,0 +1,107 @@
+/*
+ * 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.ignite.internal.metrics.exporters;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.internal.logger.IgniteLogger;
+import org.apache.ignite.internal.logger.Loggers;
+import org.apache.ignite.internal.thread.NamedThreadFactory;
+import org.apache.ignite.internal.util.IgniteUtils;
+
+/**
+ * Base class for push metrics exporters, according to terminology from {@link MetricExporter} docs.
+ * Every {@code period} of time {@link PushMetricExporter#report()} will be called
+ * to push metrics to the external system.
+ */
+public abstract class PushMetricExporter extends BasicMetricExporter {
+ /** Logger. */
+ protected final IgniteLogger log = Loggers.forClass(getClass());
+
+ /** Default export period in milliseconds. */
+ public static final long DFLT_EXPORT_PERIOD = 60_000;
+
+ /** Export period. */
+ private long period = DFLT_EXPORT_PERIOD;
+
+ /** Export task future. */
+ private ScheduledFuture<?> fut;
+
+ /** Export scheduler. */
+ private ScheduledExecutorService scheduler;
+
+ /** {@inheritDoc} */
+ @Override
+ public void start() {
+ scheduler =
+ Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("metrics-exporter", log));
+
+ fut = scheduler.scheduleWithFixedDelay(() -> {
+ try {
+ report();
+ } catch (Throwable th) {
+ log.error("Metrics export error. "
+ + "This exporter will be stopped [class=" + getClass() + ",name=" + name() + ']', th);
+
+ throw th;
+ }
+ }, period, period, TimeUnit.MILLISECONDS);
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void stop() {
+ fut.cancel(false);
+
+ IgniteUtils.shutdownAndAwaitTermination(scheduler, 10, TimeUnit.SECONDS);
+ }
+
+ // TODO: after IGNITE-17358 this period maybe shouldn't be a part of protected API
+ // TODO: and should be configured throw configuration API
+ /**
+ * Sets period in milliseconds after {@link #report()} method should be called.
+ *
+ * @param period Period in milliseconds.
+ */
+ protected void setPeriod(long period) {
+ this.period = period;
+ }
+
+ /**
+ * Returns export period.
+ *
+ * @return Period in milliseconds after {@link #report()} method should be called.
+ */
+ public long getPeriod() {
+ return period;
+ }
+
+ /**
+ * A heart of the push exporter.
+ * Inside this method all needed operations to send the metrics outside must be implemented.
+ *
+ * <p>This method will be executed periodically by internal exporter's scheduler.
+ *
+ * <p>In case of any exceptions exporter's internal scheduler will be stopped
+ * and no new {@link #report()} will be executed.
+ */
+ public abstract void report();
+}