refactor metrics defaultCollector&&agg (#12206)

* remove unused generic

* use request event

* fix test

* add licence

* bugfix

* code opt

* code opt

* code opt

* code opt

* code opt

* code opt

* fix ci

* fix

* revert

* opt

* opt

* bugfix

---------

Co-authored-by: x-shadow-man <1494445739@qq.com>
This commit is contained in:
wxbty 2023-05-02 21:56:54 +08:00 committed by GitHub
parent d711c0ca85
commit acd4212f59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 1716 additions and 1606 deletions

View File

@ -20,7 +20,8 @@ package org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestBeforeEvent;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -30,19 +31,17 @@ import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
@Activate(group = CONSUMER,onClass = "org.apache.dubbo.metrics.collector.DefaultMetricsCollector")
@Activate(group = CONSUMER, onClass = "org.apache.dubbo.metrics.collector.DefaultMetricsCollector")
public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {
private ApplicationModel applicationModel;
private DefaultMetricsCollector collector;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
}
@ -65,18 +64,12 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
if (collector == null || !collector.isCollectEnabled()) {
return;
}
if (t != null && t instanceof RpcException) {
if (t instanceof RpcException) {
RpcException e = (RpcException) t;
if (e.isForbidden()) {
collector.getMethodSampler().incOnEvent(invocation,
MetricsEvent.Type.SERVICE_UNAVAILABLE.getNameByType(getSide(invocation)));
MetricsEventBus.publish(RequestBeforeEvent.toEvent(applicationModel, invocation));
}
}
}
private String getSide(Invocation invocation) {
Optional<? extends Invoker<?>> invoker = Optional.ofNullable(invocation.getInvoker());
String side = invoker.isPresent() ? invoker.get().getUrl().getSide() : PROVIDER_SIDE;
return side;
}
}

View File

