字节码基于javaagent的全链路监控六开发应用级监控(代码片段)

九师兄 九师兄     2023-01-15     471

关键词:

1.概述

上一篇文章:【字节码】基于JavaAgent的全链路监控五- ThreadLocal链路追踪

本章节转载:基于JavaAgent的全链路监控六《开发应用级监控》

在我们的监控程序中,需要对各种模块进行监控;servlet、rpc、http、jdbc、redis、logic等,那么我们在设计监控程序时就需要对监控的程序进行模块化开发,可以在需要的时候进行组装配置即可,以方便我们监控程序的扩展和可控制性。这一章节我们把监控模块剥离,采用工厂模式进行调用{目前是静态工厂在我们实际使用中可以把工厂做成动态配置化}。

2.环境准备

IntelliJ IDEA Community Edition
jdk1.8.0_45 64位

3.配置信息(路径相关修改为自己的)

配置位置:Run/Debug Configurations -> VM options
配置内容:-javaagent:/Users/lcc/IdeaProjects/lcc_work/test-byte-buddy/byte-buddy-v1x-javaagent-demo3/target/byte-buddy-v1x-javaagent-demo3-1.0-SNAPSHOT.jar=test

4. 核心代码

ApplicationAgent

package com.javaagent.bytebuddy.demo5;

import com.javaagent.bytebuddy.demo5.plugin.IPlugin;
import com.javaagent.bytebuddy.demo5.plugin.InterceptPoint;
import com.javaagent.bytebuddy.demo5.plugin.PluginFactory;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
import java.util.List;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class ApplicationAgent 

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) 

        System.out.println("基于javaagent链路追踪{源码微信公众号:bugstack虫洞栈}");
        System.out.println("==========================================================\\r\\n");
        AgentBuilder agentBuilder = new AgentBuilder.Default();

        List<IPlugin> pluginGroup = PluginFactory.pluginGroup;
        for (IPlugin plugin : pluginGroup) 
            InterceptPoint[] interceptPoints = plugin.buildInterceptPoint();
            for (InterceptPoint point : interceptPoints) 

                AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> 
                    builder = builder.visit(Advice.to(plugin.adviceClass()).on(point.buildMethodsMatcher()));
                    return builder;
                ;
                agentBuilder = agentBuilder.type(point.buildTypesMatcher())
                        .transform(transformer).asTerminalTransformation();
            
        

        //监听
        AgentBuilder.Listener listener = new AgentBuilder.Listener() 
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) 

            

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) 
                System.out.println("onTransformation:" + typeDescription);
            

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) 

            

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) 

            

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) 

            

        ;

        agentBuilder.with(listener).installOn(inst);

    



TrackManager

package com.javaagent.bytebuddy.demo5.track;

import java.util.Stack;

