第三章:基于BTrace的監(jiān)控調(diào)試

本文主要參考慕課網(wǎng)若魚老師課程Java生產(chǎn)環(huán)境下性能監(jiān)控與調(diào)優(yōu)詳解

請支持正版,抵制盜版省容,維護每一位辛苦付出的人的合法權(quán)益冬三!

本章關(guān)鍵詞:BTrace匀油、攔截、注意事項

一勾笆、入門

1.做什么的肖抱?

  • 可以在應(yīng)用程序不重啟郭计,不修改的情況下,正在運行的情況下,動態(tài)的修改字節(jié)碼倚喂,達到監(jiān)控調(diào)試的目的
  • 可以動態(tài)的向目標應(yīng)用程序的字節(jié)碼注入追蹤代碼
  • 用到的技術(shù)

JavaComplierApi、JVMTI馆铁、Agent榨为、Instrumentation+ASM

2.安裝

  • 官網(wǎng)中下載相應(yīng)版本
  • 新建環(huán)境變量BTRACE_HOME,添加Path:%BTRACE_HOME%\bin

環(huán)境變量的添加請自行百度

  • 兩種運行腳本方式
  1. JVisualVM中添加Btrace插件(參見上一章)啃勉,添加classpath

2.使用命令行btrace <pid> <trace_script>

3.使用詳解

  • 代碼示例
    btrace需要引入三個jar忽舟,就是下載的btrace程序中,build目錄下的三個


    jar包.png

引入jar包

<!--btrace -->
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-boot</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btrace-bin-1.3.11\build\btrace-boot.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-agent</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btrace-bin-1.3.11\build\btrace-agent.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-client</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>D:\btrace-bin-1.3.11\build\btrace-client.jar</systemPath>
        </dependency>

將要被攔截的代碼

package com.qinxianyun.monitor_tuning.chapter4;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Qinxianyun
 * @version V1.0
 * @time 2018/7/21.12:50
 * @description 演示btrace
 */
@RestController
@RequestMapping("ch4")
public class Ch4Controller {
    @RequestMapping("/arg1")
    public String arg1(@RequestParam("name")String name){
        return "hello," + name;
    }
}

btrace腳本(腳本和代碼沒有必要關(guān)聯(lián)性淮阐,腳本可以隨便寫在哪里叮阅,沒有必要寫在方法的一個項目里面)

package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

@BTrace
public class PrintArgSimple {
   
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            method = "arg1",
            location = @Location(Kind.ENTRY)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
        BTraceUtils.printArray(args);
        BTraceUtils.println(pcn + "," + pmn);
        BTraceUtils.println();
    }
}

@OnMethod表示我們要攔截哪個類的哪個方法,在什么時候進行攔截
Kind.ENTRY表示在入口的時候攔截(也就是一進入方法的時候)
@param pcn 攔截方法類的類名
@param pmn 攔截方法的方法名
@param args 參數(shù)

  • 進入到btrace腳本的目錄下


    進入目錄.png
  • 查看進程id


    查看進程id.png
  • 運行腳本文件


    運行中.png
  • 瀏覽器中輸入http://localhost:8080/ch4/arg1?name=qinxianyun
    出現(xiàn)如下處理結(jié)果

    處理結(jié)果.png

  • Java VisualVM打開btrace(需要已經(jīng)安裝了插件泣特,詳情見上一章)


    vm打開btrace.png

    界面詳解.png

    輸出.png

二浩姥、攔截構(gòu)造函數(shù)、同名函數(shù)

1.攔截方法(普通方法状您、構(gòu)造方法勒叠、同名方法)

  • 普通方法 @OnMethod(clazz=" ",method=" ")

參考上面的例子

  • 構(gòu)造函數(shù)@OnMethod(clazz=" ",method="<init>")

因為構(gòu)造函數(shù)在字節(jié)碼層面是叫init兜挨,所以用<init>

@RequestMapping("/constructor")
    public User arg1(User user){
        return user;
    }
package com.qinxianyun.monitor_tuning.chapter2;

