Merge branch '3.2' into 3.3

# Conflicts:
#	dubbo-dependencies-bom/pom.xml
This commit is contained in:
crazyhzm 2023-09-20 15:32:19 +08:00
commit 0f61286a78
40 changed files with 408 additions and 194 deletions

View File

@ -21,10 +21,10 @@ import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.filter.DemoService;
import org.apache.dubbo.rpc.RpcException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -56,6 +56,7 @@ class FailSafeClusterInvokerTest {
@BeforeEach
public void setUp() throws Exception {
RpcContext.removeServiceContext();
dic = mock(Directory.class);

View File

@ -24,10 +24,10 @@ import org.apache.dubbo.common.utils.LogUtil;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.log4j.Level;
import org.junit.jupiter.api.AfterEach;
@ -38,7 +38,6 @@ import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.function.Executable;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -47,7 +46,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -72,6 +71,7 @@ class FailbackClusterInvokerTest {
@BeforeEach
public void setUp() throws Exception {
RpcContext.removeServiceContext();
dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url);

View File

@ -145,6 +145,10 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
if (!guard.tryAcquire()) {
return;
}
// To avoid multiple dump, check again
if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) {
return;
}
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(() -> {
@ -169,9 +173,9 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
} catch (Exception t) {
logger.error(COMMON_UNEXPECTED_CREATE_DUMP, "", "", "dump jStack error", t);
} finally {
lastPrintTime = System.currentTimeMillis();
guard.release();
}
lastPrintTime = System.currentTimeMillis();
});
//must shutdown thread pool ,if not will lead to OOM
pool.shutdown();

View File

@ -109,6 +109,12 @@ public class MetricsConfig extends AbstractConfig {
private Boolean enableRpc;
/**
* The level of the metrics, the value can be "SERVICE", "METHOD", default is method.
*/
private String rpcLevel;
public MetricsConfig() {
}
@ -139,6 +145,14 @@ public class MetricsConfig extends AbstractConfig {
return enableJvm;
}
public String getRpcLevel() {
return rpcLevel;
}
public void setRpcLevel(String rpcLevel) {
this.rpcLevel = rpcLevel;
}
public void setEnableJvm(Boolean enableJvm) {
this.enableJvm = enableJvm;
}

View File

@ -40,6 +40,7 @@ import org.apache.dubbo.config.utils.ConfigValidationUtils;
import org.apache.dubbo.metadata.ServiceNameMapping;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.MetricsInitEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.registry.client.metadata.MetadataUtils;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
@ -560,11 +561,12 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
}
private void initServiceMethodMetrics(URL url) {
String [] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i->i.split(",")).orElse( new String[]{});
Arrays.stream(methods).forEach( method-> {
RpcInvocation invocation = new RpcInvocation(url.getServiceKey(),url.getServiceModel(),method,interfaceName, url.getProtocolServiceKey(), null, null,null,null,null,null);
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(),invocation));
});
String[] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i -> i.split(",")).orElse(new String[]{});
boolean serviceLevel = MethodMetric.isServiceLevel(application.getApplicationModel());
Arrays.stream(methods).forEach(method -> {
RpcInvocation invocation = new RpcInvocation(url.getServiceKey(), url.getServiceModel(), method, interfaceName, url.getProtocolServiceKey(), null, null, null, null, null, null);
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(), invocation, serviceLevel));
});
}
private void processServiceExecutor(URL url) {

View File

@ -1120,6 +1120,11 @@
<xsd:documentation><![CDATA[ Enable record rpc metrics. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="rpc-level" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ Is the metric for rpc requests at the METHOD level or SERVICE level ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="tracingType">

View File

@ -224,7 +224,7 @@
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.25</version>
<version>0.9.27</version>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>

View File

@ -222,7 +222,7 @@
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.25</version>
<version>0.9.27</version>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>

View File

@ -38,7 +38,7 @@
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot.version>2.7.15</spring-boot.version>
<spring-boot-maven-plugin.version>2.7.15</spring-boot-maven-plugin.version>
<micrometer-core.version>1.11.3</micrometer-core.version>
<micrometer-core.version>1.11.4</micrometer-core.version>
</properties>
<dependencyManagement>
<dependencies>

View File

@ -94,7 +94,7 @@
<spring_version>5.3.25</spring_version>
<spring_security_version>5.8.6</spring_security_version>
<javassist_version>3.29.2-GA</javassist_version>
<bytebuddy.version>1.14.7</bytebuddy.version>
<bytebuddy.version>1.14.8</bytebuddy.version>
<netty_version>3.2.10.Final</netty_version>
<netty4_version>4.1.97.Final</netty4_version>
<mina_version>2.2.1</mina_version>
@ -114,7 +114,7 @@
<cxf_version>3.5.5</cxf_version>
<thrift_version>0.19.0</thrift_version>
<hessian_version>4.0.66</hessian_version>
<protobuf-java_version>3.24.2</protobuf-java_version>
<protobuf-java_version>3.24.3</protobuf-java_version>
<javax_annotation-api_version>1.3.2</javax_annotation-api_version>
<servlet_version>3.1.0</servlet_version>
<jetty_version>9.4.52.v20230823</jetty_version>
@ -133,14 +133,14 @@
<commons_lang3_version>3.12.0</commons_lang3_version>
<protostuff_version>1.8.0</protostuff_version>
<envoy_api_version>0.1.35</envoy_api_version>
<micrometer.version>1.11.3</micrometer.version>
<micrometer.version>1.11.4</micrometer.version>
<opentelemetry.version>1.26.0</opentelemetry.version>
<zipkin-reporter.version>2.16.4</zipkin-reporter.version>
<micrometer-tracing.version>1.1.4</micrometer-tracing.version>
<micrometer-tracing.version>1.1.5</micrometer-tracing.version>
<t_digest.version>3.3</t_digest.version>
<prometheus_client.version>0.16.0</prometheus_client.version>
<reactive.version>1.0.4</reactive.version>
<reactor.version>3.5.9</reactor.version>
<reactor.version>3.5.10</reactor.version>
<rxjava.version>2.2.21</rxjava.version>
<okhttp_version>3.14.9</okhttp_version>
@ -152,7 +152,7 @@
<nacos_version>2.2.4</nacos_version>
<sentinel.version>1.8.6</sentinel.version>
<seata.version>1.6.1</seata.version>
<grpc.version>1.57.2</grpc.version>
<grpc.version>1.58.0</grpc.version>
<grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>
<jprotoc_version>1.2.2</jprotoc_version>
<!-- Log libs -->

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.validation.filter;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.rpc.AsyncRpcResult;
@ -82,8 +83,7 @@ public class ValidationFilter implements Filter {
*/
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (validation != null && !invocation.getMethodName().startsWith("$")
&& ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) {
if (needValidate(invoker.getUrl(), invocation.getMethodName())) {
try {
Validator validator = validation.getValidator(invoker.getUrl());
if (validator != null) {
@ -98,4 +98,8 @@ public class ValidationFilter implements Filter {
return invoker.invoke(invocation);
}
private boolean needValidate(URL url, String methodName) {
return validation != null && !methodName.startsWith("$") && ConfigUtils.isNotEmpty(url.getMethodParameter(methodName, VALIDATION_KEY));
}
}

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.validation.MethodValidated;
import org.apache.dubbo.validation.Validator;
@ -57,6 +58,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -89,7 +91,7 @@ public class JValidator implements Validator {
this.clazz = ReflectUtils.forName(url.getServiceInterface());
String jvalidation = url.getParameter("jvalidation");
ValidatorFactory factory;
if (jvalidation != null && jvalidation.length() > 0) {
if (StringUtils.isNotEmpty(jvalidation)) {
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
} else {
factory = Validation.buildDefaultValidatorFactory();
@ -111,8 +113,9 @@ public class JValidator implements Validator {
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
}
Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();
for (int i = 0; i < args.length; i++) {
Field field = parameterClass.getField(method.getName() + "Argument" + i);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Field field = parameterClass.getField(parameters[i].getName());
field.set(parameterBean, args[i]);
}
return parameterBean;
@ -129,10 +132,9 @@ public class JValidator implements Validator {
* @param method invoke method
* @param parameterClassName generated parameterClassName
* @return Class<?> generated methodParameterClass
* @throws Exception
*/
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
throws Exception {
throws Exception {
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
synchronized (parameterClassName.intern()) {
CtClass ctClass = null;
@ -144,28 +146,26 @@ public class JValidator implements Validator {
if (null == ctClass) {
ctClass = pool.makeClass(parameterClassName);
ClassFile classFile = ctClass.getClassFile();
classFile.setVersionToJava5();
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
// parameter fields
Class<?>[] parameterTypes = method.getParameterTypes();
Parameter[] parameters = method.getParameters();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> type = parameterTypes[i];
for (int i = 0; i < parameters.length; i++) {
Annotation[] annotations = parameterAnnotations[i];
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
Method[] members = annotation.annotationType().getMethods();
for (Method member : members) {
if (Modifier.isPublic(member.getModifiers())
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
Object value = member.invoke(annotation);
if (null != value) {
MemberValue memberValue = createMemberValue(
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
ja.addMemberValue(member.getName(), memberValue);
}
}
@ -173,12 +173,14 @@ public class JValidator implements Validator {
attribute.addAnnotation(ja);
}
}
String fieldName = method.getName() + "Argument" + i;
Parameter parameter = parameters[i];
Class<?> type = parameter.getType();
String fieldName = parameter.getName();
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
ctField.getFieldInfo().addAttribute(attribute);
ctClass.addField(ctField);
}
return ctClass.toClass(clazz.getClassLoader(), null);
return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());
} else {
return Class.forName(parameterClassName, true, clazz.getClassLoader());
}
@ -187,13 +189,16 @@ public class JValidator implements Validator {
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
StringBuilder builder = new StringBuilder().append(clazz.getName())
.append('_')
.append(toUpperMethoName(method.getName()))
.append("Parameter");
.append('_')
.append(toUpperMethodName(method.getName()))
.append("Parameter");
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
builder.append('_').append(parameterType.getName());
// In order to ensure that the parameter class can be generated correctly,
// replace "." with "_" to make the package name of the generated parameter class
// consistent with the package name of the actual parameter class.
builder.append('_').append(parameterType.getName().replace(".", "_"));
}
return builder.toString();
@ -201,19 +206,17 @@ public class JValidator implements Validator {
private static boolean hasConstraintParameter(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations != null && parameterAnnotations.length > 0) {
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
}
}
return false;
}
private static String toUpperMethoName(String methodName) {
private static String toUpperMethodName(String methodName) {
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
}
@ -263,7 +266,7 @@ public class JValidator implements Validator {
if (methodClass != null) {
groups.add(methodClass);
}
Set<ConstraintViolation<?>> violations = new HashSet<>();
Method method = clazz.getMethod(methodName, parameterTypes);
Class<?>[] methodClasses;
if (method.isAnnotationPresent(MethodValidated.class)) {
@ -275,15 +278,16 @@ public class JValidator implements Validator {
groups.add(1, clazz);
// convert list to array
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
Class<?>[] classGroups = groups.toArray(new Class[0]);
Set<ConstraintViolation<?>> violations = new HashSet<>();
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
if (parameterBean != null) {
violations.addAll(validator.validate(parameterBean, classgroups));
violations.addAll(validator.validate(parameterBean, classGroups));
}
for (Object arg : arguments) {
validate(violations, arg, classgroups);
validate(violations, arg, classGroups);
}
if (!violations.isEmpty()) {
@ -294,7 +298,7 @@ public class JValidator implements Validator {
private Class<?> methodClass(String methodName) {
Class<?> methodClass = null;
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName);
Class<?> cached = methodClassMap.get(methodClassName);
if (cached != null) {
return cached == clazz ? null : cached;

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.validation.MethodValidated;
import org.apache.dubbo.validation.Validator;
@ -57,6 +58,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -89,7 +91,7 @@ public class JValidatorNew implements Validator {
this.clazz = ReflectUtils.forName(url.getServiceInterface());
String jvalidation = url.getParameter("jvalidationNew");
ValidatorFactory factory;
if (jvalidation != null && jvalidation.length() > 0) {
if (StringUtils.isNotEmpty(jvalidation)) {
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
} else {
factory = Validation.buildDefaultValidatorFactory();
@ -111,8 +113,9 @@ public class JValidatorNew implements Validator {
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
}
Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();
for (int i = 0; i < args.length; i++) {
Field field = parameterClass.getField(method.getName() + "Argument" + i);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Field field = parameterClass.getField(parameters[i].getName());
field.set(parameterBean, args[i]);
}
return parameterBean;
@ -129,10 +132,9 @@ public class JValidatorNew implements Validator {
* @param method invoke method
* @param parameterClassName generated parameterClassName
* @return Class<?> generated methodParameterClass
* @throws Exception
*/
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
throws Exception {
throws Exception {
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
synchronized (parameterClassName.intern()) {
CtClass ctClass = null;
@ -144,28 +146,26 @@ public class JValidatorNew implements Validator {
if (null == ctClass) {
ctClass = pool.makeClass(parameterClassName);
ClassFile classFile = ctClass.getClassFile();
classFile.setVersionToJava5();
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
// parameter fields
Class<?>[] parameterTypes = method.getParameterTypes();
Parameter[] parameters = method.getParameters();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> type = parameterTypes[i];
for (int i = 0; i < parameters.length; i++) {
Annotation[] annotations = parameterAnnotations[i];
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
Method[] members = annotation.annotationType().getMethods();
for (Method member : members) {
if (Modifier.isPublic(member.getModifiers())
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
Object value = member.invoke(annotation);
if (null != value) {
MemberValue memberValue = createMemberValue(
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
ja.addMemberValue(member.getName(), memberValue);
}
}
@ -173,12 +173,14 @@ public class JValidatorNew implements Validator {
attribute.addAnnotation(ja);
}
}
String fieldName = method.getName() + "Argument" + i;
Parameter parameter = parameters[i];
Class<?> type = parameter.getType();
String fieldName = parameter.getName();
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
ctField.getFieldInfo().addAttribute(attribute);
ctClass.addField(ctField);
}
return ctClass.toClass(clazz.getClassLoader(), null);
return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());
} else {
return Class.forName(parameterClassName, true, clazz.getClassLoader());
}
@ -187,13 +189,16 @@ public class JValidatorNew implements Validator {
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
StringBuilder builder = new StringBuilder().append(clazz.getName())
.append('_')
.append(toUpperMethoName(method.getName()))
.append("Parameter");
.append('_')
.append(toUpperMethodName(method.getName()))
.append("Parameter");
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
builder.append('_').append(parameterType.getName());
// In order to ensure that the parameter class can be generated correctly,
// replace "." with "_" to make the package name of the generated parameter class
// consistent with the package name of the actual parameter class.
builder.append('_').append(parameterType.getName().replace(".", "_"));
}
return builder.toString();
@ -201,19 +206,17 @@ public class JValidatorNew implements Validator {
private static boolean hasConstraintParameter(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations.length > 0) {
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
}
}
return false;
}
private static String toUpperMethoName(String methodName) {
private static String toUpperMethodName(String methodName) {
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
}
@ -263,7 +266,7 @@ public class JValidatorNew implements Validator {
if (methodClass != null) {
groups.add(methodClass);
}
Set<ConstraintViolation<?>> violations = new HashSet<>();
Method method = clazz.getMethod(methodName, parameterTypes);
Class<?>[] methodClasses;
if (method.isAnnotationPresent(MethodValidated.class)) {
@ -275,15 +278,16 @@ public class JValidatorNew implements Validator {
groups.add(1, clazz);
// convert list to array
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
Class<?>[] classGroups = groups.toArray(new Class[0]);
Set<ConstraintViolation<?>> violations = new HashSet<>();
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
if (parameterBean != null) {
violations.addAll(validator.validate(parameterBean, classgroups));
violations.addAll(validator.validate(parameterBean, classGroups));
}
for (Object arg : arguments) {
validate(violations, arg, classgroups);
validate(violations, arg, classGroups);
}
if (!violations.isEmpty()) {
@ -294,7 +298,7 @@ public class JValidatorNew implements Validator {
private Class<?> methodClass(String methodName) {
Class<?> methodClass = null;
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName);
Class<?> cached = methodClassMap.get(methodClassName);
if (cached != null) {
return cached == clazz ? null : cached;

View File

@ -17,17 +17,24 @@
package org.apache.dubbo.validation.support.jvalidation;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget;
import org.apache.dubbo.validation.support.jvalidation.mock.ValidationParameter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
class JValidatorTest {
@Test
void testItWithNonExistMethod() {
@ -72,7 +79,7 @@ class JValidatorTest {
void testItWithCollectionArg() throws Exception {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod4", new Class<?>[]{List.class}, new Object[]{Arrays.asList("parameter")});
jValidator.validate("someMethod4", new Class<?>[]{List.class}, new Object[]{Collections.singletonList("parameter")});
}
@Test
@ -83,4 +90,83 @@ class JValidatorTest {
map.put("key", "value");
jValidator.validate("someMethod5", new Class<?>[]{Map.class}, new Object[]{map});
}
}
@Test
void testItWithPrimitiveArg() {
Assertions.assertThrows(ValidationException.class, () -> {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, null, null});
});
}
@Test
void testItWithPrimitiveArgWithProvidedMessage() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null});
Assertions.fail();
} catch (Exception e) {
assertThat(e.getMessage(), containsString("string must not be blank"));
assertThat(e.getMessage(), containsString("longValue must not be null"));
}
}
@Test
void testItWithPartialParameterValidation() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(2));
}
}
@Test
void testItWithNestedParameterValidationWithNullParam() {
Assertions.assertThrows(ValidationException.class, () -> {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{null});
});
}
@Test
void testItWithNestedParameterValidationWithNullNestedParam() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(1));
assertThat(e1.getMessage(), containsString("body must not be null"));
}
}
@Test
void testItWithNestedParameterValidationWithNullNestedParams() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();
param.setBody(new JValidatorTestTarget.Param());
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(1));
assertThat(e1.getMessage(), containsString("name must not be null"));
}
}
}

View File

@ -18,6 +18,9 @@ package org.apache.dubbo.validation.support.jvalidation.mock;
import org.apache.dubbo.validation.MethodValidated;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@ -35,7 +38,42 @@ public interface JValidatorTestTarget {
void someMethod5(Map<String, String> map);
void someMethod6(Integer intValue,
@NotBlank(message = "string must not be blank") String string,
@NotNull(message = "longValue must not be null") Long longValue);
void someMethod7(@NotNull BaseParam<Param> baseParam);
@interface Test2 {
}
class BaseParam<T> {
@Valid
@NotNull(message = "body must not be null")
private T body;
public T getBody() {
return body;
}
public void setBody(T body) {
this.body = body;
}
}
class Param {
@NotNull(message = "name must not be null")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -28,7 +28,7 @@ public class TimeWindowCounter {
private final LongAdderSlidingWindow slidingWindow;
public TimeWindowCounter(int bucketNum, int timeWindowSeconds) {
public TimeWindowCounter(int bucketNum, long timeWindowSeconds) {
this.slidingWindow = new LongAdderSlidingWindow(bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds));
}

View File

@ -41,9 +41,11 @@ import java.util.concurrent.atomic.AtomicLong;
* the key will not be displayed when exporting (to be optimized)
*/
public class MethodStatComposite extends AbstractMetricsExport {
private boolean serviceLevel;
public MethodStatComposite(ApplicationModel applicationModel) {
super(applicationModel);
this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
}
private final Map<MetricsKeyWrapper, Map<MethodMetric, AtomicLong>> methodNumStats = new ConcurrentHashMap<>();
@ -59,7 +61,8 @@ public class MethodStatComposite extends AbstractMetricsExport {
if (!methodNumStats.containsKey(wrapper)) {
return;
}
methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation), k -> new AtomicLong(0L));
methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation, serviceLevel), k -> new AtomicLong(0L));
}
public void incrementMethodKey(MetricsKeyWrapper wrapper, MethodMetric methodMetric, int size) {

View File

@ -50,9 +50,11 @@ import java.util.stream.Collectors;
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class RtStatComposite extends AbstractMetricsExport {
private boolean serviceLevel;
public RtStatComposite(ApplicationModel applicationModel) {
super(applicationModel);
this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
}
private final Map<String, List<LongContainer<? extends Number>>> rtStats = new ConcurrentHashMap<>();
@ -168,7 +170,7 @@ public class RtStatComposite extends AbstractMetricsExport {
List<Action> actions;
actions = new LinkedList<>();
for (LongContainer container : rtStats.get(registryOpType)) {
MethodMetric key = new MethodMetric(getApplicationModel(), invocation);
MethodMetric key = new MethodMetric(getApplicationModel(), invocation, serviceLevel);
Number current = (Number) container.get(key);
if (current == null) {
container.putIfAbsent(key, container.getInitFunc().apply(key));

View File

@ -1,36 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.metrics.event;
import org.apache.dubbo.rpc.model.ApplicationModel;
/**
* EmptyEvent, do nothing.
*/
public class EmptyEvent extends MetricsEvent {
private static final EmptyEvent empty = new EmptyEvent(null);
private EmptyEvent(ApplicationModel source) {
super(source, null);
}
public static EmptyEvent instance() {
return empty;
}
}

View File

@ -34,8 +34,8 @@ public class MetricsInitEvent extends TimeCounterEvent {
super(source,typeWrapper);
}
public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
MetricsInitEvent initEvent = new MetricsInitEvent(applicationModel, METRIC_EVENT);
initEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
initEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);

View File

@ -40,10 +40,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public void publishEvent(MetricsEvent event) {
if (event instanceof EmptyEvent) {
return;
}
if (validateIfApplicationConfigExist(event)) return;
for (MetricsListener listener : listeners) {
if (listener.isSupport(event)) {
@ -75,9 +71,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {
@SuppressWarnings({"rawtypes"})
private void publishTimeEvent(MetricsEvent event, Consumer<MetricsLifeListener> consumer) {
if (validateIfApplicationConfigExist(event)) return;
if (event instanceof EmptyEvent) {
return;
}
if (event instanceof TimeCounterEvent) {
((TimeCounterEvent) event).getTimePair().end();
}

View File

@ -17,12 +17,17 @@
package org.apache.dubbo.metrics.model;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
@ -36,12 +41,31 @@ public class MethodMetric extends ServiceKeyMetric {
private String group;
private String version;
public MethodMetric(ApplicationModel applicationModel, Invocation invocation) {
public MethodMetric(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
super(applicationModel, MetricsSupport.getInterfaceName(invocation));
this.methodName = RpcUtils.getMethodName(invocation);
this.side = MetricsSupport.getSide(invocation);
this.group = MetricsSupport.getGroup(invocation);
this.version = MetricsSupport.getVersion(invocation);
this.methodName = serviceLevel ? null : RpcUtils.getMethodName(invocation);
}
public static boolean isServiceLevel(ApplicationModel applicationModel) {
if(applicationModel == null){
return false;
}
ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager();
if (applicationConfigManager == null) {
return false;
}
Optional<MetricsConfig> metrics = applicationConfigManager.getMetrics();
if (!metrics.isPresent()) {
return false;
}
String rpcLevel = metrics.map(MetricsConfig::getRpcLevel).orElse(MetricsLevel.METHOD.name());
rpcLevel = StringUtils.isBlank(rpcLevel) ? MetricsLevel.METHOD.name() : rpcLevel;
return MetricsLevel.SERVICE.name().equalsIgnoreCase(rpcLevel);
}
public String getGroup() {
@ -82,13 +106,13 @@ public class MethodMetric extends ServiceKeyMetric {
@Override
public String toString() {
return "MethodMetric{" +
"applicationName='" + getApplicationName() + '\'' +
", side='" + side + '\'' +
", interfaceName='" + getServiceKey() + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
"applicationName='" + getApplicationName() + '\'' +
", side='" + side + '\'' +
", interfaceName='" + getServiceKey() + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
}
@Override
@ -100,6 +124,7 @@ public class MethodMetric extends ServiceKeyMetric {
}
private volatile int hashCode = 0;
@Override
public int hashCode() {
if (hashCode == 0) {

View File

@ -58,16 +58,6 @@ public class SimpleMetricsEventMulticasterTest {
}
@Test
void testPublishEvent() {
// emptyEvent do nothing
MetricsEvent emptyEvent = EmptyEvent.instance();
eventMulticaster.publishEvent(emptyEvent);
Assertions.assertSame(obj, objects[0]);
}
@Test
void testPublishFinishEvent() {

View File

@ -43,6 +43,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
@ -56,7 +57,7 @@ import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
* Aggregation metrics collector implementation of {@link MetricsCollector}.
* This collector only enabled when metrics aggregation config is enabled.
*/
public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>{
public class AggregateMetricsCollector implements MetricsCollector<RequestEvent> {
private int bucketNum = DEFAULT_BUCKET_NUM;
private int timeWindowSeconds = DEFAULT_TIME_WINDOW_SECONDS;
private int qpsTimeWindowMillSeconds = DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS;
@ -76,6 +77,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
private final ConcurrentMap<MethodMetric, TimeWindowAggregator> rtAgr = new ConcurrentHashMap<>();
private boolean serviceLevel;
public AggregateMetricsCollector(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
@ -96,6 +98,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
this.enableRt = Optional.ofNullable(aggregation.getEnableRt()).orElse(true);
this.enableRequest = Optional.ofNullable(aggregation.getEnableRequest()).orElse(true);
}
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
}
@ -125,7 +128,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
if (enableQps) {
MethodMetric metric = calcWindowCounter(event, MetricsKey.METRIC_REQUESTS);
TimeWindowCounter qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(qps, metric,
methodMetric -> new TimeWindowCounter(bucketNum, qpsTimeWindowMillSeconds));
methodMetric -> new TimeWindowCounter(bucketNum, TimeUnit.MILLISECONDS.toSeconds(qpsTimeWindowMillSeconds)));
qpsCounter.increment();
}
}
@ -157,7 +160,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
}
private void onRTEvent(RequestEvent event) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
long responseTime = event.getTimePair().calc();
if (enableRt) {
TimeWindowQuantile quantile = ConcurrentHashMapUtils.computeIfAbsent(rt, metric,
@ -176,7 +179,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
private MethodMetric calcWindowCounter(RequestEvent event, MetricsKey targetKey) {
MetricsPlaceValue placeType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE);
MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, placeType);
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
@ -189,7 +192,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
@Override
public List<MetricSample> collect() {
List<MetricSample> list = new ArrayList<>();
if (!isCollectEnabled()){
if (!isCollectEnabled()) {
return list;
}
collectRequests(list);
@ -266,7 +269,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
@Override
public void initMetrics(MetricsEvent event) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
if (enableQps) {
initMethodMetric(event);
initQpsMetric(metric);
@ -279,27 +282,27 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
}
}
public void initMethodMetric(MetricsEvent event){
INIT_AGG_METHOD_KEYS.stream().forEach(key->initWindowCounter(event,key));
public void initMethodMetric(MetricsEvent event) {
INIT_AGG_METHOD_KEYS.stream().forEach(key -> initWindowCounter(event, key));
}
public void initQpsMetric(MethodMetric metric){
public void initQpsMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
}
public void initRtMetric(MethodMetric metric){
public void initRtMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));
}
public void initRtAgrMetric(MethodMetric metric){
public void initRtAgrMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(rtAgr, metric, k -> new TimeWindowAggregator(bucketNum, timeWindowSeconds));
}
public void initWindowCounter(MetricsEvent event, MetricsKey targetKey){
public void initWindowCounter(MetricsEvent event, MetricsKey targetKey) {
MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());

View File

@ -48,6 +48,8 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
private static final Integer[] DEFAULT_BUCKETS_MS = new Integer[]{100, 300, 500, 1000, 3000, 5000, 10000};
private boolean serviceLevel;
public HistogramMetricsCollector(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
@ -68,6 +70,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
}
metricRegister = new HistogramMetricRegister(MetricsGlobalRegistry.getCompositeRegistry(applicationModel), histogram);
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
}
@ -92,7 +95,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
private void onRTEvent(RequestEvent event) {
if (metricRegister != null) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
long responseTime = event.getTimePair().calc();
HistogramMetricSample sample = new HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),

View File

@ -56,8 +56,8 @@ public class RequestEvent extends TimeCounterEvent {
public static RequestEvent toRequestEvent(ApplicationModel applicationModel, String appName,
MetricsDispatcher metricsDispatcher, DefaultMetricsCollector collector,
Invocation invocation, String side) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
Invocation invocation, String side, boolean serviceLevel) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
RequestEvent requestEvent = new RequestEvent(applicationModel, appName, metricsDispatcher, collector, REQUEST_EVENT);
requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
requestEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);
@ -80,13 +80,13 @@ public class RequestEvent extends TimeCounterEvent {
/**
* Acts on MetricsClusterFilter to monitor exceptions that occur before request execution
*/
public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code) {
public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code, boolean serviceLevel) {
RequestEvent event = new RequestEvent(applicationModel, appName, metricsDispatcher, null, REQUEST_ERROR_EVENT);
event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
event.putAttachment(MetricsConstants.INVOCATION_SIDE, side);
event.putAttachment(MetricsConstants.INVOCATION, invocation);
event.putAttachment(MetricsConstants.INVOCATION_REQUEST_ERROR, code);
event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation));
event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation, serviceLevel));
return event;
}

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -45,6 +46,7 @@ public class MetricsFilter implements ScopeModelAware {
private String appName;
private MetricsDispatcher metricsDispatcher;
private DefaultMetricsCollector defaultMetricsCollector;
private boolean serviceLevel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
@ -53,6 +55,7 @@ public class MetricsFilter implements ScopeModelAware {
this.appName = applicationModel.tryGetApplicationName();
this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
this.defaultMetricsCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
@ -63,7 +66,7 @@ public class MetricsFilter implements ScopeModelAware {
if (rpcMetricsEnable) {
try {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, appName, metricsDispatcher,
defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER);
defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER, serviceLevel);
MetricsEventBus.before(requestEvent);
invocation.put(METRIC_FILTER_EVENT, requestEvent);
} catch (Throwable t) {

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -42,6 +43,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
private DefaultMetricsCollector collector;
private String appName;
private MetricsDispatcher metricsDispatcher;
private boolean serviceLevel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
@ -49,6 +51,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
this.appName = applicationModel.tryGetApplicationName();
this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
@Override
@ -73,7 +76,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
if (t instanceof RpcException) {
RpcException e = (RpcException) t;
if (e.isForbidden()) {
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode()));
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode(), serviceLevel));
}
}
}

View File

@ -38,7 +38,6 @@ import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.TimePair;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
@ -90,7 +89,7 @@ class AggregateMetricsCollectorTest {
public MethodMetric getTestMethodMetric() {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
methodMetric.setGroup("TestGroup");
methodMetric.setVersion("1.0.0");
methodMetric.setSide("PROVIDER");
@ -141,8 +140,8 @@ class AggregateMetricsCollectorTest {
@Test
void testListener() {
AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
@ -200,7 +199,8 @@ class AggregateMetricsCollectorTest {
when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector(applicationModel));
DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel);
when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(defaultMetricsCollector);
when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig));
when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);
when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE);
@ -249,7 +249,7 @@ class AggregateMetricsCollectorTest {
rtList.add(30L);
for (Long requestTime: rtList) {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
@ -299,7 +299,7 @@ class AggregateMetricsCollectorTest {
double manualP99 = requestTimes.get((int) Math.round(p99Index));
for (Long requestTime : requestTimes) {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));

View File

@ -27,13 +27,13 @@ import org.apache.dubbo.metrics.TestMetricsInvoker;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.filter.MetricsFilter;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.ServiceKeyMetric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
@ -115,8 +115,8 @@ class DefaultCollectorTest {
@Test
void testListener() {
DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.MetricsInitEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.ServiceKeyMetric;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
@ -96,7 +97,7 @@ class InitServiceMetricsTest {
String protocolServiceKey=serviceKey+":dubbo";
RpcInvocation invocation = new RpcInvocation(serviceKey,null,methodName,interfaceName, protocolServiceKey, null, null,null,null,null,null);
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation));
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation, MethodMetric.isServiceLevel(applicationModel)));
}

View File

@ -19,7 +19,9 @@ package org.apache.dubbo.metrics.metrics.model;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -72,7 +74,7 @@ class MethodMetricTest {
@Test
void test() {
MethodMetric metric = new MethodMetric(applicationModel, invocation);
MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertEquals(metric.getServiceKey(), interfaceName);
Assertions.assertEquals(metric.getMethodName(), methodName);
Assertions.assertEquals(metric.getGroup(), group);
@ -88,4 +90,24 @@ class MethodMetricTest {
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
@Test
void testServiceMetrics() {
MetricsConfig metricConfig = new MetricsConfig();
applicationModel.getApplicationConfigManager().setMetrics(metricConfig);
metricConfig.setRpcLevel(MetricsLevel.SERVICE.name());
MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertEquals(metric.getServiceKey(), interfaceName);
Assertions.assertNull(metric.getMethodName(), methodName);
Assertions.assertEquals(metric.getGroup(), group);
Assertions.assertEquals(metric.getVersion(), version);
Map<String, String> tags = metric.getTags();
Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());
Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
Assertions.assertNull(tags.get(TAG_METHOD_KEY));
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
}

View File

@ -276,7 +276,7 @@ public class DefaultFuture extends CompletableFuture<Object> {
private String getTimeoutMessage(boolean scan) {
long nowTimestamp = System.currentTimeMillis();
return (sent > 0 ? "Waiting server-side response timeout" : "Sending request timeout in client-side")
return (sent > 0 && sent - start < timeout ? "Waiting server-side response timeout" : "Sending request timeout in client-side")
+ (scan ? " by scan timer" : "") + ". start time: "
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(start))) + ", end time: "
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(nowTimestamp))) + ","

View File

@ -86,6 +86,43 @@ class DefaultFutureTest {
}
}
/**
* for example, it will print like this:
* before a future is created, time is : 2023-09-03 18:20:14.535
* after a future is timeout, time is : 2023-09-03 18:20:14.669
* <p>
* The exception info print like:
* Sending request timeout in client-side by scan timer.
* start time: 2023-09-03 18:20:14.544, end time: 2023-09-03 18:20:14.598...
*/
@Test
public void clientTimeoutSend() throws Exception {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter));
// timeout after 5 milliseconds.
Channel channel = new MockedChannel();
Request request = new Request(10);
DefaultFuture f = DefaultFuture.newFuture(channel, request, 5, null);
System.gc(); // events such as Full GC will increase the time required to send messages.
// mark the future is sent
DefaultFuture.sent(channel, request);
while (!f.isDone()) {
// spin
Thread.sleep(100);
}
System.out.println("after a future is timeout , time is : " + LocalDateTime.now().format(formatter));
// get operate will throw a timeout exception, because the future is timeout.
try {
f.get();
} catch (Exception e) {
Assertions.assertTrue(e.getCause() instanceof TimeoutException, "catch exception is not timeout exception!");
System.out.println(e.getMessage());
Assertions.assertTrue(e.getMessage().startsWith(e.getCause().getClass().getCanonicalName() + ": Sending request timeout in client-side"));
}
}
/**
* for example, it will print like this:
* before a future is create , time is : 2018-06-21 15:11:31

View File

@ -92,7 +92,7 @@ public class ExceptionFilter implements Filter, Filter.Listener {
}
// directly throw if it's JDK exception
String className = exception.getClass().getName();
if (className.startsWith("java.") || className.startsWith("javax.")) {
if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("jakarta.")) {
return;
}
// directly throw if it's dubbo exception

View File

@ -87,7 +87,7 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
/**
* {@link Node} destroy
*/
private boolean destroyed = false;
private volatile boolean destroyed = false;
/**
* Whether set future to Thread Local when invocation mode is sync

View File

@ -229,6 +229,9 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
@Override
public final void onCancelByRemote(TriRpcStatus status) {
closed = true;
if (listener == null) {
return;
}
cancellationContext.cancel(status.cause);
listener.onCancel(status);
}

View File

@ -38,9 +38,9 @@
</modules>
<properties>
<micrometer.version>1.11.3</micrometer.version>
<micrometer-tracing.version>1.1.4</micrometer-tracing.version>
<opentelemetry.version>1.29.0</opentelemetry.version>
<micrometer.version>1.11.4</micrometer.version>
<micrometer-tracing.version>1.1.5</micrometer-tracing.version>
<opentelemetry.version>1.30.1</opentelemetry.version>
<zipkin-reporter.version>2.16.4</zipkin-reporter.version>
<prometheus-client.version>0.16.0</prometheus-client.version>
</properties>

View File

@ -46,7 +46,7 @@
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
<log4j2_version>2.20.0</log4j2_version>
<!-- Spring boot buddy is lower than the delivery dependency package version and can only show the defined dependency version -->
<byte-buddy.version>1.14.7</byte-buddy.version>
<byte-buddy.version>1.14.8</byte-buddy.version>
</properties>
<dependencyManagement>

View File

@ -175,7 +175,7 @@ public class IstioCitadelCertificateSigner implements XdsCertificateSigner {
IstioCertificateServiceGrpc.IstioCertificateServiceStub stub = IstioCertificateServiceGrpc.newStub(channel);
stub = MetadataUtils.attachHeaders(stub, header);
stub = stub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(header));
CountDownLatch countDownLatch = new CountDownLatch(1);
StringBuffer publicKeyBuilder = new StringBuffer();