This is in a Gradle project using Groovy for the app code as well as test code. But I\'m using a logback.xml file for configuration.
One factor here that may be signific
logback.groovy
appender("STDOUT", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level {%logger} - %class.%method:%line - %msg%n"
}
}
root(DEBUG, ["STDOUT"])
X.groovy
@GrabConfig(systemClassLoader=true)
@GrabResolver(name='maven2',root='http://repo1.maven.org/maven2/')
@Grab(group='ch.qos.logback', module='logback-classic', version='1.2.3')
@Grab(group='org.slf4j', module='slf4j-api', version='1.7.30')
import groovy.util.logging.Slf4j
@Slf4j
class A {
def f() {
log.info 'msg-info-2' //line 11
log.with{
info 'msg-info-1' //line 13
//new Exception("test").printStackTrace(System.out)
}
}
}
def a = new A()
a.f()
The command groovy X.groovy
prints:
12:24:43.134 [main] INFO {A} - A.f:11 - msg-info-1
12:24:43.139 [main] INFO {A} - sun.reflect.NativeMethodAccessorImpl.invoke0:-2 - msg-info-2
why
in logback there is a class CallerData with method extract
that extracts caller data information as an array based on a Throwable
parameter and returns an array of StackTraceElement
. It tries to cleenup the stacktrace, however for groovy it could be really complex.
For example if you uncomment the line new Exception("test").printStackTrace(System.out)
You'll see stacktrace like this:
java.lang.Exception: test
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
... + 11 elements
at A$_f_closure1.doCall(X.groovy:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
... + 15 elements
at A.f(X.groovy:12)
... + 20 elements
CallerData tries to skip the technical groovy elements from stacktrace but fails to detect the right one.
solution
It's possible to modify the Framework Packages for the logback context.
I don't know how to do that from logback.xml
, but I found how to do it using logback.groovy
logback.groovy (modified)
maybe for your case you have to add another framework (ignored) packages...
context.getFrameworkPackages().addAll([
"sun.reflect",
"java.lang.reflect",
"org.codehaus.groovy",
"groovy.lang.MetaMethod",
"jdk.internal.reflect"
])
appender("STDOUT", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level {%logger} - %class.%method:%line - %msg%n"
}
}
root(DEBUG, ["STDOUT"])
with this configuration the code above prints lines correctly:
13:12:14.410 [main] INFO {A} - A.f:11 - msg-info-2
13:12:14.416 [main] INFO {A} - A$_f_closure1.doCall:13 - msg-info-1