维护一个老系统,有个 Config 类,其中有个静态变量 DEBUG ,默认值为 0 ,定义如下:
public static int DEBUG;
目前正式环境这个值在某些情况下会被修改成 1 ,搜了下系统中代码调用,没发现可疑的重新赋值代码,想请教下大家,如何在不修改现有代码,不增加 setter 方法的情况下监控这个变量值,当值变化时触发一个回调,打印代码执行路径?
@ikas @gitdoit 感谢两位,JDI 的 ModificationWatchpointEvent 有用,非常符合我的需求,我总结了一个最简单的使用方法,供有同样需求的人使用,字数超了,使用方法总结在语雀里了
https://www.yuque.com/docs/share/70aaa901-a2c5-4ab2-9339-e9d329d19ca1?# 《debugger》 链接有效期至 2022-04-10 12:22:33
顺便求个免费的可分享markdown的在线工具,临时用下,语雀永久分享还要开会员
1
panpanpan 2022-04-06 15:04:41 +08:00
有趣,等一个大佬
|
2
paragon 2022-04-06 15:09:28 +08:00
idea 把断点打在 field 上变化的时候就会停下
|
3
xylophone21 2022-04-06 15:14:03 +08:00
|
4
0o0O0o0O0o 2022-04-06 15:16:41 +08:00 via iPhone
了解不多,java 应该没办法 watch variable 吧?所以我的思路是动态替换掉这个类,以前破解 java 应用是利用 javaagent
|
5
zhazi 2022-04-06 15:19:21 +08:00
mbean?
|
6
MakHoCheung 2022-04-06 15:23:10 +08:00
是不是通过反射来改掉的?
|
7
ikas 2022-04-06 15:28:11 +08:00
用 java 调试相关的 api 估计可以
jdi ModificationWatchpointEvent |
8
dncba 2022-04-06 15:29:19 +08:00
使用阿里的 阿尔萨斯 工具调试一把
|
9
gitdoit 2022-04-06 15:35:29 +08:00
|
10
oneisall8955 2022-04-06 15:36:37 +08:00
全局搜索 DEBUG 都没有?
|
11
liangkang1436 2022-04-06 15:36:50 +08:00 via Android
先配置远程调试,然后在本地的源码的属性上打断点,等进断点的时候看一下断点的调用栈即可
|
12
rock123 OP @paragon #2
@xylophone21 #3 感谢两位 电脑没装 eclipse ,没有测试,看了下 idea ,确实可以监控静态变量变化,把断点打在 field ,右键断点,取消勾选 suspend, Log 一行勾选 stack trace 选项,就可以在值变化时,控制台输出代码调用路径,且不阻塞代码。 不过问题背景是线上环境偶发的一个 bug ,目前还不知道怎么触发什么时间触发,部署在远程 linux 服务器,没有图形界面。所以得我电脑全天开远程 debug ,平时电脑还有其他操作,很担心对线上服务的稳定,性能造成影响。 最好是有办法可以在代码层面监控,再不济也得是第三方命令行工具部署服务器监控,实在没办法,我再试这个远程 debug 方式 |
13
cpstar 2022-04-06 15:57:38 +08:00
运行环境下,能重新 deploy Config 这个类么?如果能,那就重写 Config ,然后起一个线程一直输出这个值。如果不能,那没办法了。
|
14
rock123 OP @dncba #8 好像没有监控变量的功能,只看到有监控方法返回值的功能。 修改这个 DEBUG 是直接 Config.DEBUG = xxx ,没有方法调用的
|
15
AlisaDestiny 2022-04-06 16:16:57 +08:00 via Android
同推荐阿里的 arthas,在线调试神器
|
16
rock123 OP @cpstar #13 轮询方法不太好,因为不知道何时会触发,一直开着,时间间隔小了,日志太多,对系统也有影响,时间间隔大了,又有可能变化在时间片内,监测不到
|
17
nothingistrue 2022-04-06 17:30:04 +08:00
逐步骤监控变量的值还有办法,但是你想在值变化时做自动处理(打印些信息),你不动代码是不行的。这是个 public 成员,可以直接赋值,切面都加不上。
还是想办法做断点调试吧,一步一步的查看值的变化。当然你不能直接在线上搞远程调试,尤其是你还想长时间的监控。你这个是公共静态变量,一个断点暂停就可能让整个系统崩溃。能在本地环境复现问题然后在本地断点调试是最好的,如果不能或者不好复现,那么只能逐行看代码了。 Eclipse 有几个功能可以帮助你找到哪个代码会修改这个值:右键变量然后选择“call hierarchy”;选中变量再 Ctrl+H ,然后可以查找所有引用这个变量的地方。 |
18
cpstar 2022-04-06 17:35:04 +08:00
如果是改成写 public static final int 呢?哪里要改写,是不是会抛异常?另外在反射上,能否仍然改写呢?
|
19
zmal 2022-04-06 17:50:04 +08:00
1.用 arthas 应该是可以的。
2.把这个字段改成 final 并上线,通过流量复制手段复制线上服务请求,看报错堆栈。 但是代码真的能复杂到通过源码找不到一个 Config 类里的 static 变量是什么情况下被改变吗?有点怀疑。 |
20
hotcool100 2022-04-06 17:58:42 +08:00
继续找,或许在引入的 jar 里的类里面呢
|
21
sky857412 2022-04-06 18:30:03 +08:00 1
|
22
fxxkgw 2022-04-06 18:35:26 +08:00
修改的地方估计被打成包了 所以单纯查关键词找不到 试试 grep 搜索下
|
23
likeunix 2022-04-06 19:50:17 +08:00 via Android
还是 C#香
|
24
v2lf 2022-04-06 22:28:22 +08:00
@cpstar 发射可以修改 final
"final fields can be changed via reflection and other implementation-dependent means." 但是要注意常量表达式赋值 “If a final field is initialized to a constant expression (§15.28) in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the value of the constant expression.” 而且更改的话,会有线程安全问题 |
27
debuggeeker 2022-04-07 10:21:25 +08:00
我排查诡异调用的一种方法,如果代码层面搜索不出来,那就打好包反编译找。先打个 release 的包,然后通过 jadx 或者其他反编译工具反编译一次,代码没混淆就好,反编译之后搜索这个类和熟悉的调用。如:const.debug 看看哪里使用了,又或者包名+类名全局搜索,看看哪里使用了这个类然后看属性的调用。
|
28
Unicorns96 2022-04-07 10:49:45 +08:00
将这个变量修饰为 final ,报异常查看堆栈就可以了
|
29
rock123 OP |
30
rock123 OP @nothingistrue #17
@cpstar #18 @zmal #19 @Unicorns96 #28 ide 的查看代码调用功能试过了,只有程序启动时赋值,其他都是读取值,bug 不知道哪里触发什么时候触发,bug 发生后,日志里变量值是不对的,当时又看了内存中的变量值,是正常的,估计是哪里有动态执行代码 线上环境,不想随便修改旧代码,导致一些其他 bug ,所以加 final 不合适 arthas 只能监控方法返回值,或者手动获取静态变量值,我这边需要监控静态变量值,有变化时程序主动发出通知。或许是我不会用,请指教 |
31
aguesuka 2022-04-07 13:04:00 +08:00
|
32
BiChengfei 2022-04-11 15:58:36 +08:00
github 就可以当 markdown
链接失效了,重新发发看看怎么用的,我没看懂文档 |
33
rock123 OP |