/*
* Copyright 2012-2019 the original author or authors.
*
* 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
*
* https://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.springframework.boot.actuate.metrics.export.prometheus;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.PushGateway;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
Class that can be used to manage the pushing of metrics to a
Prometheus PushGateway
. Handles the scheduling of push operations, error handling and shutdown operations. Author: David J. M. Karlsen, Phillip Webb Since: 2.1.0
/**
* Class that can be used to manage the pushing of metrics to a {@link PushGateway
* Prometheus PushGateway}. Handles the scheduling of push operations, error handling and
* shutdown operations.
*
* @author David J. M. Karlsen
* @author Phillip Webb
* @since 2.1.0
*/
public class PrometheusPushGatewayManager {
private static final Log logger = LogFactory.getLog(PrometheusPushGatewayManager.class);
private final PushGateway pushGateway;
private final CollectorRegistry registry;
private final String job;
private final Map<String, String> groupingKey;
private final ShutdownOperation shutdownOperation;
private final TaskScheduler scheduler;
private ScheduledFuture<?> scheduled;
Create a new PrometheusPushGatewayManager
instance using a single threaded TaskScheduler
. Params: - pushGateway – the source push gateway
- registry – the collector registry to push
- pushRate – the rate at which push operations occur
- job – the job ID for the operation
- groupingKeys – an optional set of grouping keys for the operation
- shutdownOperation – the shutdown operation that should be performed when
context is closed.
/**
* Create a new {@link PrometheusPushGatewayManager} instance using a single threaded
* {@link TaskScheduler}.
* @param pushGateway the source push gateway
* @param registry the collector registry to push
* @param pushRate the rate at which push operations occur
* @param job the job ID for the operation
* @param groupingKeys an optional set of grouping keys for the operation
* @param shutdownOperation the shutdown operation that should be performed when
* context is closed.
*/
public PrometheusPushGatewayManager(PushGateway pushGateway, CollectorRegistry registry, Duration pushRate,
String job, Map<String, String> groupingKeys, ShutdownOperation shutdownOperation) {
this(pushGateway, registry, new PushGatewayTaskScheduler(), pushRate, job, groupingKeys, shutdownOperation);
}
Create a new PrometheusPushGatewayManager
instance. Params: - pushGateway – the source push gateway
- registry – the collector registry to push
- scheduler – the scheduler used for operations
- pushRate – the rate at which push operations occur
- job – the job ID for the operation
- groupingKey – an optional set of grouping keys for the operation
- shutdownOperation – the shutdown operation that should be performed when
context is closed.
/**
* Create a new {@link PrometheusPushGatewayManager} instance.
* @param pushGateway the source push gateway
* @param registry the collector registry to push
* @param scheduler the scheduler used for operations
* @param pushRate the rate at which push operations occur
* @param job the job ID for the operation
* @param groupingKey an optional set of grouping keys for the operation
* @param shutdownOperation the shutdown operation that should be performed when
* context is closed.
*/
public PrometheusPushGatewayManager(PushGateway pushGateway, CollectorRegistry registry, TaskScheduler scheduler,
Duration pushRate, String job, Map<String, String> groupingKey, ShutdownOperation shutdownOperation) {
Assert.notNull(pushGateway, "PushGateway must not be null");
Assert.notNull(registry, "Registry must not be null");
Assert.notNull(scheduler, "Scheduler must not be null");
Assert.notNull(pushRate, "PushRate must not be null");
Assert.hasLength(job, "Job must not be empty");
this.pushGateway = pushGateway;
this.registry = registry;
this.job = job;
this.groupingKey = groupingKey;
this.shutdownOperation = (shutdownOperation != null) ? shutdownOperation : ShutdownOperation.NONE;
this.scheduler = scheduler;
this.scheduled = this.scheduler.scheduleAtFixedRate(this::push, pushRate);
}
private void push() {
try {
this.pushGateway.pushAdd(this.registry, this.job, this.groupingKey);
}
catch (UnknownHostException ex) {
String host = ex.getMessage();
String message = "Unable to locate prometheus push gateway host"
+ (StringUtils.hasLength(host) ? " '" + host + "'" : "")
+ ". No longer attempting metrics publication to this host";
logger.error(message, ex);
shutdown(ShutdownOperation.NONE);
}
catch (Throwable ex) {
logger.error("Unable to push metrics to Prometheus Pushgateway", ex);
}
}
private void delete() {
try {
this.pushGateway.delete(this.job, this.groupingKey);
}
catch (Throwable ex) {
logger.error("Unable to delete metrics from Prometheus Pushgateway", ex);
}
}
Shutdown the manager, running any ShutdownOperation
. /**
* Shutdown the manager, running any {@link ShutdownOperation}.
*/
public void shutdown() {
shutdown(this.shutdownOperation);
}
private void shutdown(ShutdownOperation shutdownOperation) {
if (this.scheduler instanceof PushGatewayTaskScheduler) {
((PushGatewayTaskScheduler) this.scheduler).shutdown();
}
this.scheduled.cancel(false);
switch (shutdownOperation) {
case PUSH:
push();
break;
case DELETE:
delete();
break;
}
}
The operation that should be performed on shutdown.
/**
* The operation that should be performed on shutdown.
*/
public enum ShutdownOperation {
Don't perform any shutdown operation.
/**
* Don't perform any shutdown operation.
*/
NONE,
Perform a 'push' before shutdown.
/**
* Perform a 'push' before shutdown.
*/
PUSH,
Perform a 'delete' before shutdown.
/**
* Perform a 'delete' before shutdown.
*/
DELETE
}
TaskScheduler
used when the user doesn't specify one. /**
* {@link TaskScheduler} used when the user doesn't specify one.
*/
static class PushGatewayTaskScheduler extends ThreadPoolTaskScheduler {
PushGatewayTaskScheduler() {
setPoolSize(1);
setDaemon(true);
setThreadGroupName("prometheus-push-gateway");
}
@Override
public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {
return Executors.newSingleThreadScheduledExecutor(this::newThread);
}
}
}