#groovy
#groovy
Вопрос:
РЕДАКТИРОВАТЬ: GROOVY-6932 был зарегистрирован и теперь закрыт — проблема отмечена как исправленная в Groovy v2.4.8.
Я использую аннотацию @Slf4j, чтобы добавить ведение журнала в мои классы groovy.
Мне это нравится из-за преобразования AST, которое обертывает мои вызовы журнала внутри проверки «включения», описанной здесь
Однако я обнаружил, что предложение guard не работает, если метод log вызывается из замыкания.
Запущенный на Groovy 2.2.0, этот код регистрирует только одно сообщение, но дважды выводит «вызывается».
@Grapes([
@Grab(group='org.slf4j', module='slf4j-api', version='1.7 '),
@Grab(group='ch.qos.logback', module='logback-classic', version='1. ')])
import groovy.util.logging.Slf4j
new TestCode().doSomethingThatLogs()
@Slf4j
class TestCode {
void doSomethingThatLogs(){
log.info createLogString(1)
log.trace createLogString(2)
Closure c = { log.trace createLogString(3) }
c()
}
String createLogString(int p){
println "called with $p"
return "blah: $p"
}
}
Я попытался добавить спецификаторы «this», «owner» и «delegate» в инструкцию log, но результат тот же.
Контекст, в котором я нашел это, был, когда я пытался зарегистрировать некоторые узлы с помощью XmlUtil.serialize во время синтаксического анализа XML с помощью XMLSlurper.
Я работаю над решением проблемы, оборачивая объект NodeChild в облегченный объект с помощью метода toString(), который вызывает класс XmlUtil. Это будет работать нормально, и о накладных расходах на дополнительные классы-оболочки не стоит беспокоиться. Меня больше интересует поиск простого способа решения этой проблемы, чтобы я мог вернуться к тому, чтобы не думать о стоимости создания сообщений журнала, когда они все равно не регистрируются.
Вопрос, который я задаю: есть ли какой-либо способ заставить условие защиты уровня ведения журнала работать должным образом в замыканиях, вместо того, чтобы добавлять вызовы «log.traceEnabled» самостоятельно?
Комментарии:
1. Попробуйте добавить делегат в инструкцию log: delegate.log
2. Я попробовал ваш пример, это указывает на тестовый код класса, я также проверил источник аннотации Slf4j. На мой взгляд, это должно сработать, поэтому я думаю, что вам следует сообщить о проблеме Groovy. Мне жаль, что я не смог помочь.
3. у вас такая же проблема, если вы используете
@Log4j
?4. Вы пробовали просматривать сгенерированный код в декомпиляторе (в IntelliJ он уже встроен, или используйте что-то вроде Jad) — это может помочь увидеть, что генерируется преобразованиями AST.
Ответ №1:
Просто быстрая мысль. Как вы узнаете, что log.traceEnabled
будет при выполнении закрытия? Смотрите измененный пример …
@Grapes([
@Grab(group='org.slf4j', module='slf4j-api', version='1.7 '),
@Grab(group='ch.qos.logback', module='logback-classic', version='1. ')])
import groovy.util.logging.Slf4j
import jline.internal.Log
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
new TestCode().doSomethingThatLogs()
@Slf4j
class TestCode {
void doSomethingThatLogs(){
log.info createLogString(1)
log.trace createLogString(2)
Closure c = { log.trace createLogString(3) }
Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.setLevel(Level.TRACE);
c()
}
String createLogString(int p){
println "called with $p"
return "blah: $p"
}
}
Теперь во время создания замыкания log.traceEnabled
значение false, но при выполнении замыкания это изменилось.
Вывод:
called with 1
16:53:15.408 [main] INFO TestCode - blah: 1
called with 3
16:53:15.414 [main] TRACE TestCode - blah: 3
Обратите внимание, что второе TRACE
все еще не напечатано 🙂
Комментарии:
1. На самом деле я не знаю, но я предположил, что Groovy генерирует тот же код, который вы написали бы вручную, то есть окружает операторы журнала сгенерированным байт-кодом для «if log.isDebugEnabled()». Вы хотите сказать, что, по вашему мнению, Groovy удаляет байт-код во время компиляции / загрузки?
2. Извините… Я не был в теме. Я углубился в детали, но не смог понять всю логику за кулисами (Groovy!?) Однако некоторые замечания: 1. Поскольку Groovy является динамическим, это не весь «байт-код», а метаклассы и некоторая скрытая магия. 2. Если вы посмотрите на код @Slf4j , вы можете увидеть, что «перенос» выполняется с помощью TernaryExpression / isTraceEnabled? log… : NULL / который вызывается динамически 3. Однако, когда это происходит в закрытии, этот вызов сохраняется, но он выполняется после оценки аргумента и …
3. … таким образом, вызывается ваш метод. Однако вы правы … похоже на ОШИБКУ!