feature:support pushGateway push metrics

pull/504/head
wulingxiao 3 years ago
parent 3f672a8213
commit f140292f8b

@ -79,6 +79,7 @@
<protobuf-java.version>3.16.1</protobuf-java.version>
<bcprov-jdk15on.version>1.69</bcprov-jdk15on.version>
<guava.version>31.0.1-jre</guava.version>
<pushgateway.version>0.12.0</pushgateway.version>
<!-- Maven Plugin Versions -->
<maven-source-plugin.version>3.2.0</maven-source-plugin.version>
@ -252,6 +253,12 @@
<artifactId>byte-buddy</artifactId>
<version>${byte-buddy.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
<version>${pushgateway.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

@ -69,6 +69,11 @@
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>
</dependencies>
</project>

@ -17,6 +17,10 @@
package com.tencent.cloud.rpc.enhancement.stat.config;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@ -47,6 +51,10 @@ public class PolarisStatProperties {
*/
private String path = "/metrics";
/**
* PushGatewayProperties.
*/
private PushGatewayProperties pushgateway;
public boolean isEnabled() {
return enabled;
@ -79,4 +87,108 @@ public class PolarisStatProperties {
public void setPath(String path) {
this.path = path;
}
public PushGatewayProperties getPushgateway() {
return pushgateway;
}
public void setPushgateway(PushGatewayProperties pushgateway) {
this.pushgateway = pushgateway;
}
public static class PushGatewayProperties {
/**
* Enable publishing via a Prometheus pushGateway.
*/
private Boolean enabled = false;
/**
* Required host:port or ip:port of the pushGateway.
*/
private String address = "localhost:9091";
/**
* Required identifier for this application instance.
*/
private String job;
/**
* Frequency with which to push metrics to pushGateway,default 1 minutes.
*/
private Duration pushRate = Duration.ofMinutes(1);
/**
* PushGateway shutDownStrategy when application is is shut-down.
*/
private ShutDownStrategy shutDownStrategy;
/**
* Used to group metrics in pushGateway. eg:instance:instanceName
*/
private Map<String, String> groupingKeys = new HashMap<>();
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Duration getPushRate() {
return pushRate;
}
public void setPushRate(Duration pushRate) {
this.pushRate = pushRate;
}
public Map<String, String> getGroupingKeys() {
return groupingKeys;
}
public void setGroupingKeys(Map<String, String> groupingKeys) {
this.groupingKeys = groupingKeys;
}
public ShutDownStrategy getShutDownStrategy() {
return shutDownStrategy;
}
public void setShutDownStrategy(ShutDownStrategy shutDownStrategy) {
this.shutDownStrategy = shutDownStrategy;
}
}
/**
* PushGateway shutDownStrategy when application is is shut-down.
*/
public enum ShutDownStrategy {
/**
* Delete metrics from pushGateway when application is shut-down.
*/
DELETE,
/**
* Push metrics right before shut-down. Mostly useful for batch jobs.
*/
PUSH
}
}

@ -17,9 +17,15 @@
package com.tencent.cloud.rpc.enhancement.stat.config;
import java.time.Duration;
import java.util.Map;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.rpc.enhancement.stat.config.plugin.PrometheusPushGatewayContainer;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -40,4 +46,36 @@ public class PolarisStatPropertiesAutoConfiguration {
public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) {
return new StatConfigModifier(polarisStatProperties, environment);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.polaris.stat.pushgateway.enabled", havingValue = "true")
public static class PolarisStatPrometheusPushGatewayAutoConfiguration {
private static final String DEFAULT_JOB_NAME = "spring-cloud-tencent-application";
@Bean
@ConditionalOnMissingBean
public PrometheusPushGatewayContainer prometheusPushGatewayContainer(PolarisStatProperties polarisStatProperties,
Environment environment) {
PolarisStatProperties.PushGatewayProperties pushGatewayProperties = polarisStatProperties.getPushgateway();
String job = job(pushGatewayProperties, environment);
Duration pushRate = pushGatewayProperties.getPushRate();
String address = pushGatewayProperties.getAddress();
PolarisStatProperties.ShutDownStrategy shutDownStrategy = pushGatewayProperties.getShutDownStrategy();
Map<String, String> groupingKeys = pushGatewayProperties.getGroupingKeys();
return new PrometheusPushGatewayContainer(address, pushRate, job, shutDownStrategy, groupingKeys);
}
private String job(PolarisStatProperties.PushGatewayProperties pushGatewayProperties, Environment environment) {
String job = pushGatewayProperties.getJob();
if (StringUtils.isBlank(job)) {
job = environment.getProperty("spring.application.name");
}
if (StringUtils.isBlank(job)) {
job = DEFAULT_JOB_NAME;
}
return job;
}
}
}

@ -0,0 +1,129 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.rpc.enhancement.stat.config.plugin;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties;
import com.tencent.polaris.client.util.NamedThreadFactory;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.PushGateway;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* PrometheusPushGatewayContainer will push the metrics aggregated by
* {@link com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandler} to Prometheus pushGateway.
*
* @author lingxiao.wlx
*/
public class PrometheusPushGatewayContainer {
private final Logger logger = LoggerFactory.getLogger(PrometheusPushGatewayContainer.class);
/**
* {@link com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandler} register the Collector with
* CollectorRegistry.defaultRegistry.
*/
private final CollectorRegistry collectorRegistry = CollectorRegistry.defaultRegistry;
private final String address;
private final String job;
private final PolarisStatProperties.ShutDownStrategy shutDownStrategy;
private final PushGateway pushGateway;
private final Map<String, String> groupingKey;
private final ScheduledExecutorService executorService;
private final ScheduledFuture<?> scheduledFuture;
public PrometheusPushGatewayContainer(String address, Duration pushRate, String job,
PolarisStatProperties.ShutDownStrategy shutDownStrategy, Map<String, String> groupingKey) {
this.address = address;
this.job = job;
this.shutDownStrategy = shutDownStrategy;
this.pushGateway = new PushGateway(address);
this.groupingKey = groupingKey;
this.executorService = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("PrometheusPushGateway") {
@Override
public Thread newThread(Runnable r) {
Thread thread = super.newThread(r);
thread.setDaemon(true);
return thread;
}
});
this.scheduledFuture = executorService.scheduleAtFixedRate(() -> {
this.push();
if (logger.isDebugEnabled()) {
logger.debug("push metrics to Prometheus pushGateway success!");
}
}, 0, pushRate.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* Call by Spring to destroy PrometheusPushGatewayContainer instance.
*/
public void shutdown() {
shutdown(this.shutDownStrategy);
}
private void shutdown(PolarisStatProperties.ShutDownStrategy shutDownStrategy) {
executorService.shutdown();
scheduledFuture.cancel(false);
if (Objects.isNull(shutDownStrategy)) {
return;
}
switch (shutDownStrategy) {
case PUSH:
push();
break;
case DELETE:
delete();
break;
}
}
private void push() {
try {
pushGateway.pushAdd(collectorRegistry, this.job, this.groupingKey);
}
catch (UnknownHostException e) {
logger.error("Unable to locate host {}. No longer attempting metrics publication to this host", this.address);
// if cache UnknownHostException,shutdown task
this.shutdown(null);
}
catch (Throwable t) {
logger.error("Unable to push metrics to Prometheus pushGateway", t);
}
}
private void delete() {
try {
pushGateway.delete(this.job, this.groupingKey);
}
catch (Throwable t) {
logger.error("Unable to delete metrics from Prometheus pushGateway", t);
}
}
}

@ -46,6 +46,45 @@
"type": "java.lang.String",
"defaultValue": "/metrics",
"description": "Path for prometheus to pull."
},
{
"name": "spring.cloud.polaris.stat.pushgateway.address",
"type": "java.lang.String",
"description": "Required host:port or ip:port of the pushGateway.",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties",
"defaultValue": "localhost:9091"
},
{
"name": "spring.cloud.polaris.stat.pushgateway.enabled",
"type": "java.lang.Boolean",
"description": "Enable publishing via a Prometheus pushGateway.",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties",
"defaultValue": false
},
{
"name": "spring.cloud.polaris.stat.pushgateway.grouping-keys",
"type": "java.util.Map<java.lang.String,java.lang.String>",
"description": "Used to group metrics in pushGateway. eg:instance:instanceName",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties"
},
{
"name": "spring.cloud.polaris.stat.pushgateway.job",
"type": "java.lang.String",
"description": "Required identifier for this application instance.",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties"
},
{
"name": "spring.cloud.polaris.stat.pushgateway.push-rate",
"type": "java.time.Duration",
"description": "Frequency with which to push metrics to pushGateway,default 1 minutes.",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties",
"defaultValue": "1m"
},
{
"name": "spring.cloud.polaris.stat.pushgateway.shut-down-strategy",
"type": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$ShutDownStrategy",
"description": "PushGateway shutDownStrategy when application is is shut-down.",
"sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties$PushGatewayProperties"
}
]
}

@ -0,0 +1,68 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.rpc.enhancement.stat.plugin;
import java.util.Objects;
import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties;
import com.tencent.cloud.rpc.enhancement.stat.config.plugin.PrometheusPushGatewayContainer;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* Test for {@link PrometheusPushGatewayContainer}.
*
* @author lingxiao.wlx
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT,
classes = PrometheusPushGatewayContainerTest.TestApplication.class,
properties = {"spring.cloud.polaris.stat.pushgateway.enabled=true",
"spring.cloud.polaris.stat.pushgateway.shut-down-strategy=DELETE",
"spring.cloud.polaris.stat.pushgateway.push-rate=1m",
"spring.cloud.polaris.stat.pushgateway.job=test",
"spring.cloud.polaris.stat.pushgateway.grouping-keys.instance=test"})
public class PrometheusPushGatewayContainerTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void prometheusPushGatewayContainerTest() {
PolarisStatProperties polarisStatProperties = applicationContext.getBean(PolarisStatProperties.class);
PolarisStatProperties.PushGatewayProperties pushgateway = polarisStatProperties.getPushgateway();
Assertions.assertFalse(Objects.isNull(pushgateway));
Assertions.assertEquals(pushgateway.getJob(), "test");
Assertions.assertEquals(pushgateway.getPushRate().toMillis(), 60000);
Assertions.assertEquals(pushgateway.getShutDownStrategy(), PolarisStatProperties.ShutDownStrategy.DELETE);
applicationContext.getBean(PrometheusPushGatewayContainer.class);
}
@SpringBootApplication
protected static class TestApplication {
}
}
Loading…
Cancel
Save