virtualdogbert / logback-groovy-config

Bringing back Groovy to Logback for configuration.
Other
14 stars 4 forks source link

Logstash support #10

Open andriperalt opened 1 year ago

andriperalt commented 1 year ago

Hi, I'm trying to re-configure the logstash-logback-encoder after upgrading logback and losing Groovy support. This configuration in the logback.groovy file:

...
appender('FILE_JSON', FileAppender) {
    file = '/tmp/backend.log'
    append = true
    immediateFlush = true

    encoder(LogstashEncoder) {
        jsonGeneratorDecorator(CompositeJsonGeneratorDecorator)
        includeContext = false
        timeZone = 'GMT'

        fieldNames(LogstashFieldNames) {
            timestamp = 'timestamp'
            message = 'description'
            thread = '[ignore]'
            logger = 'instanceFullName'
            version = '[ignore]'
            levelValue = '[ignore]'
            stackTrace = 'exception'
            mdc = 'context'
        }
    }

    filter(ThresholdFilter) { level = ALL }
}
...

It's generating this exception

Failed to instantiate [ch.qos.logback.classic.LoggerContext]
Reported exception:
ch.qos.logback.core.LogbackException: Failed to initialize or to run Configurator: ch.qos.logback.classic.GroovyConfigurator
    at ch.qos.logback.classic.util.ContextInitializer.invokeConfigure(ContextInitializer.java:127)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:87)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:65)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initializeLoggerContext(LogbackServiceProvider.java:52)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initialize(LogbackServiceProvider.java:41)
    at org.slf4j.LoggerFactory.bind(LoggerFactory.java:183)
    at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:170)
    at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:455)
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:441)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:390)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)
...
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during semantic analysis: Expression [MethodCallExpression] is not allowed: this.jsonGeneratorDecorator(net.logstash.logback.decorate.CompositeJsonGeneratorDecorator)

java.lang.SecurityException: Expression [MethodCallExpression] is not allowed: this.jsonGeneratorDecorator(net.logstash.logback.decorate.CompositeJsonGeneratorDecorator)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.assertExpressionAuthorized(SecureASTCustomizer.java:1045)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1213)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitClosureExpression(SecureASTCustomizer.java:1291)
    at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:46)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:204)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:204)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitTupleExpression(SecureASTCustomizer.java:1302)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitArgumentlistExpression(SecureASTCustomizer.java:1482)
    at org.codehaus.groovy.ast.expr.ArgumentListExpression.visit(ArgumentListExpression.java:73)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1224)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitClosureExpression(SecureASTCustomizer.java:1291)
    at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:46)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:204)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:204)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitTupleExpression(SecureASTCustomizer.java:1302)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitArgumentlistExpression(SecureASTCustomizer.java:1482)
    at org.codehaus.groovy.ast.expr.ArgumentListExpression.visit(ArgumentListExpression.java:73)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1224)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer.call(SecureASTCustomizer.java:890)
    at org.codehaus.groovy.control.CompilationUnit$IPrimaryClassNodeOperation.doPhaseOperation(CompilationUnit.java:942)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:671)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:635)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:389)
    at groovy.lang.GroovyClassLoader.lambda$parseClass$3(GroovyClassLoader.java:332)
    at org.codehaus.groovy.runtime.memoize.StampedCommonCache.compute(StampedCommonCache.java:163)
    at org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(StampedCommonCache.java:154)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:330)
    at groovy.lang.GroovyShell.parseClass(GroovyShell.java:526)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:538)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:570)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:565)
    at groovy.lang.GroovyShell$parse.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at ch.qos.logback.classic.gaffer.GafferConfigurator.run(GafferConfigurator.groovy:120)
    at ch.qos.logback.classic.gaffer.GafferConfigurator$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at ch.qos.logback.classic.LogbackDSLInitializer.init(LogbackDSLInitializer.groovy:26)
    at ch.qos.logback.classic.GroovyConfigurator.configure(GroovyConfigurator.groovy:55)
    at ch.qos.logback.classic.util.ContextInitializer.invokeConfigure(ContextInitializer.java:122)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:87)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:65)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initializeLoggerContext(LogbackServiceProvider.java:52)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initialize(LogbackServiceProvider.java:41)
    at org.slf4j.LoggerFactory.bind(LoggerFactory.java:183)
    at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:170)
    at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:455)
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:441)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:390)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)

