mirror of https://github.com/hyperledger/besu
Metrics Prometheus Push Gateway Support (#638)
Sometimes metrics are hard to poll (docker containers with varying ip addresses). Because of that the push gateway exists. This extends the metrics system to support push or pull mode for metrics (but not both at the same time). Three new flags `--metrics-mode=`<`push`|`pull`> - Whether we are in pull mode (the default) where prometheus is expected to poll or push mode where pantheon pushes to a push gateway. `--metrics-push-interval=`<_integer_> the frequency, in seconds, between pushes to the push gateway. Only relevant in push mode `--metrics-prometheus-job=`<_string_> The name of the job to report in the push gateway Also, `--metrics-host=` and `--metrics-port=` gain new meaning in push mode. Instead of the server they are opening up it is the host and the port of the push gateway it should push to. Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
c7cb0264f5
commit
319ee2095c
@ -0,0 +1,106 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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 |
||||
* |
||||
* 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 tech.pegasys.pantheon.metrics.prometheus; |
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument; |
||||
|
||||
import tech.pegasys.pantheon.metrics.MetricsSystem; |
||||
import tech.pegasys.pantheon.util.NetworkUtility; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import io.prometheus.client.exporter.PushGateway; |
||||
import org.apache.logging.log4j.LogManager; |
||||
import org.apache.logging.log4j.Logger; |
||||
|
||||
class MetricsPushGatewayService implements MetricsService { |
||||
private static final Logger LOG = LogManager.getLogger(); |
||||
|
||||
private PushGateway pushGateway; |
||||
private ScheduledExecutorService scheduledExecutorService; |
||||
private final MetricsConfiguration config; |
||||
private final MetricsSystem metricsSystem; |
||||
|
||||
MetricsPushGatewayService( |
||||
final MetricsConfiguration configuration, final MetricsSystem metricsSystem) { |
||||
this.metricsSystem = metricsSystem; |
||||
validateConfig(configuration); |
||||
config = configuration; |
||||
} |
||||
|
||||
private void validateConfig(final MetricsConfiguration config) { |
||||
checkArgument( |
||||
config.getPort() == 0 || NetworkUtility.isValidPort(config.getPort()), |
||||
"Invalid port configuration."); |
||||
checkArgument(config.getHost() != null, "Required host is not configured."); |
||||
checkArgument( |
||||
MetricsConfiguration.MODE_PUSH_GATEWAY.equals(config.getMode()), |
||||
"Metrics Push Gateway Service cannot start up outside of '" |
||||
+ MetricsConfiguration.MODE_PUSH_GATEWAY |
||||
+ "' mode."); |
||||
checkArgument( |
||||
metricsSystem instanceof PrometheusMetricsSystem, |
||||
"Push Gateway requires a Prometheus Metrics System."); |
||||
} |
||||
|
||||
@Override |
||||
public CompletableFuture<?> start() { |
||||
LOG.info("Starting Metrics service on {}:{}", config.getHost(), config.getPort()); |
||||
|
||||
pushGateway = new PushGateway(config.getHost() + ":" + config.getPort()); |
||||
|
||||
// Create the executor
|
||||
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); |
||||
scheduledExecutorService.scheduleAtFixedRate( |
||||
this::pushMetrics, |
||||
config.getPushInterval() / 2, |
||||
config.getPushInterval(), |
||||
TimeUnit.SECONDS); |
||||
return CompletableFuture.completedFuture(null); |
||||
} |
||||
|
||||
@Override |
||||
public CompletableFuture<?> stop() { |
||||
final CompletableFuture<?> resultFuture = new CompletableFuture<>(); |
||||
try { |
||||
// Calling shutdown now cancels the pending push, which is desirable.
|
||||
scheduledExecutorService.shutdownNow(); |
||||
scheduledExecutorService.awaitTermination(30, TimeUnit.SECONDS); |
||||
pushGateway.delete(config.getPrometheusJob()); |
||||
resultFuture.complete(null); |
||||
} catch (final IOException | InterruptedException e) { |
||||
LOG.error(e); |
||||
resultFuture.completeExceptionally(e); |
||||
} |
||||
return resultFuture; |
||||
} |
||||
|
||||
@Override |
||||
public Optional<Integer> getPort() { |
||||
return Optional.empty(); |
||||
} |
||||
|
||||
private void pushMetrics() { |
||||
try { |
||||
pushGateway.pushAdd( |
||||
((PrometheusMetricsSystem) metricsSystem).getRegistry(), config.getPrometheusJob()); |
||||
} catch (final IOException e) { |
||||
LOG.warn("Cound not push metrics", e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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 |
||||
* |
||||
* 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 tech.pegasys.pantheon.metrics.prometheus; |
||||
|
||||
import tech.pegasys.pantheon.metrics.MetricsSystem; |
||||
|
||||
import java.util.Optional; |
||||
import java.util.concurrent.CompletableFuture; |
||||
|
||||
import io.vertx.core.Vertx; |
||||
|
||||
public interface MetricsService { |
||||
|
||||
static MetricsService create( |
||||
final Vertx vertx, |
||||
final MetricsConfiguration configuration, |
||||
final MetricsSystem metricsSystem) { |
||||
switch (configuration.getMode()) { |
||||
case MetricsConfiguration.MODE_PUSH_GATEWAY: |
||||
return new MetricsPushGatewayService(configuration, metricsSystem); |
||||
case MetricsConfiguration.MODE_SERVER_PULL: |
||||
return new MetricsHttpService(vertx, configuration, metricsSystem); |
||||
default: |
||||
throw new RuntimeException("No metrics service for mode '" + configuration.getMode() + "'"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Starts the Metrics Service and all needed backend systems. |
||||
* |
||||
* @return completion state |
||||
*/ |
||||
CompletableFuture<?> start(); |
||||
|
||||
/** |
||||
* Stops the Metrics Service and performs needed cleanup. |
||||
* |
||||
* @return completion state |
||||
*/ |
||||
CompletableFuture<?> stop(); |
||||
|
||||
/** |
||||
* If serving to a port on the client, what the port number is. |
||||
* |
||||
* @return Port number optional, serving if present. |
||||
*/ |
||||
Optional<Integer> getPort(); |
||||
} |
Loading…
Reference in new issue