/**
 * @author Qinxianyun
 * @version V1.0
 * @time 2018/7/15.14:52
 * @description 用戶實體
 */
public class User {
    private int id;

    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;

@BTrace
public class PrintConstructor {

    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter2.User",
            method = "<init>"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
        BTraceUtils.println(pcn + "," + pmn);
        BTraceUtils.printArray(args);
        BTraceUtils.println();
    }
}
運行結(jié)果.png
  • 同名方法(用參數(shù)區(qū)分)
@RequestMapping("/same1")
    public String same(@RequestParam("name")String name){
        return "hello," + name;
    }

    @RequestMapping("/same2")
    public String same(@RequestParam("name")String name,@RequestParam("id")int id){
        return "hello," + name + "," +id;
    }
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;

@BTrace
public class PrintSame {
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            method = "same"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name ,int id){
        BTraceUtils.println(pcn + "," + pmn + "," + name + "," + id);
        BTraceUtils.println();
    }
}

攔截重載的方法,是根據(jù)參數(shù)的類型區(qū)分的眯分,腳本中的名字可以和代碼中參數(shù)名不一致

運行結(jié)果:


運行結(jié)果1.png

三拌汇、攔截返回值、異常行號

1.攔截時機

  • Kind.ENTRY : 入口弊决,默認值

參考第一個例子

  • Kind.RETURN : 返回
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

@BTrace
public class PrintReturn {
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            method = "arg1",
            location = @Location(Kind.RETURN)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Return AnyType result){
        BTraceUtils.println(pcn + "," + pmn + "," + result);
        BTraceUtils.println();
    }
}

  • Kind.THROW : 異常
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

@BTrace
public class PrintOnThrow {
    @TLS
    static Throwable currentException;

    @OnMethod(
            clazz = "java.lang.Throwable",
            method = "<init>"
    )
    public static void onthrow(@Self Throwable self){//new Throwable()
        currentException = self;
    }

    @OnMethod(
            clazz = "java.lang.Throwable",
            method = "<init>"
    )
    public static void onthrow1(@Self Throwable self,String s){//new Throwable(String msg)
        currentException = self;
    }

    @OnMethod(
            clazz = "java.lang.Throwable",
            method = "<init>"
    )
    public static void onthrow1(@Self Throwable self,String s,Throwable cause){//new Throwable(String msg,Throwable cause)
        currentException = self;
    }

    @OnMethod(
            clazz = "java.lang.Throwable",
            method = "<init>"
    )
    public static void onthrow2(@Self Throwable self,Throwable cause){//new Throwable(Throwable cause)
        currentException = self;
    }

    @OnMethod(
            clazz = "java.lang.Throwable",
            method = "<init>",
            location = @Location(Kind.RETURN)
    )
    public static void onthrowreturn(){
        if (currentException != null){
            BTraceUtils.Threads.jstack(currentException);
            BTraceUtils.println("========================");
            currentException = null;
        }
    }
}

  • Kind.Line :行
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

@BTrace
public class PrintLine {
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            location = @Location(value = Kind.LINE,line = 41)
    )
    public static void anyRead(@ProbeClassName String pcn,@ProbeMethodName String pmn,int line){
        BTraceUtils.println(pcn + "," + pmn + "," + line);
        BTraceUtils.println();
    }
}

四噪舀、攔截復(fù)雜參數(shù)、環(huán)境變量飘诗、正則匹配攔截

1.攔截this与倡、入?yún)ⅰ⒎祷?/h4>
  • this:@Self
  • 入?yún)ⅲ嚎梢杂肁nyType昆稿,也可以用真實類型纺座,同名的用真實的
  • 返回:@Return

2.獲取對象的值

  • 簡單類型:直接獲取
  • 復(fù)雜類型:反射,類名+屬性名
package com.qinxianyun.monitor_tuning.chapter4;

import com.qinxianyun.monitor_tuning.chapter2.User;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

import java.lang.reflect.Field;

