Skywalking 学习之ByteBuddy 方法执行时间监控

Skywalking git:

GitHub - apache/skywalking: APM, Application Performance Monitoring System

 集成入门:

10分钟3个步骤集成使用SkyWalking - 知乎

企业级监控项目Skywalking详细介绍,来看看呀-CSDN博客 

 下面自己学习了一下ByteBuddy的用法,实战了一下:

入门教程:

ByteBuddy入门教程 - 知乎

 这篇也不错:

一、基于Byte Buddy语法创建的第一个HelloWorld | 小傅哥 bugstack 虫洞栈

 下面直接上代码

Monitor项目是服务记录时间的一个非侵入性的jar

pom


    
    
      net.bytebuddy
      byte-buddy
      1.9.2
    
    
      net.bytebuddy
      byte-buddy-agent
      1.9.2
    
  
  
    
      
        maven-assembly-plugin
        
          false
          
            
            jar-with-dependencies
          
          
            
            
              org.monitor.MonitorAgent
              org.monitor.MonitorAgent
              true
              true
            
          
        
        
          
            make-assembly
            package
            
              single
            
          
        
      
      
        org.apache.maven.plugins
        maven-compiler-plugin
        
          6
          6
        
      
    
  

两个主要的类一个是代理类一个是方法的拦截器

agentParam这个参数可以传你想要监控的包名+方法名,本例使用:号分割

package org.monitor;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class MonitorAgent {

    public static void premain(String agentParam, Instrumentation inst) {

        //命令行为-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:* 或-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:call
        System.out.println("premain监控开始--------->包路径:" + agentParam);

        final String[]  args= agentParam.split(":");
        //:号之后是方法名,如果不为*标识全部
        AgentBuilder.Transformer transformer;
        // method指定哪些方法需要被拦截,ElementMathers.any指定了所有的方法,声明intercept拦截器
        if(args[1].equals("*")){
            transformer = new AgentBuilder.Transformer() {
                @Override
                public DynamicType.Builder transform(DynamicType.Builder builder,
                                                        TypeDescription typeDescription,
                                                        ClassLoader classLoader,
                                                        JavaModule javaModule) {
                    return builder.method(ElementMatchers.any())
                            .intercept(MethodDelegation.to(MonitorIntercept.class));
                }
            };

        }else{
             transformer = new AgentBuilder.Transformer() {
                @Override
                public DynamicType.Builder transform(DynamicType.Builder builder,
                                                        TypeDescription typeDescription,
                                                        ClassLoader classLoader,
                                                        JavaModule javaModule) {
                    return builder.method(ElementMatchers.nameStartsWith(args[1]))
                            .intercept(MethodDelegation.to(MonitorIntercept.class));
                }
            };

        }


        /**
         * 1.type指定了agent拦截的包名,以[com.monitor]作为前缀
         * 2.指定了转换器transformer
         * 3.将配置安装到Instrumentation
         */
        new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith(args[0]))
                .transform(transformer)
                .installOn(inst);
    }
}
package org.monitor;

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MonitorIntercept {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable callable) throws Exception {
        long start = System.currentTimeMillis();
        try {
            return callable.call();
        } finally {
            System.out.println(method + ":" + (System.currentTimeMillis() - start) + "ms");
        }
    }
}

install 项目得到monitor-1.0-SNAPSHOT.jar

另一个用于被监控的项目monitorDemo,直接写一个main方法的项目就可以

new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith(agentParam))
                .transform(transformer)
                .installOn(inst);
package org.monitor;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        call();
    }

    public static void call(){

        System.out.println("call-------------------");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

在运行monitorDemo的main的时候需要前面设置参数:

E:/monitor/target/monitor-1.0-SNAPSHOT.jar 就是Monitor项目install后的jar路径,=号后面是你想要监控的monitorDemo项目的包名路径:号后是方法名,如果是全部方法则是*

-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:* 或-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:call

-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:*

运行后会打印出:

Connected to the target VM, address: '127.0.0.1:62854', transport: 'socket'
premain监控开始--------->包路径:org.monitor:*
Hello World!
call-------------------
public static void org.monitor.App.call():1001ms
public static void org.monitor.App.main(java.lang.String[]):2001ms
Disconnected from the target VM, address: '127.0.0.1:62854', transport: 'socket'

Process finished with exit code 0

-javaagent:E:/monitor/target/monitor-1.0-SNAPSHOT.jar=org.monitor:call

运行后:

premain监控开始--------->包路径:org.monitor:call
Hello World!
call-------------------
public static void org.monitor.App.call():1001ms

Process finished with exit code 0

只监控了call方法

完成

你可能感兴趣的:(skywalking,学习)