org.apache.dubbo.monitor.dubbo.MetricsFilter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo Show documentation
Show all versions of dubbo Show documentation
The all in one project of dubbo
/*
* 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.monitor.dubbo;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.store.DataStore;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.monitor.MetricsService;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.support.RpcUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.metrics.FastCompass;
import com.alibaba.metrics.MetricLevel;
import com.alibaba.metrics.MetricManager;
import com.alibaba.metrics.MetricName;
import com.alibaba.metrics.MetricRegistry;
import com.alibaba.metrics.common.CollectLevel;
import com.alibaba.metrics.common.MetricObject;
import com.alibaba.metrics.common.MetricsCollector;
import com.alibaba.metrics.common.MetricsCollectorFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PORT;
import static org.apache.dubbo.common.constants.CommonConstants.METRICS_PROTOCOL;
import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER;
import static org.apache.dubbo.monitor.Constants.DUBBO_CONSUMER_METHOD;
import static org.apache.dubbo.monitor.Constants.DUBBO_GROUP;
import static org.apache.dubbo.monitor.Constants.DUBBO_PROVIDER;
import static org.apache.dubbo.monitor.Constants.DUBBO_PROVIDER_METHOD;
import static org.apache.dubbo.monitor.Constants.METHOD;
import static org.apache.dubbo.monitor.Constants.SERVICE;
public class MetricsFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(MetricsFilter.class);
private static final AtomicBoolean exported = new AtomicBoolean(false);
private Integer port;
private String protocolName;
@Override
public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
if (exported.compareAndSet(false, true)) {
this.protocolName = invoker.getUrl().getParameter(METRICS_PROTOCOL) == null ?
DEFAULT_PROTOCOL : invoker.getUrl().getParameter(METRICS_PROTOCOL);
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(protocolName);
this.port = invoker.getUrl().getParameter(METRICS_PORT) == null ?
protocol.getDefaultPort() : Integer.parseInt(invoker.getUrl().getParameter(METRICS_PORT));
Invoker metricsInvoker = initMetricsInvoker();
try {
protocol.export(metricsInvoker);
} catch (RuntimeException e) {
logger.error("Metrics Service need to be configured" +
" when multiple processes are running on a host" + e.getMessage());
}
}
RpcContext context = RpcContext.getContext();
boolean isProvider = context.isProviderSide();
long start = System.currentTimeMillis();
try {
Result result = invoker.invoke(invocation); // proceed invocation chain
long duration = System.currentTimeMillis() - start;
reportMetrics(invoker, invocation, duration, "success", isProvider);
return result;
} catch (RpcException e) {
long duration = System.currentTimeMillis() - start;
String result = "error";
if (e.isTimeout()) {
result = "timeoutError";
}
if (e.isBiz()) {
result = "bisError";
}
if (e.isNetwork()) {
result = "networkError";
}
if (e.isSerialization()) {
result = "serializationError";
}
reportMetrics(invoker, invocation, duration, result, isProvider);
throw e;
}
}
private String buildMethodName(Invocation invocation) {
String methodName = RpcUtils.getMethodName(invocation);
StringBuilder method = new StringBuilder(methodName);
Class[] argTypes = RpcUtils.getParameterTypes(invocation);
method.append("(");
for (int i = 0; i < argTypes.length; i++) {
method.append(i == 0 ? "" : ", ").append(argTypes[i].getSimpleName());
}
method.append(")");
Class returnType = RpcUtils.getReturnType(invocation);
String typeName = null;
if(returnType != null) {
typeName = returnType.getTypeName();
typeName = typeName.substring(typeName.lastIndexOf(".") + 1);
}
return (typeName == null ? "void" : typeName) + " " + method;
}
private void reportMetrics(Invoker invoker, Invocation invocation, long duration, String result, boolean isProvider) {
String serviceName = invoker.getInterface().getName();
String methodName = buildMethodName(invocation);
MetricName global;
MetricName method;
if (isProvider) {
global = new MetricName(DUBBO_PROVIDER, MetricLevel.MAJOR);
method = new MetricName(DUBBO_PROVIDER_METHOD, new HashMap(4) {
{
put(SERVICE, serviceName);
put(METHOD, methodName);
}
}, MetricLevel.NORMAL);
} else {
global = new MetricName(DUBBO_CONSUMER, MetricLevel.MAJOR);
method = new MetricName(DUBBO_CONSUMER_METHOD, new HashMap(4) {
{
put(SERVICE, serviceName);
put(METHOD, methodName);
}
}, MetricLevel.NORMAL);
}
setCompassQuantity(DUBBO_GROUP, result, duration, global, method);
}
private void setCompassQuantity(String groupName, String result, long duration, MetricName... metricNames) {
for (MetricName metricName : metricNames) {
FastCompass compass = MetricManager.getFastCompass(groupName, metricName);
compass.record(duration, result);
}
}
private List getThreadPoolMessage() {
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
Map executors = dataStore.get(EXECUTOR_SERVICE_COMPONENT_KEY);
List threadPoolMetricList = new ArrayList<>();
for (Map.Entry entry : executors.entrySet()) {
ExecutorService executor = (ExecutorService) entry.getValue();
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor tp = (ThreadPoolExecutor) executor;
threadPoolMetricList.add(value2MetricObject("threadPool.active", tp.getActiveCount(), MetricLevel.MAJOR));
threadPoolMetricList.add(value2MetricObject("threadPool.core", tp.getCorePoolSize(), MetricLevel.MAJOR));
threadPoolMetricList.add(value2MetricObject("threadPool.max", tp.getMaximumPoolSize(), MetricLevel.MAJOR));
threadPoolMetricList.add(value2MetricObject("threadPool.current", tp.getPoolSize(), MetricLevel.MAJOR));
}
}
return threadPoolMetricList;
}
private MetricObject value2MetricObject(String metric, Integer value, MetricLevel level) {
if (metric == null || value == null || level == null) {
return null;
}
return new MetricObject
.Builder(metric)
.withValue(value)
.withLevel(level)
.build();
}
private Invoker initMetricsInvoker() {
return new Invoker() {
@Override
public Class getInterface() {
return MetricsService.class;
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
String group = invocation.getArguments()[0].toString();
MetricRegistry registry = MetricManager.getIMetricManager().getMetricRegistryByGroup(group);
SortedMap fastCompasses = registry.getFastCompasses();
long timestamp = System.currentTimeMillis();
double rateFactor = TimeUnit.SECONDS.toSeconds(1);
double durationFactor = 1.0 / TimeUnit.MILLISECONDS.toNanos(1);
MetricsCollector collector = MetricsCollectorFactory.createNew(
CollectLevel.NORMAL, Collections.EMPTY_MAP, rateFactor, durationFactor, null);
for (Map.Entry entry : fastCompasses.entrySet()) {
collector.collect(entry.getKey(), entry.getValue(), timestamp);
}
List res = collector.build();
res.addAll(getThreadPoolMessage());
return AsyncRpcResult.newDefaultAsyncResult(JSON.toJSONString(res), invocation);
}
@Override
public URL getUrl() {
return URL.valueOf(protocolName + "://" + NetUtils.getIpByConfig() + ":" + port + "/" + MetricsService.class.getName());
}
@Override
public boolean isAvailable() {
return false;
}
@Override
public void destroy() {
}
};
}
}