fix bugs
This commit is contained in:
57
blade-starter-prometheus/pom.xml
Normal file
57
blade-starter-prometheus/pom.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-prometheus</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</dependency>
|
||||
<!-- Blade -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-launch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-metrics</artifactId>
|
||||
</dependency>
|
||||
<!-- Auto -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.config;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
|
||||
import org.springblade.core.launch.props.BladePropertySource;
|
||||
import org.springblade.core.prometheus.endpoint.AgentEndpoint;
|
||||
import org.springblade.core.prometheus.endpoint.PrometheusApi;
|
||||
import org.springblade.core.prometheus.endpoint.ReactivePrometheusApi;
|
||||
import org.springblade.core.prometheus.endpoint.ServiceEndpoint;
|
||||
import org.springblade.core.prometheus.service.RegistrationService;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
|
||||
import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Prometheus配置类
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@BladePropertySource(value = "classpath:/blade-prometheus.yml")
|
||||
public class PrometheusConfiguration {
|
||||
|
||||
@Bean
|
||||
public RegistrationService registrationService(DiscoveryClient discoveryClient) {
|
||||
return new RegistrationService(discoveryClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AgentEndpoint agentController(NacosDiscoveryProperties properties) {
|
||||
return new AgentEndpoint(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServiceEndpoint serviceController(RegistrationService registrationService) {
|
||||
return new ServiceEndpoint(registrationService);
|
||||
}
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnBean(DiscoveryClient.class)
|
||||
@ConditionalOnDiscoveryEnabled
|
||||
// @ConditionalOnBlockingDiscoveryEnabled
|
||||
@ConditionalOnProperty(value = "spring.cloud.discovery.blocking.enabled")
|
||||
public static class PrometheusApiConfiguration {
|
||||
|
||||
@Bean
|
||||
public PrometheusApi prometheusApi(Environment environment,
|
||||
DiscoveryClient discoveryClient,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
String activeProfile = activeProfiles.length > 0 ? activeProfiles[0] : null;
|
||||
return new PrometheusApi(activeProfile, discoveryClient, eventPublisher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnBean(ReactiveDiscoveryClient.class)
|
||||
@ConditionalOnDiscoveryEnabled
|
||||
@ConditionalOnReactiveDiscoveryEnabled
|
||||
public static class ReactivePrometheusApiConfiguration {
|
||||
|
||||
@Bean
|
||||
public ReactivePrometheusApi reactivePrometheusApi(Environment environment,
|
||||
ReactiveDiscoveryClient discoveryClient,
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
String activeProfile = activeProfiles.length > 0 ? activeProfiles[0] : null;
|
||||
return new ReactivePrometheusApi(activeProfile, discoveryClient, eventPublisher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Agent
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class Agent {
|
||||
|
||||
@JsonProperty("Config")
|
||||
private Config config;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.data;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* ChangeItem
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class ChangeItem<T> {
|
||||
private final T item;
|
||||
private final long changeIndex;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Config
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class Config {
|
||||
|
||||
@JsonProperty("Datacenter")
|
||||
private String dataCenter;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.springblade.core.prometheus.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* model details see https://www.consul.io/api/catalog.html#serviceport
|
||||
*
|
||||
* @author consul
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class Service {
|
||||
|
||||
@JsonProperty("Address")
|
||||
private String address;
|
||||
|
||||
@JsonProperty("Node")
|
||||
private String node;
|
||||
|
||||
@JsonProperty("ServiceAddress")
|
||||
private String serviceAddress;
|
||||
|
||||
@JsonProperty("ServiceName")
|
||||
private String serviceName;
|
||||
|
||||
@JsonProperty("ServiceID")
|
||||
private String serviceId;
|
||||
|
||||
@JsonProperty("ServicePort")
|
||||
private int servicePort;
|
||||
|
||||
@JsonProperty("NodeMeta")
|
||||
private Map<String, String> nodeMeta;
|
||||
|
||||
@JsonProperty("ServiceMeta")
|
||||
private Map<String, String> serviceMeta;
|
||||
|
||||
/**
|
||||
* will be empty, eureka does not have the concept of service tags
|
||||
*/
|
||||
@JsonProperty("ServiceTags")
|
||||
private List<String> serviceTags;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.springblade.core.prometheus.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* model details see https://www.consul.io/api/health.html#list-nodes-for-service
|
||||
*
|
||||
* @author consul
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class ServiceHealth {
|
||||
|
||||
@JsonProperty("Node")
|
||||
private Node node;
|
||||
|
||||
@JsonProperty("Service")
|
||||
private Service service;
|
||||
|
||||
@JsonProperty("Checks")
|
||||
private List<Check> checks;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public static class Node {
|
||||
|
||||
@JsonProperty("Node")
|
||||
private String name;
|
||||
|
||||
@JsonProperty("Address")
|
||||
private String address;
|
||||
|
||||
@JsonProperty("Meta")
|
||||
private Map<String, String> meta;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public static class Service {
|
||||
|
||||
@JsonProperty("ID")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("Service")
|
||||
private String name;
|
||||
|
||||
@JsonProperty("Tags")
|
||||
private List<String> tags;
|
||||
|
||||
@JsonProperty("Address")
|
||||
private String address;
|
||||
|
||||
@JsonProperty("Meta")
|
||||
private Map<String, String> meta;
|
||||
|
||||
@JsonProperty("Port")
|
||||
private int port;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public static class Check {
|
||||
|
||||
@JsonProperty("Node")
|
||||
private String node;
|
||||
|
||||
@JsonProperty("CheckID")
|
||||
private String checkId;
|
||||
|
||||
@JsonProperty("Name")
|
||||
private String name;
|
||||
|
||||
@JsonProperty("Status")
|
||||
private String status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.endpoint;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.auto.annotation.AutoIgnore;
|
||||
import org.springblade.core.prometheus.data.Agent;
|
||||
import org.springblade.core.prometheus.data.Config;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* consul agent api
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@AutoIgnore
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class AgentEndpoint {
|
||||
private final NacosDiscoveryProperties properties;
|
||||
|
||||
@GetMapping(value = "/v1/agent/self", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Agent getNodes() {
|
||||
Config config = Config.builder().dataCenter(properties.getGroup()).build();
|
||||
return Agent.builder().config(config).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.prometheus.endpoint;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.auto.annotation.AutoIgnore;
|
||||
import org.springblade.core.prometheus.pojo.AlertMessage;
|
||||
import org.springblade.core.prometheus.pojo.TargetGroup;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* prometheus http sd
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@AutoIgnore
|
||||
@RestController
|
||||
@RequestMapping("actuator/prometheus")
|
||||
@RequiredArgsConstructor
|
||||
public class PrometheusApi {
|
||||
private final String activeProfile;
|
||||
private final DiscoveryClient discoveryClient;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@GetMapping("sd")
|
||||
public List<TargetGroup> getList() {
|
||||
List<String> serviceIdList = discoveryClient.getServices();
|
||||
if (serviceIdList == null || serviceIdList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<TargetGroup> targetGroupList = new ArrayList<>();
|
||||
for (String serviceId : serviceIdList) {
|
||||
List<ServiceInstance> instanceList = discoveryClient.getInstances(serviceId);
|
||||
List<String> targets = new ArrayList<>();
|
||||
for (ServiceInstance instance : instanceList) {
|
||||
targets.add(String.format("%s:%d", instance.getHost(), instance.getPort()));
|
||||
}
|
||||
Map<String, String> labels = new HashMap<>(4);
|
||||
// 1. 环境
|
||||
if (StringUtils.hasText(activeProfile)) {
|
||||
labels.put("profile", activeProfile);
|
||||
}
|
||||
// 2. 服务名
|
||||
labels.put("__meta_prometheus_job", serviceId);
|
||||
targetGroupList.add(new TargetGroup(targets, labels));
|
||||
}
|
||||
return targetGroupList;
|
||||
}
|
||||
|
||||
@PostMapping("alerts")
|
||||
public ResponseEntity<Object> postAlerts(@RequestBody AlertMessage message) {
|
||||
eventPublisher.publishEvent(message);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.prometheus.endpoint;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.auto.annotation.AutoIgnore;
|
||||
import org.springblade.core.prometheus.pojo.AlertMessage;
|
||||
import org.springblade.core.prometheus.pojo.TargetGroup;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* prometheus http sd
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@AutoIgnore
|
||||
@RestController
|
||||
@RequestMapping("actuator/prometheus")
|
||||
@RequiredArgsConstructor
|
||||
public class ReactivePrometheusApi {
|
||||
private final String activeProfile;
|
||||
private final ReactiveDiscoveryClient discoveryClient;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@GetMapping("sd")
|
||||
public Flux<TargetGroup> getList() {
|
||||
return discoveryClient.getServices()
|
||||
.flatMap(discoveryClient::getInstances)
|
||||
.groupBy(ServiceInstance::getServiceId, instance ->
|
||||
String.format("%s:%d", instance.getHost(), instance.getPort())
|
||||
).flatMap(instanceGrouped -> {
|
||||
Map<String, String> labels = new HashMap<>(4);
|
||||
// 1. 环境
|
||||
if (StringUtils.hasText(activeProfile)) {
|
||||
labels.put("profile", activeProfile);
|
||||
}
|
||||
// 2. 服务名
|
||||
String serviceId = instanceGrouped.key();
|
||||
labels.put("__meta_prometheus_job", serviceId);
|
||||
return instanceGrouped.collectList().map(targets -> new TargetGroup(targets, labels));
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping("alerts")
|
||||
public ResponseEntity<Object> postAlerts(@RequestBody AlertMessage message) {
|
||||
eventPublisher.publishEvent(message);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.endpoint;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.auto.annotation.AutoIgnore;
|
||||
import org.springblade.core.prometheus.data.Service;
|
||||
import org.springblade.core.prometheus.data.ServiceHealth;
|
||||
import org.springblade.core.prometheus.service.RegistrationService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* consul catalog api
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@AutoIgnore
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class ServiceEndpoint {
|
||||
private static final String CONSUL_IDX_HEADER = "X-Consul-Index";
|
||||
private static final String QUERY_PARAM_WAIT = "wait";
|
||||
private static final String QUERY_PARAM_INDEX = "index";
|
||||
private static final Pattern WAIT_PATTERN = Pattern.compile("(\\d*)(m|s|ms|h)");
|
||||
private final RegistrationService registrationService;
|
||||
|
||||
@GetMapping(value = "/v1/catalog/services", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Mono<ResponseEntity<Map<String, String[]>>> getServiceNames(
|
||||
@RequestParam(name = QUERY_PARAM_WAIT, required = false) String wait,
|
||||
@RequestParam(name = QUERY_PARAM_INDEX, required = false) Long index) {
|
||||
return registrationService.getServiceNames(getWaitMillis(wait), index)
|
||||
.map(item -> createResponseEntity(item.getItem(), item.getChangeIndex()));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/v1/catalog/service/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Mono<ResponseEntity<List<Service>>> getService(@PathVariable("appName") String appName,
|
||||
@RequestParam(value = QUERY_PARAM_WAIT, required = false) String wait,
|
||||
@RequestParam(value = QUERY_PARAM_INDEX, required = false) Long index) {
|
||||
Objects.requireNonNull(appName, "service name can not be null");
|
||||
return registrationService.getService(appName, getWaitMillis(wait), index)
|
||||
.map(item -> createResponseEntity(item.getItem(), item.getChangeIndex()));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/v1/health/service/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Mono<ResponseEntity<List<ServiceHealth>>> getServiceHealth(@PathVariable("appName") String appName,
|
||||
@RequestParam(value = QUERY_PARAM_WAIT, required = false) String wait,
|
||||
@RequestParam(value = QUERY_PARAM_INDEX, required = false) Long index) {
|
||||
Assert.isTrue(appName != null, "service name can not be null");
|
||||
return registrationService.getService(appName, getWaitMillis(wait), index)
|
||||
.map(item -> {
|
||||
List<ServiceHealth> services = item.getItem().stream()
|
||||
.map(registrationService::getServiceHealth).collect(toList());
|
||||
return createResponseEntity(services, item.getChangeIndex());
|
||||
});
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> createHeaders(long index) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(CONSUL_IDX_HEADER, String.valueOf(index));
|
||||
return headers;
|
||||
}
|
||||
|
||||
private static <T> ResponseEntity<T> createResponseEntity(T body, long index) {
|
||||
return new ResponseEntity<>(body, createHeaders(index), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Details to the wait behaviour can be found
|
||||
* https://www.consul.io/api/index.html#blocking-queries
|
||||
*/
|
||||
private static long getWaitMillis(String wait) {
|
||||
// default from consul docu
|
||||
long millis = TimeUnit.MINUTES.toMillis(5);
|
||||
if (wait != null) {
|
||||
Matcher matcher = WAIT_PATTERN.matcher(wait);
|
||||
if (matcher.matches()) {
|
||||
long value = Long.parseLong(matcher.group(1));
|
||||
TimeUnit timeUnit = parseTimeUnit(matcher.group(2));
|
||||
millis = timeUnit.toMillis(value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid wait pattern");
|
||||
}
|
||||
}
|
||||
return millis + ThreadLocalRandom.current().nextInt(((int) millis / 16) + 1);
|
||||
}
|
||||
|
||||
private static TimeUnit parseTimeUnit(String unit) {
|
||||
switch (unit) {
|
||||
case "h":
|
||||
return TimeUnit.HOURS;
|
||||
case "m":
|
||||
return TimeUnit.MINUTES;
|
||||
case "s":
|
||||
return TimeUnit.SECONDS;
|
||||
case "ms":
|
||||
return TimeUnit.MILLISECONDS;
|
||||
default:
|
||||
throw new IllegalArgumentException("No valid time unit");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.prometheus.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 告警模型
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Data
|
||||
public class AlertInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 状态 resolved|firing
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 标签集合
|
||||
*/
|
||||
private Map<String, String> labels;
|
||||
/**
|
||||
* 注释集合
|
||||
*/
|
||||
private Map<String, String> annotations;
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private OffsetDateTime startsAt;
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private OffsetDateTime endsAt;
|
||||
/**
|
||||
* identifies the entity that caused the alert
|
||||
*/
|
||||
private String generatorURL;
|
||||
/**
|
||||
* fingerprint to identify the alert
|
||||
*/
|
||||
private String fingerprint;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.prometheus.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* alert hook
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Data
|
||||
public class AlertMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version;
|
||||
/**
|
||||
* 由于 “max_alerts” 而截断了多少警报
|
||||
*/
|
||||
private Integer truncatedAlerts;
|
||||
/**
|
||||
* 分组 key
|
||||
*/
|
||||
private String groupKey;
|
||||
/**
|
||||
* 状态 resolved|firing
|
||||
*/
|
||||
private String status;
|
||||
/**
|
||||
* 接收者
|
||||
*/
|
||||
private String receiver;
|
||||
/**
|
||||
* 分组 labels
|
||||
*/
|
||||
private Map<String, String> groupLabels;
|
||||
/**
|
||||
* 通用 label
|
||||
*/
|
||||
private Map<String, String> commonLabels;
|
||||
/**
|
||||
* 通用注解
|
||||
*/
|
||||
private Map<String, String> commonAnnotations;
|
||||
/**
|
||||
* 扩展 url 地址
|
||||
*/
|
||||
private String externalURL;
|
||||
/**
|
||||
* alerts
|
||||
*/
|
||||
private List<AlertInfo> alerts;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.prometheus.pojo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* prometheus http sd 模型
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class TargetGroup {
|
||||
private final List<String> targets;
|
||||
private final Map<String, String> labels;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: DreamLu (596392912@qq.com)
|
||||
*/
|
||||
package org.springblade.core.prometheus.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.prometheus.data.ChangeItem;
|
||||
import org.springblade.core.prometheus.data.Service;
|
||||
import org.springblade.core.prometheus.data.ServiceHealth;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Returns Services and List of Service with its last changed
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RegistrationService {
|
||||
private static final String[] NO_SERVICE_TAGS = new String[0];
|
||||
private final DiscoveryClient discoveryClient;
|
||||
|
||||
public Mono<ChangeItem<Map<String, String[]>>> getServiceNames(long waitMillis, Long index) {
|
||||
return returnDeferred(waitMillis, index, () -> {
|
||||
List<String> services = discoveryClient.getServices();
|
||||
Set<String> set = new HashSet<>(services);
|
||||
Map<String, String[]> result = new HashMap<>();
|
||||
for (String item : set) {
|
||||
result.put(item, NO_SERVICE_TAGS);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<ChangeItem<List<Service>>> getService(String appName, long waitMillis, Long index) {
|
||||
return returnDeferred(waitMillis, index, () -> {
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances(appName);
|
||||
List<Service> list = new ArrayList<>();
|
||||
if (instances == null || instances.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Set<ServiceInstance> instSet = new HashSet<>(instances);
|
||||
for (ServiceInstance instance : instSet) {
|
||||
Service service = Service.builder()
|
||||
.address(instance.getHost())
|
||||
.node(instance.getServiceId())
|
||||
.serviceAddress(instance.getHost())
|
||||
.servicePort(instance.getPort())
|
||||
.serviceName(instance.getServiceId())
|
||||
.serviceId(instance.getHost() + ":" + instance.getPort())
|
||||
.nodeMeta(Collections.emptyMap())
|
||||
.serviceMeta(instance.getMetadata())
|
||||
.serviceTags(Collections.emptyList())
|
||||
.build();
|
||||
list.add(service);
|
||||
}
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
public ServiceHealth getServiceHealth(Service instanceInfo) {
|
||||
String address = instanceInfo.getAddress();
|
||||
ServiceHealth.Node node = ServiceHealth.Node.builder()
|
||||
.name(instanceInfo.getServiceName())
|
||||
.address(address)
|
||||
.meta(Collections.emptyMap())
|
||||
.build();
|
||||
ServiceHealth.Service service = ServiceHealth.Service.builder()
|
||||
.id(instanceInfo.getServiceId())
|
||||
.name(instanceInfo.getServiceName())
|
||||
.tags(Collections.emptyList())
|
||||
.address(address)
|
||||
.meta(instanceInfo.getServiceMeta())
|
||||
.port(instanceInfo.getServicePort())
|
||||
.build();
|
||||
ServiceHealth.Check check = ServiceHealth.Check.builder()
|
||||
.node(instanceInfo.getServiceName())
|
||||
.checkId("service:" + instanceInfo.getServiceId())
|
||||
.name("Service '" + instanceInfo.getServiceId() + "' check")
|
||||
// nacos 实时性很高,可认定为健康
|
||||
.status("UP")
|
||||
.build();
|
||||
return ServiceHealth.builder()
|
||||
.node(node)
|
||||
.service(service)
|
||||
.checks(Collections.singletonList(check))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static <T> Mono<ChangeItem<T>> returnDeferred(long waitMillis, Long index, Supplier<T> fn) {
|
||||
return Mono.just(new ChangeItem<>(fn.get(), System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
metrics:
|
||||
tags:
|
||||
application: ${spring.application.name}
|
||||
Reference in New Issue
Block a user