1. 程式人生 > >JAVA方法鏈路跟蹤實現思路

JAVA方法鏈路跟蹤實現思路

背景

   為了掌握鏈路中方法的執行情況,通過鏈路分析可以知道程式碼邏輯實現。

技術

   顯然,為了需要跟蹤方法的執行情況,需要對方法進行aop攔截

   生成位元組碼技術的方式有兩種,一種類於javaproxy產生的位元組碼樣式。一種是在進入方法和限出方法時注入程式碼實現aop程式碼增強(2)。具體實現見asm實現AOP的兩篇文章

另外,對於程式碼的跟蹤,還需要一個數據結構來記錄一個鏈路的程式碼執行情況。

 具體實現

   靜態AOP基於java agent方式載入

java-javaagent:myagent.jar

   基中myagent.jar就是實現鏈路方法跟蹤的jar包。

   鏈路跟蹤類的實現

public class InvokeTree {
    static ThreadLocal<InvokeTree> localTree = new ThreadLocal<InvokeTree>();

    public static class InvokeNode {
        public InvokeNode(int deep) {
            this.deep = deep;
            this.invokeCount = 1;
        }
        public InvokeNode parentNode;
        public List<InvokeNode> childNodes;
        public String invokeMethod;
        public int deep;
        public int invokeCount
        public boolean equals(InvokeNode other) {
            if (other == null) {
                return false;
            }
            if (!invokeMethod.equals(other.invokeMethod)) {
                return false;
            }
            if (childNodes == null && other.childNodes == null) {
                return true;
            }
            if (childNodes == null || other.childNodes == null) {
                return false;
            }
            int size = childNodes.size();
            if (size != other.childNodes.size()) {
                return false;
            }

            for (int i = 0; i < size; i++) {
                InvokeNode x = childNodes.get(i);
                InvokeNode y = other.childNodes.get(i);
                if (!x.equals(y)) {
                    return false;
                }
            }
            return true;
        }
    }


    public static void start(String invokeMethod) {
        ClientConfig clientConfig = Doom.getClientConfig();
        if (!clientConfig.isOpenInvokeTreeAnalyse()) {
            return;
        }
        InvokeTree tree = new InvokeTree();
        InvokeNode rootNode = new InvokeNode(0);
        rootNode.invokeMethod = invokeMethod;
        tree.rootNode = rootNode;
        tree.curNode = rootNode;
        localTree.set(tree);
    }


    public static void exit() {
        InvokeTree tree = localTree.get();
        if (tree != null) {
            tree.curNode = tree.curNode.parentNode;
        }
    }

