简体   繁体   中英

How can I include xml configuration in logback.groovy

I'm writing a Spring Boot app and need the flexibility of controlling my logback configuration using Groovy. In Spring Boot all I have to do is create src/main/resources/logback.groovy and it is automatically used for configuration.

What I would like to do though is start with Spring Boot's default logback configuration, and just override or modify settings as needed.

If I were using logback.xml instead of logback.groovy I could do something like the following.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

Is there something similar to the include line above that I can use in logback.groovy? I can look at the contents of base.xml and it's other included files to see how to replicate this manually, but it would add a bit of boilerplate code I'd like to avoid.

Thanks for any help you can provide.

There's an online tool that translates given logback.xml file to equivalent logback.groovy . In your case it resulted in:

//
// Built on Thu Jul 16 09:35:34 CEST 2015 by logback-translator
// For more information on configuration files in Groovy
// please see http://logback.qos.ch/manual/groovy.html

// For assistance related to this tool or configuration files
// in general, please contact the logback user mailing list at
//    http://qos.ch/mailman/listinfo/logback-user

// For professional support please see
//   http://www.qos.ch/shop/products/professionalSupport

import static ch.qos.logback.classic.Level.DEBUG

logger("org.springframework.web", DEBUG)

When it comes to <include> it's not supported for groovy configurations.

How do you feel about instead of adding/overriding your configuration, you reload it again?

You can create a Spring Bean that will see if a logback file is in a location you specify, and if it is, reload using that file

Example

@Component
public class LoggingHelper {

    public static final String LOGBACK_GROOVY = "logback.groovy";

    @PostConstruct
    public void resetLogging() {
        String configFolder = System.getProperty("config.folder");
        Path loggingConfigFile = Paths.get(configFolder, LOGBACK_GROOVY);
        if (Files.exists(loggingConfigFile) && Files.isReadable(loggingConfigFile)) {

            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            ContextInitializer ci = new ContextInitializer(loggerContext);
            loggerContext.reset();
            try {
                ci.configureByResource(loggingConfigFile.toUri().toURL());
            } catch (JoranException e) {
                // StatusPrinter will handle this
            } catch (MalformedURLException e) {
                System.err.println("Unable to configure logger " + loggingConfigFile);
            }
            StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
        }
    }

}

I am using this snippet to start my logback.groovy file

import ch.qos.logback.classic.joran.JoranConfigurator
import org.xml.sax.InputSource

def configurator = new JoranConfigurator()
configurator.context = context
def xmlString = '<?xml version="1.0" encoding="UTF-8"?>\n<configuration>\n    <include resource="org/springframework/boot/logging/logback/base.xml"/>\n</configuration>'
configurator.doConfigure(new InputSource(new StringReader(xmlString)))

Contrary to the documentation stating that:

Everything you can do using XML in configuration files, you can do in Groovy with a much shorter syntax.

include is not possible with Groovy out-of-the-box. However, thanks to a bug ticket that was opened in 2014, there are a couple of workarounds. I am including them here (slightly edited), but all credit goes to "Yih Tsern" from the original JIRA bug:

logback.groovy

include(new File('logback-fragment.groovy'))

root(DEBUG, ["CONSOLE"])

def include(File fragmentFile) {
  GroovyShell shell = new GroovyShell(
    getClass().classLoader,
    binding,
    new org.codehaus.groovy.control.CompilerConfiguration(scriptBaseClass: groovy.util.DelegatingScript.name))

  Script fragment = shell.parse(fragmentFile.text)
  fragment.setDelegate(this)

  fragment.run()
}

logback-fragment.groovy:

// NOTE: No auto-import
import ch.qos.logback.core.*
import ch.qos.logback.classic.encoder.*

appender("CONSOLE", ConsoleAppender) {
  encoder(PatternLayoutEncoder) {
    pattern = "%d [%thread] %level %mdc %logger{35} - %msg%n"
  }
}

Given the workaround and a pull-request to add the feature, I'm not sure why the functionality hasn't been added to Logback core yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM