This commit is contained in:
2025-11-28 16:23:32 +08:00
commit a9e0e16c29
826 changed files with 89805 additions and 0 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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()));
}
}

View File

@@ -0,0 +1,8 @@
management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: ${spring.application.name}