• Btrace 进阶学习


    Btrace 使用方法

    设置环境变量 (BTRACE\_HOME) ,并 将(bin) 添加到PATH,随后在命令行输出以下命令即可运行。

    btrace pid fileName.java 
    

    或者将 (fileName.java) 放在 (/brace/bin) 目录下运行

    进阶细节

    1.若监测的类为接口类,则需要在类名前加 (+) ,例如:

    +cn.freemethod.business.MyInterface
    


    2.若监测的为注解,则需在注解名前加 (@) ,例如:

    @javax.annotation.Resource
    


    3.若要使用正则表达式,需要将类名或者方法名写在两个斜杠中间,如:

    "/com\.ewan\..+/"
    

    注意斜杠要被转义,所以特殊符号前要两个斜杠



    4.若要指定监测方法的类型,可以在 (@OnMethod) 注解中使用 (type~=~...) 进行指定,也可以指定监测的位置,使用 (location= @Location(value = ...)) 指定,例如:

        @OnMethod(
                clazz = "/com\.mfp\.business\.cfg\.service\..+/",
                method = "/s.*/",
                type = "void (com.business.net.protocol.vo.RequestObject, com.business.net.protocol.vo.ResponseObject)",
                location = @Location(value = Kind.RETURN)
        )
    


    5.(@Self 注释的this, 完整的参数列表,@Return 注释的返回值) 若要传入这三者,则一定要按照这样的顺序排列,若不需要可以省略,但参数列表一定要完整,否则无法定位到你要监测的函数



    6.假如你要监测的类集合的传入参数或返回值不统一,则可以使用 (AnyType[]~args) 方法传入,返回值使用 (AnyType) ,例如:

        @OnMethod(clazz = "/cn\.freemethod\.business\..+/", method = "/.+/", location = @Location(value = Kind.RETURN))
        public static void dataCaptrue(@ProbeClassName String className, @ProbeMethodName String methodName, AnyType[] args){
            println(className);
            println(methodName);
            if(args.length > 0)
                printFields(args[0]);
            //printArray(args);
        }
    

    若要打印参数列表,则使用 (printArray(args)) , 若 (args) 含有非JAVA基本类型,则会输出类名,不会输出实例。



    7.若你要将监测到的结果输入到文件,只需加上 (-o~mydata.log) 参数即可,例如:

    btrace -o mydata.log 17272 MyBtrace.java
    

    建议不要使用此方法,这种方法产生的 mydata.log 会产生在你监测的 (pid) 的应用程序的启动目录下,而不是在你的脚本的目录下
    实测!若你使用过 (-o) 方法运行过 (btrace~pid) 那么无论你是否加 (-o) 参数,(btrace) 都会默认输出到 (mydata.log) 中,这就导致无论怎么样你的 (console) 都不会有输出,为了解决这种情况,必须得重启整个项目。
    因此最好的输出到文件的方法应该是使用liunx的重定向:

    btrace 17272 MyBtrace.java > mydata.log
    


    8.若你传入的参数不是JAVA基本类型,而是自定义的类,则需要用 (AnyType[]~args) 先传入,然后再通过 (printFields(args[0])) 方法来反射得到这个类,JAVA 中 (Object) 的继承类输出是 (JSON) 格式。



    打印复杂类

    有些同学可能会发现有时候如果你要监测的类里面有嵌套的类,(printFields(args[0])) 打印出来会是类对象地址(引用),而btrace中不允许调用其他类方法,只能使用包(com.sun.btrace.BTraceUtils) 中自带的方法,经过查找资料,发现 (com.sun.btrace.BTraceUtils) 中自带类解析相关的方法,例如: (classOf) , (field) 等方法。


    还有一种打印复杂类的方法就是重写监测类的 (toString()) 方法。但需要监测的类很多时,这种方法不太实用。而且这种方法存在一种情况无法处理,经过查看 (BtraceUtils) 源代码发现:

    public static String str(Object obj) {
          if (obj == null) {
            return "null";
          }
          else if (obj instanceof String) {
            return (String) obj;
          }
          else if (obj.getClass().getClassLoader() == null) {
            try {
              return obj.toString();
            } catch (NullPointerException e) {
              // NPE can be thrown from inside the toString() method we have no control over
              return "null";
            }
          } else {
            return identityStr(obj);
          }
    }
    
    private static void addFieldValues(
          StringBuilder buf, Object obj, Class<?> clazz, boolean classNamePrefix) {
        Field[] fields = getAllFields(clazz);
        for (Field f : fields) {
          int modifiers = f.getModifiers();
          if (!Modifier.isStatic(modifiers)) {
            if (classNamePrefix) {
              buf.append(f.getDeclaringClass().getName());
              buf.append('.');
            }
            buf.append(f.getName());
            buf.append('=');
            try {
              buf.append(Strings.str(f.get(obj)));
            } catch (Exception exp) {
              throw translate(exp);
            }
            buf.append(", ");
          }
        }
        Class<?> sc = clazz.getSuperclass();
        if (sc != null) {
          addFieldValues(buf, obj, sc, classNamePrefix);
        }
      }
    
    public static void printFields(Object obj) {
        Reflective.printFields(obj, false);
    }
    public static void printFields(Object obj, boolean classNamePrefix) {
        Reflective.printFields(obj, classNamePrefix);
    }
    
    

    也就是说,只有当你的类对象满足 $obj.getClass().getClassLoader() == null$ 才会调用 $ toString $ 方法,因此必须得保证这个类是自己写的类而不是引入的外部类(即Extension Loader中加载的class)。

    下面是我trace服务器项目中 (RequestObject)(ResponseObject) 类的方法,其中两者中都含有 (JSONObject) 类,因此要解析 (JSONObject) 中的内容必须得一层一层的进行 (field) 反射

    import com.sun.btrace.AnyType;
    import com.sun.btrace.annotations.*;
    
    import java.lang.reflect.Field;
    import java.lang.Class;
    
    import static com.sun.btrace.BTraceUtils.*;
    
    @BTrace
    public class OnMethodTrace {
    
        @OnMethod(
                clazz = "/cn\.freemethod\.business\..+/",
                method = "/.*/",
                type = "void (cn.freemethod.business.RequestObject, cn.freemethod.business.ResponseObject)",
                location = @Location(value = Kind.RETURN)
        )
        public static void dataTrace(@ProbeClassName String className, @ProbeMethodName String methodName, AnyType[] args) {
            println(className);
            println(methodName);
            /*
             * RequestObject
             */
            Class cl = classOf(args[0]);
            Field fd = field(cl, "cpv", false);
            if(fd != null) {
                println(str(get(fd, args[0])));
            }
            fd = field(cl, "jsonObject", false);
            if(fd != null) {
                printFields(get(fd, args[0]));
            }
    
            /*
             * ResponseObject
             */
            cl = classOf(args[1]);
            fd = field(cl, "jsonObject", false);
            if(fd != null) {
                printFields(get(fd, args[1]));
            }
        }
    }
    
    
  • 相关阅读:
    tar解压出错
    HUNNU11352:Digit Solitaire
    cocos2d-x 二进制文件的读写
    电子支付概述(1)
    新一批思科电子书下载
    HUNNU11354:Is the Name of This Problem
    POJ 3181 Dollar Dayz 简单DP
    Spring中IOC和AOP的详细解释
    atheros wifi 动因分析
    Android ActionBar相关
  • 原文地址:https://www.cnblogs.com/Yuzao/p/14592342.html
Copyright © 2020-2023  润新知