美文网首页基于JavaA...Java 杂谈
基于JavaAgent的全链路监控六《开发应用级监控》

基于JavaAgent的全链路监控六《开发应用级监控》

作者: bugstack虫洞栈 | 来源:发表于2019-08-07 20:54 被阅读13次

    章节列表 | 关注微信公众号,bugstack虫洞栈,回复<基于JavaAgent的全链路监控>获取源码

    • 基于JavaAgent的全链路监控一《嗨!JavaAgent》
    • 基于JavaAgent的全链路监控二《通过字节码增加监控执行耗时》
    • 基于JavaAgent的全链路监控三《ByteBuddy操作监控方法字节码》
    • 基于JavaAgent的全链路监控四《JVM内存与GC信息》
    • 基于JavaAgent的全链路监控五《ThreadLocal链路追踪》
    • 基于JavaAgent的全链路监控六《开发应用级监控》

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

    环境准备
    1、IntelliJ IDEA Community Edition
    2、jdk1.8.0_45 64位

    配置信息(路径相关修改为自己的)
    1、配置位置:Run/Debug Configurations -> VM options
    2、配置内容:-javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-06\target\itstack-demo-agent-06-1.0.0-SNAPSHOT.jar=testargs

    代码示例

    itstack-demo-agent-06
    ├── pom.xml
    └── src
        ├── main
        │   ├── java
        │   │   └── org.itstack.demo.agent
        │   │       ├── plugin
        │   │       │   ├── impl
        │   │       │   │   ├── jvm
        │   │       │   │   │   ├── JvmAdvice.java
        │   │       │   │   │   ├── JvmPlugin.java
        │   │       │   │   │   └── JvmStack.java   
        │   │       │   │   └── link    
        │   │       │   │       ├── LinkAdvice.java
        │   │       │   │       └── LinkPlugin.java 
        │   │       │   ├── InterceptPoint.java
        │   │       │   ├── IPlugin.java
        │   │       │   └── PluginFactory.java
        │   │       │   
        │   │       ├── track
        │   │       │   ├── Span.java   
        │   │       │   ├── TrackContext.java   
        │   │       │   └── TrackManager.java   
        │   │       └── MyAgent.java
        │   └── resources
        │       └── META-INF
        │           └── MANIFEST.MF     
        └── test
             └── java
                 └── org.itstack.demo.test
                     └── ApiTest.java
    

    JvmAdvice.java

    /**
     * 博客: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.java

    /**
     * 博客: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;
        }
        
    }
    

    LinkAdvice.java

    /**
     * 博客: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");
        }
    
    }
    

    LinkPlugin.java

    /**
     * 博客: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("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 LinkAdvice.class;
        }
    
    }
    

    InterceptPoint.java

    /**
     * 拦截点
     * 博客:http://itstack.org
     * 论坛:http://bugstack.cn
     * 公众号:bugstack虫洞栈  {获取学习源码}
     * create by fuzhengwei on 2019
     */
    public interface InterceptPoint {
    
        //类匹配规则
        ElementMatcher<TypeDescription> buildTypesMatcher();
    
        //方法匹配规则
        ElementMatcher<MethodDescription> buildMethodsMatcher();
    
    }
    

    IPlugin.java

    /**
     * 监控组件
     * 博客:http://itstack.org
     * 论坛:http://bugstack.cn
     * 公众号:bugstack虫洞栈  {获取学习源码}
     * create by fuzhengwei on 2019
     */
    public interface IPlugin {
    
        //名称
        String name();
    
        //监控点
        InterceptPoint[] buildInterceptPoint();
    
        //拦截器类
        Class adviceClass();
    
    }
    

    PluginFactory.java

    /**
     * 博客: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());
        }
    
    }
    

    TrackManager.java

    /**
     * 追踪管控
     * 博客: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();
        }
    
    
    }
    

    MyAgent.java

    /**
     * 博客:http://itstack.org
     * 论坛:http://bugstack.cn
     * 公众号:bugstack虫洞栈  {获取学习源码}
     * create by fuzhengwei on 2019
     */
    public class MyAgent {
    
        //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).asDecorator();
                }
            }
    
            //监听
            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);
    
        }
    
    }
    

    MANIFEST.MF

    Manifest-Version: 1.0
    Premain-Class: org.itstack.demo.agent.MyAgent
    Can-Redefine-Classes: true
    
    

    ApiTest.java

    **
     * 链路追踪
     * VM options:
     * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-06\target\itstack-demo-agent-06-1.0.0-SNAPSHOT.jar=testargs
     *
     * 按需打开需要测试的模块
     * 链路监控
     * pluginGroup.add(new LinkPlugin());
     * Jvm监控
     * pluginGroup.add(new JvmPlugin());
     *
     * 博客:http://itstack.org
     * 论坛:http://bugstack.cn
     * 公众号:bugstack虫洞栈  {获取学习源码}
     * create by fuzhengwei on 2019
     *
     */
    public class ApiTest {
    
        public static void main(String[] args) {
    
            //线程一
            new Thread(() -> new ApiTest().http_lt1("哪咤")).start();
    
            //线程二
            new Thread(() -> {
                new ApiTest().http_lt2("悟空");
            }).start();
    
        }
    
        public void http_lt1(String name) {
            try {
                Thread.sleep((long) (Math.random() * 500));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("测试结果:hi1 " + name);
            http_lt2(name);
        }
    
        public void http_lt2(String name) {
            try {
                Thread.sleep((long) (Math.random() * 500));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("测试结果:hi2 " + name);
            http_lt3(name);
        }
    
        public void http_lt3(String name) {
            try {
                Thread.sleep((long) (Math.random() * 500));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("测试结果:hi3 " + name);
        }
    
    }
    

    测试结果

    基于javaagent链路追踪{源码微信公众号:bugstack虫洞栈}
    ==========================================================
    
    onTransformation:class org.itstack.demo.test.ApiTest
    测试结果:hi2 悟空
    测试结果:hi1 哪咤
    测试结果:hi3 悟空
    链路追踪(MQ):608a1cbf-ef1f-4195-bdc7-c3729a114f8d org.itstack.demo.test.ApiTest.http_lt3 耗时:111ms
    测试结果:hi2 哪咤
    
    init: 192MB  max: 2708MB     used: 43MB  committed: 184MB    use rate: 23%
    init: 2MB    max: 0MB    used: 13MB  committed: 14MB     use rate: 95%
    
    name: PS Scavenge    count:0     took:0  pool name:[PS Eden Space, PS Survivor Space]
    name: PS MarkSweep   count:0     took:0  pool name:[PS Eden Space, PS Survivor Space, PS Old Gen]
    -------------------------------------------------------------------------------------------------
    链路追踪(MQ):608a1cbf-ef1f-4195-bdc7-c3729a114f8d org.itstack.demo.test.ApiTest.http_lt2 耗时:338ms
    
    init: 192MB  max: 2708MB     used: 43MB  committed: 184MB    use rate: 23%
    init: 2MB    max: 0MB    used: 13MB  committed: 14MB     use rate: 95%
    
    name: PS Scavenge    count:0     took:0  pool name:[PS Eden Space, PS Survivor Space]
    name: PS MarkSweep   count:0     took:0  pool name:[PS Eden Space, PS Survivor Space, PS Old Gen]
    -------------------------------------------------------------------------------------------------
    测试结果:hi3 哪咤
    链路追踪(MQ):2f28ed75-650a-4f0f-bd69-fe0709a8985e org.itstack.demo.test.ApiTest.http_lt3 耗时:221ms
    
    init: 192MB  max: 2708MB     used: 43MB  committed: 184MB    use rate: 23%
    init: 2MB    max: 0MB    used: 13MB  committed: 14MB     use rate: 95%
    
    name: PS Scavenge    count:0     took:0  pool name:[PS Eden Space, PS Survivor Space]
    name: PS MarkSweep   count:0     took:0  pool name:[PS Eden Space, PS Survivor Space, PS Old Gen]
    -------------------------------------------------------------------------------------------------
    链路追踪(MQ):2f28ed75-650a-4f0f-bd69-fe0709a8985e org.itstack.demo.test.ApiTest.http_lt2 耗时:316ms
    
    init: 192MB  max: 2708MB     used: 43MB  committed: 184MB    use rate: 23%
    init: 2MB    max: 0MB    used: 13MB  committed: 14MB     use rate: 95%
    
    name: PS Scavenge    count:0     took:0  pool name:[PS Eden Space, PS Survivor Space]
    name: PS MarkSweep   count:0     took:0  pool name:[PS Eden Space, PS Survivor Space, PS Old Gen]
    -------------------------------------------------------------------------------------------------
    链路追踪(MQ):2f28ed75-650a-4f0f-bd69-fe0709a8985e org.itstack.demo.test.ApiTest.http_lt1 耗时:547ms
    
    init: 192MB  max: 2708MB     used: 43MB  committed: 184MB    use rate: 23%
    init: 2MB    max: 0MB    used: 13MB  committed: 14MB     use rate: 95%
    
    name: PS Scavenge    count:0     took:0  pool name:[PS Eden Space, PS Survivor Space]
    name: PS MarkSweep   count:0     took:0  pool name:[PS Eden Space, PS Survivor Space, PS Old Gen]
    -------------------------------------------------------------------------------------------------
    
    Process finished with exit code 0
    
    

    关注{bugstack虫洞栈}公众号获取源码,回复<基于JavaAgent的全链路监控>

    微信公众号,bugstack虫洞栈

    相关文章

      网友评论

        本文标题:基于JavaAgent的全链路监控六《开发应用级监控》

        本文链接:https://www.haomeiwen.com/subject/ccxgrctx.html