    public static void enter(String invokeMethod) {
        InvokeTree tree = localTree.get();
        if (tree == null) {
            return;
        }
        InvokeNode parentNode = tree.curNode;
        InvokeNode newNode = new InvokeNode(parentNode.deep + 1);
        newNode.invokeMethod = invokeMethod;
        newNode.parentNode = parentNode;
        if (parentNode.childNodes == null) {
            parentNode.childNodes = new ArrayList<InvokeNode>();
        }
        parentNode.childNodes.add(newNode);

        tree.curNode = newNode;

        //
重複呼叫整理         cleanRepeatNode(parentNode);     }     public static void cleanRepeatNode(InvokeNode parentNode) {         if (parentNode == null) {             return;         }         int len = parentNode.childNodes.size();         if (len <= 1) {             cleanRepeatNode(parentNode.parentNode);             return;         }         InvokeNode a = parentNode.childNodes.get(len - 2);         InvokeNode b = parentNode.childNodes.get(len - 1);         if (a.equals(b)) {             parentNode.childNodes.remove(len - 1);             a.invokeCount++;         }         cleanRepeatNode(parentNode.parentNode);     }     public static void clear() {         localTree.set(null);     }     public InvokeNode rootNode;     public InvokeNode curNode;     public static InvokeTree getCurrentTree() {         return localTree.get();     }     public String toString() {         if (rootNode == null) {             rootNode = curNode;         }         if (rootNode == null) {             return "Empty Tree";         } else {             StringBuilder sb = new StringBuilder();             buildShow(rootNode, "", sb, true);             return sb.toString();         }     }     private void buildShow(InvokeNode node, String space, StringBuilder sb, boolean isParentLastNode) {         if (node != null) {             sb.append(space);             if (node.parentNode != null) {                 sb.append("|-");             }             sb.append(node.invokeMethod).append(node.invokeCount > 1 ? ("[
[email protected]
" + node.invokeCount) + "]\n" : "\n");             if (node.deep <= 8) {                 if (node.childNodes != null && node.childNodes.size() > 0) {                     for (int i = 0; i < node.childNodes.size(); i++) {                         InvokeNode chNode = node.childNodes.get(i);                         buildShow(chNode, space + ((node.parentNode != null                                         && isParentLastNode) ? "|   " : "    "),                                 sb, (i != node.childNodes.size() - 1));                     }                 }             }         }     }     public static void main(String[] args) {         ClientConfig clientConfig = new ClientConfig();         clientConfig.setOpenInvokeTreeAnalyse(true);         BootConfig.clientConfig = clientConfig;         InvokeTree.start("test");         InvokeTree.enter("hello");         InvokeTree.enter("invoke1");         InvokeTree.enter("invokeSub1");         InvokeTree.exit();         InvokeTree.enter("invokeSub2");         InvokeTree.exit();         InvokeTree.enter("invokeSub2");         InvokeTree.exit();         InvokeTree.exit();         InvokeTree.enter("invoke2");         InvokeTree.enter("invoke21");         InvokeTree.exit();         InvokeTree.exit();         InvokeTree.enter("invoke2");         InvokeTree.enter("invoke21");         InvokeTree.exit();         InvokeTree.exit();         InvokeTree.exit();         InvokeTree.exit();         System.out.println(InvokeTree.getCurrentTree().toString());     } }

最後結合原生剛剛實現的AOP攔截

public class AutoMocker implements AsmMocker {

    private String name;

    @Override
    public String getClassName() {
        return name;
    }


    public AutoMocker(String name) {
        this.name = name;
    }

    @Override
    public List<String> getMethodPatterns() {
//攔截所有方法
   List<String> patterns = new ArrayList<String>();
        patterns.add("* *(*)");
        return patterns;
    }

    @Override
    public InvocationInterceptor getInterceptor() {
        return new InvocationInterceptor() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//獲取方法名
                String invokeMethod = InvokeBuilder.buildIdentity(method.getDeclaringClass(), method);
                InvokeTree.enter(invokeMethod);
                try {
                    return AsmInjector.invoke(proxy, method, args);
                } finally {
                    InvokeTree.exit();
                }
            }
        };
    }

    @Override
    public boolean isIgnorePrivate() {
        return true;
    }

    @Override
    public boolean isIgnoreProtected() {
        return false;
    }

    @Override
    public List<String> getExcludePatterns() {
        return null;
    }

}

//生成相關AOP程式碼並載入到記憶體中。

AutoMocker autoMocker = new AutoMocker(className);
//對所攔截的類生成AOP增強位元組碼
byte[] classBytes = AopUtils.buildMockedByeWithAsmMocker(autoMocker, classLoader, bytes);

 

相關推薦

JAVA方法跟蹤實現思路

背景    為了掌握鏈路中方法的執行情況,通過鏈路分析可以知道程式碼邏輯實現。 技術    顯然,為了需要跟蹤方法的執行情況,需要對方法進行aop攔截    生成位元組碼技術的方式有兩種,一種類於javaproxy產生的位元組碼樣式。一種是在進入方法和限出方法時注入程式

cat 如何實現分散式跟蹤

轉載 https://www.cnblogs.com/xing901022/p/6237874.html Cat是美團點評出的一款APM工具,同類的產品也有不少,知名的開源產品如zipkin和pinpoint;國內收費的產品如oneapm。考慮到Cat在網際網路公司的應用比較廣

【第七章】分布式跟蹤(Sleuth)

default -o github nta 5.1 append comment 等等 1.2 當我們進行微服務架構開發時,通常會根據業務來劃分微服務,各業務之間通過REST進行調用。一個用戶操作,可能需要很多微服務的協同才能完成,如果在業務調用鏈路上任何一個微服務出現問題

SpringCloud學習成長之 九 服務跟蹤

ast 完成 rgs scope image 網絡超時 結束 發現 ip地址 這篇文章主要講述服務追蹤組件zipkin,Spring Cloud Sleuth集成了zipkin組件。 一、簡介 Spring Cloud Sleuth 主要功能就是在分布式系統中提供追蹤解決方

A10的上網負載實現

也不能 運營商 exc 公網 AC 配置過程 lac 國家 pin 其實目前國內大多數鏈路負載設備的實現形式都是目的地址是哪個運營商就走哪個運營商的線路,不明確目的地址到底是屬於哪個運營商的就默認給其中一條線路。再通過對鏈路的連通性檢測(一般是ping運營商網關,其實並不科

spring cloud 分布式跟蹤(集成zipkin)

ava 分享圖片 復雜 客戶 我們 集成 客戶端 erp -a 篇寫了分布式鏈路追蹤 spring cloud 分布式鏈路追蹤 這樣的鏈路追蹤雖然可以解決問題 但日誌太過於分散 如果微服務過多 就會變的相當復雜 zipkin就可以幫我們把鏈路調用的過程全部收集起來 它

spring cloud分布式使用日誌跟蹤

html 參考 服務 文件 add 當我 一點 pub https 首先要明白一點,為什麽要使用鏈路跟蹤? 當我們微服務之間調用的時候可能會出錯,但是我們不知道是哪個服務的問題,這時候就可以通過日誌鏈路跟蹤發現哪個服務出錯。 它還有一個好處:當我們在企業中,可能每個人都負責

spring cloud分布式整合zipkin的跟蹤

pre configure .cn pub erp https 分析 java clas 為什麽使用zipkin? 上篇主要寫了:spring cloud分布式日誌鏈路跟蹤 從上篇中可以看出服務之間的調用,假設現在有十幾臺服務,那麽在查找日誌的時候比較繁瑣、復雜,而且在查看

方位話機同一號碼雙註冊實現冗余

bubuko 交換機 鏈路 雙鏈路 alt image 如果 ima 表現 測試電話:http://10.11.12.33/ 現狀:   IP電話(方位X2)接網線上聯到有POE功能的交換機,通過交換機的voice vlan獲取IP地址,最後通過網絡註冊到天潤服務器。   

SpringCloud+skywalking跟蹤

SpringCloud+skywalking鏈路跟蹤   一、  環境準備 1.  基礎環境 CentOS 6.9 Eclpse Oxygen.2 Release (4.7.2) 2.  SkyWalking版本(3.2.6)和相關要求資訊: 被

【spring cloud】spring cloud Sleuth 和Zipkin 進行分散式跟蹤

spring cloud 分散式微服務架構下,所有請求都去找閘道器,對外返回也是統一的結果,或者成功,或者失敗。 但是如果失敗,那分散式系統之間的服務呼叫可能非常複雜,那麼要定位到發生錯誤的具體位置,就是一個比較麻煩的問題。 所以定位故障點,就引入了spring cloud Sleuth【Sleuth是獵

Java Web分頁顯示實現思路

實現效果 一.需求描述 從資料庫中將所有資料查詢出來,分頁顯示在前端頁面上,每頁顯示若干條資料,並實現"首頁","上一頁","下一頁","尾頁","跳轉至指定頁碼","顯示當前頁碼"等功能   二.實現思路  我的思路是將當前頁碼的值作為引數傳給servlet

springcloud(十二):使用Spring Cloud Sleuth和Zipkin進行分散式跟蹤

Spring Cloud Sleuth 一般的,一個分散式服務跟蹤系統,主要有三部分:資料收集、資料儲存和資料展示。根據系統大小不同,每一部分的結構又有一定變化。譬如,對於大規模分散式系統,資料儲存可分為實時資料和全量資料兩部分,實時資料用於故障排查(troubleshooting),全量資料用於系統優化;資

Spring Cloud:使用Spring Cloud Sleuth和Zipkin進行分散式跟蹤(12)

隨著業務發展,系統拆分導致系統呼叫鏈路愈發複雜一個前端請求可能最終需要呼叫很多次後端服務才能完成,當整個請求變慢或不可用時,我們是無法得知該請求是由某個或某些後端服務引起的,這時就需要解決如何快讀定位服務故障點,以對症下藥。於是就有了分散式系統呼叫跟蹤的誕生。 現今業界分散式服務跟蹤的理論基礎主

springcloud+springboot(十二):使用Spring Cloud Sleuth和Zipkin進行分散式跟蹤

Spring Cloud Sleuth 一般的,一個分散式服務跟蹤系統,主要有三部分:資料收集、資料儲存和資料展示。根據系統大小不同,每一部分的結構又有一定變化。譬如,對於大規模分散式系統,資料儲存可分為實時資料和全量資料兩部分,實時資料用於故障排查(troubleshooting),全量資料用於系統優化

Spring Cloud 分散式跟蹤 Sleuth + Zipkin + Elasticsearch

隨著業務越來越複雜,系統也隨之進行各種拆分,特別是隨著微服務架構的興起,看似一個簡單的應用,後臺可能很多服務在支撐;一個請求可能需要多個服務的呼叫;當請求遲緩或不可用時,無法得知是哪個微服務引起的,這時就需要解決如何快速定位服務故障點,Zipkin 分散式跟蹤系統就能很好的解決這樣的問題。 如果想學習Java

Spring Cloud 分散式跟蹤 Sleuth + Zipkin + Elasticsear

隨著業務越來越複雜,系統也隨之進行各種拆分,特別是隨著微服務架構的興起,看似一個簡單的應用,後臺可能很多服務在支撐;一個請求可能需要多個服務的呼叫;當請求遲緩或不可用時,無法得知是哪個微服務引起的,這時就需要解決如何快速定位服務故障點,Zipkin 分散式跟蹤系統就能很好的解決這樣的問題。 那麼到底怎麼使用

SpringCloud與zipkin(跟蹤)

一、下載、安裝zipkin zipkin的github地址:https://github.com/openzipkin/zipkin 下載:zipkin-server-2.11.5-exec.jar 執行:java -jar zipkin-server-2.11.5-e

spring cloud分布式日誌跟蹤

logging 通過 page 源碼分析 刷新 出錯 gin 好處 自動創建 首先要明白一點,為什麽要使用鏈路跟蹤? 當我們微服務之間調用的時候可能會出錯,但是我們不知道是哪個服務的問題,這時候就可以通過日誌鏈路跟蹤發現哪個服務出錯。 它還有一個好處:當我們在企業中,可能每

Spring Cloud Sleuth跟蹤之使用Mysq儲存服務跟蹤資訊(學習總結)

一、簡介 我們在上上一篇文章(https://blog.csdn.net/Weixiaohuai/article/details/82883280)已經實現了通過RabbitMQ訊息中介軟體的方式來收集服務鏈路跟蹤資訊,但是當zipkin-server服務端重啟之後,你會發