使用 byte buddy 或一些库进行分析

Profiling using byte buddy or some library

我正在尝试构建一个查询日志记录分析器,它可以计算每个查询的执行时间,并在查询花费更多时间时进行记录。 与 Wrapper 相比,使用 AspectJ 需要更多时间。因此,如果有性能改进的余地,我想使用 byte buddy 或其他一些库。

这是我目前使用 AspectJ 的实现。

@Aspect
public class QueryLoggerProfiler {
    private static final Logger LOGGER = Logger.getLogger(QueryLoggerProfiler.class.getName());

    public static final String QUERY_LOGGING_POINTCUT = "execution(* com.abc.PreparedStatement.execute*(..))";

    @
    Pointcut(QUERY_LOGGING_POINTCUT)
    private void queryPointcut() {}

    @
    Around("queryPointcut()")
    public Object profile(ProceedingJoinPoint joinPoint) throws Throwable {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        long start = System.currentTimeMillis();
        Object output = joinPoint.proceed();
        long elapsedTime = System.currentTimeMillis() - start;
        if (elapsedTime >= 5) {
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... Going to call the method ... " + method.getName());
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... With parameter ... " + method.getParameters());
            LOGGER.info(">>>>>>>>>>>>>>>>>>>... Method execution time: " + elapsedTime + " milliseconds.");
        }
        return output;
    }
}

有没有什么方法既可以登录又没有性能瓶颈?

最简单的方法是将 Advice 组件与 AgentBuilder 一起使用。这将允许您定义类似于以下内容的代理:

public static void premain(String arg, Instrumentation inst) {
  new AgentBuilder.Default()
    .type(named("com.abc.PreparedStatement"))
    .transform(new Transformer() {
      public DynamicType.Builder transform(DynamicType.Builder builder) {
       return builder.visit(Advice.to(MyAdvice.class).on(nameStartsWith("execute")));
     } 
    }).installOn(inst);
}

这将为指定的类型和名称应用 MyAdvice class 中定义的方法。查看 Advice 的 javadoc 以了解如何获取参数或如何指定要调用的方法。

有关如何使用 Byte Buddy 和 Javaagents 检测代码的一般信息,请参阅 this article

实际上我的代码如下。

public static void premain(String agentArgument, Instrumentation instrumentation) {
    System.out.println(">>>>>>>>>>>>>>>>>> Entered premain");
    try {
        new AgentBuilder.Default()
                .type(ElementMatchers.nameStartsWith("com.mycomp.hikari.LoggingPreparedStatement"))
                .transform((builder, typeDescription, classLoader) -> builder
                        .method(ElementMatchers.any())
                        .intercept(MethodDelegation.to(new Interceptor())))
                .installOn(instrumentation);
    } catch (RuntimeException e) {
        System.out.println(">>>>>>>>>>>>>>>>>> Exception instrumenting code : " + e);
        e.printStackTrace();
    }
}

然后 class 拦截器作为....

public class Interceptor {
@RuntimeType
public Object intercept(@SuperCall Callable<?> callable, @AllArguments Object[] allArguments, @Origin Method method, @Origin Class clazz) throws Exception {
    long startTime = System.currentTimeMillis();
    Object response;
    try {
        response = callable.call();
    } catch (Exception e) {
        System.out.println(">>>>>>>>>>>>>>>>>>>> .... Exception occurred in method call: " + methodName(clazz, method, allArguments) + " Exception = " + e);
        throw e;
    } finally {
        long elapsedTime = System.currentTimeMillis() - startTime;
        if (elapsedTime > 3)
        System.out.println(">>>>>>>>>>>>>>>>>>>> .... Method " + methodName(clazz, method, allArguments) + " completed in " + elapsedTime + " milliseconds");
    }
    return response;
}

private String methodName(Class clazz, Method method, Object[] allArguments) {
    StringBuilder builder = new StringBuilder();
    builder.append(clazz.getName());
    builder.append(".");
    builder.append(method.getName());
    builder.append("(");
    for (int i = 0; i < method.getParameters().length; i++) {

        builder.append(method.getParameters()[i].getName());
        if (allArguments != null) {
            Object arg = allArguments[i];
            builder.append("=");
            builder.append(arg != null ? arg.toString() : "null");
        }

        if (i < method.getParameters().length - 1) {
            builder.append(", ");
        }
    }
    builder.append(")");
    return builder.toString();
  }
}