一、springboot项目集成大众点评cat
一、 什么是CAT
1.cat簡介
Cat是基于Java開發的實時應用監控平臺,為美團點評提供了全面的實時監控告警服務
 ? CAT作為服務端項目基礎組件,提供了java, c/c++, node, python, go等多語言客戶端,已經在美團點評的基礎架構中間件框架(MVC框架,RPC框架,數據庫框架,緩存框架等,消息隊列,配置系統等)深度集成,為美團點評各業務線提供系統豐富的性能指標、健康狀況、實時告警等。
 ? CAT很大的優勢是它是一個實時系統,CAT大部分系統是分鐘級統計,但是從數據生成到服務端處理結束是秒級別,秒級定義是48分鐘40秒,基本上看到48分鐘38秒數據,整體報表的統計粒度是分鐘級;第二個優勢,監控數據是全量統計,客戶端預計算;鏈路數據是采樣計算。
2.Cat的產品價值
? 減少線上問題的發現時間
 ? 減少問題故障的定位時間
 ? 輔助應用程序的優化工具
3.Cat的優勢
? 實時處理:信息的價值會隨時間銳減,尤其是事故處理過程中。
 ? 全量數據:最開始的設計目標就是全量采集,全量的好處有很多。
 ? 高可用:所有應用都倒下了,需要監控還站著,并告訴工程師發生了什么,做到故障還原和問題定位。
 ? 故障容忍:CAT 本身故障不應該影響業務正常運轉,CAT 掛了,應用不該受影響,只是監控能力暫時減弱。
 ? 高吞吐:要想還原真相,需要全方位地監控和度量,必須要有超強的處理吞吐能力。
 ? 可擴展:支持分布式、跨 IDC 部署,橫向擴展的監控系統。
4.CAT支持的監控消息類型包括
? Transaction 適合記錄跨越系統邊界的程序訪問行為,比如遠程調用,數據庫調用,也適合執行時間較長的業務邏輯監控,Transaction用來記錄一段代碼的執行時間和次數。
 ? Event 用來記錄一件事發生的次數,比如記錄系統異常,它和transaction相比缺少了時間的統計,開銷比transaction要小。
 ? Heartbeat 表示程序內定期產生的統計信息, 如CPU%, MEM%, 連接池狀態, 系統負載等。
 ? Metric 用于記錄業務指標、指標可能包含對一個指標記錄次數、記錄平均值、記錄總和,業務指標最低統計粒度為1分鐘。
二、cat客戶端的集成步驟:
1.在需要被監控的項目里引入cat-client 的meven依賴:
<dependency><groupId>com.dianping.cat</groupId><artifactId>cat-client</artifactId><version>3.0.0</version></dependency>2.引入cat的核心過濾器:
package com.kye.map.ucenter.controller;import com.dianping.cat.servlet.CatFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;/*** Description:cat的的核心過濾器* * Date: 2018/10/24 15:34**/ @Configuration public class CatFilterConfigure {@Beanpublic FilterRegistrationBean catFilter() {FilterRegistrationBean registration = new FilterRegistrationBean();CatFilter filter = new CatFilter();registration.setFilter(filter);registration.addUrlPatterns("/*");registration.setName("cat-filter");registration.setOrder(1);return registration;} }引入這個以后cat項目就能監控到你訪問的url
3.在需要被監控的項目建立如下結構:
app.name=ucenter 這個必須有,cat服務端必須通過這個找到相應的項目
 
4.需要在你的項目的根目錄建立如下結構的文件夾:
client.xml內容如下:
<?xml version="1.0" encoding="utf-8"?><config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd"><servers><!-- Local mode for development --><server ip="10.10.242.9" port="2280" http-port="8080" /><!-- If under production environment, put actual server address as list. --><!-- <server ip="192.168.7.71" port="2280" /> <server ip="192.168.7.72" port="2280" /> --></servers> </config>cat項目的日志目錄:
 )如果項目啟動出問題,或者cat監控不到自己的項目,可以看看這里的日志)
 