Is possible to customize the ScriptExpressionChecker to be able to use this?

Versions:

virtualdogbert commented 1 year ago

As of right now, there is no way to customize the ScriptExpressionChecker, because opening that up would invalidate what security the library provides. That being said adding support for logstash does seem like a worthwhile addition. I'm not sure if jsonGeneratorDecorator is something that the logstash extension somehow adds or is an overlooked part of the logback DSL. When I took over this part of logback I added the security to quell fears from the log4j issues and provide a justification for bringing the functionality back, because it was taken out because of security fears. However, there was no easily discernable list of DSL methods, and I haven't really had the time to dive deep and really understand how the DSL is built up. Although even looking at the code now it seems to be highly dynamic and I might not get any easy answers out of it, so I could have a better way of accounting for the DSL methods.

I can find some time and add jsonGeneratorDecorator and fieldNames to the list of allowed DSL methods hopefully sometime this week.

andriperalt commented 1 year ago

Yes, I got, it's still an amazing work!

The jsonGeneratorDecorator is defined by the CompositeJsonEncoder, so I would say its something specific of the logstash-logback-encoder

virtualdogbert commented 1 year ago

Just did a release adding a couple of the methods to be allowed in the DSL give it a try when you have a chance with 1.13.5. If that works I'll close this issue for now, and if you find any other missing DSL methods you can open a new issue.

andriperalt commented 1 year ago

Thank you, I will validate it and get back to you

andriperalt commented 1 year ago

Hello, sorry for the late response, I tested the 1.13.5 version, and I think is close, but I'm getting an error that I don't get:

Failed to instantiate [ch.qos.logback.classic.LoggerContext]
Reported exception:
ch.qos.logback.core.LogbackException: Failed to initialize or to run Configurator: ch.qos.logback.classic.GroovyConfigurator
    at ch.qos.logback.classic.util.ContextInitializer.invokeConfigure(ContextInitializer.java:127)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:87)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:65)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initializeLoggerContext(LogbackServiceProvider.java:52)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initialize(LogbackServiceProvider.java:41)
    at org.slf4j.LoggerFactory.bind(LoggerFactory.java:183)
    at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:170)
    at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:455)
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:441)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:390)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)
    at com.addi.library.logging.LoggerService.<init>(LoggerService.java:14)
    at com.addi.library.logging.LoggerServiceFactory.get(LoggerServiceFactory.java:10)
    at com.addi.library.vertx.HttpServerWithOpenApi.<clinit>(HttpServerWithOpenApi.java:36)
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during semantic analysis: Indirect import checks prevents usage of expression

