未验证 提交 36a15400 编写于 作者: J Jamson Liu 提交者: GitHub

Merge pull request #1 from dianping/master

sync commits
......@@ -55,7 +55,7 @@ public class TokenBuilder implements ITokenBuilder<SigninContext, Token> {
int expectedCheckSum = getCheckSum(value.substring(0, value.lastIndexOf(SP) + 1));
if (checkSum == expectedCheckSum) {
if (remoteIp.equals(ctx.getRequest().getRemoteAddr())) {
if (remoteIp.equals(HttpRequestUtils.getAddr(ctx.getRequest()))) {
if (lastLoginDate + ONE_DAY > System.currentTimeMillis()) {
return new Token( realName, userName);
}
......
......@@ -104,7 +104,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.24.Final</version>
<version>4.0.25.Final</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
......
# CAT异常告警
## 1、部署
### 1.1、CAT服务端
### 1.1.1、修改告警模板
CAT告警的模板(主要是邮件使用)中,链接到CAT管理页面的url是写死的,而我们公司内部署CAT后都会指定一个host域名,
没有域名的一般也有ip:port。看下文件cat/cat-home/src/main/resources/freemaker/exceptionAlert.ftl<br/>
```html
[CAT异常告警] [项目: ${domain}] : ${content}[时间: ${date}]
<a href='http://cat-url/cat/r/p?domain=${domain}&date=${linkDate}'>点击此处查看详情</a><br/>
${contactInfo}<br/>
```
把其中的cat-url修改为你部署的cat的域名或ip:port,比如:
```html
[CAT异常告警] [项目: ${domain}] : ${content}[时间: ${date}]
<a href='http://127.0.0.1:2281/cat/r/p?domain=${domain}&date=${linkDate}'>点击此处查看详情</a><br/>
${contactInfo}<br/>
```
### 1.1.2、添加微信渠道支持
* 修改代码生成配置文件<br/>
cat/cat-core/src/main/resources/META-INF/dal/jdbc/report-codegen.xml,在project表的phone字段后添加
```xml
<member name="weixin" field="weixin" value-type="String" length="200" />
```
* 修改jsp添加微信配置输入框<br/>
修改/Users/xuyanhua/IdeaProjects/cat/cat-home/src/main/webapp/jsp/system/project/project.jsp,在项目组号码后添加
```html
<tr>
<td>项目组微信</td>
<td><input type="text" name="project.weixin" class="input-xxlarge" value="${model.project.weixin}"/></td>
<td>字段(多个,逗号分割)<span style="color:red">【此字段会和CMDB信息同步】</span></td>
</tr>
```
* 添加联系人获取微信方式<br/>
修改cat/cat-home/src/main/java/com/dianping/cat/report/alert/sender/receiver/ProjectContactor.java,修改方法queryWeiXinContactors
```Java
@Override
public List<String> queryWeiXinContactors(String id) {
List<String> weixinReceivers = new ArrayList<String>();
Receiver receiver = m_configManager.queryReceiverById(getId());
if (receiver != null && !receiver.isEnable()) {
return weixinReceivers;
} else {
weixinReceivers.addAll(buildDefaultWeixinReceivers(receiver));
if (StringUtils.isNotEmpty(id)) {
Project project = m_projectService.findByDomain(id);
if (project != null) {
weixinReceivers.addAll(split(project.getWeixin()));//由getMail() --> getWeixin()
}
}
return weixinReceivers;
}
}
```
### 1.2、告警服务端
#### 1.2.1、下载与安装
下载cat/框架埋点方案集成/cat-alert/cat-alert
#### 1.2.2、环境要求
linux系统、Python2.7
#### 1.2.3、运行
```bash
bogon:tmp xuyanhua$ cd cat-alert/
bogon:cat-alert xuyanhua$ ls
ChangeLog.txt README cat-alert cat-alert.sh main.spec requirements.txt setup.py
bogon:cat-alert xuyanhua$ chmod +x cat-alert.sh
bogon:cat-alert xuyanhua$ ./cat-alert.sh
USAGE: ./cat-alert.sh start [port]
./cat-alert.sh stop
./cat-alert.sh restart [port]
bogon:cat-alert xuyanhua$ ./cat-alert.sh start 8888
start ok!
see log use "tail -f debug.log"
bogon:cat-alert xuyanhua$ tail -f debug.log
[2018-01-18 16:59:20] [INFO] main.py[line:65] ----------------------------------------------
[2018-01-18 16:59:20] [INFO] main.py[line:66] cat-alert Server startup and listen on 8888.
[2018-01-18 16:59:20] [INFO] main.py[line:67] ----------------------------------------------
```
### 1.3、数据库脚本
* 添加微信配置字段的sql脚本
```sql
alter table project add column weixin varchar(200) after phone;
```
### 1.4、依赖支持
#### 1.4.1、邮件告警
发送邮件,需要依赖邮件服务器,目前cat的邮件服务器由运维同事提供,在后续的2.1.3 全局告警配置-告警服务端中配置。
如果想通过公网邮件服务器,需要开通访问外网的权限
#### 1.4.2、微信告警
微信消息的发送,是基于微信企业号。需要访问外网权限,具体来说是https://qyapi.weixin.qq.com
## 2、配置
### 2.1、全局告警配置
#### 2.1.1、全局告警配置-告警策略
```xml
<?xml version="1.0" encoding="utf-8"?>
<alert-policy>
<type id="Network">
<group id="default">
<level id="error" send="mail,weixin,sms" suspendMinute="3"/>
<level id="warning" send="mail,weixin"/>
</group>
</type>
<type id="Exception">
<group id="default">
<level id="error" send="mail,weixin"/>
<level id="warning" send="weixin"/>
</group>
</type>
<type id="Business">
<group id="default">
<level id="error" send="mail,weixin,sms" suspendMinute="5"/>
<level id="warning" send="mail,weixin" suspendMinute="5"/>
</group>
</type>
<type id="System">
<group id="default">
<level id="error" send="mail"/>
<level id="warning" send="mail"/>
</group>
</type>
<type id="ThirdParty">
<group id="default">
<level id="warning" send=""/>
</group>
</type>
<type id="FrontEnd">
<group id="default">
<level id="warning" send="mail"/>
</group>
</type>
<type id="App">
<group id="default">
<level id="warning" send="mail,weixin"/>
<level id="error" send="mail,weixin,sms"/>
</group>
</type>
<type id="Web">
<group id="default">
<level id="warning" send="mail"/>
<level id="error" send="mail,weixin,sms"/>
</group>
</type>
<type id="Heartbeat">
<group id="default">
<level id="warning" send="mail"/>
<level id="error" send="mail,weixin,sms"/>
</group>
</type>
<type id="default">
<group id="default">
<level id="warning" send="mail"/>
<level id="error" send="mail,weixin,sms"/>
</group>
</type>
</alert-policy>
```
#### 2.1.2、全局告警配置-默认告警人
```xml
<?xml version="1.0" encoding="utf-8"?>
<alert-config>
<receiver id="Network" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="Exception" enable="true">
<email>cat@yourcompany.com</email>
<weixin>152********</weixin>
</receiver>
<receiver id="FrontEndException" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="Business" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="System" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="ThirdParty" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="App" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="Web" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
<receiver id="Heartbeat" enable="false">
<email>cat@yourcompany.com</email>
<phone>152********</phone>
</receiver>
</alert-config>
```
#### 2.1.3、全局告警配置-告警服务端
```xml
<?xml version="1.0" encoding="utf-8"?>
<sender-config>
<sender id="mail" url="http://127.0.0.1:8888/mail/" type="post" successCode="200" batchSend="true">
<par id="type=1500"/>
<par id="subject=${title}"/>
<par id="content=${content}"/>
<par id="smtp_server=smtp.sina.com"/>
<par id="from_addr=cat@sina.com"/>
<par id="username=cat@sina.com"/>
<par id="password=***"/>
<par id="to_addrs=${receiver}"/>
</sender>
<sender id="weixin" url="http://127.0.0.1:8888/weixin/" type="post" successCode="success" batchSend="true">
<par id="domain=${domain}"/>
<par id="weixins=${receiver}"/>
<par id="title=${title}"/>
<par id="content=${content}"/>
<par id="type=${type}"/>
</sender>
<sender id="sms" url="http://127.0.0.1:8888/sms/" type="post" successCode="200" batchSend="false">
<par id="jsonm={type:808,mobile:'${receiver}',pair:{body='${content}'}}"/>
</sender>
</sender-config>
```
`注:这里的“http://127.0.0.1:8888”指的是1.2节中提到的"告警服务端"的 ip:port`
### 2.2、项目告警配置
想要使用告警功能,需要三步
* 配置项目基本信息,如项目名、小组名、负责人,邮箱地址、微信id等(建议由管理员配置)
* 配置阈值配置,有两个阈值,分别为warning和error两个级别,两个级别分别控制发送邮件和微信
* 异常过滤配置,如果项目中某个异常没有“危害”,可以将之过滤掉
#### 2.2.1、项目配置信息-项目基本信息
![](docs/imgs/alert1.png)
#### 2.2.2、应用监控配置-异常告警配置-异常阈
![](docs/imgs/alert2.png)
`注意,这里的Total指所有异常,如果想指定特定异常也可以。`
#### 2.2.1、应用监控配置-异常告警配置-异常过滤配置
![](docs/imgs/alert3.png)
如果某些异常不想报警,也可以过滤掉
要想接收微信告警,要扫码加入微信企业号。
加入微信企业号,然后在项目基本信息中配置上,在发生异常时就能收到告警消息了。<br/>
`注:扫完后要进去点一下申请加入,填写自己的真实姓名和手机号。`<br/>
`注:由于目前微信企业号的pc端对mac的支持不好,因此使用mac电脑的同事,需要安装微信企业,pc端才能收到告警消息。`<br/>
下载地址:https://work.weixin.qq.com/<br/>
`注:如果pc端登录着微信,手机端微信可以接收到告警消息,但没有通知栏提醒,可以通过下面的二微码安装企业微信客户端。`
## 3、告警效果一览
### 3.1、邮件告警效果
![](docs/imgs/email.png)
### 3.2、微信告警效果
![](docs/imgs/weixin.png)
## 4、后记
最后,如果大家遇到问题,欢迎在"开源实时监控CAT二群"微信群里 @徐岩华@宜信致诚。
# -*- coding: utf-8 -*-
# @Time : 2018/1/27 上午11:23
# @Author : 宜信致诚,徐岩华
# @File : cat-alert.sh
# @Software: PyCharm
#!/bin/sh
function start()
{
python cat-alert/main.py &
if [ $? -eq 0 ]; then
echo 'start ok!'
fi
echo 'see log use "tail -f debug.log"'
}
function stop()
{
pid=`ps -ef |grep python | grep cat-alert|awk '{print $2}'`
if [ ! $pid ] ; then
echo 'cat-alert has stopped.'
else
kill -9 $pid
if [ $? -eq 0 ]; then
echo 'stop ok!'
fi
fi
}
# command error
if [ $# -lt 1 ] ; then
echo "USAGE: $0 start [port]"
echo " $0 stop"
echo " $0 restart [port]"
exit 1;
fi
# port get
port=8888
if [ $# -eq 2 ] ; then
port=$2
fi
if [ $1 == 'start' ] ; then
start $port
elif [ $1 == 'stop' ] ; then
stop
elif [ $1 == 'restart' ] ; then
stop
start $port
fi
# -*- coding: utf-8 -*-
# @Time : 2018/1/27 上午11:23
# @Author : 宜信致诚,徐岩华
# @File : main.py
# @Software: PyCharm
import BaseHTTPServer
import urllib
import sys
import logging
import sender
logging.basicConfig(level=logging.INFO,
format='[%(asctime)s] [%(levelname)s] %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='debug.log',
filemode='w')
def start_server(port):
'''
cat告警服务端
:param port:服务监听端口
:return:
'''
http_server = BaseHTTPServer.HTTPServer(("", port), MyHttpHandler)
logging.info('----------------------------------------------')
logging.info('cat-alert Server startup and listen on %d.', port)
logging.info('----------------------------------------------')
http_server.serve_forever()
class MyHttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(self):
url = self.path
logging.info('receive request,url:%s', url)
datas = self.rfile.read(int(self.headers['content-length']))
params = trans_dicts(datas)
sender_obj = 0
if url == '/mail/':
sender_obj = sender.sender_mail(params)
elif url == '/sms/':
sender_obj = sender.sender_sms(params)
elif url == '/weixin/':
sender_obj = sender.sender_weixin(params)
else:
logging.error("unsupport alert channel :%s", url)
if sender_obj != 0:
sender_obj.send()
# for key in params:
# print key, '-->', params[key]
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write('200')
def trans_dicts(params):
dicts = {}
if len(params) == 0:
return
params = params.replace('+', '%20')
params = params.split('&')
for param in params:
idx = param.find('=')
key = param[:idx]
value = urllib.unquote(param[idx + 1:]).decode("utf-8", "ignore")
dicts[key] = value
return dicts
if __name__ == '__main__':
port = 8888
if len(sys.argv) > 1 and sys.argv[1]:
port = int(sys.argv[1])
start_server(port)
# -*- coding: utf-8 -*-
# @Time : 2018/1/27 上午11:23
# @Author : 宜信致诚,徐岩华
# @File : sender.py
# @Software: PyCharm
__metaclass__ = type
from email.mime.text import MIMEText
from email.header import Header
import smtplib
import logging
import urllib2
import urllib
import json
from string import Template
import re
# 消息发送接口
class sender:
logging.basicConfig(level=logging.INFO,
format='[%(asctime)s] [%(levelname)s] %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='debug.log',
filemode='w')
def __init__(self, params):
self.params = params
def send(self):
pass
# 消息发送接口
class sender_mail(sender):
def __init__(self, params):
super(sender_mail, self).__init__(params)
def send(self):
"""
username --> ***@sina.com
from_addr --> ***@sina.com
smtp_server --> smtp.sina.com
content --> [CAT 第三方告警] [项目: ] : [[type=get details=HTTP URL[1234568888888888.com?] GET访问出现异常]][时间: 2015-01-15 18:20]
<a href='http://cat/r/p?domain=&date=2015011518'>点击此处查看详情</a>
to_addrs --> ***@yourcompany.com
password --> ****
type --> 1500
subject --> [CAT第三方告警] [项目: ]
"""
mail_from = self.params.get('from_addr')
mail_to = self.params.get('to_addrs')
subject = self.params.get('subject')
smtp_server = self.params.get('smtp_server')
content = self.params.get('content')
username = self.params.get('username')
password = self.params.get('password')
if not mail_from or not mail_to or not smtp_server or not username:
logging.error('mail require info is null,title is %s', subject)
return
try:
msg = MIMEText(content, 'html', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['from'] = mail_from
msg['to'] = mail_to
smtp = smtplib.SMTP()
smtp.connect(smtp_server)
smtp.login(username, password)
to_list = mail_to.split(',')
smtp.sendmail(mail_from, to_list, msg.as_string())
smtp.quit()
logging.info('mail send ok ~. title is %s.', subject)
except Exception, e:
logging.error('mail send exception -> %s', e.message)
# 消息发送接口
class sender_sms(sender):
def __init__(self, params):
self.params = params
def send(self):
logging.warn('channel[sms] is not supported!')
#这个字典用以缓存access_token
weixin_token_dict = {
'access_token': 'zszwVW_VgAIqhu_QZZQOzgjPZmOft2p5OZcCZMmvR97oYHMxjMS0JuBgmGLZxjo8tBT7tWodSIXKxPwgO8iCBVvGGJimOGpSG3C8kzj1pB5WAKnm6tRbsVUc1V-nijwZO0azh1fO4nlE52UGq0iEOoArf3dPJ5drK23gwFyZE8cYLBXwR6dOk8WblP4tvXxwuSm4FVe2F6_F1gJUiGxtkg'}
# 微信发送
class sender_weixin(sender):
def __init__(self, params):
super(sender_weixin, self).__init__(params)
# CAT告警应用参数
self.weixin_dict = {'CorpID': '****',
'AgentId': '1000001',
'Secret': '****'}
url_template_gettoken = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${CorpID}&corpsecret=${Secret}'
self.url_gettoken = Template(url_template_gettoken).substitute(self.weixin_dict)
def get_token(self):
if len(weixin_token_dict) == 0:
response = urllib2.urlopen(self.url_gettoken)
content = response.read()
s = json.loads(content)
access_token = s['access_token']
weixin_token_dict['access_token'] = access_token
logging.info('new get token -> %s', access_token)
else:
access_token = weixin_token_dict['access_token']
return access_token
def send(self):
logging.info("weixin-send:%s", self.params)
title = self.params.get('title')
content = self.params.get('content')
weixins = self.params.get('weixins')
if not title or not content or not weixins:
logging.error('weixin require info is null,title is %s', title)
return
try:
weixins = weixins.replace(',', '|')
logging.info('weixin-content--->%s', content)
matchObj = re.findall(r'\[\s*(.*?)\s*\]', content, re.M)
msg = "\n".join(matchObj).replace(u'异常数量', u'\n异常数量')
access_token = self.get_token()
url_template_send = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${access_token}'
send_url = Template(url_template_send).substitute({'access_token': access_token})
params = {"touser": weixins, "toparty": "", "totag": "", "msgtype": "text",
"agentid": self.weixin_dict['AgentId'], "text": {"content": msg}, "safe": 0}
data_dict = json.dumps(params)
header_dict = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
"Content-Type": "application/json"}
req = urllib2.Request(url=send_url, data=data_dict, headers=header_dict)
res = urllib2.urlopen(req)
send_res = res.read()
send_res = json.loads(send_res)
errcode = send_res['errcode'] # https://work.weixin.qq.com/api/doc#10649
errmsg = send_res['errmsg']
if errcode == 0:
logging.info('weixin send ok ~.title is %s', title)
elif errcode == 42001 or errcode == 40014:
logging.error('access_token expired.')
weixin_token_dict.clear()
self.send()
else:
logging.error('weixin send error , more info->errcode:%d,errmsg:%s', errcode, errmsg)
except Exception, e:
logging.error('weixin send exception -> %s', e.message)
# -*- coding: utf-8 -*-
# @Time : 2018/1/27 上午11:23
# @Author : 宜信致诚,徐岩华
# @File : send_mail_test.py
# @Software: PyCharm
import smtplib
from email.mime.text import MIMEText
from email.header import Header
def send_mail():
'''
1、send_mail()函数以最简单的方式测试邮件发送
2、建议使用mail.sina.com,其他的如163邮箱、126邮箱、qq邮箱,安全级别非常高,有许多垃圾邮件拦截策略,会让你的测试工作事倍功半
3、
'''
# 发送者邮箱、用户名和密码,注:用户名和发送者邮箱一样
sender = '***@sina.com'
username = '***@sina.com'
password = '******'
# 发送服务器设置
smtp_server = 'smtp.sina.com'
# 接收者,你的公司邮箱
receiver = '***@yourcompany.com'
msg = MIMEText('这里有异常', 'plain', 'utf-8')
subject = 'CAT报警'
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = sender
msg['To'] = receiver
smtp = smtplib.SMTP()
smtp.connect(smtp_server)
smtp.login(username, password)
smtp.set_debuglevel(0)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
if __name__ == '__main__':
send_mail()
# -*- coding: utf-8 -*-
# @Time : 2018/1/27 上午11:23
# @Author : 宜信致诚,徐岩华
# @File : send_weixin_test.py
# @Software: PyCharm
import urllib2
import json
#
# weixin_token_dict = {
# 'access_token': 'FnXy6dPw4J8CuzRjCYvgWp1L2MWr9SJ2_XUkEELU736FI5aGvuNHbaL7n8Ab-9ZhYA2isbnHnTjx1k5TJCRppK7N74AEyYmnE3RvTd8he3jGrDFtU9dAGpMlHU94QnvSobXQY6uhbXcqSuAsvgCiJ9MjVnmaWC_8ntj9_D6rAo6dMzDd7_4gdE60eF-5wRD385GA_VVjmXun8b0qToNvEg'}
weixin_token_dict = {}
def send_weixin():
'''
1、send_weixin()函数以最简单的方式测试微信发送功能
2、首先要去企业信息官网注册账号(https://work.weixin.qq.com),注册后有详细的开发文档(https://work.weixin.qq.com/api/doc)
3、除了注册企业微信之外,发送微信剩下的就是使用python的内建模块发送http请求了,下面两篇相关文章:
http request:https://www.cnblogs.com/landhu/p/5104628.html
json:https://www.cnblogs.com/kaituorensheng/p/3877382.html
'''
if len(weixin_token_dict) == 0:
ID = '***'
SECRECT = '***'
response = urllib2.urlopen(
'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=' + ID + '&corpsecret=' + SECRECT)
content = response.read()
s = json.loads(content)
weixin_token_dict['access_token'] = s['access_token']
# 获取到token后,复制到weinxin_token_dict的value中,因为token有2个小时有的效期,且获取频率受限
print 'new get token ->', weixin_token_dict['access_token']
access_token = weixin_token_dict['access_token']
send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + access_token
params = {"touser": "user1|user2",
"toparty": "",
"totag": "",
"msgtype": "text",
"agentid": 1000001,
"text": {
"content": "你的快递已到3,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
},
"safe": 0}
data_dict = json.dumps(params)
header_dict = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko',
"Content-Type": "application/json"}
req = urllib2.Request(url=send_url, data=data_dict, headers=header_dict)
res = urllib2.urlopen(req)
send_res = res.read()
send_res = json.loads(send_res)
errcode = send_res['errcode'] # https://work.weixin.qq.com/api/doc#10649
errmsg = send_res['errmsg']
print errcode
if errcode == 0:
print 'send weixin ok ~'
elif errcode == 42001 or errcode == 40014:
print 'access_token expired.'
else:
print 'send weixin error , more info:', errmsg
send_res
if __name__ == '__main__':
send_weixin()
需要的模块有以下几个,可以在python交互终端验证是否存在,我使用的python2.7都已存在,不需要额外安装
BaseHTTPServer
urllib
email
smtplib
sys
logging
\ No newline at end of file
## javaagent 方式埋点方案
1. 主要是利用aspectj提供的LTW功能,提供了对一些组件的埋点模板。
2. 具体使用方法见“Cat 客户端埋点插件用户手册.docx”。
\ No newline at end of file
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qbao</groupId>
<artifactId>cat-client-agent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>catclientagent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestEntries>
<Premain-Class>
com.qbao.catagent.CatAgent
</Premain-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
/*
* 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 com.qbao.catagent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
/**
* @author andersen
*
*/
public class CatAgent {
private static Instrumentation s_instrumentation;
private static ClassFileTransformer s_transformer;
public static void premain(String options, Instrumentation instrumentation) {
/* Handle duplicate agents */
if (s_instrumentation != null) {
return;
}
s_instrumentation = instrumentation;
s_transformer = new ClassPathPreSetAgentAdapter(options);
s_instrumentation.addTransformer(s_transformer);
}
public static void agentmain(String options, Instrumentation instrumentation) {
premain(options, instrumentation);
}
public static Instrumentation getInstrumentation() {
if (s_instrumentation == null) {
throw new UnsupportedOperationException(
"CatClient agent was started via '-javaagent' (preMain) ");
}
return s_instrumentation;
}
}
/*
* 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 com.qbao.catagent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Properties;
import com.qbao.catagent.processor.JettyClassPathPreSetProcessor;
import com.qbao.catagent.processor.NullOperProcessor;
import com.qbao.catagent.processor.SpringbootClassPathPreSetProcessor;
import com.qbao.catagent.processor.TomcatClassPathPreSetProcessor;
import com.qbao.catagent.util.AppTypeEnum;
import com.qbao.catagent.util.PropertyUtil;
public class ClassPathPreSetAgentAdapter implements ClassFileTransformer{
private static final String DEFAULT_APPTYPE_PROPERTY_NAME = "app.type";
private static ClassPathPreSetProcessor s_preProcessor;
public ClassPathPreSetAgentAdapter(String confFilePath){
Properties p = null;
if (confFilePath == null || confFilePath.trim() == "" || !confFilePath.endsWith(".properties") || (p = PropertyUtil.getProperties(confFilePath)) == null){
System.out.println("Warn: CatAgent disabled! missing config file after javaagent or file format is invalid!");
s_preProcessor = new NullOperProcessor();
}else{
if (p.get(DEFAULT_APPTYPE_PROPERTY_NAME) == null){
System.out.println(String.format("Warn: CatAgent disabled! missing %s setting in %s! ", DEFAULT_APPTYPE_PROPERTY_NAME, confFilePath));
s_preProcessor = new NullOperProcessor();
}else{
String appType = String.valueOf(p.get(DEFAULT_APPTYPE_PROPERTY_NAME));
switch(AppTypeEnum.getAppType(appType)){
case TOMCAT :
s_preProcessor = new TomcatClassPathPreSetProcessor();
break;
case JETTY :
s_preProcessor = new JettyClassPathPreSetProcessor();
break;
case SPRINGBOOT :
s_preProcessor = new SpringbootClassPathPreSetProcessor();
break;
default :
System.out.println(String.format("Warn: CatAgent disabled! app.type[%s] is not supported! ", DEFAULT_APPTYPE_PROPERTY_NAME, appType));
s_preProcessor = new NullOperProcessor();
break;
}
}
}
s_preProcessor.initialize(p);
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.contains("com/dianping/cat/message/internal/MessageIdFactory")){
System.out.println(className + " >>>>>>>>>>>> " + loader.getClass().getName() + "$" + Integer.toHexString(loader.hashCode()));
}
return s_preProcessor.preProcess(className, classfileBuffer, loader, protectionDomain);
}
}
/*
* 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 com.qbao.catagent;
import java.security.ProtectionDomain;
import java.util.Properties;
/**
* @author andersen
*
*/
public interface ClassPathPreSetProcessor {
/**
*
* @param prop 解析出来的配置信息
*/
void initialize(Properties prop);
/**
* untouch
* @param className
* @param bytes
* @param classLoader
* @param a protection domain that may be used for defining extraneous classes generated as part of modifying the one passed in
* @return
*/
byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader, ProtectionDomain protectionDomain);
}
/*
* 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 com.qbao.catagent.processor;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import com.qbao.catagent.ClassPathPreSetProcessor;
/**
* 负责在进行类加载前加载指定
*
* @author andersen
*
*/
public abstract class AbstractClassPathPreSetProcessor implements ClassPathPreSetProcessor {
// 保存已经加载过指定路径类的classloader
private ConcurrentHashMap<ClassLoader, Method> invokedMethods = new ConcurrentHashMap<ClassLoader, Method>();
// 配置文件中指定cat-client相关jar包位置的key
private final String DEFAULT_CAT_CLIENT_PROPERTY_NAME = "cat.client.path";
// 需加载的cat-client相关jar包
private List<File> catClientJarFiles = new ArrayList<File>();
// 配置文件中指定plugin相关jar包位置的key
private final String DEFAULT_PLUGIN_PROPERTY_NAME = "cat.plugins.path";
// 需加载的客户端plugin相关jar包
private List<File> pluginJarFiles = new ArrayList<File>();
// 默认方法
private Method DEFAULT_METHOD = null;
// 能否预设类路径
private boolean enable = true;
// 反射生成的classloader类名
private final String deleLoader = "sun.reflect.DelegatingClassLoader";
// 配置的忽略的classloader类名
public List<String> loadersToSkip = null;
// 跟aspectj保持一致,可配置跳过的classloader
private final String LOADER_TO_SKIP_CLASSLOADER_PROPERTY_NAME = "aj.weaving.loadersToSkip";
@Override
public void initialize(Properties p) {
if (p.getProperty(DEFAULT_CAT_CLIENT_PROPERTY_NAME) == null){
System.out.println(String.format("Warn: CatAgent disabled , Missing %s in config file", DEFAULT_CAT_CLIENT_PROPERTY_NAME));
enable = false;
return;
}
if (p.getProperty(DEFAULT_PLUGIN_PROPERTY_NAME) == null){
System.out.println(String.format("Warn: CatAgent disabled , Missing %s in config file", DEFAULT_PLUGIN_PROPERTY_NAME));
enable = false;
return;
}
// 组装忽略的classloader列表
String loadersToSkipProperty = System.getProperty(LOADER_TO_SKIP_CLASSLOADER_PROPERTY_NAME, "");
StringTokenizer st = new StringTokenizer(loadersToSkipProperty, ",");
if (loadersToSkipProperty != null && loadersToSkip == null) {
if (st.hasMoreTokens()) {
loadersToSkip = new ArrayList<String>();
}
while (st.hasMoreTokens()) {
String nextLoader = st.nextToken();
loadersToSkip.add(nextLoader);
}
}
// 初始化默认方法
try {
DEFAULT_METHOD = new Object().getClass().getMethod("toString");
} catch (NoSuchMethodException e) {
enable = false;
} catch (SecurityException e) {
enable = false;
}
// 初始化cat-client相关jar包路径
File catClientPath = new File(p.getProperty(DEFAULT_CAT_CLIENT_PROPERTY_NAME));
if (catClientPath.exists() == false) {
System.out.println("Warn: CatAgent disabled! file structure is not meet needs!");
enable = false;
return;
}
addJars(catClientPath, catClientJarFiles);
// 初始化cat-plugins相关jar包路径
File catPluginsPath = new File(p.getProperty(DEFAULT_PLUGIN_PROPERTY_NAME));
if (catPluginsPath.exists() == false) {
System.out.println("Warn: CatAgent disabled! file structure is not meet needs!");
enable = false;
return;
}
addJars(catPluginsPath, pluginJarFiles);
if (catClientJarFiles.isEmpty() && pluginJarFiles.isEmpty()) {
enable = false;
return;
}
}
/**
* 把指定目录下所有jar包加入指定列表
*
* @param rootPath
* @param files
*/
private void addJars(File f, List<File> fileList) {
if (f.isFile() && f.getName().endsWith(".jar")) {
fileList.add(f);
}
if (f.isDirectory()) {
for (File tmpF : f.listFiles()) {
addJars(tmpF, fileList);
}
}
}
/**
* 在脂定classloader内加入cp路径
*
* @param classLoader
*/
private void loadPluginJars(ClassLoader classLoader) {
Method method = null;
if ((method = (Method) invokedMethods.get(classLoader)) == null) {
try {
if (classLoader != null) {
if (classLoader instanceof URLClassLoader) {
// javaagent的classloader一般是AppClassLoader
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
boolean shouldLoadCatJars = shouldLoadCatJars(classLoader, systemClassLoader);
boolean shouldLoadPluginsJars = shouldLoadPluginsJars(classLoader, systemClassLoader);
if (shouldLoadCatJars || shouldLoadPluginsJars){
try {
method = classLoader.getClass().getDeclaredMethod("addURL", new Class[] { URL.class });
} catch (Throwable t) {
method = classLoader.getClass().getSuperclass().getDeclaredMethod("addURL",
new Class[] { URL.class });
}
if (method == null) {
invokedMethods.put(classLoader, DEFAULT_METHOD);
return;
}
method.setAccessible(true);
}
if (shouldLoadCatJars){
for (File f : catClientJarFiles)
method.invoke(classLoader, new Object[] { f.toURI().toURL() });
}
if (shouldLoadPluginsJars){
for (File f : pluginJarFiles)
method.invoke(classLoader, new Object[] { f.toURI().toURL() });
}
invokedMethods.put(classLoader, method == null ? DEFAULT_METHOD : method);
}else{
invokedMethods.put(classLoader, DEFAULT_METHOD);
}
}
} catch (Exception e) {
System.err.println("init ClassLoader path occured error");
}
}
}
@Override
public byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader,
ProtectionDomain protectionDomain) {
if (classLoader == null || className == null || deleLoader.equals(classLoader.getClass().getName())) {
// skip boot loader, null classes (hibernate), or those from a
// reflection loader
return bytes;
}
// 忽略过指定classloader
/*if (loadersToSkip != null) {
if (loadersToSkip.contains(classLoader.getClass().getName())) {
return bytes;
}
}*/
// 如果没出问题,则加入预加载类
if (enable) {
loadPluginJars(classLoader);
}
return bytes;
}
/**
* 是否需要设置cat相关jar包路径
* @param preProcessLoader 正在加载的classloader
* @param systemClassLoader 本agent运行时系统loader
* @return true:需要加载 false:不需要加载
*/
protected abstract boolean shouldLoadCatJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader);
/**
* 是否需要设置plugin相关jar包路径
* @param preProcessLoader 正在加载的classloader
* @param systemClassLoader 本agent运行时系统loader
* @return true:需要加载 false:不需要加载
*/
protected abstract boolean shouldLoadPluginsJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader);
}
/**
*
*/
package com.qbao.catagent.processor;
/**
* 针对jetty应用进行的路径设置
* @author andersen
*
*/
public class JettyClassPathPreSetProcessor extends AbstractClassPathPreSetProcessor {
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPathPreSetProcessor#shouldLoadCatJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadCatJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader == systemClassLoader){
return true;
}
return false;
}
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPathPreSetProcessor#shuoldLoadPluginsJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadPluginsJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader == systemClassLoader){
return true;
}
if (preProcessLoader.getClass().getName().endsWith("WebAppClassLoader")){
return true;
}
return false;
}
}
/**
*
*/
package com.qbao.catagent.processor;
import java.security.ProtectionDomain;
import java.util.Properties;
import com.qbao.catagent.ClassPathPreSetProcessor;
/**
* 不做任何处理,直接返回输入的字节流
* @author andersen
*
*/
public class NullOperProcessor implements ClassPathPreSetProcessor {
/* (non-Javadoc)
* @see com.qbao.catagent.ClassPreLoadProcessor#initialize(java.util.Properties)
*/
@Override
public void initialize(Properties prop) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see com.qbao.catagent.ClassPreLoadProcessor#preProcess(java.lang.String, byte[], java.lang.ClassLoader, java.security.ProtectionDomain)
*/
@Override
public byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader,
ProtectionDomain protectionDomain) {
return bytes;
}
}
/**
*
*/
package com.qbao.catagent.processor;
/**
* @author andersen
*
*/
public class SpringbootClassPathPreSetProcessor extends AbstractClassPathPreSetProcessor {
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPathPreSetProcessor#shouldLoadCatJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadCatJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader == systemClassLoader){
return true;
}
return false;
}
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPathPreSetProcessor#shuoldLoadPluginsJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadPluginsJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader == systemClassLoader){
return true;
}
return false;
}
}
/**
*
*/
package com.qbao.catagent.processor;
/**
* 针对tomcat应用进行的路径设置
* @author andersen
*
*/
public class TomcatClassPathPreSetProcessor extends AbstractClassPathPreSetProcessor {
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPreLoadProcessor#shouldLoadCatJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadCatJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader == systemClassLoader){
return true;
}
return false;
}
/* (non-Javadoc)
* @see com.qbao.catagent.processor.AbstractClassPreLoadProcessor#shuoldLoadPluginsJars(java.lang.ClassLoader, java.lang.ClassLoader)
*/
@Override
protected boolean shouldLoadPluginsJars(ClassLoader preProcessLoader, ClassLoader systemClassLoader) {
if (preProcessLoader.getParent() == systemClassLoader){
return true;
}
if (preProcessLoader.getClass().getName().endsWith("WebappClassLoader")){
return true;
}
return false;
}
}
/**
*
*/
package com.qbao.catagent.util;
/**
* 应用类型,现只支持tomcat,jetty,springboot
* @author andersen
*
*/
public enum AppTypeEnum {
TOMCAT("tomcat"), JETTY("jetty"), SPRINGBOOT("springboot");
private String name;
private AppTypeEnum(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static AppTypeEnum getAppType(String type){
for (AppTypeEnum at : AppTypeEnum.values()){
if (at.getName().equals(type)){
return at;
}
}
return null;
}
}
package com.qbao.catagent.util;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
public class PropertyUtil {
public static Properties getProperties(String propertyFilePath) {
Properties prop = new Properties();
try {
// 读取属性文件a.properties
InputStream in = new BufferedInputStream(new FileInputStream(propertyFilePath));
prop.load(new InputStreamReader(in, "utf-8")); /// 加载属性列表
in.close();
return prop;
} catch (Exception e) {
System.out.println("Warn: CatAgent can't resolve properties file : " + propertyFilePath);
return null;
}
}
}
#注:文件分隔符请用 "/", 文件用utf-8编码,否则中文路径会有问题
#cat-client及其相关jar包所放路径
cat.client.path=E:/catagent/cat-client
#plugin及期相关jar包所放路径(不要与cat-client放在同一文件夹下)
cat.plugins.path=E:/catshare/cat/框架埋点方案集成/javaagent-client-agent/cat-client-plugin/target
#应用类型 tomcat|jetty|springboot
#tomcat: 需在tomcat中运行的应用
#jetty : 需在jetty中运行的应用
#springboot: 以springboot方式启动的应用(引用spring-boot标签,但是放在tomcat中的应用还是属于tomcat)
app.type=tomcat
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cat-client-plugin</groupId>
<artifactId>cat-client-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<aspectj.version>1.8.10</aspectj.version>
</properties>
<dependencies>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- Cat Client -->
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-client</artifactId>
<version>1.3.6</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
<scope>provided</scope>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.2.2</version>
<scope>provided</scope>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
<scope>provided</scope>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<!-- HttpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/**
*
*/
package com.qbao.cat.plugin;
/**
* @author andersen
*
*/
public interface CatPluginConstants {
/**
* 调用者地址参数名
*/
public static final String D_CLIENT_ADDR ="X-CAT-CLIENT-ADDR";
/**
* 调用者domain参数名
*/
public static final String D_CLIENT_DOMAIN ="X-CAT-CLIENT-DOMAIN";
/**
* 服务者地址参数名
*/
public static final String D_CALL_SERVER_ADDR ="X-CAT-SERVER-ADDR";
/**
* 服务者domain参数名
*/
public static final String D_CALL_SERVER_DOMAIN ="X-CAT-SERVER-DOMAIN";
/**
* 远程服务者Domain
*/
public static final String E_CALLEE_APP="Callee.app";
/**
* 发起调用者Domain
*/
public static final String E_CALL_APP="Call.app";
/**
* 远程服务者主机Addr
*/
public static final String E_CALLEE_ADDR="Callee.Addr";
/**
* 远程调用标记参数名
*/
public static final String D_CALL_TRACE_MODE = "X-CAT-TRACE-MODE";
/**
* dubbo服务端transaction-type
*/
public static final String TYPE_DUBBO_SERVER = "Call.Dubbo.Server";
/**
* dubbo客户端transaction-type
*/
public static final String TYPE_DUBBO_CLIENT = "Call.Dubbo.Client";
/**
* http服务端transaction-type
*/
public static final String TYPE_HTTP_SERVER = "Call.Http.Server";
/**
* htt客户端transaction-type
*/
public static final String TYPE_HTTP_CLIENT = "Call.Http.Client";
/**
* http服务端返回码
*/
public static final String TYPE_URL_SERVER_RESOPONSE_CODE = "URL.Server.Response.Code";
/**
* http客户端代理信息,取自x-forwarded-for
*/
public static final String TYPE_URL_SERVER = "URL.Server";
/**
* http客户端refer信息
*/
public static final String TYPE_URL_SERVER_REFERER = "URL.Server.Referer";
/**
* http客户端user-agent信息
*/
public static final String TYPE_URL_SERVER_AGENT = "URL.Server.Agent";
/**
* http客户端请求方式
*/
public static final String TYPE_URL_METHOD = "URL.Method";
}
/*
* 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 com.qbao.cat.plugin;
/**
*
*/
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
/**
* @author andersen
*
*/
public abstract class DefaultPluginTemplate implements PluginTemplate{
protected static Properties config = new Properties();
private static AtomicBoolean isInited = new AtomicBoolean(false);
static{
if (isInited.compareAndSet(false, true) && System.getProperty("CATPLUGIN_CONF") != null){
String configPath = System.getProperty("CATPLUGIN_CONF");
try {
// 读取属性文件a.properties
InputStream in = new BufferedInputStream(new FileInputStream(configPath));
config.load(new InputStreamReader(in, "utf-8")); /// 加载属性列表
in.close();
} catch (Exception e) {
System.out.println("Warn: CatPlugin can't resolve properties file : " + configPath);
}
}else{
System.out.println("Warn: CatPlugin miss properties file! You can set it with -DCATPLUGIN_CONF=/opt/.... !");
}
}
@Override
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return proxyCollector(pjp);
}
public Object proxyCollector(ProceedingJoinPoint pjp) throws Throwable {
Transaction transaction = proxyBeginLog(pjp);
Object obj = null;
try {
obj = pjp.proceed();
proxySuccess(transaction);
return obj;
} catch (Throwable e) {
exception(transaction, e);
throw e;
} finally {
proxyEndLog(transaction, obj, pjp.getArgs());
}
}
protected void proxySuccess(Transaction transaction){
try {
transaction.setStatus(Transaction.SUCCESS);
} catch (Throwable e) {}
}
protected void exception(Transaction transaction, Throwable t) {
try {
if (isNotNull(transaction)) {
transaction.setStatus(t);
Cat.logError(t);
}
} catch (Throwable e) {
}
}
protected Transaction proxyBeginLog(ProceedingJoinPoint pjp) {
try {
return beginLog(pjp);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
protected void proxyEndLog(Transaction transaction, Object retVal, Object... params) {
try {
if (isNotNull(transaction)) {
endLog(transaction, retVal, params);
}
} catch (Throwable e) {
}finally{
if (isNotNull(transaction)) {
transaction.complete();
}
}
}
protected Transaction newTransaction(String type,String name) {
return Cat.newTransaction(type,name);
}
/**
* 方法执行前开始埋点
* @param pjp 方法执行上下文
* @return 埋点生成的transaction对象 注:可在其中加入若干event
*/
protected abstract Transaction beginLog(ProceedingJoinPoint pjp);
/**
* 方法执行后进行收尾工作
* @param transaction beginLog中生成的transaction对象,注:不用手动调用complete结束,模板已调用
* @param retVal 方法返回结果
* @param params 方法调用时传入参数
*/
protected abstract void endLog(Transaction transaction, Object retVal, Object... params);
public boolean isNull(Object obj) {
return obj == null;
}
public boolean isNotNull(Object obj) {
return !isNull(obj);
}
public boolean isNullOrEmpty(String param){
return isNull(param)||param.trim().equals("");
}
@Override
public void doReturn(JoinPoint joinPoint, Object retVal) {
// TODO Auto-generated method stub
}
@Override
public void doThrowing(JoinPoint joinPoint, Throwable ex) {
// TODO Auto-generated method stub
}
@Override
public void doBefore(JoinPoint joinPoint) {
// TODO Auto-generated method stub
}
@Override
public void doAfter(JoinPoint joinPoint) {
// TODO Auto-generated method stub
}
public String getConcreteUri(String uri) {
int index = -1;
if((index=uri.indexOf(";"))>-1){
uri = uri.substring(0, index);
}
return uri;
}
}
/*
* 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 com.qbao.cat.plugin;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public interface PluginTemplate {
String POINTCUT_NAME = "scope()";
void doBefore(JoinPoint joinPoint);
void doAfter(JoinPoint joinPoint);
Object doAround(ProceedingJoinPoint pjp) throws Throwable;
void doReturn(JoinPoint joinPoint, Object retVal);
void doThrowing(JoinPoint joinPoint, Throwable ex);
/**
* 标识方法,保持空方法体即可,aspectj会在运行时动态生成里面内容
*/
void scope();
}
/**
*
*/
package com.qbao.cat.plugin;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
/**
* @author andersen
*
*/
@Aspect
public abstract class TestPluginTemplate implements PluginTemplate {
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
// TODO Auto-generated method stub
}
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Method Signatrue --- " + pjp.getSignature().toLongString());
Object retVal = pjp.proceed();
System.out.println("retrun value --- " + retVal);
return retVal;
}
}
/*
* 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 com.qbao.cat.plugin.cache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
import redis.clients.jedis.BinaryClient;
@Aspect
public abstract class RedisPluginTemplate extends DefaultPluginTemplate {
@Override
@Pointcut
public void scope() {
}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
public Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
BinaryClient jedis = (BinaryClient)pjp.getTarget();
if (jedis != null){
transaction = Cat.newTransaction("Cache.Redis_" + jedis.getHost(), pjp.getSignature().toString());
}
return transaction;
}
@Override
public void endLog(Transaction transaction, Object retVal, Object... params) {
}
}
/*
* 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 com.qbao.cat.plugin.common;
import java.util.StringTokenizer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
@Aspect
public abstract class CommonPluginTemplate extends DefaultPluginTemplate {
@Override
@Pointcut
public void scope() {}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
StringBuilder type = new StringBuilder();
String packageStr = pjp.getSignature().getDeclaringType().getPackage().getName();
StringTokenizer st = new StringTokenizer(packageStr, ".");
for(int i=0;i<2;i++){
type.append(st.nextToken());
type.append(".");
}
type.append("Method");
Transaction transaction = Cat.newTransaction(type.toString(),pjp.getSignature().toString());
return transaction;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {}
}
/*
* 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 com.qbao.cat.plugin.common;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
@Aspect
public abstract class CommonPluginTemplate2 extends DefaultPluginTemplate {
@Pointcut
public void scope() {
}
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = Cat.newTransaction("Common.Method", pjp.getSignature().toString());
return transaction;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
}
}
\ No newline at end of file
/**
*
*/
package com.qbao.cat.plugin.common;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class ThreadPluginTemplate extends DefaultPluginTemplate {
@Override
@Pointcut
public void scope() {}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
String className = pjp.getTarget().getClass().getName();
Transaction transaction = Cat.newTransaction("Thread",className);
return transaction;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {}
}
/**
*
*/
/*
* 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 com.qbao.cat.plugin.db.nosql;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.mongodb.client.MongoCollection;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class NewMongoPluginTemplate extends DefaultPluginTemplate {
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.DefaultPluginTemplate#beginLog(org.aspectj.lang.ProceedingJoinPoint)
*/
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
transaction = newTransaction("MongoDB", String.valueOf(pjp.getSignature().toShortString()));
MongoCollection collector = (MongoCollection) pjp.getTarget();
Cat.logEvent("DB.Collection", collector.getNamespace().getFullName());
Cat.logEvent("Method", pjp.getSignature().toString());
return transaction;
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.DefaultPluginTemplate#endLog(com.dianping.cat.message.Transaction, java.lang.Object, java.lang.Object[])
*/
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
// TODO Auto-generated method stub
}
}
/*
* 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 com.qbao.cat.plugin.db.nosql;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.mongodb.DBCollection;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* 根据 <a href="https://stackoverflow.com/questions/29364787/mongocollection-versus-dbcollection-java">
* https://stackoverflow.com/questions/29364787/mongocollection-versus-dbcollection-java</a>介绍;
* 3.0以后的客户端版本一般用MongoCollection, 而不再用DbCollection
* @author andersen
*
*/
@Aspect
public abstract class OldMongoPluginTemplate extends DefaultPluginTemplate {
@Pointcut
public void scope() {
}
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
transaction = newTransaction("MongoDB", String.valueOf(pjp.getSignature().toShortString()));
DBCollection collector = (DBCollection) pjp.getTarget();
Cat.logEvent("Host", collector.getDB().getMongo().getServerAddressList().toString());
Cat.logEvent("Connection", collector.toString());
Cat.logEvent("DB", collector.getDB().getName());
Cat.logEvent("Method", pjp.getSignature().toString());
return transaction;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
}
}
\ No newline at end of file
/**
*
*/
package com.qbao.cat.plugin.db.sql;
import java.lang.reflect.Field;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Transaction;
import com.mysql.jdbc.ConnectionImpl;
import com.mysql.jdbc.PreparedStatement;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* 说明:
* 1. 本plugin只针对用PreparedStatement执行sql的情况,pointcut表达式中如果埋到其它类中则无效
* @author andersen
*
*/
@Aspect
public abstract class MySQLPreparedStatementPluginTemplate extends DefaultPluginTemplate {
private volatile static boolean effective = true;
private volatile static Field originalSqlField = null;
public MySQLPreparedStatementPluginTemplate() {
try {
originalSqlField = PreparedStatement.class.getDeclaredField("originalSql");
if(isNotNull(originalSqlField)){
originalSqlField.setAccessible(true);
}else{
effective = false;
}
} catch (Exception e) {
effective = false;
}
}
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.PluginTemplate#scope()
*/
@Pointcut
public void scope() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.DefaultPluginTemplate#beginLog(org.aspectj.lang.ProceedingJoinPoint)
*/
protected Transaction beginLog(ProceedingJoinPoint pjp) {
try {
if (effective && pjp.getTarget() instanceof PreparedStatement){
Transaction transaction = this.newTransaction(CatConstants.TYPE_SQL, (String)originalSqlField.get(pjp.getTarget()));
PreparedStatement ps = (PreparedStatement)pjp.getTarget();
if (ps.getConnection() instanceof ConnectionImpl){
Cat.logEvent(CatConstants.TYPE_SQL_DATABASE, ((ConnectionImpl)((PreparedStatement)pjp.getTarget()).getConnection()).getURL());
}
if ("true".equals(config.getProperty("plugin.mysql.ps.includefullsql"))){
transaction.addData("FullSQL", ps.toString().split(":")[1]);
}
return transaction;
}else{
return null;
}
}catch (Exception e1) {
return null;
}
}
/* (non-Javadoc)
* @see cat.qbao.cat.plugin.DefaultPluginTemplate#endLog(com.dianping.cat.message.Transaction, java.lang.Object, java.lang.Object[])
*/
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
// TODO Auto-generated method stub
}
}
/**
*
*/
package com.qbao.cat.plugin.remote;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.aspectj.lang.ProceedingJoinPoint;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
public abstract class ClientPluginTemplate<T> extends DefaultPluginTemplate {
protected RemoteContext getClientTrace() {
RemoteContext context = new RemoteContext();
Cat.logRemoteCallClient(context);
return context;
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
if (isNotNull(pjp.getArgs()) && pjp.getArgs().length >= 1) {
T requestContext = getRequestContext(pjp);
transaction = newTransaction(getTransactionType(),getTransactionName(requestContext));
//send client addr
sendClientAddr(requestContext,getClientAddrDataKey(),getClientAddrData());
//send client domain
sendClientDomain(requestContext,getClientDomainDataKey(),getClientDomainData());
specialHandling(requestContext);
//¼Message䵽
logRemoteTrace(requestContext);
}
return transaction;
}
protected abstract T getRequestContext(ProceedingJoinPoint pjp);
protected abstract String getTransactionType();
protected abstract String getTransactionName(T requestContext);
protected abstract void sendClientAddr(T request,String key,String value);
protected abstract void sendClientDomain(T request,String key,String value);
protected abstract void specialHandling(T request);
protected abstract void logTrace(T handler, Entry<String, String> entry);
protected abstract boolean enableTrace(T handler);
/**
*
* @return
*/
protected String getClientAddrDataKey(){
return CatPluginConstants.D_CLIENT_ADDR;
}
protected String getServerAddrDataKey(){
return CatPluginConstants.D_CALL_SERVER_ADDR;
}
protected String getServerDomainDataKey(){
return CatPluginConstants.D_CALL_SERVER_DOMAIN;
}
protected String getClientAddrData(){
return Cat.getManager().getThreadLocalMessageTree().getIpAddress();
}
protected String getClientDomainDataKey(){
return CatPluginConstants.D_CLIENT_DOMAIN;
}
protected String getClientDomainData(){
return Cat.getManager().getThreadLocalMessageTree().getDomain();
}
protected String getDomainKey(){
return CatConstants.E_CALL_APP;
}
protected void logServerDomain(String serverDomain){
Cat.logEvent(CatConstants.E_CALLEE_APP,serverDomain);
}
protected void logServerAddr(String serverAddr){
Cat.logEvent(CatConstants.E_CALLEE_ADDR,serverAddr);
}
protected void logRemoteTrace(T handler) {
if (enableTrace(handler)) {
for (Entry<String, String> entry : this.getClientTrace().getAllData().entrySet()) {
logTrace(handler, entry);
}
}
}
public static class RemoteContext implements Cat.Context {
private Map<String, String> traceData = new HashMap<String, String>();
@Override
public void addProperty(String key, String value) {
traceData.put(key, value);
}
@Override
public String getProperty(String key) {
return traceData.get(key);
}
public Map<String, String> getAllData() {
return traceData;
}
}
}
/**
*
*/
package com.qbao.cat.plugin.remote;
import java.util.HashMap;
import java.util.Map;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
public abstract class ServerPluginTemplate<T> extends DefaultPluginTemplate{
public abstract boolean isEnableTrace(T request);
protected void logClientTrace(String messsageId, String parentId, String rootId) {
RemoteContext context = new RemoteContext();
context.addProperty(Cat.Context.CHILD, messsageId);
context.addProperty(Cat.Context.PARENT, parentId);
context.addProperty(Cat.Context.ROOT, rootId);
Cat.logRemoteCallServer(context);
}
protected void logClientInfo(String clientAddr, String clientDomain) {
Cat.logEvent(CatConstants.E_CLIENT_ADDR,clientAddr);
Cat.logEvent(CatConstants.E_CALL_APP,clientDomain);
}
public static class RemoteContext implements Cat.Context {
private Map<String, String> traceData = new HashMap<String, String>();
@Override
public void addProperty(String key, String value) {
traceData.put(key, value);
}
@Override
public String getProperty(String key) {
return traceData.get(key);
}
public Map<String, String> getAllData() {
return traceData;
}
}
}
/**
*
*/
package com.qbao.cat.plugin.remote.dubbo;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.remote.ClientPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class DubboClientPluginTemplate extends ClientPluginTemplate<RpcInvocation> {
private static final ThreadLocal<AtomicBoolean> Entered = new ThreadLocal<AtomicBoolean>(){
@Override
protected AtomicBoolean initialValue() {
return new AtomicBoolean(false);
}
};
@Override
@Pointcut
public void scope() {
}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
boolean result = true;
try{
result = Entered.get().compareAndSet(false, true);
}catch(Throwable t){}
if(result){
obj = super.doAround(pjp);
try{
Entered.get().set(false);
}catch(Throwable tt){}
}else{
obj = pjp.proceed();
}
return obj;
}
@Override
protected RpcInvocation getRequestContext(ProceedingJoinPoint pjp) {
//ʼinvoker
RpcInvocation rpcInvocation = (RpcInvocation)pjp.getArgs()[0];
if(isNull(rpcInvocation.getInvoker())){
rpcInvocation.setInvoker((Invoker<?>)pjp.getThis());
}
return (RpcInvocation)pjp.getArgs()[0];
}
@Override
protected String getTransactionType() {
return CatPluginConstants.TYPE_DUBBO_CLIENT;
}
@Override
protected String getTransactionName(RpcInvocation requestContext) {
return requestContext.getInvoker().getInterface().getSimpleName()+"."+requestContext.getMethodName();
}
@Override
protected void sendClientAddr(RpcInvocation request, String key, String value) {
request.setAttachment(key, value);
}
@Override
protected void sendClientDomain(RpcInvocation request, String key, String value) {
request.setAttachment(key, value);
}
@Override
protected void specialHandling(RpcInvocation request) {
}
@Override
protected void logTrace(RpcInvocation handler, Entry<String, String> entry) {
handler.setAttachment(entry.getKey(),entry.getValue());
}
@Override
protected boolean enableTrace(RpcInvocation handler) {
handler.setAttachment(CatPluginConstants.D_CALL_TRACE_MODE, "trace");
return true;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
Result result = ((Result)retVal);
String serverDomain = result.getAttachment(CatPluginConstants.D_CALL_SERVER_DOMAIN);
String serverAddr = result.getAttachment(CatPluginConstants.D_CALL_SERVER_ADDR);
if(isNotNull(serverDomain)){
logServerDomain(serverDomain);
}
if(isNotNull(serverAddr)){
logServerAddr(serverAddr);
}
}
}
/**
*
*/
package com.qbao.cat.plugin.remote.dubbo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.RpcResult;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.remote.ServerPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class DubboServerPluginTemplate extends ServerPluginTemplate<Invocation>{
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
@Pointcut
public void scope() {
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
RpcInvocation request = (RpcInvocation)pjp.getArgs()[0];
if(this.isEnableTrace(request)){
logClientTrace(request);
transaction = newTransaction(CatPluginConstants.TYPE_DUBBO_SERVER,getRpcName(request,(Invoker<?>)pjp.getTarget()));
logClientInfo(request.getAttachment(CatPluginConstants.D_CLIENT_ADDR),request.getAttachment(CatPluginConstants.D_CLIENT_DOMAIN));
}
return transaction;
}
private String getRpcName(RpcInvocation request,Invoker<?> invoker){
return invoker.getInterface().getName()+"."+request.getMethodName();
}
@Override
public boolean isEnableTrace(Invocation request) {
return request.getAttachment(CatPluginConstants.D_CALL_TRACE_MODE) != null;
}
protected void logClientTrace(Invocation request){
logClientTrace(request.getAttachment(Cat.Context.CHILD),request.getAttachment(Cat.Context.PARENT),request.getAttachment(Cat.Context.ROOT));
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
((RpcResult)retVal).setAttachment(CatPluginConstants.D_CALL_SERVER_DOMAIN, Cat.getManager().getDomain());
((RpcResult)retVal).setAttachment(CatPluginConstants.D_CALL_SERVER_ADDR, Cat.getManager().getThreadLocalMessageTree().getIpAddress());
}
}
/**
*
*/
package com.qbao.cat.plugin.remote.http;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.remote.ClientPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class HttpClientPluginTemplate extends ClientPluginTemplate<HttpMessage> {
private static final ThreadLocal<AtomicBoolean> Entered = new ThreadLocal<AtomicBoolean>(){
@Override
protected AtomicBoolean initialValue() {
return new AtomicBoolean(false);
}
};
@Override
@Pointcut
public void scope() {}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
boolean result = true;
try{
result = Entered.get().compareAndSet(false, true);
}catch(Throwable t){}
if(result){
obj = super.doAround(pjp);
try{
Entered.get().set(false);
}catch(Throwable tt){}
}else{
obj = pjp.proceed();
}
return obj;
}
@Override
public Transaction beginLog(ProceedingJoinPoint pjp) {
HttpHost httpHost = null;
HttpUriRequest uriRequest = null;
HttpRequest request = null;
for(Object param : pjp.getArgs()){
if(param instanceof HttpHost){
httpHost = (HttpHost)param;
}
if(param instanceof HttpUriRequest){
uriRequest = (HttpUriRequest)param;
}
if(param instanceof HttpRequest){
request = (HttpRequest)param;
}
}
if(isNotNull(uriRequest)){
return logTransaction(uriRequest,uriRequest.getURI(),uriRequest.getMethod());
}
//if httpHost != null ,request must not null
if(isNotNull(httpHost) && isNotNull(request)){
try {
return logTransaction(request,new URI(request.getRequestLine().getUri()),request.getRequestLine().getMethod());
} catch (URISyntaxException e) {
}
}
return null;
}
private Transaction logTransaction(HttpMessage message, URI uri,String method) {
Transaction transaction;
transaction = this.newTransaction(this.getTransactionType(),uri.getScheme()+"://"+uri.getAuthority()+getConcreteUri(uri.getPath()));
sendClientAddr(message, getClientAddrDataKey(),getClientAddrData());
sendClientDomain(message,getClientDomainDataKey(),getClientDomainData());
Cat.logEvent("Http.Method", method);
logRemoteTrace(message);
return transaction;
}
@Override
public boolean enableTrace(HttpMessage handler) {
handler.setHeader(CatPluginConstants.D_CALL_TRACE_MODE, "trace");
return true;
}
@Override
public void endLog(Transaction transaction, Object retVal, Object... params) {
Header addr = ((HttpResponse)retVal).getFirstHeader(getServerAddrDataKey());
Header domain = ((HttpResponse)retVal).getFirstHeader(getServerDomainDataKey());
if(isNotNull(addr)){
logServerAddr(addr.getValue());
}
if(isNotNull(domain)){
logServerDomain(domain.getValue());
}
}
@Override
public void logTrace(HttpMessage handler, Entry<String, String> entry) {
handler.setHeader(entry.getKey(), entry.getValue());
}
@Override
protected HttpMessage getRequestContext(ProceedingJoinPoint pjp) {
return null;
}
@Override
protected String getTransactionType() {
return CatPluginConstants.TYPE_HTTP_CLIENT;
}
@Override
protected String getTransactionName(HttpMessage requestContext) {
return null;
}
@Override
protected void sendClientAddr(HttpMessage request, String key, String value) {
request.setHeader(key, value);
}
@Override
protected void sendClientDomain(HttpMessage request, String key, String value) {
request.setHeader(key, value);
}
@Override
protected void specialHandling(HttpMessage request) {
}
}
/**
*
*/
package com.qbao.cat.plugin.remote.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.remote.ServerPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class HttpServerPluginTemplate extends ServerPluginTemplate<HttpServletRequest> {
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
@Pointcut()
public void scope() {
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
Transaction transaction = null;
HttpServletRequest request = (HttpServletRequest)pjp.getArgs()[0];
if(this.isEnableTrace(request)){
logClientTrace(request);
transaction = newTransaction(CatPluginConstants.TYPE_HTTP_SERVER,getConcreteUri(request.getRequestURI()));
HttpServletResponse response = (HttpServletResponse)pjp.getArgs()[1];
logClientInfo(request.getHeader(CatPluginConstants.D_CLIENT_ADDR),request.getHeader(CatPluginConstants.D_CLIENT_DOMAIN));
notifyServerInfo(response);
}
return transaction;
}
protected void notifyServerInfo(HttpServletResponse response){
response.setHeader(CatPluginConstants.D_CALL_SERVER_DOMAIN, Cat.getManager().getDomain());
response.setHeader(CatPluginConstants.D_CALL_SERVER_ADDR, Cat.getManager().getThreadLocalMessageTree().getIpAddress());
}
@Override
public boolean isEnableTrace(HttpServletRequest request) {
return request.getHeader(CatPluginConstants.D_CALL_TRACE_MODE) != null;
}
protected void logClientTrace(HttpServletRequest request){
logClientTrace(request.getHeader(Cat.Context.CHILD),request.getHeader(Cat.Context.PARENT),request.getHeader(Cat.Context.ROOT));
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
}
}
/**
*
*/
package com.qbao.cat.plugin.spring;
import java.util.StringTokenizer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class SpringControllerPluginTemplate extends DefaultPluginTemplate {
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.DefaultPluginTemplate#beginLog(org.aspectj.lang.ProceedingJoinPoint)
*/
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
StringBuilder type = new StringBuilder();
String packageStr = pjp.getSignature().getDeclaringType().getPackage().getName();
StringTokenizer st = new StringTokenizer(packageStr, ".");
for(int i=0;i<2;i++){
type.append(st.nextToken());
type.append(".");
}
type.append("Controller");
Transaction transaction = Cat.newTransaction(type.toString(),pjp.getSignature().toShortString());
return transaction;
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.DefaultPluginTemplate#endLog(com.dianping.cat.message.Transaction, java.lang.Object, java.lang.Object[])
*/
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
// TODO Auto-generated method stub
}
}
/**
*
*/
package com.qbao.cat.plugin.spring;
import java.util.StringTokenizer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class SpringServicePluginTemplate extends DefaultPluginTemplate{
@Override
@Pointcut
public void scope() {}
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
StringBuilder type = new StringBuilder();
String packageStr = pjp.getSignature().getDeclaringType().getPackage().getName();
StringTokenizer st = new StringTokenizer(packageStr, ".");
for(int i=0;i<2;i++){
type.append(st.nextToken());
type.append(".");
}
type.append("Service");
Transaction transaction = Cat.newTransaction(type.toString(),pjp.getSignature().toShortString());
return transaction;
}
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {}
}
/**
*
*/
package com.qbao.cat.plugin.web;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
public abstract class BaseUrlPluginTemplate extends DefaultPluginTemplate{
/* (non-Javadoc)
* @see com.qbao.cat.plugin.DefaultPluginTemplate#beginLog(org.aspectj.lang.ProceedingJoinPoint)
*/
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
HttpServletRequest request = getHttpRequest(pjp);
Transaction transaction = newTransaction(CatConstants.TYPE_URL,getConcreteUri(request.getRequestURI()));
if(isNotNull(transaction)){
logRequestClientInfo(request);
}
return transaction;
}
protected abstract HttpServletRequest getHttpRequest(ProceedingJoinPoint pjp);
protected abstract HttpServletResponse getHttpResponse(ProceedingJoinPoint pjp);
protected void logResponseInfo(HttpServletResponse response){
Cat.logEvent(CatConstants.TYPE_URL, CatPluginConstants.TYPE_URL_SERVER_RESOPONSE_CODE, Message.SUCCESS, String.valueOf(response.getStatus()));
}
protected void logRequestClientInfo(HttpServletRequest req) {
Cat.logEvent(CatConstants.TYPE_URL, CatPluginConstants.TYPE_URL_SERVER, Message.SUCCESS, getRequestServerInfo(req));
String referer = req.getHeader("referer");
if(isNotNull(referer)){
Cat.logEvent(CatConstants.TYPE_URL, CatPluginConstants.TYPE_URL_SERVER_REFERER, Message.SUCCESS,referer);
}
String userAgent = req.getHeader("user-agent");
if(isNotNull(userAgent)){
Cat.logEvent(CatConstants.TYPE_URL, CatPluginConstants.TYPE_URL_SERVER_AGENT, Message.SUCCESS,userAgent);
}
Cat.logEvent(CatConstants.TYPE_URL,CatPluginConstants.TYPE_URL_METHOD, Message.SUCCESS, getRequestMethodInfo(req));
}
protected String getRequestMethodInfo(HttpServletRequest req){
StringBuilder sb = new StringBuilder(256);
sb.append(req.getScheme().toUpperCase()).append('/');
sb.append(req.getMethod()).append(' ').append(req.getRequestURI());
String qs = req.getQueryString();
if (qs != null) {
sb.append('?').append(qs);
}
return sb.toString();
}
protected String getRequestServerInfo(HttpServletRequest req){
StringBuilder sb = new StringBuilder(1024);
String ip = "";
String ipForwarded = req.getHeader("x-forwarded-for");
if (ipForwarded == null) {
ip = req.getRemoteAddr();
} else {
ip = ipForwarded;
}
sb.append("IPS=").append(ip);
sb.append("&VirtualIP=").append(req.getRemoteAddr());
sb.append("&Server=").append(req.getServerName());
return sb.toString();
}
}
/**
*
*/
package com.qbao.cat.plugin.web;
import java.util.StringTokenizer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.DefaultPluginTemplate;
/**
* @author andersen
*
*/
@Aspect
public abstract class FilterPluginTemplate extends DefaultPluginTemplate {
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.DefaultPluginTemplate#beginLog(org.aspectj.lang.ProceedingJoinPoint)
*/
@Override
protected Transaction beginLog(ProceedingJoinPoint pjp) {
StringBuilder type = new StringBuilder();
String packageStr = pjp.getSignature().getDeclaringType().getPackage().getName();
StringTokenizer st = new StringTokenizer(packageStr, ".");
for(int i=0;i<2;i++){
type.append(st.nextToken());
type.append(".");
}
type.append("Filter");
Transaction transaction = Cat.newTransaction(type.toString(),pjp.getSignature().toShortString());
return transaction;
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.DefaultPluginTemplate#endLog(com.dianping.cat.message.Transaction, java.lang.Object, java.lang.Object[])
*/
@Override
protected void endLog(Transaction transaction, Object retVal, Object... params) {
}
}
/**
*
*/
package com.qbao.cat.plugin.web;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.qbao.cat.plugin.CatPluginConstants;
/**
* @author andersen
*
*/
@Aspect
public abstract class JettyUrlPluginTemplate extends BaseUrlPluginTemplate {
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
}
public HttpServletRequest getHttpRequest(ProceedingJoinPoint pjp){
HttpServletRequest request = (HttpServletRequest)pjp.getArgs()[2];
return request;
}
public HttpServletResponse getHttpResponse(ProceedingJoinPoint pjp){
HttpServletResponse response = (HttpServletResponse)pjp.getArgs()[3];
return response;
}
@Override
protected void endLog(Transaction transaction,Object retVal,Object...params) {
HttpServletRequest request = (HttpServletRequest)params[2];
HttpServletResponse response = (HttpServletResponse)params[3];
logResponseInfo(response);
Throwable cause = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if(isNotNull(cause)){
Cat.logError(cause);
}
}
}
/**
*
*/
package com.qbao.cat.plugin.web;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
/**
* @author andersen
*
*/
@Aspect
public abstract class TomcatUrlPluginTemplate extends BaseUrlPluginTemplate {
@Override
@Around(POINTCUT_NAME)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
return super.doAround(pjp);
}
/* (non-Javadoc)
* @see com.qbao.cat.plugin.PluginTemplate#scope()
*/
@Override
@Pointcut
public void scope() {
}
public HttpServletRequest getHttpRequest(ProceedingJoinPoint pjp){
HttpServletRequest request = (HttpServletRequest)pjp.getArgs()[0];
return request;
}
public HttpServletResponse getHttpResponse(ProceedingJoinPoint pjp){
HttpServletResponse response = (HttpServletResponse)pjp.getArgs()[1];
return response;
}
@Override
protected void endLog(Transaction transaction,Object retVal,Object...params) {
HttpServletRequest request = (HttpServletRequest)params[0];
HttpServletResponse response = (HttpServletResponse)params[1];
logResponseInfo(response);
Throwable cause = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if(isNotNull(cause)){
Cat.logError(cause);
}
}
}
<aspectj>
<aspects>
<!-- Redis -->
<concrete-aspect name="com.qbao.cat.plugin.cache.RedisPluginTemplateDump" extends ="com.qbao.cat.plugin.cache.RedisPluginTemplate">
<pointcut name="scope" expression="(execution(public * redis.clients.jedis.BinaryClient.*(..)))
&amp;&amp; !(execution(public * redis.clients.jedis.BinaryClient.isInMulti(..)))
&amp;&amp; !(execution(public * redis.clients.jedis.BinaryClient.isInWatch(..)))
&amp;&amp; !(execution(public * redis.clients.jedis.BinaryClient.getDB(..)))" />
</concrete-aspect>
<!-- MongoDB -->
<concrete-aspect name="com.qbao.cat.plugin.db.nosql.OldMongoPluginTemplateDump" extends ="com.qbao.cat.plugin.db.nosql.OldMongoPluginTemplate">
<pointcut name="scope" expression="(execution(public * com.mongodb.DBCollection.count*(..)))
|| (execution(public * com.mongodb.DBCollection.insert(java.util.List, com.mongodb.InsertOptions)))
|| (execution(public * com.mongodb.DBCollection.updateImpl(..)))
|| (execution(public * com.mongodb.DBCollection.find*(..)))
|| (execution(public * com.mongodb.DBCollection.remove*(..)))" />
</concrete-aspect>
<concrete-aspect name="com.qbao.cat.plugin.db.nosql.NewMongoPluginTemplateDump" extends ="com.qbao.cat.plugin.db.nosql.NewMongoPluginTemplate">
<pointcut name="scope" expression="(execution(public * com.mongodb.client.MongoCollection+.count*(..)))
|| (execution(public * com.mongodb.client.MongoCollection+.insert*(java.lang.Object,com.mongodb.client.model.InsertOneOptions)))
|| (execution(public * com.mongodb.client.MongoCollection+.update*(..)))
|| (execution(public * com.mongodb.client.MongoCollection+.find(org.bson.conversions.Bson,java.lang.Class)))
|| (execution(public * com.mongodb.client.MongoCollection+.delete*(..)))
|| (execution(public * com.mongodb.client.MongoCollection+.bulkWrite(java.util.List, com.mongodb.client.model.BulkWriteOptions)))" />
</concrete-aspect>
<!-- MySQL-->
<!-- MySQL PreparedStatement-->
<concrete-aspect name="com.qbao.cat.plugin.db.sql.MySQLPreparedStatementPluginTemplateDump" extends ="com.qbao.cat.plugin.db.sql.MySQLPreparedStatementPluginTemplate">
<pointcut name="scope" expression="(execution( * com.mysql.jdbc.PreparedStatement+.execute()))
|| (execution( * com.mysql.jdbc.PreparedStatement+.executeQuery()))
|| (execution( * com.mysql.jdbc.PreparedStatement+.executeUpdate()))" />
</concrete-aspect>
<!-- Dubbo -->
<concrete-aspect name="com.qbao.cat.plugin.remote.dubbo.DubboClientPluginTemplateDump" extends ="com.qbao.cat.plugin.remote.dubbo.DubboClientPluginTemplate">
<pointcut name="scope" expression="execution(public * com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(..))" />
</concrete-aspect>
<concrete-aspect name="com.qbao.cat.plugin.remote.dubbo.DubboServerPluginTemplateDump" extends ="com.qbao.cat.plugin.remote.dubbo.DubboServerPluginTemplate">
<pointcut name="scope" expression="execution(public * com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(..))" />
</concrete-aspect>
<!-- Http RPC -->
<!-- HttpClient client -->
<concrete-aspect name="com.qbao.cat.plugin.remote.http.HttpClientPluginTemplateDump" extends ="com.qbao.cat.plugin.remote.http.HttpClientPluginTemplate"> <pointcut name="scope" expression="execution(public * org.apache.http.client.HttpClient+.*(..))" />
</concrete-aspect>
<!-- SpringMVC Controller server -->
<concrete-aspect name="com.qbao.cat.plugin.remote.http.HttpServerPluginTemplateDump" extends ="com.qbao.cat.plugin.remote.http.HttpServerPluginTemplate"> <pointcut name="scope" expression="execution(* org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,org.springframework.web.method.HandlerMethod))" />
</concrete-aspect>
<!-- Spring -->
<!-- Controller -->
<concrete-aspect name="com.qbao.cat.plugin.spring.SpringControllerPluginTemplateDump" extends ="com.qbao.cat.plugin.spring.SpringControllerPluginTemplate">
<pointcut name="scope" expression="execution(* (@org.springframework.stereotype.Controller *).*(..))" />
</concrete-aspect>
<!-- Service -->
<concrete-aspect name="com.qbao.cat.plugin.spring.SpringServicePluginTemplateDump" extends ="com.qbao.cat.plugin.spring.SpringServicePluginTemplate">
<pointcut name="scope" expression="execution(* (@org.springframework.stereotype.Service *).*(..))" />
</concrete-aspect>
<!-- Web Filter -->
<concrete-aspect name="com.qbao.cat.plugin.web.FilterPluginTemplateDump" extends ="com.qbao.cat.plugin.web.FilterPluginTemplate">
<pointcut name="scope" expression="execution(public * javax.servlet.Filter+.doFilter(..))" />
</concrete-aspect>
<!-- Pool -->
<concrete-aspect name="com.qbao.cat.plugin.common.CommonPluginTemplateDump" extends ="com.qbao.cat.plugin.common.CommonPluginTemplate">
<pointcut name="scope" expression="execution(public * org.apache.commons.pool2.impl.GenericObjectPool.borrowObject())" />
</concrete-aspect>
<!-- Thread -->
<concrete-aspect name="com.qbao.cat.plugin.common.ThreadPluginTemplateDump" extends ="com.qbao.cat.plugin.common.ThreadPluginTemplate">
<pointcut name="scope" expression="execution(public * (com.qbao..* &amp;&amp; java.lang.Runnable+).run())" />
</concrete-aspect>
<!-- URL -->
<!-- Jetty(Eclipse embedded-Not Standalone server) -->
<concrete-aspect name="com.qbao.cat.plugin.web.JettyUrlPluginTemplateDump" extends ="com.qbao.cat.plugin.web.JettyUrlPluginTemplate">
<pointcut name="scope" expression="execution(public * org.eclipse.jetty.servlet.ServletHandler.doHandle(..))" />
</concrete-aspect>
<!-- Tomcat(and spring embedded tomcat) -->
<concrete-aspect name="com.qbao.cat.plugin.web.TomcatUrlPluginTemplateDump" extends ="com.qbao.cat.plugin.web.TomcatUrlPluginTemplate">
<pointcut name="scope" expression="execution(public * org.apache.catalina.core.StandardEngineValve.invoke(..))" />
</concrete-aspect>
<!-- Test -->
<concrete-aspect name="com.qbao.cat.plugin.TestPluginTemplateDump" extends ="com.qbao.cat.plugin.TestPluginTemplate">
<pointcut name="scope" expression="(execution(public * com.qbao.cat.test.web.controller..*.index(..)))
|| (execution(public * com.qbao.cat.test.web.controller..*.hello(..)))" />
</concrete-aspect>
</aspects>
<!--<weaver options="-Xset:weaveJavaxPackages=true -Xlint:ignore -verbose -showWeaveInfo">
<include within="com.qbao..*" />
<dump within="com.qbao.test..*"/>
</weaver> -->
<weaver options="-Xlint:ignore">
<include within="com.qbao..*" />
<include within="redis.clients..*"/>
<include within="org.eclipse..*" />
<include within="com.mongodb..*" />
<include within="org.apache..*" />
<include within="com.mysql..*" />
<include within="com.alibaba..*" />
<include within="org.springframework..*" />
<exclude within="org.aspectj..*" />
<!--<exclude within="com.qbao.cat.plugin..*"/>-->
<dump within="org.eclipse.jetty.servlet..*"/>
</weaver>
</aspectj>
# 是否包含填充过参数的sql语句(注:不建议开启,开启后会有数据安全问题)
plugin.mysql.ps.includefullsql=true
\ No newline at end of file
......@@ -210,7 +210,7 @@ public class CatMybatisPlugin implements Interceptor {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
value = "'" + formatter.format((Date)obj) + "'";
} else {
if (obj != null) {
value = obj.toString();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册