@BTrace
public class PrintArgComplex {
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            method = "arg2",
            location = @Location(Kind.ENTRY)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user){
        BTraceUtils.printFields(user);
        Field field2 = BTraceUtils.field("com.qinxianyun.monitor_tuning.chapter2.User","name");
        BTraceUtils.println(BTraceUtils.get(field2,user));
        BTraceUtils.println(pcn + "," + pmn);
        BTraceUtils.println();
    }
}

注意:
復(fù)雜類型.png

引用的需要加上-cp

3.正則表達式

  • 攔截任意方法
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;

@BTrace
public class PrintRegex {
    @OnMethod(
            clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
            method = "/.*/"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn){
        BTraceUtils.println(pcn + "," + pmn);
        BTraceUtils.println();
    }
}

4.打印環(huán)境變量

  • 打印(輸出類似Jinfo命令)
package com.qinxianyun.monitor_tuning.chapter4;

import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;

@BTrace
public class PrintJinfo {
    static {
        BTraceUtils.println("System Properties:");
        BTraceUtils.printProperties();
        BTraceUtils.println("VM Flags:");
        BTraceUtils.printVmArguments();
        BTraceUtils.println("OS Enviroment:");
        BTraceUtils.printEnv();
        BTraceUtils.exit();
    }
}
  • 輸出結(jié)果


    輸出.png

注意事項:
1.默認只能本地運行
2.生產(chǎn)環(huán)境下可以使用溉潭,但是被修改的字節(jié)碼不會被還原(即使btrace退出)
因此比驻,腳本中不要有太耗系統(tǒng)資源的東西,否則會影響服務(wù)器岛抄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末别惦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子夫椭,更是在濱河造成了極大的恐慌掸掸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹭秋,死亡現(xiàn)場離奇詭異扰付,居然都是意外死亡,警方通過查閱死者的電腦和手機仁讨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門羽莺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洞豁,你說我怎么就攤上這事盐固。” “怎么了丈挟?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵刁卜,是天一觀的道長。 經(jīng)常有香客問我曙咽,道長蛔趴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任例朱,我火速辦了婚禮孝情,結(jié)果婚禮上鱼蝉,老公的妹妹穿的比我還像新娘。我一直安慰自己箫荡,他們只是感情好魁亦,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菲茬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪派撕。 梳的紋絲不亂的頭發(fā)上婉弹,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音终吼,去河邊找鬼镀赌。 笑死,一個胖子當(dāng)著我的面吹牛际跪,可吹牛的內(nèi)容都是我干的商佛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼姆打,長吁一口氣:“原來是場噩夢啊……” “哼良姆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起幔戏,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤玛追,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后闲延,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊剖,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年垒玲,在試婚紗的時候發(fā)現(xiàn)自己被綠了陆馁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡合愈,死狀恐怖叮贩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情佛析,我是刑警寧澤妇汗,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站说莫,受9級特大地震影響杨箭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜储狭,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一互婿、第九天 我趴在偏房一處隱蔽的房頂上張望捣郊。 院中可真熱鬧,春花似錦慈参、人聲如沸呛牲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娘扩。三九已至,卻和暖如春壮锻,著一層夾襖步出監(jiān)牢的瞬間琐旁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工猜绣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灰殴,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓掰邢,卻偏偏與公主長得像牺陶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辣之,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,373評論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,097評論 1 32
  • 你是春天里 向上生長 一抺清新的綠 你是大海旁 由心蕩漾 一汪澄澈的水 這就是足夠的理由 讓人們在此駐足 讓輕風(fēng)為...
    風(fēng)的色彩00閱讀 331評論 0 0
  • 在2017年的鐘聲臨近的日子掰伸,我決定好好總結(jié)一下自己2016年的生活。從總體來說怀估,2016我是痛并快樂著碱工。 首先,...
    小小墨色的鉛筆閱讀 143評論 0 0
  • Webpack 是一個前端資源加載/打包工具奏夫。它將根據(jù)模塊的依賴關(guān)系進行靜態(tài)分析怕篷,然后將這些模塊按照指定的規(guī)則生成...
    Vivian33閱讀 235評論 0 1