5.集成mybatis攔截器(目前只能攔截到增刪改)
package com.kye.map.ucenter.config;import com.alibaba.druid.pool.DruidDataSource; import com.dianping.cat.Cat; import com.dianping.cat.message.Message; import com.dianping.cat.message.Transaction; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.type.TypeHandlerRegistry; import org.mybatis.spring.transaction.SpringManagedTransaction; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.util.ReflectionUtils;import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.DateFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher;/** * 對MyBatis進行攔截,添加Cat監控 * 目前僅支持RoutingDataSource和Druid組合配置的數據源 * * @author Steven */@Intercepts({@Signature(method = "query", type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class }),@Signature(method = "update", type = Executor.class, args = { MappedStatement.class, Object.class }) }) public class CatMybatisPlugin implements Interceptor {private static Log logger = LogFactory.getLog(CatMybatisPlugin.class);//緩存,提高性能private static final Map<String, String> sqlURLCache = new ConcurrentHashMap<String, String>(256);private static final String EMPTY_CONNECTION = "jdbc:mysql://localhost:3306/%s?useUnicode=true";private Executor target;@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];//得到類名,方法String[] strArr = mappedStatement.getId().split("\\.");String methodName = strArr[strArr.length - 2] + "." + strArr[strArr.length - 1];Transaction t = Cat.newTransaction("SQL", methodName);//得到sql語句Object parameter = null;if(invocation.getArgs().length > 1){parameter = invocation.getArgs()[1];}BoundSql boundSql = mappedStatement.getBoundSql(parameter);Configuration configuration = mappedStatement.getConfiguration();String sql = showSql(configuration, boundSql);//獲取SQL類型SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();Cat.logEvent("SQL.Method", sqlCommandType.name().toLowerCase(), Message.SUCCESS, sql);String s = this.getSQLDatabase();Cat.logEvent("SQL.Database", s);Object returnObj = null;try {returnObj = invocation.proceed();t.setStatus(Transaction.SUCCESS);} catch (Exception e) {t.setStatus(e);Cat.logError(e);} finally {t.complete();}return returnObj;}private javax.sql.DataSource getDataSource() {org.apache.ibatis.transaction.Transaction transaction = this.target.getTransaction();if (transaction == null) {logger.error(String.format("Could not find transaction on target [%s]", this.target));return null;}if (transaction instanceof SpringManagedTransaction) {String fieldName = "dataSource";Field field = ReflectionUtils.findField(transaction.getClass(), fieldName, javax.sql.DataSource.class);if (field == null) {logger.error(String.format("Could not find field [%s] of type [%s] on target [%s]",fieldName, javax.sql.DataSource.class, this.target));return null;}ReflectionUtils.makeAccessible(field);javax.sql.DataSource dataSource = (javax.sql.DataSource) ReflectionUtils.getField(field, transaction);return dataSource;}logger.error(String.format("---the transaction is not SpringManagedTransaction:%s", transaction.getClass().toString()));return null;}private String getSqlURL() {javax.sql.DataSource dataSource = this.getDataSource();if (dataSource == null) {return null;}if (dataSource instanceof AbstractRoutingDataSource) {String methodName = "determineTargetDataSource";Method method = ReflectionUtils.findMethod(AbstractRoutingDataSource.class, methodName);if (method == null) {logger.error(String.format("---Could not find method [%s] on target [%s]",methodName, dataSource));return null;}ReflectionUtils.makeAccessible(method);javax.sql.DataSource dataSource1 = (javax.sql.DataSource) ReflectionUtils.invokeMethod(method, dataSource);if (dataSource1 instanceof DruidDataSource) {DruidDataSource druidDataSource = (DruidDataSource) dataSource1;return druidDataSource.getUrl();} else {logger.error("---only surpport DruidDataSource:" + dataSource1.getClass().toString());}} else if(dataSource instanceof BasicDataSource){return ((BasicDataSource) dataSource).getUrl();}return null;}private String getSQLDatabase() { // String dbName = RouteDataSourceContext.getRouteKey();String dbName = null; //根據設置的多數據源修改此處,獲取dbnameif (dbName == null) {dbName = "DEFAULT";}String url = CatMybatisPlugin.sqlURLCache.get(dbName);if (url != null) {return url;}url = this.getSqlURL();//目前監控只支持mysql ,其余數據庫需要各自修改監控服務端if (url == null) {url = String.format(EMPTY_CONNECTION, dbName);}CatMybatisPlugin.sqlURLCache.put(dbName, url);return url;}/*** 解析sql語句* @param configuration* @param boundSql* @return*/public String showSql(Configuration configuration, BoundSql boundSql) {Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();String sql = boundSql.getSql().replaceAll("[\\s]+", " ");if (parameterMappings.size() > 0 && parameterObject != null) {TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);for (ParameterMapping parameterMapping : parameterMappings) {String propertyName = parameterMapping.getProperty();if (metaObject.hasGetter(propertyName)) {Object obj = metaObject.getValue(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));} else if (boundSql.hasAdditionalParameter(propertyName)) {Object obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));}}}}return sql;}/*** 參數解析* @param obj* @return*/private String getParameterValue(Object obj) {String value = null;if (obj instanceof String) {value = "'" + obj.toString() + "'";} else if (obj instanceof Date) {DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);value = "'" + formatter.format((Date)obj) + "'";} else {if (obj != null) {value = obj.toString();} else {value = "";}}return value;}@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {this.target = (Executor) target;return Plugin.wrap(target, this);}return target;}@Overridepublic void setProperties(Properties properties) {}}6.將mybatis攔截器注入到sqlSessionFactory
package com.kye.map.ucenter.config;import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;@Configuration public class MybatisConfig implements EnvironmentAware {private Environment environment;@Beanpublic DataSource getDateSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(environment.getProperty("spring.datasource.url"));dataSource.setUsername(environment.getProperty("spring.datasource.username"));dataSource.setPassword(environment.getProperty("spring.datasource.password"));dataSource.setMaxActive(10);dataSource.setDriverClassName(environment.getProperty("spring.datasource.driverClassName"));dataSource.setMaxIdle(5);return dataSource;}@Beanpublic SqlSessionFactory getSqlSession(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);CatMybatisPlugin catMybatisPlugin = new CatMybatisPlugin();factoryBean.setPlugins(new Interceptor[]{catMybatisPlugin});Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/**/*.xml");factoryBean.setMapperLocations(resources);SqlSessionFactory sessionFactory = factoryBean.getObject();return sessionFactory;}@Beanpublic MapperScannerConfigurer getMapperScannerConfigurer(SqlSessionFactory sqlSessionFactory){MapperScannerConfigurer configurer = new MapperScannerConfigurer();configurer.setBasePackage("com.kye.map.ucenter.domain.mappers");configurer.setSqlSessionFactory(sqlSessionFactory);return configurer;}@Beanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);} // // @Bean // @Override // public PlatformTransactionManager annotationDrivenTransactionManager() { // return new DataSourceTransactionManager(dataSource); // }@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;} }7.@CatAnnotation注解的使用:
只需要在需要攔截的方法上加上@CatAnnotation 即可 type和value的值可以自定義
@Override@CatAnnotation(type = "ServiceGetById",value = "getById")public Resource getById(String resourceId) {return resourceMapper.get(resourceId);}三、相關的參考文檔
- CAT項目的開源地址: https://github.com/dianping/cat
- CAT官方站點:http://unidal.org/cat/r
- 微盟的CAT接入文檔:http://tx.cat.weimob.com/cat/doc.html
- 參考文檔:http://fanlychie.github.io/post/cat-setup.html
四、 系列文章
總結
以上是生活随笔為你收集整理的一、springboot项目集成大众点评cat的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: windows重建linux引导,Lin
- 下一篇: 【学习笔记】Linux_RedHat7.
