2016-07-27 3 views
1

動作しません使用して...のJavaエージェントバイトバディは私の実装で間違っているものを見つけることであなたの助けが必要

私はバイト仲間を使用して簡単なJVMランタイムプロファイラを実装しようとしています。 一般に、私が必要とするのは、すべてのメソッド呼び出しが、別のオブジェクトで管理するスタックに記録されるということです。

には、いくつかの記事を読んだ後、私はそれが代わりに「MethodDelegation」の「アドバイス」のアプローチを使用することをお勧めしますことを理解し、ここに私が出てきたものです:

Agent.java:

package com.panaya.java.agent; 

import net.bytebuddy.agent.builder.AgentBuilder; 
import net.bytebuddy.asm.Advice; 
import net.bytebuddy.description.type.TypeDescription; 
import net.bytebuddy.matcher.ElementMatchers; 
import net.bytebuddy.utility.JavaModule; 

import java.lang.instrument.Instrumentation; 
import java.security.ProtectionDomain; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import java.util.regex.PatternSyntaxException; 

public class Agent { 
    private static List<Pattern> pkgIncl = new ArrayList<Pattern>(); 
    private static List<Pattern> pkgExcl = new ArrayList<Pattern>(); 

    private static void initMatcherPatterns(String argument) { 
     if (argument == null) { 
      System.out.println("Missing configuration argument"); 
      return; 
     } 

     System.out.println("Argument is: " + argument); 

     String[] tokens = argument.split(";"); 

     if (tokens.length < 1) { 
      System.out.println("Missing delimeter ;"); 
      return; 
     } 

     for (String token : tokens) { 
      String[] args = token.split("="); 
      if (args.length < 2) { 
       System.out.println("Missing argument delimeter =:" + token); 
       return; 
      } 

      String argtype = args[0]; 

      if (!argtype.equals("incl") && !argtype.equals("excl")) { 
       System.out.println("Wrong argument: " + argtype); 
       return; 
      } 

      String[] patterns = args[1].split(","); 

      for (String pattern : patterns) { 
       Pattern p = null; 
       System.out.println("Compiling " + argtype + " pattern:" + pattern + "$"); 
       try { 
        p = Pattern.compile(pattern + "$"); 
       } catch (PatternSyntaxException pse) { 
        System.out.println("pattern: " + pattern + " not valid, ignoring"); 
       } 
       if (argtype.equals("incl")) 
        pkgIncl.add(p); 
       else 
        pkgExcl.add(p); 
      } 
     } 

    } 

    private static boolean isShouldInstrumentClass(String className) { 
     System.out.println("Testing " + className + " for match."); 
     boolean match = false; 
     String name = className.replace("/", "."); 

     for (Pattern p : pkgIncl) { 
      Matcher m = p.matcher(name); 
      if (m.matches()) { 

       match = true; 
       break; 
      } 
     } 

     for (Pattern p : pkgExcl) { 
      Matcher m = p.matcher(name); 
      if (m.matches()) { 

       match = false; 
       break; 
      } 
     } 

     if (match) { 
      System.out.println("Class " + name + "should be instrumented."); 
     } else { 
      System.out.println("Skipping class: " + name); 
     } 
     return match; 
    } 

    public static void premain(String agentArgument, Instrumentation instrumentation) { 
     System.out.println("Premain started"); 
     try { 
      initMatcherPatterns(agentArgument); 

      new AgentBuilder.Default() 
        .with(AgentBuilder.TypeStrategy.Default.REBASE) 
        .type(new AgentBuilder.RawMatcher() { 
         public boolean matches(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, Class<?> aClass, ProtectionDomain protectionDomain) { 
          return isShouldInstrumentClass(typeDescription.getActualName()); 
         } 
        }) 
        .transform((builder, typeDescription, classLoader) -> builder 
          .visit(Advice.to(ProfilingAdvice.class) 
            .on(ElementMatchers.any()))).installOn(instrumentation); 

     } catch (RuntimeException e) { 
      System.out.println("Exception instrumenting code : " + e); 
      e.printStackTrace(); 
     } 

    } 
} 

そしてProfilingAdvice.java:何らかの理由で

package com.panaya.java.agent; 

import com.panaya.java.profiler.MethodStackCollector; 
import net.bytebuddy.asm.Advice; 

public class ProfilingAdvice { 
    @Advice.OnMethodEnter 
    public static void enter(@Advice.Origin("#t.#m") String signature) { 
     System.out.println("OnEnter :" + signature); 
     try { 
      MethodStackCollector.getInstance().push(signature); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Advice.OnMethodExit 
    public static void exit(@Advice.Return long value) { 
     System.out.println("OnExit - value = " + value); 
     try { 
      MethodStackCollector.getInstance().pop(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 
} 

は、「入り」とProfilingAdviceクラスの「出口」の方法は、すべてで呼び出されていません。

私は間違っていますか?

ありがとう、 Elad。

+0

エージェントはどのように見えますか?インストゥルメンテーションに問題がないかどうかを確認するために 'AgentBuilder.Listener'を登録しましたか? –

+0

@RafaelWinterhalter、私はあなたの質問を理解しているかどうかわかりません...どういう意味ですか?あなたのエージェントはどのように見えますか?あなたの質問を教えていただけますか?私のエージェントクラスは上に掲載されています...それは正常に読み込まれましたが、アドバイスメカニズムは機能しません。 – esaar

+0

'premain' /' agentmain'メソッドがどのように見えるのだろうか。 'AgentBuilder'を使ってどこかでアドバイスを組み立てる必要があります。 –

答えて

0

私はあなたの例を試してみましたが、唯一に終了印刷コマンドへのアドバイスやごマッチャーを減少させた後、いくつかのクラスfoo.Bar一致:計装は問題なく動作します

package foo; 
public class Bar { 
    public long qux() { return 0L; } 
} 

を。私はあなたのAdvice一致者がany()を指定していて、ProfilingAdviceにはlongの戻り値が必要ですが、ちょっと怪しいです。あなたのアドバイスに注釈を付けずに、コンソールにのみ印刷しようとしましたか?

あなたはsetttingことにより、このような問題をデバッグすることができます。計測中に潜在的なエラーがコンソールに出力され

new AgentBuilder.Default() 
    .with(AgentBuilder.Listener.StreamWriting.toSystemOut()); 

+0

リスナーをアタッチするとき、私はアドバイスメソッドが実際に呼び出されたことに気づきましたが、実際にリターンタイプに問題がありました。 exitメソッドからreturnパラメータを削除した後、ほとんどの計測は正常に動作しますが、特定のケースではjava.langという例外が発生します。IllegalStateException:オペランドスタックの予期しない剰余:-1 \t at net.bytebuddy.utility.StackAwareMethodVisitor.drainStack(StackAwareMethodVisitor.java:120)....別の問題を投稿します。 – esaar

+0

してください。あなたが再建を行うことができれば、これは素晴らしいことです。 1.4.16にも更新してください。最近私は関連する問題を修正しました。 –

+0

1.4.16へのアップデートが以前の問題を解決したにもかかわらず、 "ElementMatchers"の組み合わせを変更すると、再びこの例外が発生するようです。 – esaar

関連する問題