Java动态,安全追踪工具
Java动态,安全追踪工具
在我们日常的开发中,总是难以避免的要解决线上的问题.如果线上的问题我们在本地调试的时候无论调试多少次发现明明本地调用了这个方法呀,怎么线上就是没调呢?还有就是出了问题的时候由于没有打日志,所以不得不去价格logger,然后换个包,然后再重启,然后再调用,如果在用户很多的时候这么搞,无疑面临着巨大的风险,还不得不去处理用户的大量的投诉,在领导面前也只能默默的低着头承受着批评
那么有没有一种方法可以不用重启应用,又可以在线上追踪代码呢? 答案当然是有的,就是使用Btrace这个工具了
BTrace是sun公司推出的一款Java 动态、安全追踪(监控)工具,可以在不用重启的情况下监控系统运行情况,方便的获取程序运行时的数据信息,如方法参数、返回值、全局变量和堆栈信息等,并且做到最少的侵入,占用最少的系统资源。
应用场景:
- 服务慢,但是不知道慢在哪一步,哪个函数慢
- 谁调用了System.gc(),调用栈如何?
- 谁构造了一个超大的ArrayList?
- 执行某个方法抛出异常时,分析运行时参数
......
快速开始
btrace的官方的网址是http://github.com/btraceio/btrace , 可以从里面下载最新的版本, 目前版本是1.3.11.2
下载好之后doc里面有很多例子, 我们这里来跑一个UserGuide的例子
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnMethod;
import static com.sun.deploy.trace.Trace.println;
/**
* @author luozhiyun on 2019-01-06.
*/
@BTrace
public class HelloWorld {
@OnMethod(clazz="java.lang.Thread", method="start")
public static void onThreadStart() {
println("thread start!");
}
}
然后在要监控的机器上打jps, 找到应用的pid, 然后 btrace $pid HelloWorld.java就可以跑起来了
如果还想要监控其他内容,直接修改HelloWorld.java的内容,然后再执行一次btrace就可以了,完全不需要重启应用!!!
拦截
1.直接指出类和方法 ,如HelloWorld的例子
2.正则表达式拦截
如下, 拦截所有的有关InputStream类的readXXX方法,正则表达式要写在两个/中间
package com.sun.btrace.samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
/**
* This BTrace class demonstrates that we can
* probe into multiple classes and methods by a
* single probe specification using regular
* expressions for class and/or method names as
* given below. In the example, we put probe into
* all readXXX methods of all InputStream classes.
*/
@BTrace public class MultiClass {
@OnMethod(
clazz="/java\\.io\\..*Input.*/",
method="/read.*/"
)
public static void onread(@ProbeClassName String pcn) {
println("read on " + pcn);
}
}
3.拦截所有有这个注解的类或方法
如: @OnMethod( clazz="@javax.jws.WebService", method="@javax.jws.WebMethod" )
4.拦截接口的实现类
如:@OnMethod( clazz="+java.lang.Runnable", method="run" )
5.拦截构造器
@OnMethod(clazz="java.net.ServerSocket", method="<init>")
6.拦截静态内部类
@OnMethod(clazz="com.vip.MyServer$MyInnerClass", method="hello") 只要在类和内部类前面加上$
拦截时机
Kind.ENTRY
在@onMethod这个注解里面可以加上一个location参数,表示拦截的这个方法的拦截时机,如果不加,默认就是Kind.ENTRY
Kind.RETURN
如果要获得返回结果或执行时间, 那么就要加上Kind.RETURN.
OnMethod(clazz = "java.net.ServerSocket", method = "getLocalPort", location = @Location(Kind.RETURN))
public static void onGetPort(@Return int port, @Duration long duration)
duration的单位是纳秒,要除以 1,000,000 才是毫秒。
Kind.Error, Kind.Throw和 Kind.Catch
这几个主要用于异常情况的跟踪
在拦截函数的参数定义里注入一个Throwable的参数,代表异常。
@OnMethod(clazz = "java.net.ServerSocket", method = "bind", location = @Location(Kind.ERROR))
public static void onBind(Throwable exception, @Duration long duration)
Kind.Line
下例监控代码是否到达了Socket类的第363行
@OnMethod(clazz = "java.net.ServerSocket", location = @Location(value = Kind.LINE, line = 363))
public static void onBind4() {
println("socket bind reach line:363");
}
Kind.Call
下例就是打印出run()方法里面调用的所有其他方法
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.println;
/**
* @author luozhiyun on 2019-01-06.
*/
@BTrace
public class HelloWorld {
@OnMethod(clazz="BtraceCase", method="run",
location =@Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/", where = Where.AFTER))
public static void onThreadStart(@Self Object self, @TargetInstance Object instance,
@TargetMethodOrField String method, @Duration long duration) {
println("self: " + self);
println("instance: " + instance);
println("method: " + method);
println("duration: " + duration);
}
}
BtraceCase
import java.util.Random;
/**
* @author luozhiyun on 2019-01-06.
*/
public class BtraceCase {
public static Random random = new Random();
public int size;
public static void main(String[] args) throws Exception {
Thread.sleep(1000*15);
new BtraceCase().run();
}
public void run() throws Exception {
while (true) {
add(random.nextInt(10), random.nextInt(10));
}
}
public int add(int a, int b) throws Exception {
Thread.sleep(random.nextInt(10) * 100);
return a + b;
}
}
打印结果:
self: BtraceCase@63947c6b
instance: BtraceCase@63947c6b
method: add
duration: 402211413
self: BtraceCase@63947c6b
instance: java.util.Random@2b193f2d
method: nextInt
duration: 2602
所调用的类及方法名所注入到@TargetInstance与 @TargetMethodOrField中.如果想获得执行时间,必须把Where定义成AFTER
打印this,参数与返回值
import com.sun.btrace.AnyType;
@OnMethod(clazz = "java.io.File", method = "createTempFile", location = @Location(value = Kind.RETURN))
public static void o(@Self Object self, String prefix, String suffix, @Return AnyType result)
Self:
如果是静态函数,self为空 , 用@Self可以表示当前方法,也就是this
参数:
参数列表要么不要定义, 要定义就要定义完整,否则BTrace无法处理不同参数的同名函数
结果:
结果的类型用AnyType来定义,特别是用正则表达式匹配多个函数的时候,连void都可以表示
一点经验
用于匹配方法入参或返回类型时,因嫌麻烦不想引入外部依赖(一般也没有必要),外部类型请用AnyType代替,而不是Object!因为你可能用Object来准确匹配方法返回参数或返回类型。
启动跟踪脚本时,请使用和启动Java进程相同的Linux账号,不然会因为权限问题而attach失败。
另一个和BTrace类似的Java诊断工具greys-anatomy,由阿里释出,感兴趣的也可以学习一下。
若报错"Port 2020 unavailable.",则使用
btrace -p 2021 ...来指定其它端口。Linux下已经有个命令也叫btrace,注意别用混了。
由于Btrace会把脚本逻辑直接侵入到运行的代码中,所以在使用上做很多限制:
1、不能创建对象
2、不能使用数组
3、不能抛出或捕获异常
4、不能使用循环
5、不能使用synchronized关键字
6、属性和方法必须使用static修饰根据官方声明,不恰当的使用BTrace可能导致JVM崩溃,如在BTrace脚本使用错误的class文件,所以在上生产环境之前,务必在本地充分的验证脚本的正确性。
Java动态,安全追踪工具的更多相关文章
- java动态编译笔记
1 前言 Java的动态编译知识,真真在实际开发中并不是经常遇到.但是学习java动态编译有助于我们从更深一层次去了解java.对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知 ...
- Java动态代理全面分析
代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1 主题:规定代理类和真实对象共同对外暴露的接口: 2 代理类:专门代理真实对象的类: 3 ...
- 推荐6款常用的Java开源报表制作工具
JasperReports是一个基于Java的开源报表工具,它可以在Java环境下像其它IDE报表工具一样来制作报表.JasperReports 支持PDF.HTML.XLS.CSV和XML文件输出格 ...
- 常用 Java 静态代码分析工具的分析与比较
常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...
- [转]java动态代理(JDK和cglib)
转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...
- 彻底理解JAVA动态代理
代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 代理模式的结构如下图所示. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public ...
- 四种java代码静态检查工具
[转载]常用 Java 静态代码分析工具的分析与比较 转载自 开源中国社区 http://www.oschina.net/question/129540_23043 1月16日厦门 OSC ...
- Java 动态眨眼 EyesJPanel (整理)
/** * Java 动态眨眼 EyesJPanel (整理) * * 2016-1-2 深圳 南山平山村 曾剑锋 * 注意事项: * 1.本程序为java程序,同时感谢您花费宝贵的时间来阅读本文档: ...
- Java动态代理简单应用
概念 代理模式是基本的设计模式之一,它是开发者为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象.这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色. Java动态代理比 ...
随机推荐
- 你需要知道的c# Timer 的垃圾回收机制。
通常我们需要定时执行一段任务的时候,我们就需要定时器,这时我们就可以使用c# System.Threading空间中的 Timer定时器;他是个异步定时器,时间到时每次都是在线程池中分配一个线程去执行 ...
- Codeblocks 批量注释与对齐快捷键的教学方法
Ctrl+Shift+C 批量注释 Ctrl+shift+X 批量取消注释 Click Settings->Editor->KeyboardShortcuts (in the left o ...
- 面试超火题 This的问题!!!
this问题 (1)this是js的一个关键字,指定一个对象,然后替代this: 函数中的this指向行为发生的主体,函数外的this都指向window,没有意义 (2)函数内的this跟函数在什么环 ...
- PATA 1011 World Cup Betting (20)
1011. World Cup Betting (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Wit ...
- Python 爬虫从入门到进阶之路(十四)
之前的文章我们已经可以根据 re 模块,Xpath 模块和 BeautifulSoup4 模块来爬取网站上我们想要的数据并且存储在本地,但是我们并没有对存储数据的格式有要求,本章我们就来看数据的存储格 ...
- NEST 6.X升级到7.X
升级比对可访问 NEST 6.X升级到7.X 查看 ElasticClient-CreateIndex 升级前代码,NEST版本6.6.0 ICreateIndexResponse response ...
- C++智能指针的几种用法
auto在c++11中已经弃用. 一.auto_ptr模板 auto_ptr与shared_ptr.unique_ptr都定义了类似指针的对象,可以将new到的地址赋给这一对象,当智能指针过期时,析构 ...
- Siimple DP (Dynamic Programing)
HDU 2084:https://vjudge.net/problem/HDU-2084 Problem Describe : When it comes to the DP algorithm, a ...
- .Net Core 学习依赖注入自定义Service
1. 定义一个服务,包含一个方法 public class TextService { public string Print(string m) { return m; } } 2. 写一个扩展方法 ...
- HTML连载23-属性选择器(上)
一.属性选择器 1. (1)定义:根据指定的 属性名称找到对应的标签,然后设置属性 (2)格式:标签[属性=值]:{属性:值:] 注意:前一个值是不带引号的 (3)例子: <style> ...