/**
 * 追踪管控
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class TrackManager 

    private static final ThreadLocal<Stack<Span>> track = new ThreadLocal<>();

    private static Span createSpan() 
        Stack<Span> stack = track.get();
        if (stack == null) 
            stack = new Stack<>();
            track.set(stack);
        
        String linkId;
        if (stack.isEmpty()) 
            linkId = TrackContext.getLinkId();
            if (linkId == null) 
                linkId = "nvl";
                TrackContext.setLinkId(linkId);
            
         else 
            Span span = stack.peek();
            linkId = span.getLinkId();
            TrackContext.setLinkId(linkId);
        
        return new Span(linkId);
    

    public static Span createEntrySpan() 
        Span span = createSpan();
        Stack<Span> stack = track.get();
        stack.push(span);
        return span;
    


    public static Span getExitSpan() 
        Stack<Span> stack = track.get();
        if (stack == null || stack.isEmpty()) 
            TrackContext.clear();
            return null;
        
        return stack.pop();
    

    public static Span getCurrentSpan() 
        Stack<Span> stack = track.get();
        if (stack == null || stack.isEmpty()) 
            return null;
        
        return stack.peek();
    




TrackContext

package com.javaagent.bytebuddy.demo5.track;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class TrackContext 

    private static final ThreadLocal<String> trackLocal = new ThreadLocal<>();

    public static void clear()
        trackLocal.remove();
    

    public static String getLinkId()
        return trackLocal.get();
    

    public static void setLinkId(String linkId)
        trackLocal.set(linkId);
    



Span

package com.javaagent.bytebuddy.demo5.track;

import java.util.Date;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class Span 

    private String linkId;  //链路ID
    private Date enterTime; //方法进入时间

    public Span()

    public Span(String linkId)
        this.linkId = linkId;
        this.enterTime = new Date();
    

    public String getLinkId() 
        return linkId;
    

    public void setLinkId(String linkId) 
        this.linkId = linkId;
    

    public Date getEnterTime() 
        return enterTime;
    

    public void setEnterTime(Date enterTime) 
        this.enterTime = enterTime;
    


PluginFactory

package com.javaagent.bytebuddy.demo5.plugin;

import com.javaagent.bytebuddy.demo5.plugin.impl.jvm.JvmPlugin;
import com.javaagent.bytebuddy.demo5.plugin.impl.link.LinkPlugin;

import java.util.ArrayList;
import java.util.List;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class PluginFactory 

    public static List<IPlugin> pluginGroup = new ArrayList<>();

    static 
        //链路监控
        pluginGroup.add(new LinkPlugin());
        //Jvm监控
        pluginGroup.add(new JvmPlugin());
    



IPlugin

package com.javaagent.bytebuddy.demo5.plugin;

/**
 * 监控组件
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public interface IPlugin 

    //名称
    String name();

    //监控点
    InterceptPoint[] buildInterceptPoint();

    //拦截器类
    Class adviceClass();



InterceptPoint

package com.javaagent.bytebuddy.demo5.plugin;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

/**
 * 拦截点
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public interface InterceptPoint 

    //类匹配规则
    ElementMatcher<TypeDescription> buildTypesMatcher();

    //方法匹配规则
    ElementMatcher<MethodDescription> buildMethodsMatcher();



LinkPlugin

package com.javaagent.bytebuddy.demo5.plugin.impl.link;

import com.javaagent.bytebuddy.demo5.plugin.IPlugin;
import com.javaagent.bytebuddy.demo5.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class LinkPlugin implements IPlugin 

    @Override
    public String name() 
        return "link";
    

    @Override
    public InterceptPoint[] buildInterceptPoint() 
        return new InterceptPoint[]
                new InterceptPoint() 
                    @Override
                    public ElementMatcher<TypeDescription> buildTypesMatcher() 
                        return ElementMatchers.nameStartsWith("com.javaagent.bytebuddy.demo5_1");
                    

                    @Override
                    public ElementMatcher<MethodDescription> buildMethodsMatcher() 
                        return ElementMatchers.isMethod()
                                .and(ElementMatchers.any())
                                .and(ElementMatchers.not(ElementMatchers.nameStartsWith("main")));
                    
                
        ;
    

    @Override
    public Class adviceClass() 
        return LinkAdvice.class;
    



LinkAdvice

package com.javaagent.bytebuddy.demo5.plugin.impl.link;

import com.javaagent.bytebuddy.demo5.track.Span;
import com.javaagent.bytebuddy.demo5.track.TrackContext;
import com.javaagent.bytebuddy.demo5.track.TrackManager;
import net.bytebuddy.asm.Advice;

import java.util.UUID;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class LinkAdvice 

    @Advice.OnMethodEnter()
    public static void enter(@Advice.Origin("#t") String className, @Advice.Origin("#m") String methodName) 
        Span currentSpan = TrackManager.getCurrentSpan();
        if (null == currentSpan) 
            String linkId = UUID.randomUUID().toString();
            TrackContext.setLinkId(linkId);
        
        TrackManager.createEntrySpan();
    

    @Advice.OnMethodExit()
    public static void exit(@Advice.Origin("#t") String className, @Advice.Origin("#m") String methodName) 
        Span exitSpan = TrackManager.getExitSpan();
        if (null == exitSpan) return;
        System.out.println("链路追踪(MQ):" + exitSpan.getLinkId() + " " + className + "." + methodName + " 耗时:" + (System.currentTimeMillis() - exitSpan.getEnterTime().getTime()) + "ms");
    



JvmAdvice

package com.javaagent.bytebuddy.demo5.plugin.impl.jvm;

import net.bytebuddy.asm.Advice;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class JvmAdvice 

    @Advice.OnMethodExit()
    public static void exit() 
        JvmStack.printMemoryInfo();
        JvmStack.printGCInfo();
    



JvmPlugin

package com.javaagent.bytebuddy.demo5.plugin.impl.jvm;

import com.javaagent.bytebuddy.demo5.plugin.IPlugin;
import com.javaagent.bytebuddy.demo5.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class JvmPlugin implements IPlugin 

    @Override
    public String name() 
        return "jvm";
    

    @Override
    public InterceptPoint[] buildInterceptPoint() 
        return new InterceptPoint[]
                new InterceptPoint() 
                    @Override
                    public ElementMatcher<TypeDescription> buildTypesMatcher() 
                        return ElementMatchers.nameStartsWith("org.itstack.demo.test");
                    

                    @Override
                    public ElementMatcher<MethodDescription> buildMethodsMatcher() 
                        return ElementMatchers.isMethod()
                                .and(ElementMatchers.any())
                                .and(ElementMatchers.not(ElementMatchers.nameStartsWith("main")));
                    
                
        ;
    

    @Override
    public Class adviceClass() 
        return JvmAdvice.class;
    
    


JvmStack

package com.javaagent.bytebuddy.demo5.plugin.impl.jvm;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.Arrays;
import java.util.List;

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class JvmStack 

    private static final long MB = 1048576L;

    public static void printMemoryInfo() 
        MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
        MemoryUsage headMemory = memory.getHeapMemoryUsage();

        String info = String.format("\\ninit: %s\\t max: %s\\t used: %s\\t committed: %s\\t use rate: %s\\n",
                headMemory.getInit() / MB + "MB",
                headMemory.getMax() / MB + "MB", headMemory.getUsed() / MB + "MB",
                headMemory.getCommitted() / MB + "MB",
                headMemory.getUsed() * 100 / headMemory.getCommitted() + "%"

        );

        System.out.print(info);

        MemoryUsage nonheadMemory = memory.getNonHeapMemoryUsage();

        info = String.format("init: %s\\t max: %s\\t used: %s\\t committed: %s\\t use rate: %s\\n",
                nonheadMemory.getIn

字节码基于javaagent的全链路监控五-threadlocal链路追踪(代码片段)

1.概述转载:基于JavaAgent的全链路监控五《ThreadLocal链路追踪》Google开源的Dapper链路追踪组件,并在2010年发表了论文《Dapper,aLarge-ScaleDistributedSystemsTracingInfrastructure》,这篇文章是业内实现链路追踪的标杆和理论基础&#x... 查看详情

字节码基于javaagent的全链路监控四-jvm内存与gc信息(代码片段)

1.概述转载:基于JavaAgent的全链路监控四《JVM内存与GC信息》2.案例简述除了监控java方法的执行耗时,我们还需要获取应用实例的jvm内存与gc信息,以实时把控我们的服务器性能是否在安全范围。监控jvm内存与gc信息是... 查看详情

字节码javaagent的全链路监控篇二,通过字节码增加监控执行耗时(代码片段)

1.概述上一篇文章:【字节码】javaagent入门案例最简单的案例转载:https://github.com/fuzhengwei/itstack-demo-bytecode通过上一章节的介绍,我们已经知道通过配置-javaagent:文件.jar后,在java程序启动时候会执行premain方法。接... 查看详情

基线监控:基于依赖关系的全链路智能监控报警

更多技术交流、求职机会、试用福利,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群字节跳动数据平台开发套件数据开发团队自研了基于依赖关系的全链路智能监控报警——基线监控,目前已在字节跳动内... 查看详情

字节码javaagent入门案例最简单的案例(代码片段)

...种机制(Instrumentation)可以在加载class文件之前修改方法的字节码(此时字节码尚未加入JVM),动态更改类方法实现AOP,提供监控服务如;方法调用时长、可用率、内存等。本章节初步怎么让java代码执行时可以进入我们的agent方法。开... 查看详情

javaagent简介(代码片段)

...叫做Java探针,是在JDK1.5引入的一种可以动态修改Java字节码的技术。Java类编译之后形成字节码被JVM执行,在JVM在执行这些字节码之前获取这些字节码信息,并且通过字节码转换器对这些字节码进行修改,来完成一... 查看详情

字节码增强技术之javaagent入门(代码片段)

...外一种方式:依赖JavaAgent技术,修改目标方法的字节码,做到无侵入的埋点。这种利用JavaAgent的方式的采集器,也叫做探针。在应用程序启动时使用-javaagent参数,或者运行时使用attach(pid)方式,就可以将探... 查看详情

字节码byte-buddy监控方法执行耗时动态获取出入参类型和值(代码片段)

1.概述上一篇文章:【字节码】基于ByteBuddy语法创建的第一个HelloWorld转载:https://github.com/fuzhengwei/itstack-demo-bytecode案例是剥去外衣包装展示出核心功能的最佳学习方式!就像是我们研究字节码编程最终是需要应用到实... 查看详情

字节码增强技术之javaagent入门(代码片段)

文章目录前言JavaAgent简介JavaInstrumentation核心方法JavaAgent核心流程JavaAgent使⽤demo预演总结前言分布式链路追踪中为了获取服务之间调用链信息,采集器通常需要在方法的前后做埋点。在Java生态中,常见的埋点方式有两种&#... 查看详情

火山引擎dataleap推出全链路智能监控报警平台

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 随着大数据开发场景下需要运维管理的任务越来越多,在日常运维中开发者经常会面临以下几个问题:任务多,依赖关系复杂:... 查看详情

字节码插桩之javaagent(代码片段)

字节码插桩之JavaAgent本篇文章将详细讲解有关JavaAgent的知识,揭开它神秘的面纱,帮助开发人员了解它的黑魔法,帮助我们完成更多业务需求WhatisJavaAgentJavaAgent又称为Java探针,它提供了向现有已编译的Java类添加... 查看详情

字节码插桩之javaagent(代码片段)

字节码插桩之JavaAgent本篇文章将详细讲解有关JavaAgent的知识,揭开它神秘的面纱,帮助开发人员了解它的黑魔法,帮助我们完成更多业务需求WhatisJavaAgentJavaAgent又称为Java探针,它提供了向现有已编译的Java类添加... 查看详情

字节码插桩之javaagent(代码片段)

字节码插桩之JavaAgent本篇文章将详细讲解有关JavaAgent的知识,揭开它神秘的面纱,帮助开发人员了解它的黑魔法,帮助我们完成更多业务需求WhatisJavaAgentJavaAgent又称为Java探针,它提供了向现有已编译的Java类添加... 查看详情

java综合专栏「渐入佳境」全链路追踪原理之javaagent探针的底层运作原理和分析(中篇)(代码片段)

...JDK1.5之后引入的新特性,此特性为用户提供了在JVM将字节码文件读入内存之后,JVM使用对应的字节流在Java堆中生成一个Class对象之前,用户可以对其字节码进行修改的能力,从而JVM也将会使用用户修改过之后的字... 查看详情

字节码javaagentbytebuddy操作监控方法字节码(代码片段)

1.概述上一篇文章:【字节码】javaagent入门案例最简单的案例转载:https://github.com/fuzhengwei/itstack-demo-bytecode在第二章中我们已经可以监控方法执行耗时,虽然它能完成我们一些基本需要,但是为了增强代码的扩展... 查看详情

基于javaagent实现apm(代码片段)

一、APM概述APM系统(ApplicationPerformanceManagement,即应用性能管理),用于对应用系统做实时监控,目的是实现对应用性能管理和故障定位。1.1、为什么需要APMAPM主要用于对微服务做“监控及故障发现”,如... 查看详情

基于javaagent实现apm(代码片段)

一、APM概述APM系统(ApplicationPerformanceManagement,即应用性能管理),用于对应用系统做实时监控,目的是实现对应用性能管理和故障定位。1.1、为什么需要APMAPM主要用于对微服务做“监控及故障发现”,如... 查看详情

javaagent简介(代码片段)

...叫做Java探针,是在JDK1.5引入的一种可以动态修改Java字节码的技术。Java类编译之后形成字节码被JVM执行࿰ 查看详情