├── .gitignore ├── .settings ├── org.eclipse.wst.jsdt.ui.superType.name ├── org.eclipse.wst.validation.prefs ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.core.resources.prefs ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.jdt.core.prefs ├── .jsdtscope └── org.eclipse.wst.common.component ├── README.md ├── src └── main │ ├── webapp │ ├── index.jsp │ └── WEB-INF │ │ └── web.xml │ ├── resources │ └── META-INF │ │ └── dubbo │ │ ├── com.alibaba.dubbo.registry.RegistryFactory │ │ └── com.alibaba.dubbo.rpc.Filter │ └── java │ └── net │ └── tomjerry │ └── catmonitor │ ├── datasource │ ├── RoutingDataSource.java │ ├── DataSourceHolder.java │ ├── DataSource.java │ ├── AnnotationDataSourceAspect.java │ └── DataSourceAspectUtil.java │ ├── common │ ├── CatContext.java │ └── CatConstants.java │ ├── util │ ├── ThreadHelper.java │ ├── cache │ │ ├── CatRedisClient.java │ │ └── RedisClient.java │ └── http │ │ ├── CatCrossHttpClientProxy.java │ │ └── HttpClientProxy.java │ ├── dubbospi │ ├── AppNameAppendFilter.java │ ├── registry │ │ └── CatRegistryFactoryWrapper.java │ └── DubboCatCrossFilter.java │ ├── filter │ └── HttpCatCrossFliter.java │ └── mybatisext │ └── CatMybatisPlugin.java ├── target ├── classes │ ├── META-INF │ │ └── dubbo │ │ │ ├── com.alibaba.dubbo.registry.RegistryFactory │ │ │ └── com.alibaba.dubbo.rpc.Filter │ └── net │ │ └── tomjerry │ │ └── catmonitor │ │ ├── common │ │ ├── CatConstants.class │ │ └── CatContext.class │ │ ├── util │ │ ├── ThreadHelper.class │ │ ├── cache │ │ │ ├── RedisClient$1.class │ │ │ ├── RedisClient$2.class │ │ │ ├── RedisClient$3.class │ │ │ ├── RedisClient$4.class │ │ │ ├── RedisClient.class │ │ │ ├── CatRedisClient.class │ │ │ ├── RedisClient$JedisCallback.class │ │ │ ├── CatRedisClient$CatJedisCallback.class │ │ │ └── RedisClient$SharedRedisCallback.class │ │ └── http │ │ │ ├── HttpClientProxy.class │ │ │ ├── CatCrossHttpClientProxy.class │ │ │ └── HttpClientProxy$StringResponseHandler.class │ │ ├── datasource │ │ ├── DataSource.class │ │ ├── DataSourceHolder.class │ │ ├── RoutingDataSource.class │ │ ├── DataSourceAspectUtil.class │ │ ├── DataSourceAspectUtil$1.class │ │ └── AnnotationDataSourceAspect.class │ │ ├── filter │ │ └── HttpCatCrossFliter.class │ │ ├── dubbospi │ │ ├── AppNameAppendFilter.class │ │ ├── DubboCatCrossFilter.class │ │ └── registry │ │ │ ├── CatRegistryFactoryWrapper.class │ │ │ └── CatRegistryFactoryWrapper$RegistryWrapper.class │ │ └── mybatisext │ │ └── CatMybatisPlugin.class └── m2e-wtp │ └── web-resources │ └── META-INF │ ├── MANIFEST.MF │ └── maven │ └── net.tomjerry │ └── cat-monitor │ ├── pom.properties │ └── pom.xml ├── .classpath ├── .project └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cat-monitor 2 | 提供基于大众点评CAT监控的扩展,主要是跨服务的消息树(dubbo、http方式)、Cache以及DB监控等 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /target/classes/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory: -------------------------------------------------------------------------------- 1 | catRegistryFactoryWrapper=net.tomjerry.catmonitor.registry.CatRegistryFactoryWrapper -------------------------------------------------------------------------------- /src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory: -------------------------------------------------------------------------------- 1 | catRegistryFactoryWrapper=net.tomjerry.catmonitor.dubbospi.registry.CatRegistryFactoryWrapper -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Build-Jdk: 1.7.0_79 3 | Built-By: lenovo 4 | Created-By: Maven Integration for Eclipse 5 | 6 | -------------------------------------------------------------------------------- /target/classes/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter: -------------------------------------------------------------------------------- 1 | dubboCatFilter=net.tomjerry.catmonitor.dubbospi.DubboCatFilter 2 | appnameAppend=net.tomjerry.catmonitor.AppNameAppendFilter -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/common/CatConstants.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/common/CatConstants.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/common/CatContext.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/common/CatContext.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/ThreadHelper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/ThreadHelper.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/DataSource.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/DataSource.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$1.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$2.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$3.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$4.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/filter/HttpCatCrossFliter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/filter/HttpCatCrossFliter.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/CatRedisClient.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/CatRedisClient.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/http/HttpClientProxy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/http/HttpClientProxy.class -------------------------------------------------------------------------------- /src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter: -------------------------------------------------------------------------------- 1 | dubboCatCrossFilter=net.tomjerry.catmonitor.dubbospi.DubboCatCrossFilter 2 | appnameAppend=net.tomjerry.catmonitor.dubbospi.AppNameAppendFilter -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/DataSourceHolder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/DataSourceHolder.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/RoutingDataSource.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/RoutingDataSource.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/dubbospi/AppNameAppendFilter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/dubbospi/AppNameAppendFilter.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/dubbospi/DubboCatCrossFilter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/dubbospi/DubboCatCrossFilter.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/mybatisext/CatMybatisPlugin.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/mybatisext/CatMybatisPlugin.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/DataSourceAspectUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/DataSourceAspectUtil.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/DataSourceAspectUtil$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/DataSourceAspectUtil$1.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/http/CatCrossHttpClientProxy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/http/CatCrossHttpClientProxy.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$JedisCallback.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$JedisCallback.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/datasource/AnnotationDataSourceAspect.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/datasource/AnnotationDataSourceAspect.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/dubbospi/registry/CatRegistryFactoryWrapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/dubbospi/registry/CatRegistryFactoryWrapper.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/CatRedisClient$CatJedisCallback.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/CatRedisClient$CatJedisCallback.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$SharedRedisCallback.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/cache/RedisClient$SharedRedisCallback.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/util/http/HttpClientProxy$StringResponseHandler.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/util/http/HttpClientProxy$StringResponseHandler.class -------------------------------------------------------------------------------- /target/classes/net/tomjerry/catmonitor/dubbospi/registry/CatRegistryFactoryWrapper$RegistryWrapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/summerpotato/cat-monitor/HEAD/target/classes/net/tomjerry/catmonitor/dubbospi/registry/CatRegistryFactoryWrapper$RegistryWrapper.class -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/maven/net.tomjerry/cat-monitor/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven Integration for Eclipse 2 | #Mon Jun 20 12:01:28 CST 2016 3 | version=0.0.1-SNAPSHOT 4 | groupId=net.tomjerry 5 | m2e.projectName=cat-monitor 6 | m2e.projectLocation=D\:\\Zorkspace\\luna4.4-workspc2\\cat-monitor 7 | artifactId=cat-monitor 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.7 9 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/datasource/RoutingDataSource.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.datasource; 2 | 3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 4 | 5 | /** 6 | * 根据线程中数据源名称,返回数据源 7 | * @author potato 8 | * 9 | */ 10 | public class RoutingDataSource extends AbstractRoutingDataSource { 11 | 12 | @Override 13 | protected Object determineCurrentLookupKey() { 14 | return DataSourceHolder.getDBName(); 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/datasource/DataSourceHolder.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.datasource; 2 | 3 | /** 4 | * 在当前线程中保存数据源信息 5 | * 6 | * @author potato 7 | */ 8 | public class DataSourceHolder { 9 | 10 | private static final ThreadLocal contextHolder = new ThreadLocal(); 11 | 12 | public static void setDBName(String dbName) { 13 | contextHolder.set(dbName); 14 | } 15 | 16 | public static String getDBName() { 17 | return contextHolder.get(); 18 | } 19 | 20 | public static void clearDBName() { 21 | contextHolder.remove(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/common/CatContext.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.common; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.dianping.cat.Cat; 7 | 8 | /** 9 | * 实现CAT上下文,以用来传递messageTreeId 10 | * @author potato 11 | * @date 2016-6-8 12 | */ 13 | public class CatContext implements Cat.Context { 14 | 15 | private Map properties = new HashMap(); 16 | 17 | @Override 18 | public void addProperty(String key, String value) { 19 | properties.put(key, value); 20 | } 21 | 22 | @Override 23 | public String getProperty(String key) { 24 | return properties.get(key); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/datasource/DataSource.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.datasource; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 多数据源标签 - 根据value值切换数据源 12 | * @author potato 13 | * 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ElementType.METHOD, ElementType.TYPE}) 17 | @Inherited 18 | @Documented 19 | public @interface DataSource { 20 | 21 | /** 22 | * database name 23 | * @return 24 | */ 25 | String value() default ""; 26 | } 27 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/datasource/AnnotationDataSourceAspect.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.datasource; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.springframework.core.Ordered; 7 | 8 | /** 9 | * 将数据库名(DataSource注解的value值)保存到当前线程 10 | * @author potato 11 | * 12 | */ 13 | @Aspect 14 | public class AnnotationDataSourceAspect implements Ordered { 15 | 16 | @Around("@annotation(net.tomjerry.catmonitor.datasource.DataSource)") 17 | public Object selectDataSource(ProceedingJoinPoint point) throws Throwable { 18 | return DataSourceAspectUtil.selectDataSource(point); 19 | } 20 | 21 | @Override 22 | public int getOrder() { 23 | //确保在@Transactional之前调用 24 | return 0; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/util/ThreadHelper.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.util; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * 线程相关工具类 7 | * 8 | * @author potato 9 | */ 10 | public class ThreadHelper { 11 | 12 | /** 13 | * sleep等待,单位为ms,已捕捉并处理InterruptedException. 14 | */ 15 | public static void sleep(long durationMillis){ 16 | try { 17 | Thread.sleep(durationMillis); 18 | } catch (InterruptedException e) { 19 | Thread.currentThread().interrupt(); 20 | } 21 | } 22 | 23 | /** 24 | * sleep等待,已捕捉并处理InterruptedException. 25 | */ 26 | public static void sleep(long duration, TimeUnit unit){ 27 | try { 28 | Thread.sleep(unit.toMillis(duration)); 29 | } catch (InterruptedException e) { 30 | Thread.currentThread().interrupt(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/dubbospi/AppNameAppendFilter.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.dubbospi; 2 | 3 | import com.alibaba.dubbo.common.Constants; 4 | import com.alibaba.dubbo.common.extension.Activate; 5 | import com.alibaba.dubbo.rpc.Filter; 6 | import com.alibaba.dubbo.rpc.Invocation; 7 | import com.alibaba.dubbo.rpc.Invoker; 8 | import com.alibaba.dubbo.rpc.Result; 9 | import com.alibaba.dubbo.rpc.RpcContext; 10 | import com.alibaba.dubbo.rpc.RpcException; 11 | 12 | /** 13 | * 获取application-name 14 | * @author potato 15 | */ 16 | @Activate(group = {Constants.CONSUMER}) 17 | public class AppNameAppendFilter implements Filter { 18 | 19 | @Override 20 | public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { 21 | RpcContext.getContext().setAttachment(Constants.APPLICATION_KEY, invoker.getUrl().getParameter(Constants.APPLICATION_KEY)); 22 | return invoker.invoke(invocation); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/common/CatConstants.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.common; 2 | 3 | /** 4 | * CAT相关关键字定义 5 | * @author potato 6 | * 7 | */ 8 | public interface CatConstants { 9 | 10 | public static final String CROSS_CONSUMER = "PigeonCall"; 11 | 12 | public static final String CROSS_SERVER = "PigeonService"; 13 | 14 | public static final String CONSUMER_CALL_SERVER = "PigeonCall.server"; 15 | 16 | public static final String CONSUMER_CALL_APP = "PigeonCall.app"; 17 | 18 | public static final String CONSUMER_CALL_PORT = "PigeonCall.port"; 19 | 20 | public static final String PROVIDER_SERVICE_CLIENT = "PigeonService.client"; 21 | 22 | public static final String PROVIDER_SERVICE_APP = "PigeonService.app"; 23 | 24 | public static final String CLIENT_APPLICATION_NAME = "ClientApplication.Name"; 25 | 26 | public static final String DUBBO_PROVIDER_APPLICATION_NAME = "serverApplicationName"; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cat-monitor 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | org.eclipse.wst.validation.validationbuilder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/dubbospi/registry/CatRegistryFactoryWrapper.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.dubbospi.registry; 2 | 3 | import java.util.List; 4 | 5 | import net.tomjerry.catmonitor.common.CatConstants; 6 | 7 | import com.alibaba.dubbo.common.Constants; 8 | import com.alibaba.dubbo.common.URL; 9 | import com.alibaba.dubbo.registry.NotifyListener; 10 | import com.alibaba.dubbo.registry.Registry; 11 | import com.alibaba.dubbo.registry.RegistryFactory; 12 | 13 | /** 14 | * 获取应用名称 15 | * @author potato 16 | */ 17 | public class CatRegistryFactoryWrapper implements RegistryFactory { 18 | 19 | private RegistryFactory registryFactory; 20 | 21 | public CatRegistryFactoryWrapper(RegistryFactory registryFactory) { 22 | this.registryFactory = registryFactory; 23 | } 24 | 25 | @Override 26 | public Registry getRegistry(URL url) { 27 | return new RegistryWrapper(registryFactory.getRegistry(url)); 28 | } 29 | 30 | class RegistryWrapper implements Registry { 31 | private Registry originRegistry; 32 | private URL appendProviderAppName(URL url){ 33 | String side = url.getParameter(Constants.SIDE_KEY); 34 | if(Constants.PROVIDER_SIDE.equals(side)){ 35 | url = url.addParameter(CatConstants.DUBBO_PROVIDER_APPLICATION_NAME, url.getParameter(Constants.APPLICATION_KEY)); 36 | } 37 | return url; 38 | } 39 | 40 | public RegistryWrapper(Registry originRegistry) { 41 | this.originRegistry = originRegistry; 42 | } 43 | 44 | @Override 45 | public URL getUrl() { 46 | return originRegistry.getUrl(); 47 | } 48 | 49 | @Override 50 | public boolean isAvailable() { 51 | return originRegistry.isAvailable(); 52 | } 53 | 54 | @Override 55 | public void destroy() { 56 | originRegistry.destroy(); 57 | } 58 | 59 | @Override 60 | public void register(URL url) { 61 | originRegistry.register(appendProviderAppName(url)); 62 | } 63 | 64 | @Override 65 | public void unregister(URL url) { 66 | originRegistry.unregister(appendProviderAppName(url)); 67 | } 68 | 69 | @Override 70 | public void subscribe(URL url, NotifyListener listener) { 71 | originRegistry.subscribe(url, listener); 72 | } 73 | 74 | @Override 75 | public void unsubscribe(URL url, NotifyListener listener) { 76 | originRegistry.unsubscribe(url, listener); 77 | } 78 | 79 | @Override 80 | public List lookup(URL url) { 81 | return originRegistry.lookup(appendProviderAppName(url)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/datasource/DataSourceAspectUtil.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.datasource; 2 | 3 | import org.aspectj.lang.JoinPoint; 4 | import org.aspectj.lang.ProceedingJoinPoint; 5 | import org.aspectj.lang.reflect.MethodSignature; 6 | import org.springframework.core.annotation.AnnotationUtils; 7 | import org.springframework.util.ConcurrentReferenceHashMap; 8 | 9 | import java.lang.annotation.Annotation; 10 | import java.lang.reflect.Method; 11 | import java.util.Map; 12 | 13 | /** 14 | * 动态切换数据源,切面可调用本方法 15 | * @author potato 16 | */ 17 | public class DataSourceAspectUtil { 18 | 19 | //注解缓存,提高性能 20 | private static final Map findAnnotationCache = 21 | new ConcurrentReferenceHashMap(256); 22 | 23 | 24 | public static Object selectDataSource(ProceedingJoinPoint point) throws Throwable { 25 | String currentDB = DataSourceHolder.getDBName(); 26 | if (currentDB == null) { 27 | /** 28 | * 只有在上下文中没有指定数据库时才选择数据库 29 | * 确保在一个嵌套Session中使用同一个DB 30 | * 即:如果在Controller和DAO(或Mapper)中指定同时指定了DB,Controller中的值将被使用 31 | */ 32 | DataSource a = getDataSourceAnnotation(point); 33 | if (a != null && a != NULL_ANNOTATION) { 34 | String dbName = a.value(); 35 | DataSourceHolder.setDBName(dbName); 36 | } 37 | } 38 | 39 | try { 40 | Object result = point.proceed(); 41 | return result; 42 | } finally { 43 | //恢复当前线程中的设置 44 | DataSourceHolder.setDBName(currentDB); 45 | } 46 | } 47 | 48 | /** 49 | * 从方法或类或实现的接口中获取DataSource注解 50 | */ 51 | private static DataSource getDataSourceAnnotation(JoinPoint point) throws NoSuchMethodException, SecurityException { 52 | Object target = point.getTarget(); 53 | Class classz = target.getClass(); 54 | String methodName = point.getSignature().getName(); 55 | Class[] parameterTypes = ((MethodSignature) point.getSignature()) 56 | .getMethod().getParameterTypes(); 57 | Method method = target.getClass().getMethod(methodName, parameterTypes); 58 | 59 | DataSource result = findAnnotationCache.get(method); 60 | if (result == NULL_ANNOTATION) { 61 | return null; 62 | } 63 | if (result != null) { 64 | return result; 65 | } 66 | 67 | result = AnnotationUtils.findAnnotation(method, DataSource.class); 68 | if (result == null) { 69 | result = AnnotationUtils.findAnnotation(classz, DataSource.class); 70 | } 71 | if (result == null) { 72 | result = NULL_ANNOTATION; 73 | } 74 | 75 | findAnnotationCache.put(method, result);//保存到缓存 76 | 77 | return result; 78 | } 79 | 80 | 81 | //定义个NULL常量,方便缓存 82 | private static final DataSource NULL_ANNOTATION = new DataSource() { 83 | @Override 84 | public Class annotationType() { 85 | return null; 86 | } 87 | 88 | @Override 89 | public String value() { 90 | return null; 91 | } 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/util/cache/CatRedisClient.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.util.cache; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import redis.clients.jedis.Jedis; 8 | 9 | import com.dianping.cat.Cat; 10 | import com.dianping.cat.message.Transaction; 11 | 12 | /** 13 | * 添加了Cat监控的Redis工具类 14 | * 只对execute(JedisCallback jedisCallback, String key)添加了监控 15 | * execute(SharedRedisCallback redisCallback)需要自己添加cat监控 16 | * 17 | * @author potato 18 | */ 19 | public class CatRedisClient extends RedisClient { 20 | 21 | private Logger logger = LoggerFactory.getLogger(CatRedisClient.class); 22 | 23 | public static final String REDIS_TYPE_PREFIX = "Cache."; 24 | public static final String REDIS_EVENT_TYPE = "Cache.redis.server"; 25 | private static final String REDIS_SERVER_IP_PATTERN = "%s(%s)"; 26 | 27 | //cat auth level,设置这个字段在cat报表中区分不同的auth level 28 | private String catAuthLevel = "default"; 29 | 30 | private String redisGroup; //需注入来初始化,redis分组,用于在CAT分类redis服务器 31 | private String redisType; 32 | 33 | public String getRedisGroup() { 34 | return redisGroup; 35 | } 36 | 37 | public void setRedisGroup(String redisGroup) { 38 | this.redisGroup = redisGroup; 39 | 40 | if(StringUtils.isBlank(redisGroup)){ 41 | this.redisType = "Cache.redis"; 42 | }else{ 43 | this.redisType = REDIS_TYPE_PREFIX + this.redisGroup; 44 | } 45 | } 46 | 47 | @Override 48 | public T execute(JedisCallback jedisCallback, String key) { 49 | return super.execute(new CatJedisCallback(jedisCallback), key); 50 | } 51 | 52 | public class CatJedisCallback implements JedisCallback { 53 | private JedisCallback callback; 54 | public CatJedisCallback(JedisCallback callback) { 55 | this.callback = callback; 56 | } 57 | 58 | @Override 59 | public T doInJedis(Jedis jedis) { 60 | String host = jedis.getClient().getHost(); 61 | int port = jedis.getClient().getPort(); 62 | 63 | Transaction t = Cat.newTransaction(redisType, CatRedisClient.this.catAuthLevel + ':' + this.callback.redisMethodName()); 64 | 65 | Cat.logEvent(REDIS_EVENT_TYPE, String.format(REDIS_SERVER_IP_PATTERN, host, port)); 66 | try { 67 | T ret = this.callback.doInJedis(jedis); 68 | t.setStatus(Transaction.SUCCESS); 69 | return ret; 70 | } catch (Exception e) { 71 | t.setStatus(e.getClass().getSimpleName()); 72 | //throw e; 73 | 74 | logger.error("--- redis cat error : ", e); 75 | return null; 76 | 77 | } finally { 78 | t.complete(); 79 | } 80 | } 81 | 82 | @Override 83 | public String redisMethodName() { 84 | return this.callback.redisMethodName(); 85 | } 86 | } 87 | 88 | public String getCatAuthLevel() { 89 | return catAuthLevel; 90 | } 91 | 92 | public void setCatAuthLevel(String catAuthLevel) { 93 | this.catAuthLevel = catAuthLevel; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/maven/net.tomjerry/cat-monitor/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.tomjerry 5 | cat-monitor 6 | war 7 | 0.0.1-SNAPSHOT 8 | cat-monitor Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 3.2.9.RELEASE 13 | 4.4 14 | 3.4 15 | 1.7.12 16 | 2.8.0 17 | 18 | 19 | 20 | 21 | junit 22 | junit 23 | 3.8.1 24 | test 25 | 26 | 27 | 28 | org.springframework 29 | spring-context 30 | ${spring.version} 31 | 32 | 33 | org.springframework 34 | spring-jdbc 35 | ${spring.version} 36 | 37 | 38 | org.apache.httpcomponents 39 | httpclient 40 | ${httpclient.version} 41 | 42 | 43 | org.slf4j 44 | slf4j-api 45 | ${slf4j.version} 46 | 47 | 48 | org.apache.commons 49 | commons-lang3 50 | ${commons.lang3.version} 51 | 52 | 53 | 54 | com.alibaba 55 | dubbo 56 | 2.8.4 57 | 58 | 59 | 60 | com.dianping.cat 61 | cat-client 62 | 1.3.6 63 | 64 | 65 | 66 | redis.clients 67 | jedis 68 | ${jedis.version} 69 | 70 | 71 | 72 | 73 | 74 | org.mybatis 75 | mybatis 76 | 3.3.1 77 | 78 | 79 | 80 | org.mybatis 81 | mybatis-spring 82 | 1.2.2 83 | 84 | 85 | 86 | 87 | mysql 88 | mysql-connector-java 89 | 5.1.38 90 | 91 | 92 | 93 | 94 | com.alibaba 95 | druid 96 | 1.0.16 97 | 98 | 99 | 100 | 101 | cat-monitor 102 | 103 | 104 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.tomjerry 5 | cat-monitor 6 | jar 7 | 1.0.0.RELEASE 8 | cat-monitor Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 3.2.9.RELEASE 13 | 4.4 14 | 3.4 15 | 1.7.12 16 | 2.8.0 17 | 18 | UTF-8 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 3.8.1 26 | test 27 | 28 | 29 | 30 | org.springframework 31 | spring-context 32 | ${spring.version} 33 | 34 | 35 | org.springframework 36 | spring-jdbc 37 | ${spring.version} 38 | 39 | 40 | org.apache.httpcomponents 41 | httpclient 42 | ${httpclient.version} 43 | 44 | 45 | org.slf4j 46 | slf4j-api 47 | ${slf4j.version} 48 | 49 | 50 | org.apache.commons 51 | commons-lang3 52 | ${commons.lang3.version} 53 | 54 | 55 | 56 | com.alibaba 57 | dubbo 58 | 2.8.4 59 | 60 | 61 | 62 | com.dianping.cat 63 | cat-client 64 | 1.3.6 65 | 66 | 67 | 68 | redis.clients 69 | jedis 70 | ${jedis.version} 71 | 72 | 73 | 74 | 75 | 76 | org.mybatis 77 | mybatis 78 | 3.3.1 79 | 80 | 81 | 82 | org.mybatis 83 | mybatis-spring 84 | 1.2.2 85 | 86 | 87 | 88 | 89 | mysql 90 | mysql-connector-java 91 | 5.1.38 92 | 93 | 94 | 95 | 96 | com.alibaba 97 | druid 98 | 1.0.16 99 | 100 | 101 | 102 | 103 | 104 | 105 | cat-monitor 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/filter/HttpCatCrossFliter.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import net.tomjerry.catmonitor.common.CatConstants; 17 | import net.tomjerry.catmonitor.common.CatContext; 18 | 19 | import com.dianping.cat.Cat; 20 | import com.dianping.cat.message.Event; 21 | import com.dianping.cat.message.Transaction; 22 | import com.dianping.cat.message.internal.AbstractMessage; 23 | import com.dianping.cat.message.internal.NullMessage; 24 | 25 | /** 26 | * 服务提供侧串联消息树 27 | * @author potato 28 | * @date 2016-6-8 11:36:10 29 | */ 30 | public class HttpCatCrossFliter implements Filter { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(HttpCatCrossFliter.class); 33 | 34 | private static final String DEFAULT_APPLICATION_NAME = "default"; 35 | 36 | @Override 37 | public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException { 38 | 39 | HttpServletRequest request = (HttpServletRequest) req; 40 | String requestURI = request.getRequestURI(); 41 | 42 | Transaction t = Cat.newTransaction(CatConstants.CROSS_SERVER, requestURI); 43 | 44 | try{ 45 | Cat.Context context = new CatContext(); 46 | context.addProperty(Cat.Context.ROOT, request.getHeader(Cat.Context.ROOT)); 47 | context.addProperty(Cat.Context.PARENT, request.getHeader(Cat.Context.PARENT)); 48 | context.addProperty(Cat.Context.CHILD, request.getHeader(Cat.Context.CHILD)); 49 | Cat.logRemoteCallServer(context); 50 | this.createProviderCross(request, t); 51 | 52 | filterChain.doFilter(req, resp); 53 | t.setStatus(Transaction.SUCCESS); 54 | } catch (Exception e) { 55 | logger.error("------ Get cat msgtree error : ", e); 56 | 57 | Event event = null; 58 | event = Cat.newEvent("HTTP_REST_CAT_ERROR", requestURI); 59 | event.setStatus(e); 60 | completeEvent(event); 61 | t.addChild(event); 62 | t.setStatus(e.getClass().getSimpleName()); 63 | } finally { 64 | t.complete(); 65 | } 66 | 67 | } 68 | 69 | @Override 70 | public void init(FilterConfig arg0) throws ServletException { 71 | } 72 | 73 | @Override 74 | public void destroy() { 75 | } 76 | 77 | /** 78 | * 串联provider端消息树 79 | * @param request 80 | * @param t 81 | */ 82 | private void createProviderCross(HttpServletRequest request, Transaction t){ 83 | 84 | Event crossAppEvent = Cat.newEvent(CatConstants.PROVIDER_SERVICE_APP, request.getHeader(CatConstants.CLIENT_APPLICATION_NAME)); //clientName 85 | Event crossServerEvent = Cat.newEvent(CatConstants.PROVIDER_SERVICE_CLIENT, request.getRemoteAddr()); //clientIp 86 | crossAppEvent.setStatus(Event.SUCCESS); 87 | crossServerEvent.setStatus(Event.SUCCESS); 88 | completeEvent(crossAppEvent); 89 | completeEvent(crossServerEvent); 90 | t.addChild(crossAppEvent); 91 | t.addChild(crossServerEvent); 92 | } 93 | 94 | private void completeEvent(Event event){ 95 | if (event != NullMessage.EVENT) { 96 | AbstractMessage message = (AbstractMessage) event; 97 | message.setCompleted(true); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/util/http/CatCrossHttpClientProxy.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.util.http; 2 | 3 | import java.io.IOException; 4 | 5 | import net.tomjerry.catmonitor.common.CatConstants; 6 | import net.tomjerry.catmonitor.common.CatContext; 7 | 8 | import org.apache.http.annotation.ThreadSafe; 9 | import org.apache.http.client.methods.HttpRequestBase; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.dianping.cat.Cat; 14 | import com.dianping.cat.message.Event; 15 | import com.dianping.cat.message.Transaction; 16 | import com.dianping.cat.message.internal.AbstractMessage; 17 | import com.dianping.cat.message.internal.NullMessage; 18 | 19 | /** 20 | * 支持CatCross监控的HttpClient类 21 | * 22 | * @author potato 23 | * @date 2016-6-8 24 | */ 25 | @ThreadSafe 26 | public class CatCrossHttpClientProxy extends HttpClientProxy { 27 | 28 | private Logger logger = LoggerFactory.getLogger(CatCrossHttpClientProxy.class); 29 | 30 | //please inject this attr in the spring-applicationContext 31 | private String applicationName; 32 | 33 | public String getApplicationName() { 34 | return applicationName; 35 | } 36 | 37 | public void setApplicationName(String applicationName) { 38 | this.applicationName = applicationName; 39 | } 40 | 41 | /** 42 | * 发起Http请求 43 | * 较复杂的请求如设置HttpHeader等,可调用本方法执行 44 | * @param request 45 | * @param socketTimeout 46 | * @param connectTimeout 47 | * @return 48 | * @throws IOException 49 | */ 50 | public String execute(HttpRequestBase request, int socketTimeout, int connectTimeout) throws IOException { 51 | Transaction t = Cat.newTransaction(CatConstants.CROSS_CONSUMER, request.getURI().getPath()); 52 | 53 | //串联message-tree埋点 54 | this.createConsumerCross(request, t); 55 | Cat.Context context = new CatContext(); 56 | Cat.logRemoteCallClient(context); 57 | request.setHeader(Cat.Context.ROOT, context.getProperty(Cat.Context.ROOT)); 58 | request.setHeader(Cat.Context.PARENT, context.getProperty(Cat.Context.PARENT)); 59 | request.setHeader(Cat.Context.CHILD, context.getProperty(Cat.Context.CHILD)); 60 | 61 | //设置服务消费方的clientName 62 | request.setHeader(CatConstants.CLIENT_APPLICATION_NAME, applicationName); 63 | 64 | try { 65 | String ret = super.execute(request, socketTimeout, connectTimeout); 66 | t.setStatus(Transaction.SUCCESS); 67 | return ret; 68 | } catch (IOException e) { 69 | 70 | Event event = null; 71 | event = Cat.newEvent("HTTP_REST_CAT_ERROR", request.getURI().getPath()); 72 | event.setStatus(e); 73 | completeEvent(event); 74 | t.addChild(event); 75 | t.setStatus(e.getClass().getSimpleName()); 76 | throw e; 77 | } finally { 78 | t.complete(); 79 | } 80 | } 81 | 82 | private void createConsumerCross(HttpRequestBase request, Transaction t) { 83 | 84 | String uriPath = request.getURI().getPath(); 85 | Event crossAppEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_APP, uriPath.substring(0, uriPath.lastIndexOf("/"))); //serverName 86 | Event crossServerEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_SERVER, request.getURI().getHost()); //serverIp 87 | Event crossPortEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_PORT, String.valueOf(request.getURI().getPort())); 88 | crossAppEvent.setStatus(Event.SUCCESS); 89 | crossServerEvent.setStatus(Event.SUCCESS); 90 | crossPortEvent.setStatus(Event.SUCCESS); 91 | completeEvent(crossAppEvent); 92 | completeEvent(crossPortEvent); 93 | completeEvent(crossServerEvent); 94 | t.addChild(crossAppEvent); 95 | t.addChild(crossPortEvent); 96 | t.addChild(crossServerEvent); 97 | } 98 | 99 | private void completeEvent(Event event){ 100 | if (event != NullMessage.EVENT) { 101 | AbstractMessage message = (AbstractMessage) event; 102 | message.setCompleted(true); 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/mybatisext/CatMybatisPlugin.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.mybatisext; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.Map; 6 | import java.util.Properties; 7 | 8 | import net.tomjerry.catmonitor.datasource.DataSourceHolder; 9 | 10 | import org.apache.ibatis.executor.Executor; 11 | import org.apache.ibatis.mapping.MappedStatement; 12 | import org.apache.ibatis.mapping.SqlCommandType; 13 | import org.apache.ibatis.plugin.Interceptor; 14 | import org.apache.ibatis.plugin.Intercepts; 15 | import org.apache.ibatis.plugin.Invocation; 16 | import org.apache.ibatis.plugin.Plugin; 17 | import org.apache.ibatis.plugin.Signature; 18 | import org.apache.ibatis.session.ResultHandler; 19 | import org.apache.ibatis.session.RowBounds; 20 | import org.mybatis.spring.transaction.SpringManagedTransaction; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 24 | import org.springframework.util.ConcurrentReferenceHashMap; 25 | import org.springframework.util.ReflectionUtils; 26 | 27 | import com.alibaba.druid.pool.DruidDataSource; 28 | import com.dianping.cat.Cat; 29 | import com.dianping.cat.message.Transaction; 30 | 31 | /** 32 | * 对MyBatis进行拦截,添加Cat监控 33 | * 目前仅支持RoutingDataSource和Druid组合配置的数据源 34 | * 35 | * @author potato 36 | */ 37 | 38 | @Intercepts({ 39 | @Signature(method = "query", type = Executor.class, args = { 40 | MappedStatement.class, Object.class, RowBounds.class, 41 | ResultHandler.class }), 42 | @Signature(method = "update", type = Executor.class, args = { MappedStatement.class, Object.class }) 43 | }) 44 | public class CatMybatisPlugin implements Interceptor { 45 | 46 | private static Logger logger = LoggerFactory.getLogger(CatMybatisPlugin.class); 47 | 48 | //缓存,提高性能 49 | private static final Map sqlURLCache = new ConcurrentReferenceHashMap(256); 50 | 51 | private static final String EMPTY_CONNECTION = "jdbc:mysql://unknown:3306/%s?useUnicode=true"; 52 | 53 | private Executor target; 54 | 55 | @Override 56 | public Object intercept(Invocation invocation) throws Throwable { 57 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 58 | //得到类名,方法 59 | String[] strArr = mappedStatement.getId().split("\\."); 60 | String methodName = strArr[strArr.length - 2] + "." + strArr[strArr.length - 1]; 61 | 62 | 63 | Transaction t = Cat.newTransaction("SQL", methodName); 64 | 65 | //获取SQL类型 66 | SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); 67 | Cat.logEvent("SQL.Method", sqlCommandType.name().toLowerCase()); 68 | 69 | String s = this.getSQLDatabase(); 70 | Cat.logEvent("SQL.Database", s); 71 | 72 | Object returnObj = null; 73 | try { 74 | returnObj = invocation.proceed(); 75 | t.setStatus(Transaction.SUCCESS); 76 | } catch (Exception e) { 77 | Cat.logError(e); 78 | } finally { 79 | t.complete(); 80 | } 81 | 82 | return returnObj; 83 | } 84 | 85 | private javax.sql.DataSource getDataSource() { 86 | org.apache.ibatis.transaction.Transaction transaction = this.target.getTransaction(); 87 | if (transaction == null) { 88 | logger.error(String.format("Could not find transaction on target [%s]", this.target)); 89 | return null; 90 | } 91 | if (transaction instanceof SpringManagedTransaction) { 92 | String fieldName = "dataSource"; 93 | Field field = ReflectionUtils.findField(transaction.getClass(), fieldName, javax.sql.DataSource.class); 94 | 95 | if (field == null) { 96 | logger.error(String.format("Could not find field [%s] of type [%s] on target [%s]", 97 | fieldName, javax.sql.DataSource.class, this.target)); 98 | return null; 99 | } 100 | 101 | ReflectionUtils.makeAccessible(field); 102 | javax.sql.DataSource dataSource = (javax.sql.DataSource) ReflectionUtils.getField(field, transaction); 103 | return dataSource; 104 | } 105 | 106 | logger.error(String.format("---the transaction is not SpringManagedTransaction:%s", transaction.getClass().toString())); 107 | 108 | return null; 109 | } 110 | 111 | private String getSqlURL() { 112 | javax.sql.DataSource dataSource = this.getDataSource(); 113 | 114 | if (dataSource == null) { 115 | return null; 116 | } 117 | 118 | if (dataSource instanceof AbstractRoutingDataSource) { 119 | String methodName = "determineTargetDataSource"; 120 | Method method = ReflectionUtils.findMethod(AbstractRoutingDataSource.class, methodName); 121 | 122 | if (method == null) { 123 | logger.error(String.format("---Could not find method [%s] on target [%s]", 124 | methodName, dataSource)); 125 | return null; 126 | } 127 | 128 | ReflectionUtils.makeAccessible(method); 129 | javax.sql.DataSource dataSource1 = (javax.sql.DataSource) ReflectionUtils.invokeMethod(method, dataSource); 130 | if (dataSource1 instanceof DruidDataSource) { 131 | DruidDataSource druidDataSource = (DruidDataSource) dataSource1; 132 | return druidDataSource.getUrl(); 133 | } else { 134 | logger.error("---only surpport DruidDataSource:" + dataSource1.getClass().toString()); 135 | } 136 | } 137 | return null; 138 | } 139 | 140 | private String getSQLDatabase() { 141 | String dbName = DataSourceHolder.getDBName(); 142 | if (dbName == null) { 143 | dbName = "DEFAULT"; 144 | } 145 | String url = CatMybatisPlugin.sqlURLCache.get(dbName); 146 | if (url != null) { 147 | return url; 148 | } 149 | 150 | url = this.getSqlURL(); 151 | if (url == null) { 152 | url = String.format(EMPTY_CONNECTION, dbName); 153 | } 154 | CatMybatisPlugin.sqlURLCache.put(dbName, url); 155 | return url; 156 | } 157 | 158 | 159 | @Override 160 | public Object plugin(Object target) { 161 | if (target instanceof Executor) { 162 | this.target = (Executor) target; 163 | return Plugin.wrap(target, this); 164 | } 165 | return target; 166 | } 167 | 168 | @Override 169 | public void setProperties(Properties properties) { 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/util/cache/RedisClient.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.util.cache; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import redis.clients.jedis.Jedis; 6 | import redis.clients.jedis.ShardedJedis; 7 | import redis.clients.jedis.ShardedJedisPool; 8 | 9 | /** 10 | * redis工具类 11 | * @author potato 12 | * @date 2016-6-16 13 | */ 14 | public class RedisClient { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(RedisClient.class); 17 | 18 | private ShardedJedisPool shardedJedisPool; 19 | private int redisTimeout; //redis缓存默认过时时间(秒) 20 | 21 | 22 | public boolean set(final String key, final String value) { 23 | return this.execute(new JedisCallback() { 24 | @Override 25 | public Boolean doInJedis(Jedis jedis) { 26 | String s = jedis.set(key, value); 27 | 28 | return "OK".equals(s); 29 | } 30 | 31 | @Override 32 | public String redisMethodName() { 33 | return "set"; 34 | } 35 | }, key); 36 | } 37 | 38 | /** 39 | * 支持value为byte[] 40 | * @date 2016-8-15 41 | */ 42 | public boolean setByte(final String key, final byte[] value){ 43 | 44 | return this.execute(new JedisCallback() { 45 | @Override 46 | public Boolean doInJedis(Jedis jedis) { 47 | String s = jedis.set(key.getBytes(), value); 48 | 49 | return "OK".equals(s); 50 | } 51 | 52 | @Override 53 | public String redisMethodName() { 54 | return "set"; 55 | } 56 | }, key); 57 | 58 | } 59 | 60 | 61 | /** 62 | * 使用默认超时时间 63 | * @param key 64 | * @param value 65 | * @return 66 | */ 67 | public boolean setex(final String key, final String value) { 68 | return this.setex(key, value, this.redisTimeout); 69 | } 70 | 71 | public boolean setex(final String key, final byte[] value) { 72 | return this.setexByte(key, value, this.redisTimeout); 73 | } 74 | 75 | /** 76 | * 77 | * @param key 78 | * @param value 79 | * @param timeout 超时时间(秒) 80 | * @return 81 | */ 82 | public boolean setex(final String key, final String value, final int timeout) { 83 | return this.execute(new JedisCallback() { 84 | @Override 85 | public Boolean doInJedis(Jedis jedis) { 86 | String s = jedis.setex(key, timeout, value); 87 | return "OK".equals(s); 88 | } 89 | 90 | @Override 91 | public String redisMethodName() { 92 | return "setex"; 93 | } 94 | }, key); 95 | } 96 | 97 | /** 98 | * 支持byte[] 99 | * @param key 100 | * @param value 101 | * @param timeout 102 | * @return 103 | */ 104 | public boolean setexByte(final String key, final byte[] value, final int timeout) { 105 | return this.execute(new JedisCallback() { 106 | @Override 107 | public Boolean doInJedis(Jedis jedis) { 108 | String s = jedis.setex(key.getBytes(), timeout, value); 109 | return "OK".equals(s); 110 | } 111 | 112 | @Override 113 | public String redisMethodName() { 114 | return "setex"; 115 | } 116 | }, key); 117 | } 118 | 119 | public String get(final String key) { 120 | return this.execute(new JedisCallback() { 121 | @Override 122 | public String doInJedis(Jedis jedis) { 123 | String value = jedis.get(key); 124 | return value; 125 | } 126 | 127 | @Override 128 | public String redisMethodName() { 129 | return "get"; 130 | } 131 | }, key); 132 | } 133 | 134 | /** 135 | * 支持key为byte[] 136 | * @param key 137 | * @return 138 | */ 139 | public byte[] getByte(final String key) { 140 | return this.execute(new JedisCallback() { 141 | @Override 142 | public byte[] doInJedis(Jedis jedis) { 143 | byte[] value = jedis.get(key.getBytes()); 144 | return value; 145 | } 146 | 147 | @Override 148 | public String redisMethodName() { 149 | return "get"; 150 | } 151 | }, key); 152 | } 153 | 154 | public Long delete(final String key) { 155 | return this.execute(new JedisCallback() { 156 | @Override 157 | public Long doInJedis(Jedis jedis) { 158 | return jedis.del(key); 159 | } 160 | 161 | @Override 162 | public String redisMethodName() { 163 | return "delete"; 164 | } 165 | }, key); 166 | } 167 | 168 | public T execute(SharedRedisCallback redisCallback) { 169 | ShardedJedis jedis = null; 170 | try { 171 | jedis = this.getShardedJedisPool().getResource(); 172 | return redisCallback.doInRedis(jedis); 173 | } finally { 174 | if (jedis != null) { 175 | try { 176 | jedis.close(); 177 | } catch (Exception e) { 178 | log.error("redis close exception", e); 179 | } 180 | } 181 | } 182 | } 183 | 184 | public T execute(JedisCallback jedisCallback, String key) { 185 | ShardedJedis sharededJedis = null; 186 | try { 187 | sharededJedis = this.getShardedJedisPool().getResource(); 188 | Jedis j = sharededJedis.getShard(key); 189 | return jedisCallback.doInJedis(j); 190 | } finally { 191 | if (sharededJedis != null) { 192 | try { 193 | sharededJedis.close(); 194 | } catch (Exception e) { 195 | log.error("redis close exception", e); 196 | } 197 | } 198 | } 199 | } 200 | 201 | public ShardedJedisPool getShardedJedisPool() { 202 | return shardedJedisPool; 203 | } 204 | 205 | public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) { 206 | this.shardedJedisPool = shardedJedisPool; 207 | } 208 | 209 | public int getRedisTimeout() { 210 | return redisTimeout; 211 | } 212 | 213 | public void setRedisTimeout(int redisTimeout) { 214 | this.redisTimeout = redisTimeout; 215 | } 216 | 217 | public static interface SharedRedisCallback { 218 | 219 | public T doInRedis(ShardedJedis jedis); 220 | } 221 | 222 | /** 223 | * 使用于只对一个key进行操作的情况 224 | * @param 225 | */ 226 | public static interface JedisCallback { 227 | 228 | public T doInJedis(Jedis jedis); 229 | 230 | /** 231 | * 返回要执行的redis方法名,如setex, get等 232 | */ 233 | public String redisMethodName(); 234 | 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/util/http/HttpClientProxy.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.util.http; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import org.apache.http.Consts; 7 | import org.apache.http.HttpEntity; 8 | import org.apache.http.annotation.ThreadSafe; 9 | import org.apache.http.client.config.RequestConfig; 10 | import org.apache.http.client.methods.HttpGet; 11 | import org.apache.http.client.methods.HttpPost; 12 | import org.apache.http.client.methods.HttpRequestBase; 13 | import org.apache.http.config.SocketConfig; 14 | import org.apache.http.entity.ContentType; 15 | import org.apache.http.entity.StringEntity; 16 | import org.apache.http.impl.client.BasicResponseHandler; 17 | import org.apache.http.impl.client.CloseableHttpClient; 18 | import org.apache.http.impl.client.HttpClientBuilder; 19 | import org.apache.http.impl.client.HttpClients; 20 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 21 | import org.apache.http.util.EntityUtils; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | import org.springframework.beans.factory.InitializingBean; 25 | 26 | /** 27 | * Http Client的包装类,基于4.4实现 28 | * 应根据具体应用个性化maxPerRoute, maxTotal, timeToLive参数 29 | * 30 | * @author potato 31 | */ 32 | @ThreadSafe 33 | public class HttpClientProxy implements InitializingBean { 34 | 35 | private Logger logger = LoggerFactory.getLogger(HttpClientProxy.class); 36 | 37 | private static final int DEFAULT_MAX_PER_ROUTE = 15; 38 | private static final int DEFAULT_MAX_TOTAL = 100; 39 | private static final int DEFAULT_TIME_TO_LIVE = 3000; //毫秒 40 | 41 | private CloseableHttpClient httpClient; 42 | 43 | private Integer maxPerRoute; 44 | 45 | private Integer maxTotal; 46 | 47 | private Integer timeToLive; 48 | 49 | private Integer defaultSocketTimeout = 1000; 50 | 51 | private Integer defaultConnectTimeout = 1000; 52 | 53 | public String get(String url) throws IOException { 54 | return this.get(url, -1, -1); 55 | } 56 | 57 | public String get(String url, int socketTimeout, int connectTimeout) throws IOException { 58 | HttpGet httpGet = new HttpGet(url); 59 | return this.execute(httpGet, socketTimeout, connectTimeout); 60 | } 61 | 62 | public String postJson(String url, String json) throws IOException { 63 | return this.postJson(url, json, -1, -1); 64 | } 65 | 66 | public String postJson(String url, String json, int socketTimeout, int connectTimeout) throws IOException { 67 | StringEntity entity = new StringEntity(json, Consts.UTF_8); 68 | entity.setContentEncoding(ContentType.APPLICATION_JSON.getCharset().name()); 69 | entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); 70 | return this.post(url, entity, socketTimeout, connectTimeout); 71 | } 72 | 73 | public String post(String url, HttpEntity entity) throws IOException { 74 | return this.post(url, entity, -1, -1); 75 | } 76 | 77 | public String post(String url, HttpEntity entity, int socketTimeout, int connectTimeout) throws IOException { 78 | HttpPost method = new HttpPost(url); 79 | method.setEntity(entity); 80 | return this.execute(method, socketTimeout, connectTimeout); 81 | } 82 | 83 | public String execute(HttpRequestBase request) throws IOException { 84 | return this.execute(request, -1, -1); 85 | } 86 | 87 | /** 88 | * 发起Http请求 89 | * 较复杂的请求如设置HttpHeader等,可调用本方法执行 90 | * @param request 91 | * @param socketTimeout 92 | * @param connectTimeout 93 | * @return 94 | * @throws IOException 95 | */ 96 | public String execute(HttpRequestBase request,int socketTimeout, int connectTimeout) throws IOException { 97 | if (socketTimeout <= 0) { 98 | socketTimeout = this.defaultSocketTimeout; 99 | } 100 | if (connectTimeout <= 0) { 101 | connectTimeout = this.defaultConnectTimeout; 102 | } 103 | 104 | RequestConfig requestConfig = RequestConfig.custom() 105 | .setSocketTimeout(socketTimeout) 106 | .setConnectTimeout(connectTimeout) 107 | .build(); 108 | 109 | request.setConfig(requestConfig); 110 | return httpClient.execute(request, new StringResponseHandler()); 111 | } 112 | 113 | @Override 114 | public void afterPropertiesSet() throws Exception { 115 | if (this.httpClient != null) { 116 | return; 117 | } 118 | 119 | int timeToLive; 120 | if (this.timeToLive != null) { 121 | timeToLive = this.timeToLive.intValue(); 122 | } else { 123 | timeToLive = DEFAULT_TIME_TO_LIVE; 124 | } 125 | PoolingHttpClientConnectionManager connectionManager = 126 | new PoolingHttpClientConnectionManager(timeToLive, TimeUnit.MILLISECONDS); 127 | 128 | SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build(); 129 | connectionManager.setDefaultSocketConfig(socketConfig); 130 | 131 | connectionManager.setValidateAfterInactivity(1000); 132 | 133 | if (this.maxPerRoute != null) { 134 | connectionManager.setDefaultMaxPerRoute(this.maxPerRoute); 135 | } else { 136 | connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); 137 | } 138 | if (this.maxTotal != null) { 139 | connectionManager.setMaxTotal(this.maxTotal); 140 | } else { 141 | connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL); 142 | } 143 | 144 | HttpClientBuilder clientBuilder = HttpClients.custom(); 145 | clientBuilder.setConnectionManager(connectionManager); 146 | this.httpClient = clientBuilder.build(); 147 | } 148 | 149 | public void setHttpClient(CloseableHttpClient httpClient) { 150 | this.httpClient = httpClient; 151 | } 152 | 153 | public CloseableHttpClient getHttpClient() { 154 | return this.httpClient; 155 | } 156 | 157 | public Integer getMaxPerRoute() { 158 | return maxPerRoute; 159 | } 160 | 161 | public void setMaxPerRoute(Integer maxPerRoute) { 162 | this.maxPerRoute = maxPerRoute; 163 | } 164 | 165 | public Integer getMaxTotal() { 166 | return maxTotal; 167 | } 168 | 169 | public void setMaxTotal(Integer maxTotal) { 170 | this.maxTotal = maxTotal; 171 | } 172 | 173 | public Integer getTimeToLive() { 174 | return timeToLive; 175 | } 176 | 177 | public void setTimeToLive(Integer timeToLive) { 178 | this.timeToLive = timeToLive; 179 | } 180 | 181 | public Integer getSocketTimeout() { 182 | return defaultSocketTimeout; 183 | } 184 | 185 | public void setSocketTimeout(Integer socketTimeout) { 186 | this.defaultSocketTimeout = socketTimeout; 187 | } 188 | 189 | public Integer getConnectTimeout() { 190 | return defaultConnectTimeout; 191 | } 192 | 193 | public void setConnectTimeout(Integer connectTimeout) { 194 | this.defaultConnectTimeout = connectTimeout; 195 | } 196 | 197 | /** 198 | * 将Http响应解析为字符串 199 | * 默认编码格式设置为UTF-8 200 | */ 201 | public static class StringResponseHandler extends BasicResponseHandler { 202 | @Override 203 | public String handleEntity(final HttpEntity entity) throws IOException { 204 | return EntityUtils.toString(entity, "UTF-8"); 205 | } 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/net/tomjerry/catmonitor/dubbospi/DubboCatCrossFilter.java: -------------------------------------------------------------------------------- 1 | package net.tomjerry.catmonitor.dubbospi; 2 | 3 | import java.util.Map; 4 | 5 | import net.tomjerry.catmonitor.common.CatConstants; 6 | import net.tomjerry.catmonitor.common.CatContext; 7 | 8 | import com.alibaba.dubbo.common.Constants; 9 | import com.alibaba.dubbo.common.URL; 10 | import com.alibaba.dubbo.common.extension.Activate; 11 | import com.alibaba.dubbo.common.utils.StringUtils; 12 | import com.alibaba.dubbo.remoting.RemotingException; 13 | import com.alibaba.dubbo.remoting.TimeoutException; 14 | import com.alibaba.dubbo.rpc.Filter; 15 | import com.alibaba.dubbo.rpc.Invocation; 16 | import com.alibaba.dubbo.rpc.Invoker; 17 | import com.alibaba.dubbo.rpc.Result; 18 | import com.alibaba.dubbo.rpc.RpcContext; 19 | import com.alibaba.dubbo.rpc.RpcException; 20 | import com.dianping.cat.Cat; 21 | import com.dianping.cat.message.Event; 22 | import com.dianping.cat.message.Transaction; 23 | import com.dianping.cat.message.internal.AbstractMessage; 24 | import com.dianping.cat.message.internal.NullMessage; 25 | 26 | /** 27 | * 消息树串联:dubbo-rpc服务调用 28 | * @author potato 29 | * 30 | */ 31 | @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}, order = -9000) 32 | public class DubboCatCrossFilter implements Filter { 33 | 34 | private static final ThreadLocal CAT_CONTEXT_LOCAL = new ThreadLocal(); 35 | 36 | @Override 37 | public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { 38 | 39 | URL url = invoker.getUrl(); 40 | String sideKey = url.getParameter(Constants.SIDE_KEY); 41 | String loggerName = invoker.getInterface().getSimpleName() + "." + invocation.getMethodName(); 42 | String type = CatConstants.CROSS_CONSUMER; 43 | if(Constants.PROVIDER_SIDE.equals(sideKey)){ 44 | type = CatConstants.CROSS_SERVER; 45 | } 46 | Transaction t = Cat.newTransaction(type, loggerName); 47 | Result result = null; 48 | try{ 49 | Cat.Context context = this.getCatContext(); 50 | if(Constants.CONSUMER_SIDE.equals(sideKey)){ 51 | this.createConsumerCross(url, t); 52 | Cat.logRemoteCallClient(context); 53 | }else{ 54 | this.createProviderCross(url, t); 55 | Cat.logRemoteCallServer(context); 56 | } 57 | this.setAttachment(context); 58 | result = invoker.invoke(invocation); 59 | 60 | if(result.hasException()){ 61 | //给调用接口出现异常进行打点 62 | Throwable throwable = result.getException(); 63 | Event event = null; 64 | if(RpcException.class == throwable.getClass()){ 65 | Throwable caseBy = throwable.getCause(); 66 | if(caseBy != null && caseBy.getClass() == TimeoutException.class){ 67 | event = Cat.newEvent("DUBBO_TIMEOUT_ERROR", loggerName); 68 | }else{ 69 | event = Cat.newEvent("DUBBO_REMOTING_ERROR", loggerName); 70 | } 71 | }else if(RemotingException.class.isAssignableFrom(throwable.getClass())){ 72 | event = Cat.newEvent("DUBBO_REMOTING_ERROR", loggerName); 73 | }else{ 74 | event = Cat.newEvent("DUBBO_BIZ_ERROR", loggerName); 75 | } 76 | event.setStatus(result.getException()); 77 | this.completeEvent(event); 78 | t.addChild(event); 79 | t.setStatus(result.getException().getClass().getSimpleName()); 80 | }else{ 81 | t.setStatus(Transaction.SUCCESS); 82 | } 83 | return result; 84 | }catch (RuntimeException e){ 85 | Event event = null; 86 | if(RpcException.class == e.getClass()){ 87 | Throwable caseBy = e.getCause(); 88 | if(caseBy != null && caseBy.getClass() == TimeoutException.class){ 89 | event = Cat.newEvent("DUBBO_TIMEOUT_ERROR", loggerName); 90 | }else{ 91 | event = Cat.newEvent("DUBBO_REMOTING_ERROR", loggerName); 92 | } 93 | }else{ 94 | event = Cat.newEvent("DUBBO_BIZ_ERROR", loggerName); 95 | } 96 | event.setStatus(e); 97 | this.completeEvent(event); 98 | t.addChild(event); 99 | t.setStatus(e.getClass().getSimpleName()); 100 | if(result == null){ 101 | throw e; 102 | }else{ 103 | return result; 104 | } 105 | } finally { 106 | t.complete(); 107 | CAT_CONTEXT_LOCAL.remove(); 108 | } 109 | } 110 | 111 | 112 | private Cat.Context getCatContext(){ 113 | Cat.Context context = CAT_CONTEXT_LOCAL.get(); 114 | if(context == null){ 115 | context = initCatContext(); 116 | CAT_CONTEXT_LOCAL.set(context); 117 | } 118 | return context; 119 | } 120 | 121 | private Cat.Context initCatContext(){ 122 | Cat.Context context = new CatContext(); 123 | Map attachments = RpcContext.getContext().getAttachments(); 124 | if(attachments != null && attachments.size() > 0){ 125 | for(Map.Entry entry : attachments.entrySet()){ 126 | if(Cat.Context.CHILD.equals(entry.getKey()) || Cat.Context.ROOT.equals(entry.getKey()) || Cat.Context.PARENT.equals(entry.getKey())){ 127 | context.addProperty(entry.getKey(), entry.getValue()); 128 | } 129 | } 130 | } 131 | return context; 132 | } 133 | 134 | private void setAttachment(Cat.Context context){ 135 | RpcContext.getContext().setAttachment(Cat.Context.ROOT, context.getProperty(Cat.Context.ROOT)); 136 | RpcContext.getContext().setAttachment(Cat.Context.CHILD, context.getProperty(Cat.Context.CHILD)); 137 | RpcContext.getContext().setAttachment(Cat.Context.PARENT, context.getProperty(Cat.Context.PARENT)); 138 | } 139 | 140 | private void createConsumerCross(URL url, Transaction t){ 141 | Event crossAppEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_APP, this.getProviderAppName(url)); 142 | Event crossServerEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_SERVER, url.getHost()); 143 | Event crossPortEvent = Cat.newEvent(CatConstants.CONSUMER_CALL_PORT, url.getPort()+""); 144 | crossAppEvent.setStatus(Event.SUCCESS); 145 | crossServerEvent.setStatus(Event.SUCCESS); 146 | crossPortEvent.setStatus(Event.SUCCESS); 147 | completeEvent(crossAppEvent); 148 | completeEvent(crossPortEvent); 149 | completeEvent(crossServerEvent); 150 | t.addChild(crossAppEvent); 151 | t.addChild(crossPortEvent); 152 | t.addChild(crossServerEvent); 153 | } 154 | 155 | private void createProviderCross(URL url, Transaction t){ 156 | String consumerAppName = RpcContext.getContext().getAttachment(Constants.APPLICATION_KEY); 157 | if(StringUtils.isEmpty(consumerAppName)){ 158 | consumerAppName = RpcContext.getContext().getRemoteHost() + ":" + RpcContext.getContext().getRemotePort(); 159 | } 160 | Event crossAppEvent = Cat.newEvent(CatConstants.PROVIDER_SERVICE_APP, consumerAppName); 161 | Event crossServerEvent = Cat.newEvent(CatConstants.PROVIDER_SERVICE_CLIENT, url.getHost()); 162 | crossAppEvent.setStatus(Event.SUCCESS); 163 | crossServerEvent.setStatus(Event.SUCCESS); 164 | completeEvent(crossAppEvent); 165 | completeEvent(crossServerEvent); 166 | t.addChild(crossAppEvent); 167 | t.addChild(crossServerEvent); 168 | } 169 | 170 | private String getProviderAppName(URL url){ 171 | String appName = url.getParameter(CatConstants.DUBBO_PROVIDER_APPLICATION_NAME); 172 | if(StringUtils.isEmpty(appName)){ 173 | String interfaceName = url.getParameter(Constants.INTERFACE_KEY); 174 | appName = interfaceName.substring(0,interfaceName.lastIndexOf('.')); 175 | } 176 | return appName; 177 | } 178 | 179 | private void completeEvent(Event event){ 180 | if (event != NullMessage.EVENT) { 181 | AbstractMessage message = (AbstractMessage) event; 182 | message.setCompleted(true); 183 | } 184 | } 185 | 186 | } 187 | --------------------------------------------------------------------------------