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

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
简介: 在我们的监控程序中,需要对各种模块进行监控;servlet、rpc、http、jdbc、redis、logic等,那么我们在设计监控程序时就需要对监控的程序进行模块化开发,可以在需要的时候进行组装配置即可,以方便我们监控程序的扩展和可控制性。这一章节我们把监控模块剥离,采用工厂模式进行调用{目前是静态工厂在我们实际使用中可以把工厂做成动态配置化}。

12.jpg

案例简述

在我们的监控程序中,需要对各种模块进行监控;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


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
4月前
|
监控 Kubernetes Go
全链路追踪 & 性能监控,GO 应用可观测全面升级
当前,大多数面向 Golang 应用的监控能力主要是通过 SDK 方式接入,需要开放人员手动进行埋点,会存在一定问题。对此,可观测 Go Agent 应运而生。本文介绍的阿里云可观测 Go Agent 方案,能通过无侵入的方式实现应用监控能力。
108697 23
|
3月前
|
Prometheus 监控 Cloud Native
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
|
存储 消息中间件 监控
代码级别监控:常见的全链路监控工具介绍
代码级别监控:常见的全链路监控工具介绍
|
Prometheus 监控 Cloud Native
业务端skywalking接入方案
业务端skywalking接入方案
753 1
|
SQL 存储 监控
21 PostgreSQL 监控2 趋势监控数据收集和分析 nagios实时监控部署和自定义监控|学习笔记(一)
快速学习21 PostgreSQL 监控2 趋势监控数据收集和分析nagios实时监控部署和自定义监控
269 0
21 PostgreSQL 监控2 趋势监控数据收集和分析 nagios实时监控部署和自定义监控|学习笔记(一)
|
监控 网络协议 关系型数据库
21 PostgreSQL 监控2 趋势监控数据收集和分析 nagios 实时监控部署和自定义监控|学习笔记(二)
快速学习21 PostgreSQL 监控2 趋势监控数据收集和分析 nagios 实时监控部署和自定义监控
138 0
21 PostgreSQL 监控2 趋势监控数据收集和分析 nagios 实时监控部署和自定义监控|学习笔记(二)
|
存储 监控 前端开发
【SkyWalking】从零接入全链路追踪解决方案
Skywalking是一个国产的开源框架,2015年有吴晟个人开源,2017年加入Apache孵化器,国人开源的产品,本次分享下从零接入SkyWalking。
688 0
【SkyWalking】从零接入全链路追踪解决方案
|
存储 监控 数据可视化
链路监控(skywalking)集成
链路监控(skywalking)集成
282 0
链路监控(skywalking)集成
|
SQL 存储 监控
如何使用skywalking 进行全链路监控
skywalking-nginx-lua[2] 这是 skywalking 的另一个项目,可以通过它来对nginx进行监控。skywalking-nginx-lua 是使用lua来织入 agent 的。所以要求你的 nginx 要么有 lua 模块,要么用 openResty 这样的自带 Lua 功能模块的软件。
如何使用skywalking 进行全链路监控
|
存储 监控 Java
实现一个全链路监控平台很难吗?Pinpoint、SkyWalking、Zipkin,哪个实现比较好?
随着微服务架构的流行,服务按照不同的维度进行拆分 ,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上 ,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心 。因此,就需要一些可以帮助理解系统行为
实现一个全链路监控平台很难吗?Pinpoint、SkyWalking、Zipkin,哪个实现比较好?