@ -15,23 +15,17 @@
* limitations under the License.
*/
package org.apache.dubbo.metrics.metrics.event;
package org.apache.dubbo.common.lang;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
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;
class RTEventTest {
@Test
void testNewEvent() {
MethodMetric metric = new MethodMetric();
Long rt = 5L;
RTEvent event = new RTEvent(ApplicationModel.defaultModel(), metric, rt);
Assertions.assertEquals(event.getSource(), ApplicationModel.defaultModel());
Assertions.assertEquals(event.getRt(), rt);
}
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Nullable {
}

View File

@ -18,7 +18,12 @@ package org.apache.dubbo.common.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* A utility class that provides methods for accessing and manipulating private fields and methods of an object.
@ -28,7 +33,8 @@ import java.util.Arrays;
*/
public class ReflectionUtils {
private ReflectionUtils(){}
private ReflectionUtils() {
}
/**
* Retrieves the value of the specified field from the given object.
@ -92,7 +98,50 @@ public class ReflectionUtils {
return true;
}
public static class ReflectionException extends RuntimeException{
/**
* Returns a list of distinct {@link Class} objects representing the generics of the given class that implement the
* given interface.
*
* @param clazz the class to retrieve the generics for
* @param interfaceClass the interface to retrieve the generics for
* @return a list of distinct {@link Class} objects representing the generics of the given class that implement the
* given interface
*/
public static List<Class<?>> getClassGenerics(Class<?> clazz, Class<?> interfaceClass) {
List<Class<?>> generics = new ArrayList<>();
Type[] genericInterfaces = clazz.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
Type rawType = parameterizedType.getRawType();
if (rawType instanceof Class && interfaceClass.isAssignableFrom((Class<?>) rawType)) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof Class) {
generics.add((Class<?>) actualTypeArgument);
}
}
}
}
}
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof Class) {
generics.add((Class<?>) actualTypeArgument);
}
}
}
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
generics.addAll(getClassGenerics(superclass, interfaceClass));
}
return generics.stream().distinct().collect(Collectors.toList());
}
public static class ReflectionException extends RuntimeException {
public ReflectionException(Throwable cause) {
super(cause);
}

View File

@ -19,6 +19,11 @@ package org.apache.dubbo.metrics;
public interface MetricsConstants {
String INVOCATION = "metric_filter_invocation";
String INVOCATION_METRICS_COUNTER = "metric_filter_invocation_counter";
String INVOCATION_SIDE = "metric_filter_side";
String ATTACHMENT_KEY_SERVICE = "serviceKey";
String ATTACHMENT_KEY_SIZE = "size";
String ATTACHMENT_KEY_LAST_NUM_MAP = "lastNumMap";

View File

@ -20,15 +20,18 @@ package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.metrics.data.BaseStatComposite;
import org.apache.dubbo.metrics.event.MetricsEventMulticaster;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.Invocation;
import java.util.List;
import static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;
public abstract class CombMetricsCollector<E extends TimeCounterEvent> implements ApplicationMetricsCollector<E>, ServiceMetricsCollector<E> {
public abstract class CombMetricsCollector<E extends TimeCounterEvent> extends AbstractMetricsListener<E> implements ApplicationMetricsCollector<E>, ServiceMetricsCollector<E>, MethodMetricsCollector<E> {
private final BaseStatComposite stats;
private MetricsEventMulticaster eventMulticaster;
@ -43,7 +46,7 @@ public abstract class CombMetricsCollector<E extends TimeCounterEvent> implement
}
@Override
public void setNum(MetricsKey metricsKey, String applicationName, String serviceKey, int num) {
public void setNum(MetricsKeyWrapper metricsKey, String applicationName, String serviceKey, int num) {
this.stats.setServiceKey(metricsKey, applicationName, serviceKey, num);
}
@ -52,8 +55,8 @@ public abstract class CombMetricsCollector<E extends TimeCounterEvent> implement
this.stats.incrementApp(metricsKey, applicationName, SELF_INCREMENT_SIZE);
}
public void increment(String applicationName, String serviceKey, MetricsKey metricsKey, int size) {
this.stats.incrementServiceKey(metricsKey, applicationName, serviceKey, size);
public void increment(String applicationName, String serviceKey, MetricsKeyWrapper metricsKeyWrapper, int size) {
this.stats.incrementServiceKey(metricsKeyWrapper, applicationName, serviceKey, size);
}
@Override
@ -65,11 +68,24 @@ public abstract class CombMetricsCollector<E extends TimeCounterEvent> implement
stats.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime);
}
@SuppressWarnings({"rawtypes"})
protected List<GaugeMetricSample> export(MetricsCategory category) {
@Override
public void increment(String applicationName, Invocation invocation, MetricsKeyWrapper wrapper, int size) {
this.stats.incrementMethodKey(wrapper, applicationName, invocation, size);
}
@Override
public void addRt(String applicationName, Invocation invocation, String registryOpType, Long responseTime) {
stats.calcMethodKeyRt(applicationName, invocation, registryOpType, responseTime);
}
protected List<MetricSample> export(MetricsCategory category) {
return stats.export(category);
}
public MetricsEventMulticaster getEventMulticaster() {
return eventMulticaster;
}
@Override
public void onEvent(TimeCounterEvent event) {
eventMulticaster.publishEvent(event);

View File

@ -15,33 +15,19 @@
* limitations under the License.
*/
package org.apache.dubbo.metrics.event;
package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.rpc.Invocation;
/**
* RtEvent.
* Method-level metrics collection for rpc invocation scenarios
*/
public class RTEvent extends MetricsEvent {
private Long rt;
private final Object metric;
public interface MethodMetricsCollector<E extends TimeCounterEvent> extends MetricsCollector<E> {
public RTEvent(ApplicationModel applicationModel, Object metric, Long rt) {
super(applicationModel);
this.rt = rt;
this.metric = metric;
setAvailable(true);
}
void increment(String applicationName, Invocation invocation, MetricsKeyWrapper wrapper, int size);
public Long getRt() {
return rt;
}
public void setRt(Long rt) {
this.rt = rt;
}
public Object getMetric() {
return metric;
}
void addRt(String applicationName, Invocation invocation, String registryOpType, Long responseTime);
}

View File

@ -18,19 +18,17 @@
package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
/**
* Application-level collector.
* Service-level collector.
* registration center, configuration center and other scenarios
*
* @Params <T> metrics type
*/
public interface ServiceMetricsCollector<E extends TimeCounterEvent> extends MetricsCollector<E> {
void increment(String applicationName, String serviceKey, MetricsKey metricsKey, int size);
void increment(String applicationName, String serviceKey, MetricsKeyWrapper wrapper, int size);
void setNum(MetricsKey metricsKey, String applicationName, String serviceKey, int num);
void setNum(MetricsKeyWrapper metricsKey, String applicationName, String serviceKey, int num);
void addRt(String applicationName, String serviceKey, String registryOpType, Long responseTime);
}

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.MetricsExport;
import java.util.ArrayList;
@ -48,17 +49,9 @@ public class ApplicationStatComposite implements MetricsExport {
applicationNumStats.get(metricsKey).computeIfAbsent(applicationName, k -> new AtomicLong(0L)).getAndAdd(size);
}
public void setApplicationKey(MetricsKey metricsKey, String applicationName, int num) {
if (!applicationNumStats.containsKey(metricsKey)) {
return;
}
applicationNumStats.get(metricsKey).computeIfAbsent(applicationName, k -> new AtomicLong(0L)).set(num);
}
@SuppressWarnings({"rawtypes"})
public List<GaugeMetricSample> export(MetricsCategory category) {
List<GaugeMetricSample> list = new ArrayList<>();
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();
for (MetricsKey type : applicationNumStats.keySet()) {
Map<String, AtomicLong> stringAtomicLongMap = applicationNumStats.get(type);
for (String applicationName : stringAtomicLongMap.keySet()) {

View File

@ -20,9 +20,10 @@ package org.apache.dubbo.metrics.data;
import org.apache.dubbo.metrics.collector.MetricsCollector;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.MetricsExport;
import org.apache.dubbo.rpc.Invocation;
import java.util.ArrayList;
import java.util.List;
@ -37,14 +38,31 @@ public abstract class BaseStatComposite implements MetricsExport {
private final ApplicationStatComposite applicationStatComposite = new ApplicationStatComposite();
private final ServiceStatComposite serviceStatComposite = new ServiceStatComposite();
private final MethodStatComposite methodStatComposite = new MethodStatComposite();
private final RtStatComposite rtStatComposite = new RtStatComposite();
public BaseStatComposite() {
init(applicationStatComposite, serviceStatComposite, rtStatComposite);
init(applicationStatComposite);
init(serviceStatComposite);
init(methodStatComposite);
init(rtStatComposite);
}
protected abstract void init(ApplicationStatComposite applicationStatComposite, ServiceStatComposite serviceStatComposite, RtStatComposite rtStatComposite);
protected void init(ApplicationStatComposite applicationStatComposite) {
}
protected void init(ServiceStatComposite serviceStatComposite) {
}
protected void init(MethodStatComposite methodStatComposite) {
}
protected void init(RtStatComposite rtStatComposite) {
}
public void calcApplicationRt(String applicationName, String registryOpType, Long responseTime) {
rtStatComposite.calcApplicationRt(applicationName, registryOpType, responseTime);
@ -54,29 +72,33 @@ public abstract class BaseStatComposite implements MetricsExport {
rtStatComposite.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime);
}
public void setServiceKey(MetricsKey metricsKey, String applicationName, String serviceKey, int num) {
serviceStatComposite.setServiceKey(metricsKey, applicationName, serviceKey, num);
public void calcMethodKeyRt(String applicationName, Invocation invocation, String registryOpType, Long responseTime) {
rtStatComposite.calcMethodKeyRt(applicationName, invocation, registryOpType, responseTime);
}
public void setApplicationKey(MetricsKey metricsKey, String applicationName, int num) {
applicationStatComposite.setApplicationKey(metricsKey, applicationName, num);
public void setServiceKey(MetricsKeyWrapper metricsKey, String applicationName, String serviceKey, int num) {
serviceStatComposite.setServiceKey(metricsKey, applicationName, serviceKey, num);
}
public void incrementApp(MetricsKey metricsKey, String applicationName, int size) {
applicationStatComposite.incrementSize(metricsKey, applicationName, size);
}
public void incrementServiceKey(MetricsKey metricsKey, String applicationName, String attServiceKey, int size) {
serviceStatComposite.incrementServiceKey(metricsKey, applicationName, attServiceKey, size);
public void incrementServiceKey(MetricsKeyWrapper metricsKeyWrapper, String applicationName, String attServiceKey, int size) {
serviceStatComposite.incrementServiceKey(metricsKeyWrapper, applicationName, attServiceKey, size);
}
public void incrementMethodKey(MetricsKeyWrapper metricsKeyWrapper, String applicationName, Invocation invocation, int size) {
methodStatComposite.incrementMethodKey(metricsKeyWrapper, applicationName, invocation, size);
}
@Override
@SuppressWarnings({"rawtypes"})
public List<GaugeMetricSample> export(MetricsCategory category) {
List<GaugeMetricSample> list = new ArrayList<>();
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();
list.addAll(applicationStatComposite.export(category));
list.addAll(rtStatComposite.export(category));
list.addAll(serviceStatComposite.export(category));
list.addAll(methodStatComposite.export(category));
return list;
}

View File

@ -0,0 +1,71 @@
/*
* 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.data;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.MetricsExport;
import org.apache.dubbo.rpc.Invocation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class MethodStatComposite implements MetricsExport {
private final Map<MetricsKeyWrapper, Map<MethodMetric, AtomicLong>> methodNumStats = new ConcurrentHashMap<>();
public void initWrapper(List<MetricsKeyWrapper> metricsKeyWrappers) {
if (CollectionUtils.isEmpty(metricsKeyWrappers)) {
return;
}
metricsKeyWrappers.forEach(appKey -> methodNumStats.put(appKey, new ConcurrentHashMap<>()));
}
public void incrementMethodKey(MetricsKeyWrapper wrapper, String applicationName, Invocation invocation, int size) {
if (!methodNumStats.containsKey(wrapper)) {
return;
}
methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(applicationName, invocation), k -> new AtomicLong(0L)).getAndAdd(size);
}
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();
for (MetricsKeyWrapper wrapper : methodNumStats.keySet()) {
Map<MethodMetric, AtomicLong> stringAtomicLongMap = methodNumStats.get(wrapper);
for (MethodMetric methodMetric : stringAtomicLongMap.keySet()) {
if (methodMetric.getSampleType() == MetricSample.Type.GAUGE) {
list.add(new CounterMetricSample<>(wrapper,
methodMetric.getTags(), category, stringAtomicLongMap.get(methodMetric)));
} else {
list.add(new GaugeMetricSample<>(wrapper, methodMetric.getTags(), category, stringAtomicLongMap, value -> value.get(methodMetric).get()));
}
}
}
return list;
}
}

View File

@ -24,9 +24,11 @@ import org.apache.dubbo.metrics.model.container.AtomicLongContainer;
import org.apache.dubbo.metrics.model.container.LongAccumulatorContainer;
import org.apache.dubbo.metrics.model.container.LongContainer;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsPlaceType;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.MetricsExport;
import org.apache.dubbo.rpc.Invocation;
import java.util.ArrayList;
import java.util.Arrays;
@ -36,18 +38,19 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.stream.Collectors;
@SuppressWarnings({"rawtypes", "unchecked"})
public class RtStatComposite implements MetricsExport {
private final List<LongContainer<? extends Number>> rtStats = new ArrayList<>();
public void init(MetricsPlaceType... placeValues) {
public void init(MetricsPlaceValue... placeValues) {
if (placeValues == null) {
return;
}
Arrays.stream(placeValues).forEach(metricsPlaceType -> rtStats.addAll(initStats(metricsPlaceType)));
}
private List<LongContainer<? extends Number>> initStats(MetricsPlaceType placeValue) {
private List<LongContainer<? extends Number>> initStats(MetricsPlaceValue placeValue) {
List<LongContainer<? extends Number>> singleRtStats = new ArrayList<>();
singleRtStats.add(new AtomicLongContainer(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, placeValue)));
singleRtStats.add(new LongAccumulatorContainer(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, placeValue), new LongAccumulator(Long::min, Long.MAX_VALUE)));
@ -65,7 +68,6 @@ public class RtStatComposite implements MetricsExport {
return singleRtStats;
}
@SuppressWarnings({"rawtypes", "unchecked"})
public void calcApplicationRt(String applicationName, String registryOpType, Long responseTime) {
for (LongContainer container : rtStats.stream().filter(longContainer -> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, applicationName, container.getInitFunc());
@ -73,7 +75,6 @@ public class RtStatComposite implements MetricsExport {
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
public void calcServiceKeyRt(String applicationName, String serviceKey, String registryOpType, Long responseTime) {
for (LongContainer container : rtStats.stream().filter(longContainer -> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, applicationName + "_" + serviceKey, container.getInitFunc());
@ -81,9 +82,15 @@ public class RtStatComposite implements MetricsExport {
}
}
@SuppressWarnings({"rawtypes"})
public List<GaugeMetricSample> export(MetricsCategory category) {
List<GaugeMetricSample> list = new ArrayList<>();
public void calcMethodKeyRt(String applicationName, Invocation invocation, String registryOpType, Long responseTime) {
for (LongContainer container : rtStats.stream().filter(longContainer -> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, applicationName + "_" + invocation.getServiceName() + "_" + invocation.getMethodName(), container.getInitFunc());
container.getConsumerFunc().accept(responseTime, current);
}
}
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();
for (LongContainer<? extends Number> rtContainer : rtStats) {
MetricsKeyWrapper metricsKeyWrapper = rtContainer.getMetricsKeyWrapper();
for (Map.Entry<String, ? extends Number> entry : rtContainer.entrySet()) {

View File

@ -20,8 +20,9 @@ package org.apache.dubbo.metrics.data;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.metrics.model.MetricsCategory;
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.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.MetricsExport;
import java.util.ArrayList;
@ -32,36 +33,35 @@ import java.util.concurrent.atomic.AtomicLong;
public class ServiceStatComposite implements MetricsExport {
private final Map<MetricsKey, Map<ServiceKeyMetric, AtomicLong>> serviceNumStats = new ConcurrentHashMap<>();
private final Map<MetricsKeyWrapper, Map<ServiceKeyMetric, AtomicLong>> serviceWrapperNumStats = new ConcurrentHashMap<>();
public void init(List<MetricsKey> serviceKeys) {
if (CollectionUtils.isEmpty(serviceKeys)) {
public void initWrapper(List<MetricsKeyWrapper> metricsKeyWrappers) {
if (CollectionUtils.isEmpty(metricsKeyWrappers)) {
return;
}
serviceKeys.forEach(appKey -> serviceNumStats.put(appKey, new ConcurrentHashMap<>()));
metricsKeyWrappers.forEach(appKey -> serviceWrapperNumStats.put(appKey, new ConcurrentHashMap<>()));
}
public void incrementServiceKey(MetricsKey metricsKey, String applicationName, String serviceKey, int size) {
if (!serviceNumStats.containsKey(metricsKey)) {
public void incrementServiceKey(MetricsKeyWrapper wrapper, String applicationName, String serviceKey, int size) {
if (!serviceWrapperNumStats.containsKey(wrapper)) {
return;
}
serviceNumStats.get(metricsKey).computeIfAbsent(new ServiceKeyMetric(applicationName, serviceKey), k -> new AtomicLong(0L)).getAndAdd(size);
serviceWrapperNumStats.get(wrapper).computeIfAbsent(new ServiceKeyMetric(applicationName, serviceKey), k -> new AtomicLong(0L)).getAndAdd(size);
}
public void setServiceKey(MetricsKey type, String applicationName, String serviceKey, int num) {
if (!serviceNumStats.containsKey(type)) {
public void setServiceKey(MetricsKeyWrapper wrapper, String applicationName, String serviceKey, int num) {
if (!serviceWrapperNumStats.containsKey(wrapper)) {
return;
}
serviceNumStats.get(type).computeIfAbsent(new ServiceKeyMetric(applicationName, serviceKey), k -> new AtomicLong(0L)).set(num);
serviceWrapperNumStats.get(wrapper).computeIfAbsent(new ServiceKeyMetric(applicationName, serviceKey), k -> new AtomicLong(0L)).set(num);
}
@SuppressWarnings({"rawtypes"})
public List<GaugeMetricSample> export(MetricsCategory category) {
List<GaugeMetricSample> list = new ArrayList<>();
for (MetricsKey type : serviceNumStats.keySet()) {
Map<ServiceKeyMetric, AtomicLong> stringAtomicLongMap = serviceNumStats.get(type);
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();
for (MetricsKeyWrapper wrapper : serviceWrapperNumStats.keySet()) {
Map<ServiceKeyMetric, AtomicLong> stringAtomicLongMap = serviceWrapperNumStats.get(wrapper);
for (ServiceKeyMetric serviceKeyMetric : stringAtomicLongMap.keySet()) {
list.add(new GaugeMetricSample<>(type, serviceKeyMetric.getTags(), category, stringAtomicLongMap, value -> value.get(serviceKeyMetric).get()));
list.add(new GaugeMetricSample<>(wrapper, serviceKeyMetric.getTags(), category, stringAtomicLongMap, value -> value.get(serviceKeyMetric).get()));
}
}
return list;

View File

@ -27,7 +27,7 @@ public class EmptyEvent extends MetricsEvent {
private static final EmptyEvent empty = new EmptyEvent(null);
private EmptyEvent(ApplicationModel source) {
super(source);
super(source, null);
}
public static EmptyEvent instance() {

View File

@ -1,47 +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.metrics.model.MethodMetric;
import org.apache.dubbo.rpc.model.ApplicationModel;
public class MethodEvent extends MetricsEvent {
private String type;
private final MethodMetric methodMetric;
public MethodEvent(ApplicationModel applicationModel, MethodMetric methodMetric, String type) {
super(applicationModel);
this.type = type;
this.methodMetric = methodMetric;
setAvailable(true);
}
public MethodMetric getMethodMetric() {
return methodMetric;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -35,11 +35,12 @@ public abstract class MetricsEvent {
*/
protected transient ApplicationModel source;
private boolean available = true;
protected TypeWrapper typeWrapper;
private final TypeWrapper typeWrapper;
private final Map<String, Object> attachment = new HashMap<>(8);
public MetricsEvent(ApplicationModel source) {
public MetricsEvent(ApplicationModel source, TypeWrapper typeWrapper) {
this.typeWrapper = typeWrapper;
if (source == null) {
this.source = ApplicationModel.defaultModel();
// Appears only in unit tests
@ -51,8 +52,8 @@ public abstract class MetricsEvent {
@SuppressWarnings("unchecked")
public <T> T getAttachmentValue(String key) {
if (!attachment.containsKey(key)) {
throw new MetricsNeverHappenException("Attachment key [" + key + "] not found");
if (key == null) {
throw new MetricsNeverHappenException("Attachment key is null");
}
return (T) attachment.get(key);
}
@ -82,6 +83,10 @@ public abstract class MetricsEvent {
return getSource().getApplicationName();
}
public TypeWrapper getTypeWrapper() {
return typeWrapper;
}
public boolean isAssignableFrom(Object type) {
return typeWrapper.isAssignableFrom(type);
}

View File

@ -73,48 +73,77 @@ public class MetricsEventBus {
* @return Biz result
*/
public static <T> T post(MetricsEvent event, Supplier<T> targetSupplier, Function<T, Boolean> trFunction) {
if (event.getSource() == null) {
return targetSupplier.get();
}
ApplicationModel applicationModel = event.getSource();
if (applicationModel.isDestroyed()) {
return targetSupplier.get();
}
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
if (beanFactory.isDestroyed()) {
return targetSupplier.get();
}
MetricsDispatcher dispatcher = beanFactory.getBean(MetricsDispatcher.class);
if (dispatcher == null) {
return targetSupplier.get();
}
dispatcher.publishEvent(event);
if (!(event instanceof TimeCounterEvent)) {
return targetSupplier.get();
}
TimeCounterEvent timeCounterEvent = (TimeCounterEvent) event;
T result;
before(event);
if (trFunction == null) {
try {
result = targetSupplier.get();
} catch (Throwable e) {
dispatcher.publishErrorEvent(timeCounterEvent);
error(event);
throw e;
}
event.customAfterPost(result);
dispatcher.publishFinishEvent(timeCounterEvent);
after(event, result);
} else {
// Custom failure status
result = targetSupplier.get();
if (trFunction.apply(result)) {
event.customAfterPost(result);
dispatcher.publishFinishEvent(timeCounterEvent);
after(event, result);
} else {
dispatcher.publishErrorEvent(timeCounterEvent);
error(event);
}
}
return result;
}
public static void before(MetricsEvent event) {
before(event, null);
}
/**
* Applicable to the scene where execution and return are separated,
* eventSaveRunner saves the event, so that the calculation rt is introverted
*/
public static void before(MetricsEvent event, Runnable eventSaveRunner) {
MetricsDispatcher dispatcher = validate(event);
if (dispatcher == null) return;
dispatcher.publishEvent(event);
if (eventSaveRunner != null) {
eventSaveRunner.run();
}
}
public static void after(MetricsEvent event, Object result) {
MetricsDispatcher dispatcher = validate(event);
if (dispatcher == null) return;
event.customAfterPost(result);
dispatcher.publishFinishEvent((TimeCounterEvent) event);
}
public static void error(MetricsEvent event) {
MetricsDispatcher dispatcher = validate(event);
if (dispatcher == null) return;
dispatcher.publishErrorEvent((TimeCounterEvent) event);
}
private static MetricsDispatcher validate(MetricsEvent event) {
if (event.getSource() == null) {
return null;
}
ApplicationModel applicationModel = event.getSource();
if (applicationModel.isDestroyed()) {
return null;
}
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
if (beanFactory.isDestroyed()) {
return null;
}
MetricsDispatcher dispatcher = beanFactory.getBean(MetricsDispatcher.class);
if (dispatcher == null) {
return null;
}
if (!(event instanceof TimeCounterEvent)) {
return null;
}
return dispatcher;
}
}

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.metrics.event;
import org.apache.dubbo.metrics.model.TimePair;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.rpc.model.ApplicationModel;
/**
@ -27,8 +28,8 @@ public abstract class TimeCounterEvent extends MetricsEvent {
private final TimePair timePair;
public TimeCounterEvent(ApplicationModel source) {
super(source);
public TimeCounterEvent(ApplicationModel source, TypeWrapper typeWrapper) {
super(source, typeWrapper);
this.timePair = TimePair.start();
}

View File

@ -0,0 +1,83 @@
/*
* 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.listener;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import java.util.function.Consumer;
/**
* According to the event template of {@link MetricsEventBus},
* build a consistent static method for general and custom monitoring consume methods
*/
public abstract class AbstractMetricsKeyListener extends AbstractMetricsListener<TimeCounterEvent> implements MetricsLifeListener<TimeCounterEvent> {
private final MetricsKey metricsKey;
public AbstractMetricsKeyListener(MetricsKey metricsKey) {
this.metricsKey = metricsKey;
}
/**
* The MetricsKey type determines whether events are supported
*/
@Override
public boolean isSupport(MetricsEvent event) {
return super.isSupport(event) && event.isAssignableFrom(metricsKey);
}
@Override
public void onEvent(TimeCounterEvent event) {
}
public static AbstractMetricsKeyListener onEvent(MetricsKey metricsKey, Consumer<TimeCounterEvent> postFunc) {
return new AbstractMetricsKeyListener(metricsKey) {
@Override
public void onEvent(TimeCounterEvent event) {
postFunc.accept(event);
}
};
}
public static AbstractMetricsKeyListener onFinish(MetricsKey metricsKey, Consumer<TimeCounterEvent> finishFunc) {
return new AbstractMetricsKeyListener(metricsKey) {
@Override
public void onEventFinish(TimeCounterEvent event) {
finishFunc.accept(event);
}
};
}
public static AbstractMetricsKeyListener onError(MetricsKey metricsKey, Consumer<TimeCounterEvent> errorFunc) {
return new AbstractMetricsKeyListener(metricsKey) {
@Override
public void onEventError(TimeCounterEvent event) {
errorFunc.accept(event);
}
};
}
}

View File

@ -17,54 +17,21 @@
package org.apache.dubbo.metrics.listener;
import org.apache.dubbo.common.utils.ReflectionUtils;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import java.util.function.Consumer;
import java.util.List;
public abstract class AbstractMetricsListener implements MetricsLifeListener<TimeCounterEvent> {
public abstract class AbstractMetricsListener<E extends MetricsEvent> implements MetricsListener<E> {
private final MetricsKey metricsKey;
public AbstractMetricsListener(MetricsKey metricsKey) {
this.metricsKey = metricsKey;
/**
* Whether to support the general determination of event points depends on the event type
*/
public boolean isSupport(MetricsEvent event) {
List<Class<?>> eventTypes = ReflectionUtils.getClassGenerics(getClass(), AbstractMetricsListener.class);
return event.isAvailable() && eventTypes.stream().allMatch(clazz -> clazz.isInstance(event));
}
@Override
public boolean isSupport(MetricsEvent event) {
return event.isAvailable() && event.isAssignableFrom(metricsKey);
}
public static AbstractMetricsListener onEvent(MetricsKey metricsKey, Consumer<TimeCounterEvent> postFunc) {
return new AbstractMetricsListener(metricsKey) {
@Override
public void onEvent(TimeCounterEvent event) {
postFunc.accept(event);
}
};
}
public static AbstractMetricsListener onFinish(MetricsKey metricsKey, Consumer<TimeCounterEvent> finishFunc) {
return new AbstractMetricsListener(metricsKey) {
@Override
public void onEventFinish(TimeCounterEvent event) {
finishFunc.accept(event);
}
};
}
public static AbstractMetricsListener onError(MetricsKey metricsKey, Consumer<TimeCounterEvent> errorFunc) {
return new AbstractMetricsListener(metricsKey) {
@Override
public void onEventError(TimeCounterEvent event) {
errorFunc.accept(event);
}
};
}
public abstract void onEvent(E event);
}

View File

@ -18,24 +18,23 @@
package org.apache.dubbo.metrics.listener;
import org.apache.dubbo.metrics.collector.CombMetricsCollector;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsPlaceType;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
public class MetricsApplicationListener extends AbstractMetricsListener {
public class MetricsApplicationListener extends AbstractMetricsKeyListener {
public MetricsApplicationListener(MetricsKey metricsKey) {
super(metricsKey);
}
public static AbstractMetricsListener onPostEventBuild(MetricsKey metricsKey, CombMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onEvent(metricsKey,
public static AbstractMetricsKeyListener onPostEventBuild(MetricsKey metricsKey, CombMetricsCollector collector) {
return AbstractMetricsKeyListener.onEvent(metricsKey,
event -> collector.increment(event.appName(), metricsKey)
);
}
public static AbstractMetricsListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, CombMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onFinish(metricsKey,
public static AbstractMetricsKeyListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) {
return AbstractMetricsKeyListener.onFinish(metricsKey,
event -> {
collector.increment(event.appName(), metricsKey);
collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc());
@ -43,8 +42,8 @@ public class MetricsApplicationListener extends AbstractMetricsListener {
);
}
public static AbstractMetricsListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, CombMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onError(metricsKey,
public static AbstractMetricsKeyListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) {
return AbstractMetricsKeyListener.onError(metricsKey,
event -> {
collector.increment(event.appName(), metricsKey);
collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc());

View File

@ -19,21 +19,21 @@ package org.apache.dubbo.metrics.listener;
import org.apache.dubbo.metrics.event.MetricsEvent;
/**
* Metrics Listener.
*/
public interface MetricsListener<E extends MetricsEvent> {
default boolean isSupport(MetricsEvent event) {
return event.isAvailable();
}
boolean isSupport(MetricsEvent event);
/**
* notify event.
*
* @param event BaseMetricsEvent
*/
default void onEvent(E event) {
}
void onEvent(E event);
}

View File

@ -19,38 +19,32 @@ package org.apache.dubbo.metrics.listener;
import org.apache.dubbo.metrics.collector.ServiceMetricsCollector;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsPlaceType;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
import static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;
public class MetricsServiceListener extends AbstractMetricsListener {
public class MetricsServiceListener extends AbstractMetricsKeyListener {
public MetricsServiceListener(MetricsKey metricsKey) {
super(metricsKey);
}
public static AbstractMetricsListener onPostEventBuild(MetricsKey metricsKey, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onEvent(metricsKey,
event -> collector.increment(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), metricsKey, SELF_INCREMENT_SIZE)
public static AbstractMetricsKeyListener onPostEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsKeyListener.onEvent(metricsKey,
event -> MetricsSupport.increment(metricsKey, placeType, collector, event)
);
}
public static AbstractMetricsListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onFinish(metricsKey,
event -> incrAndAddRt(metricsKey, placeType, collector, event)
public static AbstractMetricsKeyListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsKeyListener.onFinish(metricsKey,
event -> MetricsSupport.incrAndAddRt(metricsKey, placeType, collector, event)
);
}
public static AbstractMetricsListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsListener.onError(metricsKey,
event -> incrAndAddRt(metricsKey, placeType, collector, event)
public static AbstractMetricsKeyListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {
return AbstractMetricsKeyListener.onError(metricsKey,
event -> MetricsSupport.incrAndAddRt(metricsKey, placeType, collector, event)
);
}
private static void incrAndAddRt(MetricsKey metricsKey, MetricsPlaceType placeType, ServiceMetricsCollector<TimeCounterEvent> collector, TimeCounterEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), metricsKey, SELF_INCREMENT_SIZE);
collector.addRt(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), placeType.getType(), event.getTimePair().calc());
}
}

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.metrics.model;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
@ -38,6 +39,7 @@ import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;
import static org.apache.dubbo.metrics.MetricsConstants.INVOCATION_METRICS_COUNTER;
import static org.apache.dubbo.rpc.support.RpcUtils.isGenericCall;
/**
@ -51,13 +53,21 @@ public class MethodMetric implements Metric {
private String group;
private String version;
public MethodMetric() {}
private MetricSample.Type sampleType;
public MethodMetric() {
}
public MethodMetric(String applicationName, Invocation invocation) {
this.applicationName = applicationName;
this.sampleType = (MetricSample.Type) invocation.get(INVOCATION_METRICS_COUNTER);
init(invocation);
}
public MetricSample.Type getSampleType() {
return sampleType;
}
public String getInterfaceName() {
return interfaceName;
}
@ -106,9 +116,9 @@ public class MethodMetric implements Metric {
String serviceUniqueName = invocation.getTargetServiceUniqueName();
String methodName = invocation.getMethodName();
if (invocation instanceof RpcInvocation
&& isGenericCall(((RpcInvocation) invocation).getParameterTypesDesc(), methodName)
&& invocation.getArguments() != null
&& invocation.getArguments().length == 3) {
&& isGenericCall(((RpcInvocation) invocation).getParameterTypesDesc(), methodName)
&& invocation.getArguments() != null
&& invocation.getArguments().length == 3) {
methodName = ((String) invocation.getArguments()[0]).trim();
}
String group = null;
@ -150,13 +160,13 @@ public class MethodMetric implements Metric {
@Override
public String toString() {
return "MethodMetric{" +
"applicationName='" + applicationName + '\'' +
", side='" + side + '\'' +
", interfaceName='" + interfaceName + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
"applicationName='" + applicationName + '\'' +
", side='" + side + '\'' +
", interfaceName='" + interfaceName + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
}
@Override

View File

@ -18,19 +18,36 @@
package org.apache.dubbo.metrics.model;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.metrics.collector.MethodMetricsCollector;
import org.apache.dubbo.metrics.collector.ServiceMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.exception.MetricsNeverHappenException;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_VERSION_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
import static org.apache.dubbo.metrics.MetricsConstants.INVOCATION;
import static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;
public class MetricsSupport {
@ -56,4 +73,120 @@ public class MetricsSupport {
tags.put(TAG_INTERFACE_KEY, keys[1]);
return tags;
}
public static Map<String, String> methodTags(String names) {
String[] keys = names.split("_");
if (keys.length != 3) {
throw new MetricsNeverHappenException("Error names: " + names);
}
Map<String, String> tags = applicationTags(keys[0]);
tags.put(TAG_INTERFACE_KEY, keys[1]);
tags.put(TAG_METHOD_KEY, keys[2]);
return tags;
}
public static MetricsKey getMetricsKey(RpcException e) {
MetricsKey targetKey;
targetKey = MetricsKey.METRIC_REQUESTS_FAILED;
if (e.isTimeout()) {
targetKey = MetricsKey.METRIC_REQUESTS_TIMEOUT;
}
if (e.isLimitExceed()) {
targetKey = MetricsKey.METRIC_REQUESTS_LIMIT;
}
if (e.isBiz()) {
targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;
}
if (e.isSerialization()) {
targetKey = MetricsKey.METRIC_REQUESTS_CODEC_FAILED;
}
if (e.isNetwork()) {
targetKey = MetricsKey.METRIC_REQUESTS_NETWORK_FAILED;
}
return targetKey;
}
public static MetricsKey getAggMetricsKey(RpcException e) {
MetricsKey targetKey;
targetKey = MetricsKey.METRIC_REQUESTS_FAILED_AGG;
if (e.isTimeout()) {
targetKey = MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG;
}
if (e.isLimitExceed()) {
targetKey = MetricsKey.METRIC_REQUESTS_LIMIT_AGG;
}
if (e.isBiz()) {
targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG;
}
if (e.isSerialization()) {
targetKey = MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG;
}
if (e.isNetwork()) {
targetKey = MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG;
}
return targetKey;
}
public static String getSide(Invocation invocation) {
Optional<? extends Invoker<?>> invoker = Optional.ofNullable(invocation.getInvoker());
return invoker.isPresent() ? invoker.get().getUrl().getSide() : PROVIDER_SIDE;
}
public static String getInterfaceName(Invocation invocation) {
String serviceUniqueName = invocation.getTargetServiceUniqueName();
String interfaceAndVersion;
String[] arr = serviceUniqueName.split(PATH_SEPARATOR);
if (arr.length == 2) {
interfaceAndVersion = arr[1];
} else {
interfaceAndVersion = arr[0];
}
String[] ivArr = interfaceAndVersion.split(GROUP_CHAR_SEPARATOR);
return ivArr[0];
}
/**
* Incr service num
*/
public static void increment(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector, MetricsEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), new MetricsKeyWrapper(metricsKey, placeType), SELF_INCREMENT_SIZE);
}
/**
* Dec service num
*/
public static void dec(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector, MetricsEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), new MetricsKeyWrapper(metricsKey, placeType), -SELF_INCREMENT_SIZE);
}
/**
* Incr service num&&rt
*/
public static void incrAndAddRt(MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector, TimeCounterEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), new MetricsKeyWrapper(metricsKey, placeType), SELF_INCREMENT_SIZE);
collector.addRt(event.appName(), event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), placeType.getType(), event.getTimePair().calc());
}
/**
* Incr method num
*/
public static void increment(MetricsKey metricsKey, MetricsPlaceValue placeType, MethodMetricsCollector<TimeCounterEvent> collector, MetricsEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(INVOCATION), new MetricsKeyWrapper(metricsKey, placeType), SELF_INCREMENT_SIZE);
}
/**
* Dec method num
*/
public static void dec(MetricsKey metricsKey, MetricsPlaceValue placeType, MethodMetricsCollector<TimeCounterEvent> collector, MetricsEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(INVOCATION), new MetricsKeyWrapper(metricsKey, placeType), -SELF_INCREMENT_SIZE);
}
/**
* Incr method num&&rt
*/
public static void incrAndAddRt(MetricsKey metricsKey, MetricsPlaceValue placeType, MethodMetricsCollector<TimeCounterEvent> collector, TimeCounterEvent event) {
collector.increment(event.appName(), event.getAttachmentValue(INVOCATION), new MetricsKeyWrapper(metricsKey, placeType), SELF_INCREMENT_SIZE);
collector.addRt(event.appName(), event.getAttachmentValue(INVOCATION), placeType.getType(), event.getTimePair().calc());
}
}

View File

@ -19,13 +19,20 @@ package org.apache.dubbo.metrics.model.key;
import io.micrometer.common.lang.Nullable;
/**
* The overall event set, including the event processing functions in three stages
*/
public class CategoryOverall {
private final MetricsCat post;
private MetricsCat finish;
private MetricsCat error;
public CategoryOverall(MetricsPlaceType placeType, MetricsCat post, @Nullable MetricsCat finish, @Nullable MetricsCat error) {
/**
* @param placeType When placeType is null, it means that placeType is obtained dynamically
* @param post Statistics of the number of events, as long as it occurs, it will take effect, so it cannot be null
*/
public CategoryOverall(@Nullable MetricsPlaceValue placeType, MetricsCat post, @Nullable MetricsCat finish, @Nullable MetricsCat error) {
this.post = post.setPlaceType(placeType);
if (finish != null) {
this.finish = finish.setPlaceType(placeType);

View File

@ -18,31 +18,34 @@
package org.apache.dubbo.metrics.model.key;
import org.apache.dubbo.metrics.collector.CombMetricsCollector;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;
import java.util.function.BiFunction;
import java.util.function.Function;
public class MetricsCat {
private MetricsPlaceType placeType;
private final Function<CombMetricsCollector<TimeCounterEvent>, AbstractMetricsListener> eventFunc;
private MetricsPlaceValue placeType;
private final Function<CombMetricsCollector, AbstractMetricsKeyListener> eventFunc;
public MetricsCat(MetricsKey metricsKey, BiFunction<MetricsKey, CombMetricsCollector<TimeCounterEvent>, AbstractMetricsListener> biFunc) {
public MetricsCat(MetricsKey metricsKey, BiFunction<MetricsKey, CombMetricsCollector, AbstractMetricsKeyListener> biFunc) {
this.eventFunc = collector -> biFunc.apply(metricsKey, collector);
}
public MetricsCat(MetricsKey metricsKey, TpFunction<MetricsKey, MetricsPlaceType, CombMetricsCollector<TimeCounterEvent>, AbstractMetricsListener> tpFunc) {
/**
* @param metricsKey The key that the current category listens tonot necessarily the export key(export key may be dynamic)
* @param tpFunc Build the func that outputs the MetricsListener by listen metricsKey
*/
public MetricsCat(MetricsKey metricsKey, TpFunction<MetricsKey, MetricsPlaceValue, CombMetricsCollector, AbstractMetricsKeyListener> tpFunc) {
this.eventFunc = collector -> tpFunc.apply(metricsKey, placeType, collector);
}
public MetricsCat setPlaceType(MetricsPlaceType placeType) {
public MetricsCat setPlaceType(MetricsPlaceValue placeType) {
this.placeType = placeType;
return this;
}
public Function<CombMetricsCollector<TimeCounterEvent>, AbstractMetricsListener> getEventFunc() {
public Function<CombMetricsCollector, AbstractMetricsKeyListener> getEventFunc() {
return eventFunc;
}

View File

@ -39,12 +39,12 @@ public enum MetricsKey {
METRIC_REQUESTS_TOTAL_AGG("dubbo.%s.requests.total.aggregate", "Aggregated Total Requests"),
METRIC_REQUESTS_SUCCEED_AGG("dubbo.%s.requests.succeed.aggregate", "Aggregated Succeed Requests"),
METRIC_REQUESTS_FAILED_AGG("dubbo.%s.requests.failed.aggregate", "Aggregated Failed Requests"),
METRIC_REQUESTS_BUSINESS_FAILED_AGG("dubbo.%s.requests.business.failed.aggregate", "Aggregated Business Failed Requests"),
METRIC_REQUEST_BUSINESS_FAILED_AGG("dubbo.%s.requests.business.failed.aggregate", "Aggregated Business Failed Requests"),
METRIC_REQUESTS_TIMEOUT_AGG("dubbo.%s.requests.timeout.failed.aggregate", "Aggregated timeout Failed Requests"),
METRIC_REQUESTS_LIMIT_AGG("dubbo.%s.requests.limit.aggregate", "Aggregated limit Requests"),
METRIC_REQUESTS_TOTAL_FAILED_AGG("dubbo.%s.requests.failed.total.aggregate", "Aggregated failed total Requests"),
METRIC_REQUESTS_TOTAL_NETWORK_FAILED_AGG("dubbo.%s.requests.failed.network.total.aggregate", "Aggregated failed network total Requests"),
METRIC_REQUESTS_TOTAL_CODEC_FAILED_AGG("dubbo.%s.requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_REQUESTS_NETWORK_FAILED_AGG("dubbo.%s.requests.failed.network.total.aggregate", "Aggregated failed network total Requests"),
METRIC_REQUESTS_CODEC_FAILED_AGG("dubbo.%s.requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG("dubbo.%s.requests.failed.service.unavailable.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_QPS("dubbo.%s.qps.total", "Query Per Seconds"),

View File

@ -17,9 +17,11 @@
package org.apache.dubbo.metrics.model.key;
import io.micrometer.common.lang.Nullable;
import org.apache.dubbo.metrics.model.MetricsSupport;
import java.util.Map;
import java.util.Objects;
/**
* Let {@link MetricsKey MetricsKey} output dynamic, custom string content
@ -31,15 +33,21 @@ public class MetricsKeyWrapper {
*/
private final MetricsKey metricsKey;
/**
* The value corresponding to the MetricsKey placeholder (if exist)
*/
private final MetricsPlaceValue placeType;
private final MetricsPlaceType placeType;
public MetricsKeyWrapper(MetricsKey metricsKey, MetricsPlaceType placeType) {
/**
* When the MetricsPlaceType is null, it is equivalent to a single MetricsKey.
* Use the decorator mode to share a container with MetricsKey
*/
public MetricsKeyWrapper(MetricsKey metricsKey, @Nullable MetricsPlaceValue placeType) {
this.metricsKey = metricsKey;
this.placeType = placeType;
}
public MetricsPlaceType getPlaceType() {
public MetricsPlaceValue getPlaceType() {
return placeType;
}
@ -55,11 +63,14 @@ public class MetricsKeyWrapper {
return metricsKey == getMetricsKey() && registryOpType.equals(getType());
}
public boolean isServiceLevel() {
return getPlaceType().getMetricsLevel().equals(MetricsLevel.SERVICE);
public MetricsLevel getLevel() {
return getPlaceType().getMetricsLevel();
}
public String targetKey() {
if (placeType == null) {
return metricsKey.getName();
}
try {
return String.format(metricsKey.getName(), getType());
} catch (Exception ignore) {
@ -68,6 +79,9 @@ public class MetricsKeyWrapper {
}
public String targetDesc() {
if (placeType == null) {
return metricsKey.getDescription();
}
try {
return String.format(metricsKey.getDescription(), getType());
} catch (Exception ignore) {
@ -76,6 +90,37 @@ public class MetricsKeyWrapper {
}
public Map<String, String> tagName(String key) {
return isServiceLevel() ? MetricsSupport.serviceTags(key) : MetricsSupport.applicationTags(key);
MetricsLevel level = getLevel();
switch (level) {
case APP:
return MetricsSupport.applicationTags(key);
case SERVICE:
return MetricsSupport.serviceTags(key);
case METHOD:
return MetricsSupport.methodTags(key);
}
return MetricsSupport.applicationTags(key);
}
public static MetricsKeyWrapper wrapper(MetricsKey metricsKey) {
return new MetricsKeyWrapper(metricsKey, null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MetricsKeyWrapper wrapper = (MetricsKeyWrapper) o;
if (metricsKey != wrapper.metricsKey) return false;
return Objects.equals(placeType, wrapper.placeType);
}
@Override
public int hashCode() {
int result = metricsKey != null ? metricsKey.hashCode() : 0;
result = 31 * result + (placeType != null ? placeType.hashCode() : 0);
return result;
}
}

View File

@ -18,5 +18,5 @@
package org.apache.dubbo.metrics.model.key;
public enum MetricsLevel {
APP,SERVICE,CONFIG
APP, SERVICE, METHOD, CONFIG
}

View File

@ -17,18 +17,21 @@
package org.apache.dubbo.metrics.model.key;
public class MetricsPlaceType {
/**
* The value corresponding to the placeholder in {@link MetricsKey}
*/
public class MetricsPlaceValue {
private final String type;
private final MetricsLevel metricsLevel;
private MetricsPlaceType(String type, MetricsLevel metricsLevel) {
private MetricsPlaceValue(String type, MetricsLevel metricsLevel) {
this.type = type;
this.metricsLevel = metricsLevel;
}
public static MetricsPlaceType of(String type, MetricsLevel metricsLevel) {
return new MetricsPlaceType(type, metricsLevel);
public static MetricsPlaceValue of(String type, MetricsLevel metricsLevel) {
return new MetricsPlaceValue(type, metricsLevel);
}
public String getType() {
@ -38,4 +41,22 @@ public class MetricsPlaceType {
public MetricsLevel getMetricsLevel() {
return metricsLevel;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MetricsPlaceValue that = (MetricsPlaceValue) o;
if (!type.equals(that.type)) return false;
return metricsLevel == that.metricsLevel;
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + metricsLevel.hashCode();
return result;
}
}

View File

@ -44,4 +44,5 @@ public class TypeWrapper {
Assert.notNull(type, "Type can not be null");
return type.equals(postType) || type.equals(finishType) || type.equals(errorType);
}
}

View File

@ -17,23 +17,22 @@
package org.apache.dubbo.metrics.model.sample;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import java.util.Map;
public class CounterMetricSample<T extends Number> extends MetricSample {
public class CounterMetricSample<T extends Number> extends MetricSample {
private final T value;
public CounterMetricSample(String name, String description, Map<String, String> tags,
MetricsCategory category, T value ) {
MetricsCategory category, T value) {
super(name, description, tags, Type.COUNTER, category);
this.value = value;
}
public CounterMetricSample(String name, String description, Map<String, String> tags, MetricsCategory category,
String baseUnit, T value) {
super(name, description, tags, Type.COUNTER, category, baseUnit);
this.value = value;
public CounterMetricSample(MetricsKeyWrapper metricsKeyWrapper, Map<String, String> tags, MetricsCategory category, T value) {
this(metricsKeyWrapper.targetKey(), metricsKeyWrapper.targetDesc(), tags, category, value);
}
public T getValue() {

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.metrics.model.sample;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import java.util.Map;
import java.util.Objects;
@ -37,6 +38,10 @@ public class GaugeMetricSample<T> extends MetricSample {
this(metricsKey.getName(), metricsKey.getDescription(), tags, category, null, value, apply);
}
public GaugeMetricSample(MetricsKeyWrapper metricsKeyWrapper, Map<String, String> tags, MetricsCategory category, T value, ToDoubleFunction<T> apply) {
this(metricsKeyWrapper.targetKey(), metricsKeyWrapper.targetDesc(), tags, category, null, value, apply);
}
public GaugeMetricSample(String name, String description, Map<String, String> tags, MetricsCategory category, T value, ToDoubleFunction<T> apply) {
this(name, description, tags, category, null, value, apply);
}

View File

@ -18,7 +18,7 @@
package org.apache.dubbo.metrics.report;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import java.util.List;
@ -31,6 +31,6 @@ public interface MetricsExport {
/**
* export all.
*/
List<GaugeMetricSample> export(MetricsCategory category);
List<MetricSample> export(MetricsCategory category);
}

View File

@ -19,8 +19,8 @@ package org.apache.dubbo.metrics.event;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.listener.MetricsLifeListener;
import org.apache.dubbo.metrics.listener.MetricsListener;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -39,7 +39,7 @@ public class SimpleMetricsEventMulticasterTest {
public void setup() {
eventMulticaster = new SimpleMetricsEventMulticaster();
objects = new Object[]{obj};
eventMulticaster.addListener(new MetricsListener<MetricsEvent>() {
eventMulticaster.addListener(new AbstractMetricsListener<MetricsEvent>() {
@Override
public void onEvent(MetricsEvent event) {
objects[0] = new Object();
@ -52,7 +52,7 @@ public class SimpleMetricsEventMulticasterTest {
ConfigManager configManager = new ConfigManager(applicationModel);
configManager.setApplication(applicationConfig);
applicationModel.setConfigManager(configManager);
requestEvent = new TimeCounterEvent(applicationModel) {
requestEvent = new TimeCounterEvent(applicationModel,null) {
};
}
@ -77,6 +77,11 @@ public class SimpleMetricsEventMulticasterTest {
//do onEventFinish with MetricsLifeListener
eventMulticaster.addListener((new MetricsLifeListener<TimeCounterEvent>() {
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof TimeCounterEvent;
}
@Override
public void onEvent(TimeCounterEvent event) {

View File

@ -22,9 +22,7 @@ import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metrics.collector.CombMetricsCollector;
import org.apache.dubbo.metrics.collector.MetricsCollector;
import org.apache.dubbo.metrics.config.event.ConfigCenterEvent;
import org.apache.dubbo.metrics.config.event.ConfigCenterMetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.config.event.ConfigCenterSubDispatcher;
import org.apache.dubbo.metrics.model.ConfigCenterMetric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
@ -45,7 +43,7 @@ import static org.apache.dubbo.metrics.model.MetricsCategory.CONFIGCENTER;
* Config center implementation of {@link MetricsCollector}
*/
@Activate
public class ConfigCenterMetricsCollector extends CombMetricsCollector<TimeCounterEvent> {
public class ConfigCenterMetricsCollector extends CombMetricsCollector<ConfigCenterEvent> {
private Boolean collectEnabled = null;
private final ApplicationModel applicationModel;
@ -55,7 +53,7 @@ public class ConfigCenterMetricsCollector extends CombMetricsCollector<TimeCount
public ConfigCenterMetricsCollector(ApplicationModel applicationModel) {
super(null);
this.applicationModel = applicationModel;
super.setEventMulticaster(new ConfigCenterMetricsDispatcher(this));
super.setEventMulticaster(new ConfigCenterSubDispatcher(this));
}
public void setCollectEnabled(Boolean collectEnabled) {
@ -94,9 +92,4 @@ public class ConfigCenterMetricsCollector extends CombMetricsCollector<TimeCount
}
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof ConfigCenterEvent;
}
}

View File

@ -44,8 +44,7 @@ public class ConfigCenterEvent extends TimeCounterEvent {
public ConfigCenterEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {
super(applicationModel);
super.typeWrapper = typeWrapper;
super(applicationModel,typeWrapper);
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
ConfigCenterMetricsCollector collector;
if (!beanFactory.isDestroyed()) {

View File

@ -20,7 +20,7 @@ import org.apache.dubbo.metrics.config.collector.ConfigCenterMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;
@ -30,11 +30,11 @@ import static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTAC
import static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_PROTOCOL;
public final class ConfigCenterMetricsDispatcher extends SimpleMetricsEventMulticaster {
public final class ConfigCenterSubDispatcher extends SimpleMetricsEventMulticaster {
public ConfigCenterMetricsDispatcher(ConfigCenterMetricsCollector collector) {
public ConfigCenterSubDispatcher(ConfigCenterMetricsCollector collector) {
super.addListener(new AbstractMetricsListener(MetricsKey.CONFIGCENTER_METRIC_TOTAL) {
super.addListener(new AbstractMetricsKeyListener(MetricsKey.CONFIGCENTER_METRIC_TOTAL) {
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof ConfigCenterEvent;

View File

@ -0,0 +1,70 @@
/*
* 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;
import org.apache.dubbo.common.constants.CommonConstants;
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 java.util.Arrays;
import java.util.List;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_CODEC_FAILED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_FAILED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_LIMIT;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_NETWORK_FAILED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TIMEOUT;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TOTAL_FAILED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;
public interface DefaultConstants {
String METRIC_FILTER_EVENT = "metric_filter_event";
String METRIC_THROWABLE = "metric_filter_throwable";
List<MetricsKeyWrapper> METHOD_LEVEL_KEYS = Arrays.asList(
new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUEST_BUSINESS_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUEST_BUSINESS_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_LIMIT, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_LIMIT, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_NETWORK_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_NETWORK_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD))
);
}

View File

@ -18,7 +18,6 @@
package org.apache.dubbo.metrics;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
@ -35,7 +34,6 @@ public class MetricsScopeModelInitializer implements ScopeModelInitializer {
@Override
public void initializeApplicationModel(ApplicationModel applicationModel) {
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
beanFactory.registerBean(DefaultMetricsCollector.class);
beanFactory.registerBean(MetricsDispatcher.class);
}

View File

@ -21,26 +21,32 @@ import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
import org.apache.dubbo.metrics.aggregate.TimeWindowQuantile;
import org.apache.dubbo.metrics.event.MethodEvent;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.listener.MetricsListener;
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.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.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
import static org.apache.dubbo.metrics.model.MetricsCategory.QPS;
import static org.apache.dubbo.metrics.model.MetricsCategory.REQUESTS;
import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
@ -49,68 +55,101 @@ 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, MetricsListener {
public class AggregateMetricsCollector implements MetricsCollector<RequestEvent> {
private int bucketNum;
private int timeWindowSeconds;
private final Map<String, ConcurrentHashMap<MethodMetric, TimeWindowCounter>> methodTypeCounter = new ConcurrentHashMap<>();
private final Map<MetricsKeyWrapper, ConcurrentHashMap<MethodMetric, TimeWindowCounter>> methodTypeCounter = new ConcurrentHashMap<>();
private final ConcurrentMap<MethodMetric, TimeWindowQuantile> rt = new ConcurrentHashMap<>();
private final ConcurrentHashMap<MethodMetric, TimeWindowCounter> qps = new ConcurrentHashMap<>();
private final ApplicationModel applicationModel;
private static final Integer DEFAULT_COMPRESSION = 100;
private static final Integer DEFAULT_BUCKET_NUM = 10;
private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120;
private Boolean collectEnabled = null;
public AggregateMetricsCollector(ApplicationModel applicationModel) {
this.registryEventTypeHandler();
this.applicationModel = applicationModel;
ConfigManager configManager = applicationModel.getApplicationConfigManager();
MetricsConfig config = configManager.getMetrics().orElse(null);
if (config != null && config.getAggregation() != null && (Boolean.TRUE.equals(config.getAggregation().getEnabled()))) {
if (isCollectEnabled()) {
// only registered when aggregation is enabled.
registerListener();
AggregationConfig aggregation = config.getAggregation();
this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum();
this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds();
Optional<MetricsConfig> optional = configManager.getMetrics();
if (optional.isPresent()) {
registerListener();
AggregationConfig aggregation = optional.get().getAggregation();
this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum();
this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds();
}
}
}
public void setCollectEnabled(Boolean collectEnabled) {
if (collectEnabled != null) {
this.collectEnabled = collectEnabled;
}
}
@Override
public boolean isCollectEnabled() {
if (collectEnabled == null) {
ConfigManager configManager = applicationModel.getApplicationConfigManager();
configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getAggregation().getEnabled()));
}
return Optional.ofNullable(collectEnabled).orElse(true);
}
@Override
public void onEvent(MetricsEvent event) {
if (event instanceof RTEvent) {
onRTEvent((RTEvent) event);
} else if (event instanceof MethodEvent) {
onRequestEvent((MethodEvent) event);
}
public boolean isSupport(MetricsEvent event) {
return event instanceof RequestEvent;
}
private void onRTEvent(RTEvent event) {
MethodMetric metric = (MethodMetric) event.getMetric();
Long responseTime = event.getRt();
@Override
public void onEvent(RequestEvent event) {
MethodMetric metric = calcWindowCounter(event, MetricsKey.METRIC_REQUESTS);
TimeWindowCounter qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
qpsCounter.increment();
}
@Override
public void onEventFinish(RequestEvent event) {
MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_SUCCEED;
Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);
if (throwableObj != null) {
targetKey = MetricsSupport.getAggMetricsKey((RpcException) throwableObj);
}
calcWindowCounter(event, targetKey);
onRTEvent(event);
}
@Override
public void onEventError(RequestEvent event) {
MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_FAILED;
Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);
if (throwableObj != null) {
targetKey = MetricsSupport.getAggMetricsKey((RpcException) throwableObj);
}
calcWindowCounter(event, targetKey);
onRTEvent(event);
}
private void onRTEvent(RequestEvent event) {
MethodMetric metric = new MethodMetric(applicationModel.getApplicationName(), event.getAttachmentValue(MetricsConstants.INVOCATION));
long responseTime = event.getTimePair().calc();
TimeWindowQuantile quantile = ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));
quantile.add(responseTime);
}
private void onRequestEvent(MethodEvent event) {
MethodMetric metric = event.getMethodMetric();
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.getApplicationName(), event.getAttachmentValue(MetricsConstants.INVOCATION));
String type = event.getType();
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.get(type);
if (counter == null) {
return;
}
TimeWindowCounter windowCounter = ConcurrentHashMapUtils.computeIfAbsent(counter, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
if (MetricsEvent.Type.TOTAL.getNameByType(PROVIDER_SIDE).equals(type)
|| MetricsEvent.Type.TOTAL.getNameByType(CONSUMER_SIDE).equals(type)) {
TimeWindowCounter qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
qpsCounter.increment();
}
windowCounter.increment();
return metric;
}
@Override
@ -129,21 +168,21 @@ public class AggregateMetricsCollector implements MetricsCollector, MetricsListe
}
private void collectBySide(List<MetricSample> list, String side) {
collectMethod(list, MetricsEvent.Type.TOTAL.getNameByType(side), MetricsKey.METRIC_REQUESTS_TOTAL_AGG);
collectMethod(list, MetricsEvent.Type.SUCCEED.getNameByType(side), MetricsKey.METRIC_REQUESTS_SUCCEED_AGG);
collectMethod(list, MetricsEvent.Type.UNKNOWN_FAILED.getNameByType(side), MetricsKey.METRIC_REQUESTS_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.BUSINESS_FAILED.getNameByType(side), MetricsKey.METRIC_REQUESTS_BUSINESS_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.REQUEST_TIMEOUT.getNameByType(side), MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG);
collectMethod(list, MetricsEvent.Type.REQUEST_LIMIT.getNameByType(side), MetricsKey.METRIC_REQUESTS_LIMIT_AGG);
collectMethod(list, MetricsEvent.Type.TOTAL_FAILED.getNameByType(side), MetricsKey.METRIC_REQUESTS_TOTAL_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.NETWORK_EXCEPTION.getNameByType(side), MetricsKey.METRIC_REQUESTS_TOTAL_NETWORK_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.CODEC_EXCEPTION.getNameByType(side), MetricsKey.METRIC_REQUESTS_TOTAL_CODEC_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.SERVICE_UNAVAILABLE.getNameByType(side), MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG);
collectMethod(list, MetricsEvent.Type.NO_INVOKER_AVAILABLE.getNameByType(side), MetricsKey.INVOKER_NO_AVAILABLE_COUNT);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_SUCCEED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_FAILED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_LIMIT_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_FAILED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG);
collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG);
}
private void collectMethod(List<MetricSample> list, String eventType, MetricsKey metricsKey) {
ConcurrentHashMap<MethodMetric, TimeWindowCounter> windowCounter = methodTypeCounter.get(eventType);
private void collectMethod(List<MetricSample> list, String side, MetricsKey metricsKey) {
MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(metricsKey, MetricsPlaceValue.of(side, MetricsLevel.SERVICE));
ConcurrentHashMap<MethodMetric, TimeWindowCounter> windowCounter = methodTypeCounter.get(metricsKeyWrapper);
if (windowCounter != null) {
windowCounter.forEach((k, v) -> list.add(new GaugeMetricSample<>(metricsKey.getNameByType(k.getSide()),
metricsKey.getDescription(), k.getTags(), REQUESTS, v, TimeWindowCounter::get)));
@ -164,27 +203,8 @@ public class AggregateMetricsCollector implements MetricsCollector, MetricsListe
});
}
private void registryEventTypeHandler() {
registryBySide(PROVIDER_SIDE);
registryBySide(CONSUMER_SIDE);
}
private void registryBySide(String side) {
methodTypeCounter.put(MetricsEvent.Type.TOTAL.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.SUCCEED.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.UNKNOWN_FAILED.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.BUSINESS_FAILED.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.REQUEST_TIMEOUT.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.REQUEST_LIMIT.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.TOTAL_FAILED.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.SERVICE_UNAVAILABLE.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.NETWORK_EXCEPTION.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.CODEC_EXCEPTION.getNameByType(side), new ConcurrentHashMap<>());
methodTypeCounter.put(MetricsEvent.Type.NO_INVOKER_AVAILABLE.getNameByType(side), new ConcurrentHashMap<>());
}
private void registerListener() {
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this);
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).getEventMulticaster().addListener(this);
}
}

View File

@ -16,48 +16,71 @@
*/
package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.DefaultConstants;
import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer;
import org.apache.dubbo.metrics.collector.sample.MetricsSampler;
import org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler;
import org.apache.dubbo.metrics.collector.sample.ThreadPoolMetricsSampler;
import org.apache.dubbo.metrics.data.BaseStatComposite;
import org.apache.dubbo.metrics.data.MethodStatComposite;
import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.event.DefaultSubDispatcher;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;
import org.apache.dubbo.metrics.listener.MetricsListener;
import org.apache.dubbo.metrics.event.RequestBeforeEvent;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.ApplicationMetric;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.List;
import static org.apache.dubbo.metrics.model.MetricsCategory.APPLICATION;
import static org.apache.dubbo.metrics.model.key.MetricsKey.APPLICATION_METRIC_INFO;
/**
* Default implementation of {@link MetricsCollector}
*/
public class DefaultMetricsCollector implements MetricsCollector {
@Activate
public class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent> {
private boolean collectEnabled = false;
private volatile boolean threadpoolCollectEnabled=false;
private final SimpleMetricsEventMulticaster eventMulticaster;
private final MethodMetricsSampler methodSampler = new MethodMetricsSampler(this);
private volatile boolean threadpoolCollectEnabled = false;
private final ThreadPoolMetricsSampler threadPoolSampler = new ThreadPoolMetricsSampler(this);
private String applicationName;
private ApplicationModel applicationModel;
private final List<MetricsSampler> samplers = new ArrayList<>();
public DefaultMetricsCollector() {
this.eventMulticaster = new SimpleMetricsEventMulticaster();
samplers.add(methodSampler);
super(new BaseStatComposite() {
@Override
protected void init(MethodStatComposite methodStatComposite) {
methodStatComposite.initWrapper(DefaultConstants.METHOD_LEVEL_KEYS);
}
@Override
protected void init(RtStatComposite rtStatComposite) {
rtStatComposite.init(MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD),
MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD));
}
});
super.setEventMulticaster(new DefaultSubDispatcher(this));
samplers.add(applicationSampler);
samplers.add(threadPoolSampler);
}
public void addSampler(MetricsSampler sampler){
public void addSampler(MetricsSampler sampler) {
samplers.add(sampler);
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
@ -70,10 +93,6 @@ public class DefaultMetricsCollector implements MetricsCollector {
return this.applicationModel;
}
public SimpleMetricsEventMulticaster getEventMulticaster() {
return this.eventMulticaster;
}
public void setCollectEnabled(Boolean collectEnabled) {
this.collectEnabled = collectEnabled;
}
@ -90,14 +109,6 @@ public class DefaultMetricsCollector implements MetricsCollector {
this.threadpoolCollectEnabled = threadpoolCollectEnabled;
}
public MethodMetricsSampler getMethodSampler() {
return this.methodSampler;
}
public ThreadPoolMetricsSampler getThreadPoolSampler() {
return this.threadPoolSampler;
}
public void collectApplication(ApplicationModel applicationModel) {
this.setApplicationName(applicationModel.getApplicationName());
this.applicationModel = applicationModel;
@ -111,15 +122,21 @@ public class DefaultMetricsCollector implements MetricsCollector {
@Override
public List<MetricSample> collect() {
List<MetricSample> list = new ArrayList<>();
if (!isCollectEnabled()) {
return list;
}
for (MetricsSampler sampler : samplers) {
List<MetricSample> sample = sampler.sample();
list.addAll(sample);
}
list.addAll(super.export(MetricsCategory.REQUESTS));
return list;
}
public void addListener(MetricsListener listener) {
this.eventMulticaster.addListener(listener);
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof RequestEvent || event instanceof RequestBeforeEvent;
}
public SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric> applicationSampler = new SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric>() {
@ -127,17 +144,17 @@ public class DefaultMetricsCollector implements MetricsCollector {
public List<MetricSample> sample() {
List<MetricSample> samples = new ArrayList<>();
this.getCount(MetricsEvent.Type.APPLICATION_INFO).filter(e -> !e.isEmpty())
.ifPresent(map -> map.forEach((k, v) ->
samples.add(new CounterMetricSample<>(APPLICATION_METRIC_INFO.getName(),
APPLICATION_METRIC_INFO.getDescription(),
k.getTags(), APPLICATION, v)))
);
.ifPresent(map -> map.forEach((k, v) ->
samples.add(new CounterMetricSample<>(APPLICATION_METRIC_INFO.getName(),
APPLICATION_METRIC_INFO.getDescription(),
k.getTags(), APPLICATION, v)))
);
return samples;
}
@Override
protected void countConfigure(
MetricsCountSampleConfigurer<String, MetricsEvent.Type, ApplicationMetric> sampleConfigure) {
MetricsCountSampleConfigurer<String, MetricsEvent.Type, ApplicationMetric> sampleConfigure) {
sampleConfigure.configureMetrics(configure -> new ApplicationMetric(sampleConfigure.getSource()));
}
};

View File

@ -22,22 +22,25 @@ import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.nested.HistogramConfig;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.MetricsGlobalRegistry;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.listener.MetricsListener;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.register.HistogramMetricRegister;
import org.apache.dubbo.metrics.sample.HistogramMetricSample;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
public class HistogramMetricsCollector implements MetricsListener {
public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEvent> implements MetricsCollector<RequestEvent> {
private final ConcurrentHashMap<MethodMetric, Timer> rt = new ConcurrentHashMap<>();
private HistogramMetricRegister metricRegister;
@ -63,20 +66,28 @@ public class HistogramMetricsCollector implements MetricsListener {
}
private void registerListener() {
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this);
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).getEventMulticaster().addListener(this);
}
@Override
public void onEvent(MetricsEvent event) {
if (event instanceof RTEvent) {
onRTEvent((RTEvent) event);
}
public void onEvent(RequestEvent event) {
}
private void onRTEvent(RTEvent event) {
@Override
public void onEventFinish(RequestEvent event) {
onRTEvent(event);
}
@Override
public void onEventError(RequestEvent event) {
onRTEvent(event);
}
private void onRTEvent(RequestEvent event) {
if (metricRegister != null) {
MethodMetric metric = (MethodMetric) event.getMetric();
Long responseTime = event.getRt();
MethodMetric metric = new MethodMetric(applicationModel.getApplicationName(), event.getAttachmentValue(MetricsConstants.INVOCATION));
long responseTime = event.getTimePair().calc();
HistogramMetricSample sample = new HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),
MetricsKey.METRIC_RT_HISTOGRAM.getDescription(), metric.getTags(), RT);
@ -85,4 +96,9 @@ public class HistogramMetricsCollector implements MetricsListener {
timer.record(responseTime, TimeUnit.MILLISECONDS);
}
}
@Override
public List<MetricSample> collect() {
return new ArrayList<>();
}
}

View File

@ -1,133 +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.collector.sample;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MethodEvent;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.Metric;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.Invocation;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.ToDoubleFunction;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
public class MethodMetricsSampler extends SimpleMetricsCountSampler<Invocation, String, MethodMetric> {
private final DefaultMetricsCollector collector;
public MethodMetricsSampler(DefaultMetricsCollector collector) {
this.collector = collector;
}
@Override
protected void countConfigure(
MetricsCountSampleConfigurer<Invocation, String, MethodMetric> sampleConfigure) {
sampleConfigure.configureMetrics(configure -> new MethodMetric(collector.getApplicationName(), configure.getSource()));
sampleConfigure.configureEventHandler(configure -> collector.getEventMulticaster().publishEvent(new MethodEvent(collector.getApplicationModel(), configure.getMetric(),
configure.getMetricName())));
}
@Override
public void rtConfigure(
MetricsCountSampleConfigurer<Invocation, String, MethodMetric> sampleConfigure) {
sampleConfigure.configureMetrics(configure -> new MethodMetric(collector.getApplicationName(), configure.getSource()));
sampleConfigure.configureEventHandler(configure -> collector.getEventMulticaster().publishEvent(new RTEvent(collector.getApplicationModel(), configure.getMetric(), configure.getRt())));
}
@Override
public List<MetricSample> sample() {
List<MetricSample> metricSamples = new ArrayList<>();
collect(metricSamples);
metricSamples.addAll(
this.collectRT(new MetricSampleFactory<MethodMetric, GaugeMetricSample<?>>() {
@Override
public <T> GaugeMetricSample<?> newInstance(MetricsKey key, MethodMetric metric, T value, ToDoubleFunction<T> apply) {
return createGaugeMetricSample(key, metric, MetricsCategory.RT, value, apply);
}
}));
return metricSamples;
}
private void collect(List<MetricSample> list) {
collectBySide(list, PROVIDER_SIDE);
collectBySide(list, CONSUMER_SIDE);
}
private void collectBySide(List<MetricSample> list, String side) {
count(list, MetricsEvent.Type.TOTAL.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS);
count(list, MetricsEvent.Type.SUCCEED.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_SUCCEED);
count(list, MetricsEvent.Type.UNKNOWN_FAILED.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_FAILED);
count(list, MetricsEvent.Type.PROCESSING.getNameByType(side), MetricSample.Type.GAUGE, MetricsKey.METRIC_REQUESTS_PROCESSING);
count(list, MetricsEvent.Type.BUSINESS_FAILED.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUEST_BUSINESS_FAILED);
count(list, MetricsEvent.Type.REQUEST_TIMEOUT.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_TIMEOUT);
count(list, MetricsEvent.Type.REQUEST_LIMIT.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_LIMIT);
count(list, MetricsEvent.Type.TOTAL_FAILED.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_TOTAL_FAILED);
count(list, MetricsEvent.Type.NETWORK_EXCEPTION.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_NETWORK_FAILED);
count(list, MetricsEvent.Type.SERVICE_UNAVAILABLE.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED);
count(list, MetricsEvent.Type.CODEC_EXCEPTION.getNameByType(side), MetricSample.Type.COUNTER, MetricsKey.METRIC_REQUESTS_CODEC_FAILED);
}
private <T> GaugeMetricSample<T> createGaugeMetricSample(MetricsKey metricsKey,
MethodMetric methodMetric,
MetricsCategory metricsCategory,
T value,
ToDoubleFunction<T> apply) {
return new GaugeMetricSample<>(
metricsKey.getNameByType(methodMetric.getSide()),
metricsKey.getDescription(),
methodMetric.getTags(),
metricsCategory,
value,
apply);
}
private <T extends Metric> void count(List<MetricSample> list, String eventType, MetricSample.Type type, MetricsKey metricsKey) {
getCount(eventType).filter(e -> !e.isEmpty())
.ifPresent(map -> map.forEach((k, v) -> {
if(type == MetricSample.Type.COUNTER){
list.add(createCounterMetricSample(metricsKey, k, MetricsCategory.REQUESTS, v));
}else if(type == MetricSample.Type.GAUGE){
list.add(createGaugeMetricSample(metricsKey, k, MetricsCategory.REQUESTS, v, AtomicLong::get));
}
}
));
}
private MetricSample createCounterMetricSample(MetricsKey metricsKey, MethodMetric methodMetric, MetricsCategory metricsCategory, AtomicLong value) {
return new CounterMetricSample<>(metricsKey.getNameByType(methodMetric.getSide()),
metricsKey.getDescription(),
methodMetric.getTags(), metricsCategory, value);
}
}

View File

@ -52,20 +52,10 @@ public class MetricsCountSampleConfigurer<S,K,M extends Metric> {
return this;
}
public MetricsCountSampleConfigurer<S,K,M> configureEventHandler(
Consumer<MetricsCountSampleConfigurer<S,K,M>> fireEventHandler){
this.fireEventHandler = fireEventHandler;
return this;
}
public S getSource() {
return source;
}
public K getMetricName() {
return metricName;
}
public M getMetric() {
return metric;
}

View File

@ -18,36 +18,17 @@
package org.apache.dubbo.metrics.collector.sample;
import org.apache.dubbo.metrics.model.Metric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.ToDoubleFunction;
public interface MetricsCountSampler<S, K, M extends Metric> extends MetricsSampler {
void inc(S source, K metricName);
void dec(S source, K metricName);
void incOnEvent(S source, K metricName);
void decOnEvent(S source, K metricName);
void addRT(S source, Long rt);
void addRT(S source, K metricName, Long rt);
Optional<ConcurrentMap<M, AtomicLong>> getCount(K metricName);
<R extends MetricSample> List<R> collectRT(MetricSampleFactory<M, R> factory);
<R extends MetricSample> List<R> collectRT(MetricSampleFactory<M, R> factory, K metricName);
interface MetricSampleFactory<M, R extends MetricSample> {
<T> R newInstance(MetricsKey key, M metric, T value, ToDoubleFunction<T> apply);
}
}

View File

@ -18,20 +18,13 @@
package org.apache.dubbo.metrics.collector.sample;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.metrics.model.Metric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.Function;
/**
@ -45,14 +38,6 @@ public abstract class SimpleMetricsCountSampler<S, K, M extends Metric>
private final ConcurrentMap<M, AtomicLong> EMPTY_COUNT = new ConcurrentHashMap<>();
private final Map<K, ConcurrentMap<M, AtomicLong>> metricCounter = new ConcurrentHashMap<>();
// lastRT, totalRT, rtCount, avgRT share a container, can utilize the system cache line
private final ConcurrentMap<M, AtomicLongArray> rtSample = new ConcurrentHashMap<>();
private final ConcurrentMap<M, LongAccumulator> minRT = new ConcurrentHashMap<>();
private final ConcurrentMap<M, LongAccumulator> maxRT = new ConcurrentHashMap<>();
private final ConcurrentMap<K, ConcurrentMap<M, AtomicLongArray>> rtGroupSample = new ConcurrentHashMap<>();
private final ConcurrentMap<K, ConcurrentMap<M, LongAccumulator>> groupMinRT = new ConcurrentHashMap<>();
private final ConcurrentMap<K, ConcurrentMap<M, LongAccumulator>> groupMaxRT = new ConcurrentHashMap<>();
@Override
public void inc(S source, K metricName) {
@ -62,14 +47,6 @@ public abstract class SimpleMetricsCountSampler<S, K, M extends Metric>
});
}
@Override
public void dec(S source, K metricName) {
doExecute(source, metricName, counter -> {
counter.decrementAndGet();
return false;
});
}
@Override
public void incOnEvent(S source, K metricName) {
doExecute(source, metricName, counter -> {
@ -78,91 +55,6 @@ public abstract class SimpleMetricsCountSampler<S, K, M extends Metric>
});
}
@Override
public void decOnEvent(S source, K metricName) {
doExecute(source, metricName, counter -> {
counter.decrementAndGet();
return true;
});
}
@Override
public void addRT(S source, Long rt) {
MetricsCountSampleConfigurer<S, K, M> sampleConfigure = new MetricsCountSampleConfigurer<>();
sampleConfigure.setSource(source);
this.rtConfigure(sampleConfigure);
M metric = sampleConfigure.getMetric();
AtomicLongArray rtCalculator = ConcurrentHashMapUtils.computeIfAbsent(this.rtSample, metric, k -> new AtomicLongArray(4));
// set lastRT
rtCalculator.set(0, rt);
// add to totalRT
rtCalculator.addAndGet(1, rt);
// add to rtCount
rtCalculator.incrementAndGet(2);
// calc avgRT. In order to reduce the amount of calculation, calculated when collect
//rtArray.set(3, Math.floorDiv(rtArray.get(1), rtArray.get(2)));
LongAccumulator min = ConcurrentHashMapUtils.computeIfAbsent(minRT, metric, k -> new LongAccumulator(Long::min, Long.MAX_VALUE));
min.accumulate(rt);
LongAccumulator max = ConcurrentHashMapUtils.computeIfAbsent(maxRT, metric, k -> new LongAccumulator(Long::max, Long.MIN_VALUE));
max.accumulate(rt);
sampleConfigure.setRt(rt);
sampleConfigure.getFireEventHandler().accept(sampleConfigure);
}
@Override
public void addRT(S source, K metricName, Long rt) {
MetricsCountSampleConfigurer<S, K, M> sampleConfigure = new MetricsCountSampleConfigurer<>();
sampleConfigure.setSource(source);
sampleConfigure.setMetricsName(metricName);
this.rtConfigure(sampleConfigure);
M metric = sampleConfigure.getMetric();
ConcurrentMap<M, AtomicLongArray> nameToCalculator = rtGroupSample.get(metricName);
if (nameToCalculator == null) {
ConcurrentHashMap<M, AtomicLongArray> calculator = new ConcurrentHashMap<>();
calculator.put(metric, new AtomicLongArray(4));
rtGroupSample.put(metricName, calculator);
nameToCalculator = rtGroupSample.get(metricName);
}
AtomicLongArray calculator = nameToCalculator.get(metric);
// set lastRT
calculator.set(0, rt);
// add to totalRT
calculator.addAndGet(1, rt);
// add to rtCount
calculator.incrementAndGet(2);
ConcurrentMap<M, LongAccumulator> minRT = ConcurrentHashMapUtils.computeIfAbsent(groupMinRT, metricName, k -> new ConcurrentHashMap<>());
LongAccumulator min = ConcurrentHashMapUtils.computeIfAbsent(minRT, metric, k -> new LongAccumulator(Long::min, Long.MAX_VALUE));
min.accumulate(rt);
ConcurrentMap<M, LongAccumulator> maxRT = ConcurrentHashMapUtils.computeIfAbsent(groupMaxRT, metricName, k -> new ConcurrentHashMap<>());
LongAccumulator max = ConcurrentHashMapUtils.computeIfAbsent(maxRT, metric, k -> new LongAccumulator(Long::max, Long.MIN_VALUE));
max.accumulate(rt);
sampleConfigure.setRt(rt);
sampleConfigure.getFireEventHandler().accept(sampleConfigure);
}
@Override
public Optional<ConcurrentMap<M, AtomicLong>> getCount(K metricName) {
return Optional.ofNullable(metricCounter.get(metricName) == null ?
@ -170,42 +62,6 @@ public abstract class SimpleMetricsCountSampler<S, K, M extends Metric>
metricCounter.get(metricName));
}
@Override
public <R extends MetricSample> List<R> collectRT(MetricSampleFactory<M, R> factory) {
return collect(factory, rtSample, this.minRT, this.maxRT);
}
@Override
public <R extends MetricSample> List<R> collectRT(MetricSampleFactory<M, R> factory, K metricName) {
return collect(factory, rtGroupSample.get(metricName), groupMinRT.get(metricName), groupMaxRT.get(metricName));
}
private <R extends MetricSample> List<R> collect(MetricSampleFactory<M, R> factory,
ConcurrentMap<M, AtomicLongArray> rtSample,
ConcurrentMap<M, LongAccumulator> min,
ConcurrentMap<M, LongAccumulator> max) {
final List<R> result = new ArrayList<>();
rtSample.forEach((k, v) -> {
// lastRT
result.add(factory.newInstance(MetricsKey.METRIC_RT_LAST, k, v, value -> value.get(0)));
// totalRT
result.add(factory.newInstance(MetricsKey.METRIC_RT_SUM, k, v, value -> value.get(1)));
// avgRT
result.add(factory.newInstance(MetricsKey.METRIC_RT_AVG, k, v, value -> Math.floorDiv(value.get(1), value.get(2))));
});
min.forEach((k, v) ->
result.add(factory.newInstance(MetricsKey.METRIC_RT_MIN, k, v, LongAccumulator::get)));
max.forEach((k, v) ->
result.add(factory.newInstance(MetricsKey.METRIC_RT_MAX, k, v, LongAccumulator::get)));
return result;
}
protected void rtConfigure(MetricsCountSampleConfigurer<S, K, M> configure) {
}
protected abstract void countConfigure(MetricsCountSampleConfigurer<S, K, M> sampleConfigure);
private void doExecute(S source, K metricsName, Function<AtomicLong, Boolean> counter) {

View File

@ -0,0 +1,113 @@
/*
* 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.common.constants.CommonConstants;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.collector.MethodMetricsCollector;
import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;
import org.apache.dubbo.metrics.listener.MetricsListener;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.CategoryOverall;
import org.apache.dubbo.metrics.model.key.MetricsCat;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.RpcException;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
import static org.apache.dubbo.metrics.MetricsConstants.INVOCATION;
import static org.apache.dubbo.metrics.MetricsConstants.INVOCATION_METRICS_COUNTER;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;
@SuppressWarnings({"unchecked", "rawtypes"})
public final class DefaultSubDispatcher extends SimpleMetricsEventMulticaster {
public DefaultSubDispatcher(DefaultMetricsCollector collector) {
CategoryOverall categoryOverall = initMethodRequest();
super.addListener(categoryOverall.getPost().getEventFunc().apply(collector));
super.addListener(categoryOverall.getFinish().getEventFunc().apply(collector));
super.addListener(categoryOverall.getError().getEventFunc().apply(collector));
super.addListener(new MetricsListener<RequestBeforeEvent>() {
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof RequestBeforeEvent;
}
@Override
public void onEvent(RequestBeforeEvent event) {
MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD);
MetricsSupport.increment(METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED, dynamicPlaceType, (MethodMetricsCollector) collector, event);
}
});
}
private CategoryOverall initMethodRequest() {
return new CategoryOverall(null,
new MetricsCat(MetricsKey.METRIC_REQUESTS, (key, placeType, collector) -> AbstractMetricsKeyListener.onEvent(key,
event ->
{
MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);
MetricsSupport.increment(key, dynamicPlaceType, (MethodMetricsCollector) collector, event);
// METRIC_REQUESTS_PROCESSING use GAUGE
Invocation invocation = event.getAttachmentValue(INVOCATION);
invocation.put(INVOCATION_METRICS_COUNTER, MetricSample.Type.GAUGE);
MetricsSupport.increment(MetricsKey.METRIC_REQUESTS_PROCESSING, dynamicPlaceType, (MethodMetricsCollector) collector, event);
})),
new MetricsCat(MetricsKey.METRIC_REQUESTS_SUCCEED, (key, placeType, collector) -> AbstractMetricsKeyListener.onFinish(key,
event ->
{
MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);
MetricsSupport.dec(MetricsKey.METRIC_REQUESTS_PROCESSING, dynamicPlaceType, (MethodMetricsCollector) collector, event);
Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);
MetricsKey targetKey;
if (throwableObj == null) {
targetKey = key;
} else {
targetKey = MetricsSupport.getMetricsKey((RpcException) throwableObj);
}
MetricsSupport.incrAndAddRt(targetKey, dynamicPlaceType, (MethodMetricsCollector) collector, event);
})),
new MetricsCat(MetricsKey.METRIC_REQUEST_BUSINESS_FAILED, (key, placeType, collector) -> AbstractMetricsKeyListener.onError(key,
event ->
{
Throwable throwable = event.getAttachmentValue(METRIC_THROWABLE);
MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_FAILED_AGG;
if (throwable instanceof RpcException) {
targetKey = MetricsSupport.getMetricsKey((RpcException) throwable);
}
// Dynamic metricsKey && dynamicPlaceType
MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);
MetricsSupport.increment(MetricsKey.METRIC_REQUESTS_TOTAL_FAILED, dynamicPlaceType, (MethodMetricsCollector) collector, event);
MetricsSupport.dec(MetricsKey.METRIC_REQUESTS_PROCESSING, dynamicPlaceType, (MethodMetricsCollector) collector, event);
MetricsSupport.incrAndAddRt(targetKey, dynamicPlaceType, (MethodMetricsCollector) collector, event);
}
)));
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.metrics.MetricsConstants;
import org.apache.dubbo.metrics.model.MetricsSupport;
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.rpc.Invocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
/**
* Acts on MetricsClusterFilter to monitor exceptions that occur before request execution
*/
public class RequestBeforeEvent extends TimeCounterEvent {
public RequestBeforeEvent(ApplicationModel source, TypeWrapper typeWrapper) {
super(source, typeWrapper);
}
public static RequestBeforeEvent toEvent(ApplicationModel applicationModel, Invocation invocation) {
RequestBeforeEvent event = new RequestBeforeEvent(applicationModel, new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS));
event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
event.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));
event.putAttachment(MetricsConstants.INVOCATION, invocation);
return event;
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.exception.MetricsNeverHappenException;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.model.ApplicationModel;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;
/**
* Request related events
*/
public class RequestEvent extends TimeCounterEvent {
public RequestEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {
super(applicationModel,typeWrapper);
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
DefaultMetricsCollector collector;
if (!beanFactory.isDestroyed()) {
collector = beanFactory.getBean(DefaultMetricsCollector.class);
super.setAvailable(collector != null && collector.isCollectEnabled());
}
}
public static RequestEvent toRequestEvent(ApplicationModel applicationModel, Invocation invocation) {
RequestEvent requestEvent = new RequestEvent(applicationModel, new TypeWrapper(MetricsLevel.SERVICE, METRIC_REQUESTS, METRIC_REQUESTS_SUCCEED, METRIC_REQUEST_BUSINESS_FAILED)) {
@Override
public void customAfterPost(Object postResult) {
if (postResult == null) {
return;
}
if (!(postResult instanceof Result)) {
throw new MetricsNeverHappenException("Result type error, postResult:" + postResult.getClass().getName());
}
super.putAttachment(METRIC_THROWABLE, ((Result) postResult).getException());
}
};
requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
requestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
requestEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));
return requestEvent;
}
}

View File

@ -1,110 +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.filter;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.common.constants.MetricsConstants.METRIC_FILTER_START_TIME;
public class MethodMetricsInterceptor {
private final MethodMetricsSampler sampler;
public MethodMetricsInterceptor(MethodMetricsSampler sampler) {
this.sampler = sampler;
}
public void beforeMethod(Invocation invocation) {
String side = getSide(invocation);
sampler.incOnEvent(invocation, MetricsEvent.Type.TOTAL.getNameByType(side));
sampler.incOnEvent(invocation, MetricsEvent.Type.PROCESSING.getNameByType(side));
invocation.put(METRIC_FILTER_START_TIME, System.currentTimeMillis());
}
private String getSide(Invocation invocation) {
Optional<? extends Invoker<?>> invoker = Optional.ofNullable(invocation.getInvoker());
return invoker.isPresent() ? invoker.get().getUrl().getSide() : PROVIDER_SIDE;
}
public void afterMethod(Invocation invocation, Result result) {
if (result.hasException()) {
handleMethodException(invocation, result.getException(), true);
} else {
sampler.incOnEvent(invocation, MetricsEvent.Type.SUCCEED.getNameByType(getSide(invocation)));
onCompleted(invocation);
}
}
public void handleMethodException(Invocation invocation, Throwable throwable, boolean isBusiness) {
if (throwable == null) {
return;
}
String side = getSide(invocation);
MetricsEvent.Type eventType = MetricsEvent.Type.UNKNOWN_FAILED;
if (isBusiness) {
eventType = MetricsEvent.Type.BUSINESS_FAILED;
} else if (throwable instanceof RpcException) {
RpcException e = (RpcException) throwable;
if (e.isTimeout()) {
eventType = MetricsEvent.Type.REQUEST_TIMEOUT;
}
if (e.isLimitExceed()) {
eventType = MetricsEvent.Type.REQUEST_LIMIT;
}
if (e.isBiz()) {
eventType = MetricsEvent.Type.BUSINESS_FAILED;
}
if (e.isSerialization()) {
eventType = MetricsEvent.Type.CODEC_EXCEPTION;
}
if (e.isNetwork()) {
eventType = MetricsEvent.Type.NETWORK_EXCEPTION;
}
if (e.isNoInvokerAvailableAfterFilter() && CommonConstants.CONSUMER_SIDE.equals(side)) {
eventType = MetricsEvent.Type.NO_INVOKER_AVAILABLE;
}
}
sampler.incOnEvent(invocation, eventType.getNameByType(side));
onCompleted(invocation);
sampler.incOnEvent(invocation, MetricsEvent.Type.TOTAL_FAILED.getNameByType(side));
}
private void rtTime(Invocation invocation) {
Long endTime = System.currentTimeMillis();
Long beginTime = (Long) invocation.get(METRIC_FILTER_START_TIME);
Long rt = endTime - beginTime;
sampler.addRT(invocation, rt);
}
private void onCompleted(Invocation invocation) {
rtTime(invocation);
sampler.dec(invocation, MetricsEvent.Type.PROCESSING.getNameByType(getSide(invocation)));
}
}

View File

@ -19,7 +19,8 @@ package org.apache.dubbo.metrics.filter;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
@ -32,61 +33,57 @@ import org.apache.dubbo.rpc.model.ScopeModelAware;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_FILTER_EVENT;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
@Activate(group = {CONSUMER, PROVIDER}, order = Integer.MIN_VALUE + 100)
public class MetricsFilter implements Filter, BaseFilter.Listener, ScopeModelAware {
private ApplicationModel applicationModel;
private final static ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(MetricsFilter.class);
private DefaultMetricsCollector collector = null;
private MethodMetricsInterceptor metricsInterceptor;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
if (collector != null) {
metricsInterceptor = new MethodMetricsInterceptor(collector.getMethodSampler());
}
this.applicationModel = applicationModel;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (collector == null || !collector.isCollectEnabled()) {
return invoker.invoke(invocation);
}
try {
metricsInterceptor.beforeMethod(invocation);
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, invocation);
MetricsEventBus.before(requestEvent, () -> invocation.put(METRIC_FILTER_EVENT, requestEvent));
} catch (Throwable t) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when beforeMethod.", t);
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when invoke.", t);
}
return invoker.invoke(invocation);
}
@Override
public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
if (collector == null || !collector.isCollectEnabled()) {
return;
}
try {
metricsInterceptor.afterMethod(invocation, result);
} catch (Throwable t) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when afterMethod.", t);
Object eventObj = invocation.get(METRIC_FILTER_EVENT);
if (eventObj != null) {
try {
MetricsEventBus.after((RequestEvent) eventObj, result);
} catch (Throwable t) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when onResponse.", t);
}
}
}
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
if (collector == null || !collector.isCollectEnabled()) {
return;
}
try {
metricsInterceptor.handleMethodException(invocation, t, false);
} catch (Throwable t1) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when handleMethodException.", t1);
Object eventObj = invocation.get(METRIC_FILTER_EVENT);
if (eventObj != null) {
try {
RequestEvent requestEvent = (RequestEvent) eventObj;
requestEvent.putAttachment(METRIC_THROWABLE, t);
MetricsEventBus.error(requestEvent);
} catch (Throwable throwable) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when onResponse.", throwable);
}
}
}
}

View File

@ -0,0 +1 @@
default-collector=org.apache.dubbo.metrics.collector.DefaultMetricsCollector

View File

@ -25,19 +25,29 @@ import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.TestMetricsInvoker;
import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestBeforeEvent;
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.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;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult;
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.model.ApplicationModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -57,9 +67,9 @@ import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
import static org.apache.dubbo.metrics.model.MetricsCategory.QPS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
class AggregateMetricsCollectorTest {
@ -72,6 +82,9 @@ class AggregateMetricsCollectorTest {
private String version;
private RpcInvocation invocation;
private String side;
private MetricsDispatcher metricsDispatcher;
private AggregateMetricsCollector collector;
private MetricsFilter metricsFilter;
public static MethodMetric getTestMethodMetric() {
@ -86,36 +99,13 @@ class AggregateMetricsCollectorTest {
return methodMetric;
}
public static AggregateMetricsCollector getTestCollector() {
ApplicationModel applicationModel = mock(ApplicationModel.class);
ConfigManager configManager = new ConfigManager(applicationModel);
MetricsConfig metricsConfig = spy(new MetricsConfig());
configManager.setMetrics(metricsConfig);
AggregationConfig aggregationConfig = spy(new AggregationConfig());
when(aggregationConfig.getEnabled()).thenReturn(true);
when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);
when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);
when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector());
when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
return new AggregateMetricsCollector(applicationModel);
}
@BeforeEach
public void setup() {
applicationModel = ApplicationModel.defaultModel();
ApplicationConfig config = new ApplicationConfig();
config.setName("MockMetrics");
applicationModel = ApplicationModel.defaultModel();
applicationModel.getApplicationConfigManager().setApplication(config);
defaultCollector = new DefaultMetricsCollector();
defaultCollector.setCollectEnabled(true);
MetricsConfig metricsConfig = new MetricsConfig();
AggregationConfig aggregationConfig = new AggregationConfig();
aggregationConfig.setEnabled(true);
@ -123,7 +113,16 @@ class AggregateMetricsCollectorTest {
aggregationConfig.setTimeWindowSeconds(120);
metricsConfig.setAggregation(aggregationConfig);
applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);
metricsDispatcher = applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
collector = applicationModel.getBeanFactory().getOrRegisterBean(AggregateMetricsCollector.class);
collector.setCollectEnabled(true);
defaultCollector = new DefaultMetricsCollector();
defaultCollector.setCollectEnabled(true);
metricsFilter = new MetricsFilter();
metricsFilter.setApplicationModel(applicationModel);
interfaceName = "org.apache.dubbo.MockInterface";
methodName = "mockMethod";
@ -135,10 +134,20 @@ class AggregateMetricsCollectorTest {
invocation.setAttachment(VERSION_KEY, version);
side = CommonConstants.CONSUMER;
invocation.setInvoker(new TestMetricsInvoker(side));
invocation.setTargetServiceUniqueName(group + "/" + interfaceName + ":" + version);
RpcContext.getServiceContext().setUrl(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=" + side));
}
@Test
void testListener() {
AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, invocation);
RequestBeforeEvent beforeEvent = new RequestBeforeEvent(applicationModel, new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertFalse(metricsCollector.isSupport(beforeEvent));
}
@AfterEach
public void teardown() {
applicationModel.destroy();
@ -147,19 +156,20 @@ class AggregateMetricsCollectorTest {
@Test
void testRequestsMetrics() {
String applicationName = applicationModel.getApplicationName();
AggregateMetricsCollector collector = new AggregateMetricsCollector(applicationModel);
defaultCollector.setApplicationName(applicationName);
MethodMetricsSampler methodMetricsCountSampler = defaultCollector.getMethodSampler();
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.TOTAL.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.SUCCEED.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.UNKNOWN_FAILED.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.BUSINESS_FAILED.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.NETWORK_EXCEPTION.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.SERVICE_UNAVAILABLE.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.CODEC_EXCEPTION.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.NO_INVOKER_AVAILABLE.getNameByType(side));
metricsFilter.invoke(new TestMetricsInvoker(side), invocation);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
AppResponse mockRpcResult = new AppResponse();
mockRpcResult.setException(new RpcException(RpcException.NETWORK_EXCEPTION));
Result result = AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation);
metricsFilter.onResponse(result, new TestMetricsInvoker(side), invocation);
List<MetricSample> samples = collector.collect();
@ -177,46 +187,10 @@ class AggregateMetricsCollectorTest {
@SuppressWarnings("rawtypes")
Map<String, Long> sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_TOTAL_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_SUCCEED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_BUSINESS_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_TOTAL_NETWORK_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_TOTAL_CODEC_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.INVOKER_NO_AVAILABLE_COUNT.getNameByType(side)), 1L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG.getNameByType(side)), 1L);
Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_QPS.getNameByType(side)));
}
@Test
void testRTMetrics() {
AggregateMetricsCollector collector = new AggregateMetricsCollector(applicationModel);
defaultCollector.setApplicationName(applicationModel.getApplicationName());
MethodMetricsSampler methodMetricsCountSampler = defaultCollector.getMethodSampler();
methodMetricsCountSampler.addRT(invocation, 10L);
List<MetricSample> samples = collector.collect();
for (MetricSample sample : samples) {
Map<String, String> tags = sample.getTags();
Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName);
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
@SuppressWarnings("rawtypes")
Map<String, Long> sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));
Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_RT_P99.getNameByType(side)));
Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_RT_P95.getNameByType(side)));
}
@Test
public void testQPS() {
ApplicationModel applicationModel = mock(ApplicationModel.class);
@ -262,13 +236,18 @@ class AggregateMetricsCollectorTest {
@Test
void testP95AndP99() throws InterruptedException {
AggregateMetricsCollector collector = getTestCollector();
MethodMetric methodMetric = getTestMethodMetric();
List<Double> requestTimes = new ArrayList<>(10000);
metricsDispatcher.addListener(collector);
ConfigManager configManager = applicationModel.getApplicationConfigManager();
MetricsConfig config = configManager.getMetrics().orElse(null);
AggregationConfig aggregationConfig = new AggregationConfig();
aggregationConfig.setEnabled(true);
config.setAggregation(aggregationConfig);
List<Long> requestTimes = new ArrayList<>(10000);
for (int i = 0; i < 300; i++) {
requestTimes.add(1000 * Math.random());
requestTimes.add(Double.valueOf(1000 * Math.random()).longValue());
}
Collections.sort(requestTimes);
@ -278,8 +257,14 @@ class AggregateMetricsCollectorTest {
double manualP95 = requestTimes.get((int) Math.round(p95Index));
double manualP99 = requestTimes.get((int) Math.round(p99Index));
for (Double requestTime : requestTimes) {
collector.onEvent(new RTEvent(applicationModel, methodMetric, requestTime.longValue()));
for (Long requestTime : requestTimes) {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, invocation);
TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
testRequestEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));
testRequestEvent.setRt(requestTime);
MetricsEventBus.post(testRequestEvent, () -> null);
}
Thread.sleep(4000L);
@ -304,9 +289,42 @@ class AggregateMetricsCollectorTest {
double p99 = p99Sample.applyAsDouble();
//An error of less than 5% is allowed
System.out.println(Math.abs(1 - p95 / manualP95));
Assertions.assertTrue(Math.abs(1 - p95 / manualP95) < 0.05);
Assertions.assertTrue(Math.abs(1 - p99 / manualP99) < 0.05);
}
public static class TestRequestEvent extends RequestEvent {
private long rt;
public TestRequestEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {
super(applicationModel, typeWrapper);
}
public void setRt(long rt) {
this.rt = rt;
}
@Override
public TimePair getTimePair() {
return new TestTimePair(rt);
}
}
public static class TestTimePair extends TimePair {
long rt;
public TestTimePair(long rt) {
super(rt);
this.rt = rt;
}
@Override
public long calc() {
return this.rt;
}
}
}

View File

@ -0,0 +1,244 @@
/*
* 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.collector;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.metrics.TestMetricsInvoker;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.RequestBeforeEvent;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.filter.MetricsFilter;
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;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult;
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.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_FILTER_EVENT;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TIMEOUT;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TOTAL_FAILED;
class DefaultCollectorTest {
private ApplicationModel applicationModel;
private String interfaceName;
private String methodName;
private String group;
private String version;
private RpcInvocation invocation;
private String side;
MetricsDispatcher metricsDispatcher;
DefaultMetricsCollector defaultCollector;
MetricsFilter metricsFilter;
@BeforeEach
public void setup() {
FrameworkModel frameworkModel = FrameworkModel.defaultModel();
applicationModel = frameworkModel.newApplication();
ApplicationConfig config = new ApplicationConfig();
config.setName("MockMetrics");
applicationModel.getApplicationConfigManager().setApplication(config);
metricsDispatcher = applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
defaultCollector.setCollectEnabled(true);
interfaceName = "org.apache.dubbo.MockInterface";
methodName = "mockMethod";
group = "mockGroup";
version = "1.0.0";
invocation = new RpcInvocation(methodName, interfaceName, "serviceKey", null, null);
invocation.setTargetServiceUniqueName(group + "/" + interfaceName + ":" + version);
invocation.setAttachment(GROUP_KEY, group);
invocation.setAttachment(VERSION_KEY, version);
side = CommonConstants.CONSUMER;
invocation.setInvoker(new TestMetricsInvoker(side));
invocation.setTargetServiceUniqueName(group + "/" + interfaceName + ":" + version);
RpcContext.getServiceContext().setUrl(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=" + side));
metricsFilter = new MetricsFilter();
metricsFilter.setApplicationModel(applicationModel);
}
@Test
void testListener() {
DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector();
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, invocation);
RequestBeforeEvent beforeEvent = new RequestBeforeEvent(applicationModel, new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
}
@AfterEach
public void teardown() {
applicationModel.destroy();
}
/**
* No rt metrics because Aggregate calc
*/
@Test
void testRequestEventNoRt() {
applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
DefaultMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);
collector.setCollectEnabled(true);
metricsFilter.invoke(new TestMetricsInvoker(side), invocation);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
AppResponse mockRpcResult = new AppResponse();
// mockRpcResult.setException(new RpcException("hessian"));
Result result = AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation);
metricsFilter.onResponse(result, new TestMetricsInvoker(side), invocation);
RequestEvent eventObj = (RequestEvent) invocation.get(METRIC_FILTER_EVENT);
long c1 = eventObj.getTimePair().calc();
// push finish rt +1
List<MetricSample> metricSamples = collector.collect();
//num(total+success+processing) + rt(5) = 8
Assertions.assertEquals(8, metricSamples.size());
List<String> metricsNames = metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());
// No error will contain total+success+processing
String REQUESTS = new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
String SUCCEED = new MetricsKeyWrapper(METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
String PROCESSING = new MetricsKeyWrapper(METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
Assertions.assertTrue(metricsNames.contains(REQUESTS));
Assertions.assertTrue(metricsNames.contains(SUCCEED));
Assertions.assertTrue(metricsNames.contains(PROCESSING));
for (MetricSample metricSample : metricSamples) {
if (metricSample instanceof GaugeMetricSample) {
GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;
Object objVal = gaugeMetricSample.getValue();
if (objVal instanceof Map) {
Map<ServiceKeyMetric, AtomicLong> value = (Map<ServiceKeyMetric, AtomicLong>) objVal;
if (metricSample.getName().equals(REQUESTS)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));
}
if (metricSample.getName().equals(PROCESSING)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));
}
}
} else {
AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();
if (metricSample.getName().equals(SUCCEED)) {
Assertions.assertEquals(1, value.intValue());
}
}
}
metricsFilter.invoke(new TestMetricsInvoker(side), invocation);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
metricsFilter.onError(new RpcException(RpcException.TIMEOUT_EXCEPTION, "timeout"), new TestMetricsInvoker(side), invocation);
eventObj = (RequestEvent) invocation.get(METRIC_FILTER_EVENT);
long c2 = eventObj.getTimePair().calc();
metricSamples = collector.collect();
// num(total+success+error+total_error+processing) + rt(5) = 5
Assertions.assertEquals(10, metricSamples.size());
String TIMEOUT = new MetricsKeyWrapper(METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
String TOTAL_FAILED = new MetricsKeyWrapper(METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
for (MetricSample metricSample : metricSamples) {
if (metricSample instanceof GaugeMetricSample) {
GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;
Object objVal = gaugeMetricSample.getValue();
if (objVal instanceof Map) {
Map<ServiceKeyMetric, AtomicLong> value = (Map<ServiceKeyMetric, AtomicLong>) ((GaugeMetricSample<?>) metricSample).getValue();
if (metricSample.getName().equals(REQUESTS)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 2));
}
if (metricSample.getName().equals(REQUESTS)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 2));
}
if (metricSample.getName().equals(PROCESSING)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));
}
if (metricSample.getName().equals(TIMEOUT)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));
}
if (metricSample.getName().equals(TOTAL_FAILED)) {
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));
}
}
} else {
AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();
if (metricSample.getName().equals(SUCCEED)) {
Assertions.assertEquals(1, value.intValue());
}
}
}
// calc rt
for (MetricSample sample : metricSamples) {
Map<String, String> tags = sample.getTags();
Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());
}
Map<String, Long> sampleMap = metricSamples.stream().filter(metricSample -> metricSample instanceof GaugeMetricSample).collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey()), c2);
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey()), Math.min(c1, c2));
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey()), Math.max(c1, c2));
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey()), (c1 + c2) / 2);
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey()), c1 + c2);
}
}

View File

@ -46,7 +46,10 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_PARAMETER_DESC;
import static org.apache.dubbo.common.constants.MetricsConstants.*;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -80,7 +83,7 @@ class MetricsFilterTest {
filter = new MetricsFilter();
collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);
if(!initApplication.get()) {
if (!initApplication.get()) {
collector.collectApplication(applicationModel);
initApplication.set(true);
}
@ -105,6 +108,8 @@ class MetricsFilterTest {
Assertions.assertTrue(metricsMap.isEmpty());
}
@Test
void testUnknownFailedRequests() {
collector.setCollectEnabled(true);
@ -260,14 +265,13 @@ class MetricsFilterTest {
}
@Test
public void testErrors(){
public void testErrors() {
testFilterError(RpcException.SERIALIZATION_EXCEPTION, MetricsKey.METRIC_REQUESTS_CODEC_FAILED.formatName(side));
testFilterError(RpcException.NETWORK_EXCEPTION, MetricsKey.METRIC_REQUESTS_NETWORK_FAILED.formatName(side));
}
private void testFilterError(int errorCode,MetricsKey metricsKey){
private void testFilterError(int errorCode, MetricsKey metricsKey) {
setup();
collector.setCollectEnabled(true);
given(invoker.invoke(invocation)).willThrow(new RpcException(errorCode));

View File

@ -1,209 +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.metrics.collector;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.metrics.TestMetricsInvoker;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.metrics.event.MethodEvent;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.RTEvent;
import org.apache.dubbo.metrics.listener.MetricsListener;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.*;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
class DefaultMetricsCollectorTest {
private FrameworkModel frameworkModel;
private ApplicationModel applicationModel;
private String interfaceName;
private String methodName;
private String group;
private String version;
private RpcInvocation invocation;
private String side;
@BeforeEach
public void setup() {
frameworkModel = FrameworkModel.defaultModel();
applicationModel = frameworkModel.newApplication();
ApplicationConfig config = new ApplicationConfig();
config.setName("MockMetrics");
applicationModel.getApplicationConfigManager().setApplication(config);
interfaceName = "org.apache.dubbo.MockInterface";
methodName = "mockMethod";
group = "mockGroup";
version = "1.0.0";
invocation = new RpcInvocation(methodName, interfaceName, "serviceKey", null, null);
invocation.setTargetServiceUniqueName(group + "/" + interfaceName + ":" + version);
invocation.setAttachment(GROUP_KEY, group);
invocation.setAttachment(VERSION_KEY, version);
side = CommonConstants.CONSUMER;
invocation.setInvoker(new TestMetricsInvoker(side));
RpcContext.getServiceContext().setUrl(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=" + side));
}
@AfterEach
public void teardown() {
applicationModel.destroy();
}
@Test
@SuppressWarnings("rawtypes")
void testRequestsMetrics() {
DefaultMetricsCollector collector = new DefaultMetricsCollector();
collector.setCollectEnabled(true);
collector.setApplicationName(applicationModel.getApplicationName());
MethodMetricsSampler methodMetricsCountSampler = collector.getMethodSampler();
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.TOTAL.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.PROCESSING.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.SUCCEED.getNameByType(side));
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.UNKNOWN_FAILED.getNameByType(side));
List<MetricSample> samples = collector.collect();
for (MetricSample sample : samples) {
if(sample instanceof GaugeMetricSample) {
GaugeMetricSample gaugeSample = (GaugeMetricSample) sample;
Assertions.assertEquals(gaugeSample.applyAsLong(), 1);
}else if(sample instanceof CounterMetricSample){
CounterMetricSample counterMetricSample = (CounterMetricSample) sample;
Assertions.assertEquals(counterMetricSample.getValue().longValue(), 1);
}
Map<String, String> tags = sample.getTags();
Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName);
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
methodMetricsCountSampler.dec(invocation, MetricsEvent.Type.PROCESSING.getNameByType(side));
samples = collector.collect();
Map<String, Long> sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> {
if(k instanceof GaugeMetricSample){
return ((GaugeMetricSample) k).applyAsLong();
}else if(k instanceof CounterMetricSample){
return ((CounterMetricSample)k).getValue().longValue();
}else{
throw new RuntimeException("un support sample type");
}
}));
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType(side)), 0L);
}
@Test
void testRTMetrics() {
DefaultMetricsCollector collector = new DefaultMetricsCollector();
collector.setCollectEnabled(true);
MethodMetricsSampler methodMetricsCountSampler = collector.getMethodSampler();
String applicationName = applicationModel.getApplicationName();
collector.setApplicationName(applicationName);
methodMetricsCountSampler.addRT(invocation, 10L);
methodMetricsCountSampler.addRT(invocation, 0L);
List<MetricSample> samples = collector.collect();
for (MetricSample sample : samples) {
Map<String, String> tags = sample.getTags();
Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName);
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
@SuppressWarnings("rawtypes")
Map<String, Long> sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_RT_LAST.getNameByType(side)), 0L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_RT_MIN.getNameByType(side)), 0L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_RT_MAX.getNameByType(side)), 10L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_RT_AVG.getNameByType(side)), 5L);
Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_RT_SUM.getNameByType(side)), 10L);
}
@Test
void testListener() {
DefaultMetricsCollector collector = new DefaultMetricsCollector();
MethodMetricsSampler methodMetricsCountSampler = collector.getMethodSampler();
collector.setCollectEnabled(true);
MockListener mockListener = new MockListener();
collector.addListener(mockListener);
collector.setApplicationName(applicationModel.getApplicationName());
methodMetricsCountSampler.incOnEvent(invocation, MetricsEvent.Type.TOTAL.getNameByType(side));
Assertions.assertNotNull(mockListener.getCurEvent());
Assertions.assertTrue(mockListener.getCurEvent() instanceof MethodEvent);
Assertions.assertEquals(((MethodEvent) mockListener.getCurEvent()).getType(),
MetricsEvent.Type.TOTAL.getNameByType(side));
methodMetricsCountSampler.addRT(invocation, 5L);
Assertions.assertTrue(mockListener.getCurEvent() instanceof RTEvent);
Assertions.assertEquals(((RTEvent) mockListener.getCurEvent()).getRt(), 5L);
}
static class MockListener implements MetricsListener {
private MetricsEvent curEvent;
@Override
public void onEvent(MetricsEvent event) {
curEvent = event;
}
public MetricsEvent getCurEvent() {
return curEvent;
}
}
}

View File

@ -1,192 +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.sampler;
import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer;
import org.apache.dubbo.metrics.collector.sample.MetricsCountSampler;
import org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler;
import org.apache.dubbo.metrics.model.Metric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
public class CountSamplerTest {
String side = "consumer";
public RequestMetricsCountSampler sampler = new RequestMetricsCountSampler();
@BeforeEach
public void before() {
sampler = new RequestMetricsCountSampler();
}
@Test
public void rtTest() {
String applicationName = "test";
sampler.addRT(applicationName, RTType.METHOD_REQUEST, 2L);
@SuppressWarnings("rawtypes")
Map<String, GaugeMetricSample> collect = getCollect(RTType.METHOD_REQUEST);
Assertions.assertNotNull(collect);
Assertions.assertTrue(null != collect.get(MetricsKey.METRIC_RT_LAST.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_LAST.getNameByType(side)).applyAsLong() == 2);
Assertions.assertTrue(null != collect.get(MetricsKey.METRIC_RT_MIN.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MIN.getNameByType(side)).applyAsLong() == 2);
Assertions.assertTrue(null != collect.get(MetricsKey.METRIC_RT_MAX.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MAX.getNameByType(side)).applyAsLong() == 2);
Assertions.assertTrue(null != collect.get(MetricsKey.METRIC_RT_AVG.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_AVG.getNameByType(side)).applyAsLong() == 2);
Assertions.assertTrue(null != collect.get(MetricsKey.METRIC_RT_SUM.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_SUM.getNameByType(side)).applyAsLong() == 2);
sampler.addRT(applicationName, RTType.METHOD_REQUEST, 1L);
collect = getCollect(RTType.METHOD_REQUEST);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_LAST.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_LAST.getNameByType(side)).applyAsLong() == 1);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_MIN.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MIN.getNameByType(side)).applyAsLong() == 1);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_MAX.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MAX.getNameByType(side)).applyAsLong() == 2);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_AVG.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_AVG.getNameByType(side)).applyAsLong() == 1);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_SUM.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_SUM.getNameByType(side)).applyAsLong() == 3);
sampler.addRT(applicationName, RTType.APPLICATION, 4L);
collect = getCollect(RTType.APPLICATION);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_LAST.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_LAST.getNameByType(side)).applyAsLong() == 4);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_MIN.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MIN.getNameByType(side)).applyAsLong() == 4);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_MAX.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_MAX.getNameByType(side)).applyAsLong() == 4);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_AVG.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_AVG.getNameByType(side)).applyAsLong() == 4);
Assertions.assertTrue(
null != collect.get(MetricsKey.METRIC_RT_SUM.getNameByType(side)) && collect.get(
MetricsKey.METRIC_RT_SUM.getNameByType(side)).applyAsLong() == 4);
}
@SuppressWarnings("rawtypes")
private Map<String, GaugeMetricSample> getCollect(RTType rtType) {
List<GaugeMetricSample<?>> metricSamples = sampler.collectRT(
new MetricsCountSampler.MetricSampleFactory<RequestMethodMetrics, GaugeMetricSample<?>>() {
@Override
public <T> GaugeMetricSample<?> newInstance(MetricsKey key, RequestMethodMetrics metric, T value, ToDoubleFunction<T> apply) {
return new GaugeMetricSample<>(key.getNameByType(side), key.getDescription(),
metric.getTags(), RT, value, apply);
}
}, rtType);
return metricSamples.stream()
.collect(Collectors.toMap(MetricSample::getName, v -> v));
}
public class RequestMetricsCountSampler extends SimpleMetricsCountSampler<String, RTType, RequestMethodMetrics> {
@Override
public List<MetricSample> sample() {
return null;
}
@Override
protected void countConfigure(
MetricsCountSampleConfigurer<String, RTType, RequestMethodMetrics> sampleConfigure) {
sampleConfigure.configureMetrics(
configure -> new RequestMethodMetrics(configure.getSource()));
sampleConfigure.configureEventHandler(configure -> {
System.out.println("generic event");
});
}
@Override
public void rtConfigure(
MetricsCountSampleConfigurer<String, RTType, RequestMethodMetrics> sampleConfigure) {
sampleConfigure.configureMetrics(configure -> new RequestMethodMetrics(configure.getSource()));
sampleConfigure.configureEventHandler(configure -> {
System.out.println("rt event");
});
}
}
enum RTType {
METHOD_REQUEST,
APPLICATION
}
static class RequestMethodMetrics implements Metric {
private final String applicationName;
public RequestMethodMetrics(String applicationName) {
this.applicationName = applicationName;
}
@Override
public Map<String, String> getTags() {
Map<String, String> tags = new HashMap<>();
tags.put("serviceName", "test");
tags.put("version", "1.0.0");
tags.put("uptime", "20220202");
return tags;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof RequestMethodMetrics))
return false;
RequestMethodMetrics that = (RequestMethodMetrics) o;
return Objects.equals(applicationName, that.applicationName);
}
@Override
public int hashCode() {
return Objects.hash(applicationName);
}
}
}

View File

@ -1,132 +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.sampler;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.observation.MockInvocation;
import org.apache.dubbo.rpc.Invocation;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
public class MethodMetricsTest {
private DefaultMetricsCollector collector;
private MethodMetricsSampler sampler;
private Invocation invocation;
@BeforeEach
public void setUp() {
collector = new DefaultMetricsCollector();
sampler = new MethodMetricsSampler(collector);
invocation = spy(new MockInvocation());
when(invocation.getTargetServiceUniqueName()).thenReturn("TestService-1");
}
@Test
void testRequestsCount() {
final long requestTimes = 1000L;
//METRIC_REQUESTS
for (long i = 0; i < requestTimes; i++) {
sampler.inc(invocation, MetricsEvent.Type.TOTAL.getNameByType("provider"));
}
List<MetricSample> samples = sampler.sample();
MetricSample requestsSample = samples.stream()
.filter(sample -> MetricsKey.METRIC_REQUESTS.getNameByType("provider").equals(sample.getName()))
.findFirst()
.orElse(null);
Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS sample should not be null");
Assertions.assertEquals(MetricSample.Type.COUNTER, requestsSample.getType(), "METRIC_REQUESTS sample should have a COUNTER type");
Assertions.assertTrue(requestsSample instanceof CounterMetricSample);
Assertions.assertEquals(requestTimes, ((CounterMetricSample) requestsSample).getValue().longValue());
}
@Test
void testRequestsProcessing() {
final long requestTimes = 1000L;
//METRIC_REQUESTS
for (long i = 0; i < requestTimes; i++) {
sampler.inc(invocation, MetricsEvent.Type.PROCESSING.getNameByType("provider"));
}
List<MetricSample> samples = sampler.sample();
MetricSample requestsSample = samples.stream()
.filter(sample -> MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType("provider").equals(sample.getName()))
.findFirst()
.orElse(null);
Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS_PROCESSING sample should not be null");
Assertions.assertEquals(MetricSample.Type.GAUGE, requestsSample.getType(), "METRIC_REQUESTS_PROCESSING sample should have a GAUGE type");
Assertions.assertTrue(requestsSample instanceof GaugeMetricSample);
Assertions.assertEquals(requestTimes, ((AtomicLong) ((GaugeMetricSample) requestsSample).getValue()).get());
for (long i = 0; i < requestTimes; i++) {
sampler.dec(invocation, MetricsEvent.Type.PROCESSING.getNameByType("provider"));
}
samples = sampler.sample();
requestsSample = samples.stream()
.filter(sample -> MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType("provider").equals(sample.getName()))
.findFirst()
.orElse(null);
Assertions.assertEquals(0, ((AtomicLong) ((GaugeMetricSample) requestsSample).getValue()).get());
}
@Test
void testRequestSucceed() {
final long requestTimes = 1000L;
//METRIC_REQUESTS_SUCCEED
for (long i = 0; i < requestTimes; i++) {
sampler.inc(invocation, MetricsEvent.Type.SUCCEED.getNameByType("provider"));
}
List<MetricSample> samples = sampler.sample();
MetricSample requestsSample = samples.stream()
.filter(sample -> MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType("provider").equals(sample.getName()))
.findFirst()
.orElse(null);
Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS_SUCCEED sample should not be null");
Assertions.assertEquals(MetricSample.Type.COUNTER, requestsSample.getType(), "METRIC_REQUESTS_SUCCEED sample should have a COUNTER type");
Assertions.assertTrue(requestsSample instanceof CounterMetricSample);
Assertions.assertEquals(requestTimes, ((AtomicLong) ((CounterMetricSample) requestsSample).getValue()).get());
}
}

View File

@ -18,8 +18,9 @@
package org.apache.dubbo.metrics.metadata;
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.MetricsPlaceType;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import java.util.Arrays;
import java.util.List;
@ -36,16 +37,18 @@ import static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METAD
public interface MetadataMetricsConstants {
MetricsPlaceType OP_TYPE_PUSH = MetricsPlaceType.of("push", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_SUBSCRIBE = MetricsPlaceType.of("subscribe", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_STORE_PROVIDER_INTERFACE = MetricsPlaceType.of("store.provider.interface", MetricsLevel.SERVICE);
MetricsPlaceValue OP_TYPE_PUSH = MetricsPlaceValue.of("push", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_SUBSCRIBE = MetricsPlaceValue.of("subscribe", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_STORE_PROVIDER_INTERFACE = MetricsPlaceValue.of("store.provider.interface", MetricsLevel.SERVICE);
// App-level
List<MetricsKey> APP_LEVEL_KEYS = Arrays.asList(METADATA_PUSH_METRIC_NUM, METADATA_PUSH_METRIC_NUM_SUCCEED, METADATA_PUSH_METRIC_NUM_FAILED,
METADATA_SUBSCRIBE_METRIC_NUM, METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED, METADATA_SUBSCRIBE_METRIC_NUM_FAILED);
// Service-level
List<MetricsKey> SERVICE_LEVEL_KEYS = Arrays.asList(STORE_PROVIDER_METADATA,
STORE_PROVIDER_METADATA_SUCCEED, STORE_PROVIDER_METADATA_FAILED
List<MetricsKeyWrapper> SERVICE_LEVEL_KEYS = Arrays.asList(
new MetricsKeyWrapper(STORE_PROVIDER_METADATA, OP_TYPE_STORE_PROVIDER_INTERFACE),
new MetricsKeyWrapper(STORE_PROVIDER_METADATA_SUCCEED, OP_TYPE_STORE_PROVIDER_INTERFACE),
new MetricsKeyWrapper(STORE_PROVIDER_METADATA_FAILED, OP_TYPE_STORE_PROVIDER_INTERFACE)
);
}

View File

@ -25,11 +25,9 @@ import org.apache.dubbo.metrics.data.ApplicationStatComposite;
import org.apache.dubbo.metrics.data.BaseStatComposite;
import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.data.ServiceStatComposite;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.metadata.MetadataMetricsConstants;
import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
import org.apache.dubbo.metrics.metadata.event.MetadataMetricsEventMulticaster;
import org.apache.dubbo.metrics.metadata.event.MetadataSubDispatcher;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -47,7 +45,7 @@ import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE
* Registry implementation of {@link MetricsCollector}
*/
@Activate
public class MetadataMetricsCollector extends CombMetricsCollector<TimeCounterEvent> {
public class MetadataMetricsCollector extends CombMetricsCollector<MetadataEvent> {
private Boolean collectEnabled = null;
private final ApplicationModel applicationModel;
@ -55,13 +53,21 @@ public class MetadataMetricsCollector extends CombMetricsCollector<TimeCounterEv
public MetadataMetricsCollector(ApplicationModel applicationModel) {
super(new BaseStatComposite() {
@Override
protected void init(ApplicationStatComposite applicationStatComposite, ServiceStatComposite serviceStatComposite, RtStatComposite rtStatComposite) {
protected void init(ApplicationStatComposite applicationStatComposite) {
applicationStatComposite.init(MetadataMetricsConstants.APP_LEVEL_KEYS);
serviceStatComposite.init(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(ServiceStatComposite serviceStatComposite) {
serviceStatComposite.initWrapper(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(RtStatComposite rtStatComposite) {
rtStatComposite.init(OP_TYPE_PUSH, OP_TYPE_SUBSCRIBE, OP_TYPE_STORE_PROVIDER_INTERFACE);
}
});
super.setEventMulticaster(new MetadataMetricsEventMulticaster(this));
super.setEventMulticaster(new MetadataSubDispatcher(this));
this.applicationModel = applicationModel;
}
@ -90,9 +96,4 @@ public class MetadataMetricsCollector extends CombMetricsCollector<TimeCounterEv
return list;
}
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof MetadataEvent;
}
}

View File

@ -40,8 +40,7 @@ import static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METAD
*/
public class MetadataEvent extends TimeCounterEvent {
public MetadataEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {
super(applicationModel);
super.typeWrapper = typeWrapper;
super(applicationModel,typeWrapper);
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
MetadataMetricsCollector collector;
if (!beanFactory.isDestroyed()) {

View File

@ -32,9 +32,9 @@ import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;
public final class MetadataMetricsEventMulticaster extends SimpleMetricsEventMulticaster {
public final class MetadataSubDispatcher extends SimpleMetricsEventMulticaster {
public MetadataMetricsEventMulticaster(MetadataMetricsCollector collector) {
public MetadataSubDispatcher(MetadataMetricsCollector collector) {
CategorySet.ALL.forEach(categorySet ->
{

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.metrics.metadata;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;
import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
@ -41,7 +42,9 @@ import java.util.Objects;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.*;
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_PUSH;
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;
import static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;
class MetadataMetricsCollectorTest {
@ -64,6 +67,16 @@ class MetadataMetricsCollectorTest {
collector.setCollectEnabled(true);
}
@Test
void testListener() {
MetadataEvent event = MetadataEvent.toPushEvent(applicationModel);
MetricsEvent otherEvent = new MetricsEvent(applicationModel,null){
};
Assertions.assertTrue(collector.isSupport(event));
Assertions.assertFalse(collector.isSupport(otherEvent));
}
@AfterEach
public void teardown() {
applicationModel.destroy();

View File

@ -40,10 +40,17 @@ public class MetadataStatCompositeTest {
private final BaseStatComposite statComposite = new BaseStatComposite() {
@Override
protected void init(ApplicationStatComposite applicationStatComposite, ServiceStatComposite
serviceStatComposite, RtStatComposite rtStatComposite) {
protected void init(ApplicationStatComposite applicationStatComposite) {
applicationStatComposite.init(MetadataMetricsConstants.APP_LEVEL_KEYS);
serviceStatComposite.init(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(ServiceStatComposite serviceStatComposite) {
serviceStatComposite.initWrapper(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(RtStatComposite rtStatComposite) {
rtStatComposite.init(OP_TYPE_PUSH, OP_TYPE_SUBSCRIBE, OP_TYPE_STORE_PROVIDER_INTERFACE);
}
};

View File

@ -18,8 +18,9 @@
package org.apache.dubbo.metrics.registry;
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.MetricsPlaceType;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import java.util.Arrays;
import java.util.List;
@ -45,12 +46,12 @@ import static org.apache.dubbo.metrics.model.key.MetricsKey.SUBSCRIBE_METRIC_NUM
public interface RegistryMetricsConstants {
MetricsPlaceType OP_TYPE_REGISTER = MetricsPlaceType.of("register", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_SUBSCRIBE = MetricsPlaceType.of("subscribe", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_NOTIFY = MetricsPlaceType.of("notify", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_DIRECTORY = MetricsPlaceType.of("directory", MetricsLevel.APP);
MetricsPlaceType OP_TYPE_REGISTER_SERVICE = MetricsPlaceType.of("register.service", MetricsLevel.SERVICE);
MetricsPlaceType OP_TYPE_SUBSCRIBE_SERVICE = MetricsPlaceType.of("subscribe.service", MetricsLevel.SERVICE);
MetricsPlaceValue OP_TYPE_REGISTER = MetricsPlaceValue.of("register", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_SUBSCRIBE = MetricsPlaceValue.of("subscribe", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_NOTIFY = MetricsPlaceValue.of("notify", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_DIRECTORY = MetricsPlaceValue.of("directory", MetricsLevel.APP);
MetricsPlaceValue OP_TYPE_REGISTER_SERVICE = MetricsPlaceValue.of("register.service", MetricsLevel.SERVICE);
MetricsPlaceValue OP_TYPE_SUBSCRIBE_SERVICE = MetricsPlaceValue.of("subscribe.service", MetricsLevel.SERVICE);
// App-level
List<MetricsKey> APP_LEVEL_KEYS = Arrays.asList(REGISTER_METRIC_REQUESTS, REGISTER_METRIC_REQUESTS_SUCCEED, REGISTER_METRIC_REQUESTS_FAILED,
@ -58,11 +59,17 @@ public interface RegistryMetricsConstants {
NOTIFY_METRIC_REQUESTS);
// Service-level
List<MetricsKey> SERVICE_LEVEL_KEYS = Arrays.asList(NOTIFY_METRIC_NUM_LAST,
SERVICE_REGISTER_METRIC_REQUESTS, SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, SERVICE_REGISTER_METRIC_REQUESTS_FAILED,
SERVICE_SUBSCRIBE_METRIC_NUM, SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, SERVICE_SUBSCRIBE_METRIC_NUM_FAILED,
DIRECTORY_METRIC_NUM_VALID, DIRECTORY_METRIC_NUM_TO_RECONNECT, DIRECTORY_METRIC_NUM_DISABLE, DIRECTORY_METRIC_NUM_ALL
List<MetricsKeyWrapper> SERVICE_LEVEL_KEYS = Arrays.asList(
new MetricsKeyWrapper(NOTIFY_METRIC_NUM_LAST, OP_TYPE_NOTIFY),
new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS, OP_TYPE_REGISTER_SERVICE),
new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, OP_TYPE_REGISTER_SERVICE),
new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS_FAILED, OP_TYPE_REGISTER_SERVICE),
new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM, OP_TYPE_SUBSCRIBE_SERVICE),
new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, OP_TYPE_SUBSCRIBE_SERVICE),
new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM_FAILED, OP_TYPE_SUBSCRIBE_SERVICE),
new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_VALID, OP_TYPE_DIRECTORY),
new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_TO_RECONNECT, OP_TYPE_DIRECTORY),
new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_DISABLE, OP_TYPE_DIRECTORY),
new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_ALL, OP_TYPE_DIRECTORY)
);
}

View File

@ -25,13 +25,11 @@ import org.apache.dubbo.metrics.data.ApplicationStatComposite;
import org.apache.dubbo.metrics.data.BaseStatComposite;
import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.data.ServiceStatComposite;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.registry.RegistryMetricsConstants;
import org.apache.dubbo.metrics.registry.event.RegistryEvent;
import org.apache.dubbo.metrics.registry.event.RegistryMetricsEventMulticaster;
import org.apache.dubbo.metrics.registry.event.RegistrySubDispatcher;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
@ -49,7 +47,7 @@ import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE
* Registry implementation of {@link MetricsCollector}
*/
@Activate
public class RegistryMetricsCollector extends CombMetricsCollector<TimeCounterEvent> {
public class RegistryMetricsCollector extends CombMetricsCollector<RegistryEvent> {
private Boolean collectEnabled = null;
private final ApplicationModel applicationModel;
@ -57,13 +55,21 @@ public class RegistryMetricsCollector extends CombMetricsCollector<TimeCounterEv
public RegistryMetricsCollector(ApplicationModel applicationModel) {
super(new BaseStatComposite() {
@Override
protected void init(ApplicationStatComposite applicationStatComposite, ServiceStatComposite serviceStatComposite, RtStatComposite rtStatComposite) {
protected void init(ApplicationStatComposite applicationStatComposite) {
applicationStatComposite.init(RegistryMetricsConstants.APP_LEVEL_KEYS);
serviceStatComposite.init(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(ServiceStatComposite serviceStatComposite) {
serviceStatComposite.initWrapper(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(RtStatComposite rtStatComposite) {
rtStatComposite.init(OP_TYPE_REGISTER, OP_TYPE_SUBSCRIBE, OP_TYPE_NOTIFY, OP_TYPE_REGISTER_SERVICE, OP_TYPE_SUBSCRIBE_SERVICE);
}
});
super.setEventMulticaster(new RegistryMetricsEventMulticaster(this));
super.setEventMulticaster(new RegistrySubDispatcher(this));
this.applicationModel = applicationModel;
}
@ -93,10 +99,4 @@ public class RegistryMetricsCollector extends CombMetricsCollector<TimeCounterEv
return list;
}
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof RegistryEvent;
}
}

View File

@ -38,8 +38,7 @@ import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;
*/
public class RegistryEvent extends TimeCounterEvent {
public RegistryEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {
super(applicationModel);
super.typeWrapper = typeWrapper;
super(applicationModel,typeWrapper);
ScopeBeanFactory beanFactory = getSource().getBeanFactory();
RegistryMetricsCollector collector;
if (!beanFactory.isDestroyed()) {
@ -59,7 +58,7 @@ public class RegistryEvent extends TimeCounterEvent {
public static RegistryEvent toNotifyEvent(ApplicationModel applicationModel) {
return new RegistryEvent(applicationModel, new TypeWrapper(MetricsLevel.APP, MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsKey.NOTIFY_METRIC_NUM_LAST, null)) {
return new RegistryEvent(applicationModel, new TypeWrapper(MetricsLevel.APP, MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsKey.NOTIFY_METRIC_NUM_LAST, (MetricsKey) null)) {
@Override
public void customAfterPost(Object postResult) {
super.putAttachment(ATTACHMENT_KEY_LAST_NUM_MAP, postResult);

View File

@ -18,12 +18,13 @@
package org.apache.dubbo.metrics.registry.event;
import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;
import org.apache.dubbo.metrics.listener.AbstractMetricsListener;
import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;
import org.apache.dubbo.metrics.listener.MetricsApplicationListener;
import org.apache.dubbo.metrics.listener.MetricsServiceListener;
import org.apache.dubbo.metrics.model.key.CategoryOverall;
import org.apache.dubbo.metrics.model.key.MetricsCat;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;
import java.util.Arrays;
@ -40,10 +41,10 @@ import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE;
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;
public final class RegistryMetricsEventMulticaster extends SimpleMetricsEventMulticaster {
public final class RegistrySubDispatcher extends SimpleMetricsEventMulticaster {
public RegistryMetricsEventMulticaster(RegistryMetricsCollector collector) {
public RegistrySubDispatcher(RegistryMetricsCollector collector) {
CategorySet.ALL.forEach(categorySet ->
{
@ -83,24 +84,24 @@ public final class RegistryMetricsEventMulticaster extends SimpleMetricsEventMul
// MetricsNotifyListener
MetricsCat APPLICATION_NOTIFY_POST = new MetricsCat(MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsApplicationListener::onPostEventBuild);
MetricsCat APPLICATION_NOTIFY_FINISH = new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST,
(key, placeType, collector) -> AbstractMetricsListener.onFinish(key,
(key, placeType, collector) -> AbstractMetricsKeyListener.onFinish(key,
event -> {
collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc());
Map<String, Integer> lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP));
lastNumMap.forEach(
(k, v) -> collector.setNum(key, event.appName(), k, v));
(k, v) -> collector.setNum(new MetricsKeyWrapper(key, OP_TYPE_NOTIFY), event.appName(), k, v));
}
));
MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, (key, placeType, collector) -> AbstractMetricsListener.onEvent(key,
MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, (key, placeType, collector) -> AbstractMetricsKeyListener.onEvent(key,
event ->
{
Map<MetricsKey, Map<String, Integer>> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP);
summaryMap.forEach((metricsKey, map) ->
map.forEach(
(k, v) -> collector.setNum(metricsKey, event.appName(), k, v)));
(k, v) -> collector.setNum(new MetricsKeyWrapper(key, OP_TYPE_DIRECTORY), event.appName(), k, v)));
}
));

View File

@ -20,9 +20,9 @@ package org.apache.dubbo.metrics.registry.metrics.collector;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.TimePair;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;
@ -34,6 +34,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -48,6 +49,7 @@ import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE
class RegistryMetricsCollectorTest {
private ApplicationModel applicationModel;
private RegistryMetricsCollector collector;
@BeforeEach
public void setup() {
@ -57,7 +59,9 @@ class RegistryMetricsCollectorTest {
config.setName("MockMetrics");
applicationModel.getApplicationConfigManager().setApplication(config);
applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);
collector.setCollectEnabled(true);
}
@AfterEach
@ -68,10 +72,6 @@ class RegistryMetricsCollectorTest {
@Test
void testRegisterMetrics() {
applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
RegistryMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);
collector.setCollectEnabled(true);
RegistryEvent registryEvent = RegistryEvent.toRegisterEvent(applicationModel);
MetricsEventBus.post(registryEvent,
() -> {
@ -130,9 +130,6 @@ class RegistryMetricsCollectorTest {
@Test
void testServicePushMetrics() {
applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
RegistryMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);
collector.setCollectEnabled(true);
String serviceName = "demo.gameService";
RegistryEvent registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2);
@ -195,9 +192,6 @@ class RegistryMetricsCollectorTest {
@Test
void testServiceSubscribeMetrics() {
applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);
RegistryMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);
collector.setCollectEnabled(true);
String serviceName = "demo.gameService";
RegistryEvent subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName);
@ -255,4 +249,28 @@ class RegistryMetricsCollectorTest {
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()), (c1 + c2) / 2);
Assertions.assertEquals(sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()), c1 + c2);
}
@Test
public void testNotify() {
MetricsEventBus.post(RegistryEvent.toNotifyEvent(applicationModel),
() -> {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Integer> lastNumMap = new HashMap<>();
// 1 different services
lastNumMap.put("demo.service1", 3);
lastNumMap.put("demo.service2", 4);
lastNumMap.put("demo.service3", 5);
return lastNumMap;
}
);
List<MetricSample> metricSamples = collector.collect();
// num(total+service*3) + rt(5) = 9
Assertions.assertEquals(9, metricSamples.size());
}
}

View File

@ -23,9 +23,9 @@ import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.data.ServiceStatComposite;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.container.LongContainer;
import org.apache.dubbo.metrics.registry.RegistryMetricsConstants;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.registry.RegistryMetricsConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -50,9 +50,17 @@ public class RegistryStatCompositeTest {
private final String applicationName = "app1";
private final BaseStatComposite statComposite = new BaseStatComposite() {
@Override
protected void init(ApplicationStatComposite applicationStatComposite, ServiceStatComposite serviceStatComposite, RtStatComposite rtStatComposite) {
protected void init(ApplicationStatComposite applicationStatComposite) {
applicationStatComposite.init(RegistryMetricsConstants.APP_LEVEL_KEYS);
serviceStatComposite.init(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(ServiceStatComposite serviceStatComposite) {
serviceStatComposite.initWrapper(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);
}
@Override
protected void init(RtStatComposite rtStatComposite) {
rtStatComposite.init(OP_TYPE_REGISTER, OP_TYPE_SUBSCRIBE, OP_TYPE_NOTIFY, OP_TYPE_REGISTER_SERVICE, OP_TYPE_SUBSCRIBE_SERVICE);
}
};
@ -63,7 +71,7 @@ public class RegistryStatCompositeTest {
//(rt)5 * (applicationRegister,subscribe,notify,applicationRegister.service,subscribe.service)
Assertions.assertEquals(5 * 5, statComposite.getRtStatComposite().getRtStats().size());
statComposite.getApplicationStatComposite().getApplicationNumStats().values().forEach((v ->
Assertions.assertEquals(v, new ConcurrentHashMap<>())));
Assertions.assertEquals(v, new ConcurrentHashMap<>())));
statComposite.getRtStatComposite().getRtStats().forEach(rtContainer ->
{
for (Map.Entry<String, ? extends Number> entry : rtContainer.entrySet()) {
@ -98,20 +106,20 @@ public class RegistryStatCompositeTest {
statComposite.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime1);
statComposite.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime2);
List<GaugeMetricSample> exportedRtMetrics = statComposite.export(MetricsCategory.RT);
List<MetricSample> exportedRtMetrics = statComposite.export(MetricsCategory.RT);
GaugeMetricSample minSample = exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_MIN.getNameByType("register.service")))
.findFirst().orElse(null);
GaugeMetricSample maxSample = exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_MAX.getNameByType("register.service")))
.findFirst().orElse(null);
GaugeMetricSample avgSample = exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_AVG.getNameByType("register.service")))
.findFirst().orElse(null);
GaugeMetricSample minSample = (GaugeMetricSample) exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_MIN.getNameByType("register.service")))
.findFirst().orElse(null);
GaugeMetricSample maxSample = (GaugeMetricSample) exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_MAX.getNameByType("register.service")))
.findFirst().orElse(null);
GaugeMetricSample avgSample = (GaugeMetricSample) exportedRtMetrics.stream()
.filter(sample -> sample.getTags().containsValue(applicationName))
.filter(sample -> sample.getName().equals(METRIC_RT_AVG.getNameByType("register.service")))
.findFirst().orElse(null);
Assertions.assertNotNull(minSample);
Assertions.assertNotNull(maxSample);