2013-11-29 3 views
5

Я пытался отлаживать приложение Java с помощью инструментария. Проблема с нынешней системой,Использование Instrumentation для записи необработанного исключения

  • Едва ли написано каким-либо заявление в журнале
  • Плохо обработки

исключения Это сделало очень трудно отследить причину разбитой функциональности.

Чтобы справиться с ситуацией, я разработал инструмент, java-агент, используя API Instrumentation, и мне удалось ввести инструкции журнала и решить половину проблемы.

Но следующая проблема заключается в записи Исключения. Я хочу расширить свою запись инструмента за каждое исключение, возникшее во время выполнения приложения. Я попытался использовать блок «try-catch», используя javaassist API для методов (используя addCatch, insertBefore и insertAfter), и он эффективен в определенной степени.

public byte[] transform(ClassLoader loader, 
     String    className, 
     Class<?>   classBeingRedefined, 
     ProtectionDomain protectionDomain, 
     byte[]    classfileBuffer) 
     throws IllegalClassFormatException { 
    if (className.startsWith("com/alu/")) { 
      return insertLog(className, classBeingRedefined, classfileBuffer); 
    } 

    if(className.endsWith("Exception")){ 
     System.out.println("============= exception occured "+className); 
    } 

Здесь inserLog(..) метод впрыснуть необходимое утверждение журнала и работает нормально, но когда есть какие-либо исключения он не приходит к трансформатору.

Но проблема в том, что некоторые из методов обрабатывают исключение внутри (даже с выходом log/sysout).

например:

try { 
      if(search.equals("Category")){ 
       //do operation 
      } 
     } catch (Exception e) { 
     } 

Этот код ест NullPointerException, когда значение search равно нулю, я не знаю, что это исключение, и приложение не в состоянии за некоторые вещи еще.

В конечном счете, я хочу, чтобы механизм записи любых исключений, создаваемых приложением. Следующие детали должны быть захвачены

  • Исключение Тип
  • Excpetion StackTrace
  • Метод и имя класса

Я знаю, что есть API Thread.setDefaultUncaughtExceptionHandler, но не уверен, как это использовать с Java-измерительных приборов. У меня нет какого-либо источника доступа к приложению.

[обновление 1]

Я нашел ссылку ниже говорит использовать retransformation, я дам попробовать и обновить

How to instrument java system classes?

Любое руководство будет очень полезным.

+0

> но когда есть какое-либо исключение, он не приходит к трансформатору. Просьба прояснить это утверждение. Откуда вы знаете, что Exception не приходит к трансформатору? Ожидаете ли вы '============= исключительное событие в stdout? Конечно, это не так, потому что вы применяете код, который генерирует исключение, и вы регистрируете все исключения, которые ретранслируются сами. –

+0

@AlexeyAndreev, я не совсем понимаю, что вы регистрируете все исключения, которые ретранслируются сами, не могли бы вы перефразировать его PLS –

+0

ОК, я продолжу свой ответ, так как писать сложные комментарии здесь не так просто –

ответ

3

Я думаю, вы должны использовать ASM манипулировать байткод напрямую. Вот Алгоритмы:

  1. Посетите все попробовать/поймать блоков (см visitTryCatchBlock) и сохранить все handler этикетки
  2. посещения инструкции до тех пор, один из handler меток не встречались.
  3. После handler этикетки код вставки лесозаготовительной

    GETSTATIC java/lang/System out 
    LDC "exception X occured" 
    INVOKEVIRTUAL java/io/PrintStream println (java/lang/String)V 
    

и убедитесь, что ваш javaagent работает отлично. Убедитесь, что ваш файл MANIFEST.MF содержит правильную декларацию premain и включает преобразование класса.


О вашем текущем коде. Здесь

if (className.startsWith("com/alu/")) { 
     return insertLog(className, classBeingRedefined, classfileBuffer); 
} 

Вы трансформируете классы внутри определенного пакета. Эти классы содержат код, который, в частности, исключает исключения.

А вот

if(className.endsWith("Exception")){ 
    System.out.println("============= exception occured "+className); 
} 

входа класса будучи retransfomed, когда он первым загружен JVM, когда его имя заканчивается "Exception". Не когда произошло исключение. Но преобразование исключения бесполезно. Поэтому я предполагаю, что вам следовало бы так:

if (className.startsWith("com/alu/")) { 
    System.out.println("============= class transformed "+ className); 
    return insertLog(className, classBeingRedefined, classfileBuffer); 
} 

Так вы могли бы знать, что ваш агент хотя бы работает.


Вы должны иметь дело с кодом, как этот

try { 
     if(search.equals("Category")){ 
      //do operation 
     } 
    } catch (Exception e) { 
    } 

где исключения проглатываются. Вы превращаетесь методы, которые они будут выглядеть так:

try { 
    try { 
     if(search.equals("Category")){ 
      //do operation 
     } 
    } catch (Exception e) { 
    } 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

Конечно, когда исключение проглотила первый catch, второй никогда не натыкается его. Вместо этого, вы должны преобразовываться существующие catch блоки, чтобы сам себе получить следующий код:

try { 
    if(search.equals("Category")){ 
     //do operation 
    } 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

Выше я показал вам, как добиться этого с ASM.

+0

hmmm, я получил вашу точку зрения, мне нужно посетить все блоки catch и преобразуйте его. Хорошая идея! спасибо –

+0

спасибо за указания. Я могу записать исключение из Instrumentation. Позже я загляну в asm, чтобы точно настроить мое решение. Добавлено мое решение ниже. –

+0

Я понимаю, что изменение классов системы (добавление нового поля/метода) - это что-то, что невозможно с 'javaassist', поэтому я голосую за ваше решение. –

2

После дополнительных исследований, я нашел отправную точку (благодаря @jarnbjo), который я считаю, принять меня полным решение

Существует вариант для ретрансформации System классов,

SimpleClassTransformer transformer = new SimpleClassTransformer(); 
    instrumentation.addTransformer(transformer,true); 
    try { 
     instrumentation.retransformClasses(java.lang.NullPointerException.class); 
    } catch (UnmodifiableClassException e) { 
     e.printStackTrace(); 
    } 

я применил этот код в моем классе premain и способен перезагрузить класс NullPointerException. Мне все равно придется работать над реализацией Transformer, чтобы обеспечить возможность мгновенной записи исключения.

[обновление 2]Наконец-то я получил прорыв!

После повторного преобразования требуемого класса исключения я ввел свой код прямо внутри конструктора класса Exception.

Вот мой класс трансформатор,

общественного класса SimpleClassTransformer реализует ClassFileTransformer {

public byte[] transform(ClassLoader loader, 
     String    className, 
     Class<?>   classBeingRedefined, 
     ProtectionDomain protectionDomain, 
     byte[]    classfileBuffer) 
       throws IllegalClassFormatException { 
    System.out.println("----------------- "+className); 
    if (className.startsWith("com/alu/")) { 
     return insertLog(className, classBeingRedefined, classfileBuffer); 
    } 

    if(className.endsWith("Exception")){ 
     System.out.println("============= exception occured"); 
     return recordError(className, classBeingRedefined, classfileBuffer); 
    } 

    return classfileBuffer; 
} 

private byte[] recordError(String name, Class clazz, byte[] b){ 
    ClassPool pool = ClassPool.getDefault(); 
    CtClass cl = null; 
    try { 
     cl = pool.makeClass(new java.io.ByteArrayInputStream(b)); 
     if (cl.isInterface() == false) { 
      CtConstructor[] constr=cl.getDeclaredConstructors(); 
      for(CtConstructor con:constr){ 
        con.insertAfter("System.out.println(\"Hey hurrray I got you mannnnnnn -------\"); "); 
      } 
      b = cl.toBytecode(); 
     } 
    } catch (Exception e) { 
     System.out.println(e); 
    } finally { 
     if (cl != null) { 
      cl.detach(); 
     } 
    } 
    return b; 
} 
+0

У меня есть получил исключение "java.lang.UnsupportedOperationException: retransformClasses не поддерживается в этой среде" при повторной выборке. –

+1

Для тех, кто использует этот подход: убедитесь, что у вас есть строка 'Can-Retransform-Classes: true' в вашем' MANIFEST.MF' вашего агента-банке – Raven

 Смежные вопросы

  • Нет связанных вопросов^_^