java.lang.SecurityException: Indirect import checks prevents usage of expression
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.assertExpressionAuthorized(SecureASTCustomizer.java:1070)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1213)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitClosureExpression(SecureASTCustomizer.java:1291)
    at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:46)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:204)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:204)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitTupleExpression(SecureASTCustomizer.java:1302)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitArgumentlistExpression(SecureASTCustomizer.java:1482)
    at org.codehaus.groovy.ast.expr.ArgumentListExpression.visit(ArgumentListExpression.java:73)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1224)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitClosureExpression(SecureASTCustomizer.java:1291)
    at org.codehaus.groovy.ast.expr.ClosureExpression.visit(ClosureExpression.java:46)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:204)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:204)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitTupleExpression(SecureASTCustomizer.java:1302)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitArgumentlistExpression(SecureASTCustomizer.java:1482)
    at org.codehaus.groovy.ast.expr.ArgumentListExpression.visit(ArgumentListExpression.java:73)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitMethodCallExpression(SecureASTCustomizer.java:1224)
    at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:76)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitExpressionStatement(SecureASTCustomizer.java:1134)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:40)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.visitBlockStatement(SecureASTCustomizer.java:1098)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer.call(SecureASTCustomizer.java:890)
    at org.codehaus.groovy.control.CompilationUnit$IPrimaryClassNodeOperation.doPhaseOperation(CompilationUnit.java:942)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:671)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:635)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:389)
    at groovy.lang.GroovyClassLoader.lambda$parseClass$3(GroovyClassLoader.java:332)
    at org.codehaus.groovy.runtime.memoize.StampedCommonCache.compute(StampedCommonCache.java:163)
    at org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(StampedCommonCache.java:154)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:330)
    at groovy.lang.GroovyShell.parseClass(GroovyShell.java:526)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:538)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:570)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:565)
    at groovy.lang.GroovyShell$parse.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at ch.qos.logback.classic.gaffer.GafferConfigurator.run(GafferConfigurator.groovy:120)
    at ch.qos.logback.classic.gaffer.GafferConfigurator$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at ch.qos.logback.classic.LogbackDSLInitializer.init(LogbackDSLInitializer.groovy:26)
    at ch.qos.logback.classic.GroovyConfigurator.configure(GroovyConfigurator.groovy:55)
    at ch.qos.logback.classic.util.ContextInitializer.invokeConfigure(ContextInitializer.java:122)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:87)
    at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:65)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initializeLoggerContext(LogbackServiceProvider.java:52)
    at ch.qos.logback.classic.spi.LogbackServiceProvider.initialize(LogbackServiceProvider.java:41)
    at org.slf4j.LoggerFactory.bind(LoggerFactory.java:183)
    at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:170)
    at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:455)
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:441)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:390)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:416)
    at com.addi.library.logging.LoggerService.<init>(LoggerService.java:14)
    at com.addi.library.logging.LoggerServiceFactory.get(LoggerServiceFactory.java:10)
    at com.addi.library.vertx.HttpServerWithOpenApi.<clinit>(HttpServerWithOpenApi.java:36)
Caused by: java.lang.SecurityException: Importing [java.lang.Object.jsonGeneratorDecorator] is not allowed
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer.assertStaticImportIsAllowed(SecureASTCustomizer.java:984)
    at org.codehaus.groovy.control.customizers.SecureASTCustomizer$SecuringCodeVisitor.assertExpressionAuthorized(SecureASTCustomizer.java:1057)
    ... 72 more
Caused by: java.lang.SecurityException: Importing [java.lang.Object.jsonGeneratorDecorator] is not allowed

My logback.groovy is the same, and the logbackCompiler.groovy has this:

importsAcceptList = [
        "ch.qos.logback.classic.AsyncAppender",
        "ch.qos.logback.classic.Level",
        "ch.qos.logback.classic.encoder.PatternLayoutEncoder",
        "ch.qos.logback.classic.filter.ThresholdFilter",
        "ch.qos.logback.core.hook.DefaultShutdownHook",
        "net.logstash.logback.decorate.CompositeJsonGeneratorDecorator",
        "net.logstash.logback.encoder.LogstashEncoder",
        "net.logstash.logback.fieldnames.LogstashFieldNames"
]
virtualdogbert commented 1 year ago

I got it... I had part of my test commented out. However, you should be able to work around it by adding:

'java.lang.Object.jsonGeneratorDecorator'

to the staticImportsAcceptList. I'll do another release with that included in the defaults sometime this week.

andriperalt commented 1 year ago

Glad to confirm that it works! :partying_face:

andriperalt commented 1 year ago

A small thing, after that change I get this error:

Caused by: groovy.lang.MissingPropertyException: No such property: FileAppender for class: Script1

Which I solved by just adding the import of ch.qos.logback.core.FileAppender, I was surprised that it was necessary