Java: возможно ли автоматически добавлять операторы журнала в методы? - PullRequest
5 голосов
/ 18 января 2010

Большинство методов в моем приложении написаны так:

public void m() {
    long t1 = System.currentTimeMillis();
    log.info("begin - m()");

    /* method body */

    long t2 = System.currentTimeMillis();
    log.info("end - m(), took " + (t2 - t1) + "ms.");
}

Хотелось бы, чтобы я просто аннотировал свой метод и вместо этого автоматически генерировал лог-оператор:

@Log("executionTime")
public void m() {
    /* method body */
}

Есть идеи, как поступить с этим подходом? Есть какое-нибудь известное решение?

Кто-то предложил AOP для этого. Проблема в том, что с AspectJ или Spring AOP мне пришлось бы описать все методы, которые содержат столько кода, сколько журнал вызывает в самом методе.

Ответы [ 9 ]

14 голосов
/ 18 января 2010

AspectJ и Spring AOP поддерживают что-то вроде:

execution(* com.company.project..*.*(..))

, что охватывает все методы во всех подпакетах projectПоэтому нет необходимости определять все методы один за другим.

3 голосов
/ 18 января 2010

Как было предложено вам, АОП хорошо подходит для удовлетворения этого требования. Не уверен, что вы имели в виду под «описанием всех методов». Из того, что я знаю, есть способы использования подстановочных знаков для определения методов, к которым применяются аспекты, которые могут упростить вашу работу по «описанию» ... это верно, по крайней мере, в случае Spring AOP .. не уверен в других.

И да, CGLIB, предложенный Морисом, является еще одним хорошим кандидатом на ваше рассмотрение. Никогда не использовал это все же.

2 голосов
/ 18 января 2010

CGLIB позволяет изменять код метода во время выполнения

1 голос
/ 18 января 2010

Хотя это еще не фактический практический ответ на ваш вопрос (некоторые хорошие ответы были относительно AOP), я считаю, что концепция ARM в Java 7 должна быть жизнеспособным вариантом для реализации что-то вроде этого в небольшом масштабе.

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

public class TimerFactory
{
    private static final Logger log = ...; // Obtain however

    static class Timer implements Disposable<RuntimeException>
    {
        private final long startTime;
        private final String name;

        private Timer(String name)
        {
           this.name = name;
           startTime= System.currentTimeMillis();
           log.info("begin - " + name);
        }

        public void close()
        {
           final long t2 = System.currentTimeMillis();
           log.info("end - " + name + ", took " + (t2 - t1) + "ms.");
        }
    }

    public static Timer getTimer(String name)
    {
       return new Timer(name);
    }
}

Теперь, с учетом этого шаблона (по сути, инкапсуляция вашего поведения при ведении журнала), его можно назвать следующим образом:

public void m() {
   try (TimerFactory.getTimer("m()")) {

      /* method body */

   }
}

Первый метод журнала вызывается при входе в блок try, и время начала записывается. При выходе из блока try ресурс (в данном случае Timer) автоматически будет «закрыт», что приведет к вычислению и регистрации последнего времени. Также обратите внимание, что, поскольку это блок try, регистрация конца будет происходить независимо от того, выброшено исключение или нет. Ваш исходный код, вероятно, должен использовать блок try-finally, чтобы гарантировать, что регистрация фактически завершена.

Очевидно, что для этого по-прежнему необходимо размещать некоторый код журнала на каждом сайте, так что на самом деле это не замена умных точек и AOP, даже после выхода Java 7. Тем не менее, если вы обнаружите, что время от времени включаете ведение журнала, возможно, в несколько методов, этот шаблон является хорошим способом абстрагироваться от проблем, связанных с ведением журнала, и позволяет повторно использовать его с минимальным количеством шаблонов.

1 голос
/ 18 января 2010

AspectJ имеет концепцию точки соединения , которая похожа на подстановочный знак, который может указывать любые методы, соответствующие этому подстановочному знаку (вы можете указать конкретные методы в классе или любом классе, который соответствует подстановочному знаку). Затем вы можете создать аспект , который содержит до рекомендации и после рекомендации , то есть методы, которые выполняются до и после метода, соответствующего точке соединения. Вы можете генерировать свои методы журнала таким образом.

1 голос
/ 18 января 2010

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

0 голосов
/ 03 февраля 2013

Попробуйте @Loggable аннотация от jcabi-аспекты (питание от AspectJ):

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  return url.openConnection().getContent();
}

Он регистрируется через SLF4J , который вы можете перенаправить на свое собственное средство регистрации, например, log4j.

0 голосов
/ 18 января 2010

Вы должны использовать аспект этого требования. Это требование является взаимоисключающим (беспокойство, которое «разрезает» между многими классами).

Чтобы захватить методы, которые вы хотите сопоставить, вы должны создать pointcut, который соответствует одной или нескольким точкам соединения. Точка соединения - это то, что может быть выполнено в вашем коде (например, метод).

Посмотрите на эти простые примеры о трассировке и ведении журнала и эту ссылку о подстановочных знаках и точечных символах .

0 голосов
/ 18 января 2010

Закомментируйте входящие в систему или профилирующие вызовы с помощью уникального условия поиска:

void myfunc() {

  //log-call-123: try { long log_t1 = System.currentTimeMillis();        
  //log-call-123: log.info("begin - myfunc()"); {

  ...
  normal method code
  ...

  //log-call-123: } } finally { long log_t2 = System.currentTimeMillis();         
  //log-call-123: log.info("end - myfunc(), took " + (log_t2 - log_t1) + "ms."); }

}

При поиске и замене:

Поиск: "//log-call-123:"

Замените на: "/* log-call-123 */"

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

...