jdk17 commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
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" xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-prometheus</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-plugin-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-influx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.prometheus</groupId>
|
||||
<artifactId>prometheus-metrics-tracer-initializer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.lingniu.framework.plugin.prometheus;
|
||||
|
||||
/**
|
||||
* Counter 类型代表一种样本数据单调递增的指标,即只增不减,除非监控系统发生了重置
|
||||
**/
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface PrometheusCounter {
|
||||
|
||||
/**
|
||||
* 如果name有设置值,使用name作为Metric name
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
String[] labels() default "";
|
||||
/**
|
||||
* SPEL 参数列表
|
||||
*/
|
||||
String[] parameterKeys() default "";
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
String memo() default "default";
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package cn.lingniu.framework.plugin.prometheus;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface PrometheusMetrics {
|
||||
|
||||
/**
|
||||
* 默认为空,程序使用method signature作为Metric name
|
||||
* 如果name有设置值,使用name作为Metric name
|
||||
*/
|
||||
String name() default "";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.lingniu.framework.plugin.prometheus;
|
||||
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Summary 类型
|
||||
**/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface PrometheusSummary {
|
||||
|
||||
/**
|
||||
* 如果name有设置值,使用name作为Metric name
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
String[] labels() default "";
|
||||
/**
|
||||
* SPEL 参数列表
|
||||
*/
|
||||
String[] parameterKeys() default "";
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
String memo() default "default";
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.aspect;
|
||||
|
||||
import io.micrometer.common.annotation.AnnotationHandler;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 基础类
|
||||
**/
|
||||
@Slf4j
|
||||
public abstract class BasePrometheusAspect {
|
||||
@Autowired
|
||||
MeterRegistry registry;
|
||||
@Autowired
|
||||
Map<Class/* builder class */, AnnotationHandler> annotationHandlerMap;
|
||||
|
||||
protected void addExtraTags(Object builder, ProceedingJoinPoint pjp, Object result) {
|
||||
AnnotationHandler meterTagAnnotationHandler = annotationHandlerMap.get(builder);
|
||||
if (meterTagAnnotationHandler == null) {
|
||||
return;
|
||||
}
|
||||
meterTagAnnotationHandler.addAnnotatedParameters(builder, pjp);
|
||||
meterTagAnnotationHandler.addAnnotatedMethodResult(builder, pjp, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.aspect;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.common.annotation.AnnotationHandler;
|
||||
import io.micrometer.common.annotation.NoOpValueResolver;
|
||||
import io.micrometer.common.annotation.ValueExpressionResolver;
|
||||
import io.micrometer.common.annotation.ValueResolver;
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import io.micrometer.core.aop.MeterTag;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* DistributionSummary MeterTag AnnotationHandler
|
||||
*/
|
||||
public class DistributionSummaryMeterTagAnnotationHandler extends AnnotationHandler<DistributionSummary.Builder> {
|
||||
|
||||
public DistributionSummaryMeterTagAnnotationHandler(
|
||||
Function<Class<? extends ValueResolver>, ? extends ValueResolver> resolverProvider,
|
||||
Function<Class<? extends ValueExpressionResolver>, ? extends ValueExpressionResolver> expressionResolverProvider) {
|
||||
super((keyValue, builder) -> builder.tag(keyValue.getKey(), keyValue.getValue()), resolverProvider,
|
||||
expressionResolverProvider, MeterTag.class, (annotation, o) -> {
|
||||
if (!(annotation instanceof MeterTag)) {
|
||||
return null;
|
||||
}
|
||||
MeterTag meterTag = (MeterTag) annotation;
|
||||
return KeyValue.of(resolveTagKey(meterTag),
|
||||
resolveTagValue(meterTag, o, resolverProvider, expressionResolverProvider));
|
||||
});
|
||||
}
|
||||
|
||||
static String resolveTagKey(MeterTag annotation) {
|
||||
return StringUtils.isNotBlank(annotation.value()) ? annotation.value() : annotation.key();
|
||||
}
|
||||
|
||||
static String resolveTagValue(MeterTag annotation, Object argument,
|
||||
Function<Class<? extends ValueResolver>, ? extends ValueResolver> resolverProvider,
|
||||
Function<Class<? extends ValueExpressionResolver>, ? extends ValueExpressionResolver> expressionResolverProvider) {
|
||||
String value = null;
|
||||
if (annotation.resolver() != NoOpValueResolver.class) {
|
||||
ValueResolver valueResolver = resolverProvider.apply(annotation.resolver());
|
||||
value = valueResolver.resolve(argument);
|
||||
} else if (StringUtils.isNotBlank(annotation.expression())) {
|
||||
value = expressionResolverProvider.apply(ValueExpressionResolver.class)
|
||||
.resolve(annotation.expression(), argument);
|
||||
} else if (argument != null) {
|
||||
value = argument.toString();
|
||||
}
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.aspect;
|
||||
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusCounter;
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Count实现类
|
||||
**/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class PrometheusCounterAspect extends BasePrometheusAspect {
|
||||
|
||||
|
||||
@Pointcut("@annotation(cn.lingniu.framework.plugin.prometheus.PrometheusCounter)")
|
||||
public void prometheusCounterAop() {
|
||||
}
|
||||
|
||||
@Around("prometheusCounterAop() && @annotation(prometheusCounter)")
|
||||
public Object prometheusCounterAspect(ProceedingJoinPoint point, PrometheusCounter prometheusCounter) throws Throwable {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Object val = null;
|
||||
Method signatureMethod = signature.getMethod();
|
||||
String countName = ObjectEmptyUtils.isEmpty(prometheusCounter.name()) ? signatureMethod.getName() : prometheusCounter.name();
|
||||
boolean success = true;
|
||||
try {
|
||||
val = point.proceed();
|
||||
} catch (Exception ex) {
|
||||
success = false;
|
||||
throw ex;
|
||||
} finally {
|
||||
Counter.Builder builder = Counter.builder(countName)
|
||||
.tag("response", success ? "SUCCESS" : "FAILED")
|
||||
.tags(prometheusCounter.labels())
|
||||
.description(prometheusCounter.memo());
|
||||
addExtraTags(builder, point, val);
|
||||
builder.register(registry).count();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.aspect;
|
||||
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusMetrics;
|
||||
import io.prometheus.metrics.core.datapoints.Timer;
|
||||
import io.prometheus.metrics.core.metrics.Counter;
|
||||
import io.prometheus.metrics.core.metrics.Histogram;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class PrometheusMetricsAspect {
|
||||
|
||||
private static final Counter requestTotal = Counter.builder().name("couter_all").labelNames("api").help
|
||||
("total request couter of api").register();
|
||||
private static final Counter requestError = Counter.builder().name("couter_error").labelNames("api").help
|
||||
("response Error couter of api").register();
|
||||
private static final Histogram histogram = Histogram.builder().name("histogram_consuming").labelNames("api").help
|
||||
("response consuming of api").register();
|
||||
|
||||
|
||||
@Pointcut("@annotation(cn.lingniu.framework.plugin.prometheus.PrometheusMetrics)")
|
||||
public void prometheusMetricsAop() {
|
||||
}
|
||||
|
||||
@Around(value = "prometheusMetricsAop() && @annotation(prometheusMetrics)")
|
||||
public Object prometheusMetricsAspect(ProceedingJoinPoint joinPoint, PrometheusMetrics prometheusMetrics) throws Throwable {
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
PrometheusMetrics annotation = methodSignature.getMethod().getAnnotation(PrometheusMetrics.class);
|
||||
if (annotation != null) {
|
||||
String name;
|
||||
if (StringUtils.isNotEmpty(annotation.name())) {
|
||||
name = annotation.name();
|
||||
} else {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
|
||||
.getRequest();
|
||||
name = request.getRequestURI();
|
||||
}
|
||||
requestTotal.labelValues(name).inc();
|
||||
Timer requestTimer = histogram.labelValues(name).startTimer();
|
||||
Object object;
|
||||
try {
|
||||
object = joinPoint.proceed();
|
||||
} catch (Exception e) {
|
||||
requestError.labelValues(name).inc();
|
||||
throw e;
|
||||
} finally {
|
||||
requestTimer.observeDuration();
|
||||
}
|
||||
return object;
|
||||
} else {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.aspect;
|
||||
|
||||
import cn.lingniu.framework.plugin.prometheus.PrometheusSummary;
|
||||
import cn.lingniu.framework.plugin.util.validation.ObjectEmptyUtils;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: Summary实现类
|
||||
**/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class PrometheusSummaryAspect extends BasePrometheusAspect {
|
||||
|
||||
@Pointcut("@annotation(cn.lingniu.framework.plugin.prometheus.PrometheusSummary)")
|
||||
public void prometheusSummaryAop() {
|
||||
}
|
||||
|
||||
|
||||
@Around("prometheusSummaryAop() && @annotation(prometheusSummary)")
|
||||
public Object prometheusSummaryAspect(ProceedingJoinPoint point, PrometheusSummary prometheusSummary) throws Throwable {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method signatureMethod = signature.getMethod();
|
||||
Object val = null;
|
||||
long startTime = System.currentTimeMillis();
|
||||
String summaryName = ObjectEmptyUtils.isEmpty(prometheusSummary.name()) ? signatureMethod.getName() : prometheusSummary.name();
|
||||
boolean success = true;
|
||||
try {
|
||||
val = point.proceed();
|
||||
} catch (Exception ex) {
|
||||
success = false;
|
||||
throw ex;
|
||||
} finally {
|
||||
DistributionSummary.Builder builder = DistributionSummary.builder(summaryName)
|
||||
.tag("response", success ? "SUCCESS" : "FAILED")
|
||||
.tags(prometheusSummary.labels())
|
||||
.description(prometheusSummary.memo());
|
||||
addExtraTags(builder, point, val);
|
||||
builder.register(registry).record(System.currentTimeMillis() - startTime);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.config;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ConfigurationProperties(PrometheusConfig.PRE_FIX)
|
||||
public class PrometheusConfig {
|
||||
|
||||
public static final String PRE_FIX = "framework.lingniu.prometheus";
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* 端点暴露端口,对外应用接口必须指定
|
||||
*/
|
||||
private Integer port = 30290;
|
||||
/**
|
||||
* 是否特殊节点:一般当同机器部署多应用时启用,true时才允许启用自定义管理端点端口
|
||||
*/
|
||||
private Boolean allowAssignPort = false;
|
||||
/**
|
||||
* 端点暴露
|
||||
*/
|
||||
private String exposures = "env, health, info, metrics, prometheus, threaddump";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.init;
|
||||
|
||||
|
||||
import cn.lingniu.framework.plugin.prometheus.aspect.DistributionSummaryMeterTagAnnotationHandler;
|
||||
import cn.lingniu.framework.plugin.prometheus.aspect.PrometheusCounterAspect;
|
||||
import cn.lingniu.framework.plugin.prometheus.aspect.PrometheusMetricsAspect;
|
||||
import cn.lingniu.framework.plugin.prometheus.aspect.PrometheusSummaryAspect;
|
||||
import cn.lingniu.framework.plugin.prometheus.config.PrometheusConfig;
|
||||
import cn.lingniu.framework.plugin.util.config.PropertyUtils;
|
||||
import io.micrometer.common.annotation.AnnotationHandler;
|
||||
import io.micrometer.common.annotation.ValueExpressionResolver;
|
||||
import io.micrometer.common.annotation.ValueResolver;
|
||||
import io.micrometer.core.aop.CountedMeterTagAnnotationHandler;
|
||||
import io.micrometer.core.aop.MeterTagAnnotationHandler;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
@Configuration
|
||||
@Import({PrometheusCounterAspect.class, PrometheusMetricsAspect.class, PrometheusSummaryAspect.class})
|
||||
@EnableConfigurationProperties({PrometheusConfig.class})
|
||||
@Slf4j
|
||||
public class PrometheusConfiguration implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
PrometheusConfig prometheusConfig;
|
||||
@Value("${spring.application.name: 填写项目名称}")
|
||||
private String applicationName;
|
||||
|
||||
@Bean
|
||||
MeterRegistryCustomizer<MeterRegistry> appMetricsCommonTags() {
|
||||
return registry -> registry.config().commonTags("application", applicationName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
if (log.isInfoEnabled()) {
|
||||
try {
|
||||
String port = (String) PropertyUtils.getProperty("management.server.port");
|
||||
// 验证端口号格式
|
||||
if (port != null && !port.trim().isEmpty()) {
|
||||
try {
|
||||
int portNum = Integer.parseInt(port.trim());
|
||||
if (portNum < 1 || portNum > 65535) {
|
||||
log.warn("Invalid management server port configuration: {}", port);
|
||||
port = "unknown";
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("Management server port is not a valid number: {}", port);
|
||||
port = "invalid";
|
||||
}
|
||||
} else {
|
||||
port = "not configured";
|
||||
}
|
||||
log.info("\r\n\t\t框架已开启Prometheus监控,信息收集端口:{},请至Grafana查询服务监控信息 ! ", port);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to get management server port, error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Function<Class<? extends ValueResolver>, ? extends ValueResolver> resolverProvider() {
|
||||
return aClass -> Object::toString;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
Function<Class<? extends ValueExpressionResolver>, ? extends ValueExpressionResolver> expressionResolverProvider() {
|
||||
return aClass -> new ValueExpressionResolver() {
|
||||
@Override
|
||||
public String resolve(String expression, Object parameter) {
|
||||
try {
|
||||
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||||
ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
Expression expressionToEvaluate = expressionParser.parseExpression(expression);
|
||||
return expressionToEvaluate.getValue(context, parameter, String.class);
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to evaluate SpEL expression {}", expression, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
Map<Class, AnnotationHandler> annotationHandlerMap(Function<Class<? extends ValueResolver>, ? extends ValueResolver> resolverProvider,
|
||||
Function<Class<? extends ValueExpressionResolver>, ? extends ValueExpressionResolver> expressionResolverProvider) {
|
||||
Map<Class, AnnotationHandler> map = new HashMap<>(8);
|
||||
map.put(Counter.Builder.class, new CountedMeterTagAnnotationHandler(resolverProvider, expressionResolverProvider));
|
||||
map.put(DistributionSummary.Builder.class, new DistributionSummaryMeterTagAnnotationHandler(resolverProvider, expressionResolverProvider));
|
||||
map.put(Timer.Builder.class, new MeterTagAnnotationHandler(resolverProvider, expressionResolverProvider));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package cn.lingniu.framework.plugin.prometheus.init;
|
||||
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.lingniu.framework.plugin.core.config.CommonConstant;
|
||||
import cn.lingniu.framework.plugin.util.string.StringUtil;
|
||||
import cn.lingniu.framework.plugin.util.config.PropertyUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Order(Integer.MIN_VALUE + 400)
|
||||
public class PrometheusInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
//server port
|
||||
public static final String SERVER_PORT_PROPERTY = "server.port";
|
||||
//默认管理端点端口
|
||||
public static final Integer DEFAULT_ACTUATOR_PORT = 30290;
|
||||
private static final String DEFAULT_ENDPOINT = "prometheus,feign,metrics";
|
||||
private static boolean initialized = false;
|
||||
private String applicationName;
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
if (applicationContext == null) {
|
||||
throw new IllegalArgumentException("Application context cannot be null");
|
||||
}
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
if (environment == null) {
|
||||
throw new IllegalStateException("Environment cannot be null");
|
||||
}
|
||||
applicationName = environment.getProperty(CommonConstant.SPRING_APP_NAME_KEY);
|
||||
if (applicationName == null || applicationName.trim().isEmpty()) {
|
||||
throw new IllegalStateException("Application name property is required");
|
||||
}
|
||||
String profile = environment.getProperty(CommonConstant.ACTIVE_PROFILES_PROPERTY);
|
||||
// profile can be null, which is acceptable
|
||||
this.initializeSystemProperty(environment, applicationContext, applicationName, profile);
|
||||
}
|
||||
|
||||
void initializeSystemProperty(ConfigurableEnvironment environment, ConfigurableApplicationContext applicationContext, String appName, String profile) {
|
||||
// 使用volatile确保多线程环境下的可见性
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
// 检查prometheus是否启用
|
||||
String prometheusEnabled = environment.getProperty("framework.lingniu.prometheus.enabled", "true");
|
||||
if (Boolean.FALSE.toString().equalsIgnoreCase(prometheusEnabled)) {
|
||||
return;
|
||||
}
|
||||
Integer serverPort = environment.getProperty(SERVER_PORT_PROPERTY, Integer.class, 3001);
|
||||
Integer configPort = determineConfigPort(environment, serverPort);
|
||||
// 确保配置端口不与服务器端口冲突
|
||||
if (configPort.equals(serverPort)) {
|
||||
configPort = getAvailableRandomPort(environment, serverPort);
|
||||
}
|
||||
setInitialized(true);
|
||||
setManagementProperties(environment, configPort);
|
||||
}
|
||||
|
||||
private Integer determineConfigPort(ConfigurableEnvironment environment, Integer serverPort) {
|
||||
Integer defaultPort = DEFAULT_ACTUATOR_PORT;
|
||||
Boolean allowAssignPort = environment.acceptsProfiles(Profiles.of("sit", "dev", "uat")) ||
|
||||
environment.getProperty("framework.lingniu.prometheus.allow-assign-port", Boolean.class, false);
|
||||
if (allowAssignPort) {
|
||||
return environment.getProperty("framework.lingniu.prometheus.port", Integer.class, defaultPort);
|
||||
}
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
private Integer getAvailableRandomPort(ConfigurableEnvironment environment, Integer serverPort) {
|
||||
Integer randomPort;
|
||||
int attempts = 0;
|
||||
int maxAttempts = 10; // 防止无限循环
|
||||
do {
|
||||
randomPort = RandomUtil.randomInt(2000, 5000);
|
||||
attempts++;
|
||||
if (attempts >= maxAttempts) {
|
||||
throw new RuntimeException("Failed to find available port after " + maxAttempts + " attempts");
|
||||
}
|
||||
} while (randomPort.equals(serverPort));
|
||||
|
||||
return randomPort;
|
||||
}
|
||||
|
||||
private void setManagementProperties(ConfigurableEnvironment environment, Integer configPort) {
|
||||
PropertyUtils.setDefaultInitProperty("management.server.port", configPort.toString());
|
||||
PropertyUtils.setDefaultInitProperty("management.endpoint.health.show-details", "always");
|
||||
String resultIncludes = buildEndpointIncludes(environment);
|
||||
PropertyUtils.setDefaultInitProperty("management.endpoints.web.exposure.include", resultIncludes);
|
||||
}
|
||||
|
||||
private String buildEndpointIncludes(ConfigurableEnvironment environment) {
|
||||
String resultIncludes = DEFAULT_ENDPOINT;
|
||||
String configIncludes = environment.getProperty("framework.lingniu.prometheus.exposures");
|
||||
if (!StringUtil.isEmpty(configIncludes)) {
|
||||
resultIncludes = resultIncludes + "," + configIncludes;
|
||||
}
|
||||
return resultIncludes;
|
||||
}
|
||||
|
||||
|
||||
private boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
private void setInitialized(boolean value) {
|
||||
initialized = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
cn.lingniu.framework.plugin.prometheus.init.PrometheusInit
|
||||
@@ -0,0 +1 @@
|
||||
cn.lingniu.framework.plugin.prometheus.init.PrometheusConfiguration
|
||||
@@ -0,0 +1,34 @@
|
||||
# 【重要】prometheus graf...更多使用请参考官方资料
|
||||
|
||||
## 概述 (Overview)
|
||||
|
||||
1. 定位:集成 prometheus监控框架的应用级监控组件,性能指标统计及异常监控能
|
||||
2. 核心能力
|
||||
* 支持自定义业务埋点,记录关键业务流程的性能与异常信息
|
||||
* jvm指标数据
|
||||
* 与grafana联动,实现监控数据可视化与告警
|
||||
3. 适用场景
|
||||
* 用接口性能监控(响应时间、成功率)
|
||||
* 业务流程异常追踪与问题定位
|
||||
* 系统整体运行状态监控
|
||||
* 业务指标大屏告警
|
||||
|
||||
## 如何配置--参考:PrometheusConfig
|
||||
|
||||
```yaml
|
||||
framework:
|
||||
lingniu:
|
||||
prometheus:
|
||||
enabled: true
|
||||
port: 30290
|
||||
allowAssignPort: false
|
||||
```
|
||||
|
||||
## 如何使用
|
||||
|
||||
参考三个注解、或使用原生方法使用
|
||||
- PrometheusCounter
|
||||
- PrometheusMetrics
|
||||
- PrometheusSummary
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.lingniu.framework</groupId>
|
||||
<artifactId>lingniu-framework-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../lingniu-framework-dependencies/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>lingniu-framework-plugin-skywalking</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<properties>
|
||||
<skywalking.version>9.5.0</skywalking.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>apm-toolkit-trace</artifactId>
|
||||
<version>${skywalking.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>apm-toolkit-opentracing</artifactId>
|
||||
<version>${skywalking.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,4 @@
|
||||
# skywalking agent对接可参考官方文档
|
||||
# skywalking 服务度搭建对接可参考官方文档
|
||||
|
||||
# https://skywalking.apache.org/docs/skywalking-java/v9.2.0/en/setup/service-agent/java-agent/readme/
|
||||
Reference in New Issue
Block a user