spring-projects/spring-boot

Add logback-access-spring-boot-starter to 3rd party starter list

wilkinsona opened this issue ยท 22 comments

Add logback-access-spring-boot-starter to 3rd party starter list

Hey, I'm trying to get logback-access + tomcat working with spring boot. Has anyone been able to get this working out-of-the-box? Or is there some necessary plumbing to set up?

The primary issue we hit is that the LogbackValve (https://github.com/qos-ch/logback/blob/master/logback-access/src/main/java/ch/qos/logback/access/tomcat/LogbackValve.java) takes in a filename that it assumes is accessible from the filesystem. Our log configuration file is bundled with the JAR so doesn't seem to fit that use case.

cemo commented

+1

@izeye that does not work in a spring boot app right? Does it work in a standard war deploy?

izeye commented

@dahankzter Have you tried it? IIRC, I checked it's working with an embedded Tomcat at that time.

@izeye I get stuff like this:

Caused by: java.io.FileNotFoundException: class path resource [logback-access.xml] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/apps/.....

izeye commented

@dahankzter Well, it works for me with both IntelliJ and repackaged jar.

In logs/http/http.log:

GET / HTTP/1.1
host: localhost:18080
connection: keep-alive
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
accept-encoding: gzip, deflate, sdch
accept-language: ko,zh-CN;q=0.8,zh;q=0.6,en-US;q=0.4,en;q=0.2
cookie: _ga=GA1.1.2128301213.1414071979; archiva_login=%7B%22username%22%3A%22admin%22%2C%22password%22%3A%22admin1%22%2C%22confirmPassword%22%3Anull%2C%22fullName%22%3A%22the%20administrator%22%2C%22email%22%3A%22izeye%40naver.com%22%2C%22permanent%22%3Afalse%2C%22validated%22%3Atrue%2C%22timestampAccountCreation%22%3Anull%2C%22timestampLastLogin%22%3Anull%2C%22timestampLastPasswordChange%22%3Anull%2C%22locked%22%3Afalse%2C%22passwordChangeRequired%22%3Afalse%2C%22assignedRoles%22%3A%5B%5D%2C%22modified%22%3Afalse%2C%22readOnly%22%3Afalse%2C%22userManagerId%22%3Anull%2C%22rememberme%22%3Afalse%2C%22logged%22%3Afalse%7D



HTTP/1.1 200 OK
Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-compound_text, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp
Content-Length: 12
Date: Mon, 07 Dec 2015 09:34:00 GMT
Content-Type: text/html;charset=UTF-8

Hello World!

Does it work when you move the jar somewhere where the source is not available?

izeye commented

@dahankzter Oops. Sorry I didn't check that. You're right.

As a workaround, you can copy the access xml from the class path to the filesystem and run it there as part of your configuration class

Files.copy(this.getClass().getResourceAsStream("/logback-access.xml"),Paths.get("log-access.xml"),StandardCopyOption.REPLACE_EXISTING);
logbackValve.setFilename("log-access.xml");

where logback-access.xml is my config file in the resources folder.

nodje commented

Awesome @mattreyuk !

pires commented

Here's a code snippet if it helps:

    @Autowired
    private ResourceLoader resourceLoader;

   // class code, etc.

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) container;
            final LogbackValve logbackValve = new LogbackValve();

            // load from classpath or if it doesn't work, try the filesystem
            try {
                final File xmlFile = resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + "logback-access.xml").getFile();
                logbackValve.setFilename(xmlFile.getCanonicalPath());
            } catch (IOException e) {
                log.warn("Couldn't setup logback-acccess with classpath. Falling back to file");
                logbackValve.setFilename("logback-access.xml");
            }

            containerFactory.addContextValves(logbackValve);
        }
    }

There is already a project providing that feature: https://github.com/akihyro/spring-boot-ext-logback-access
I'd be happy to see it in Spring Boot core, though!

gezzi commented

@mattreyuk this solution worked, but I am hopping something like spring-boot-ext-logback-access that @adammichalik mentioned is added to spring boot.
@pires the solution you mentioned does not work when logback-access is in a jar

Since logback 1.1.6 there is no need of any workarounds in order to load the logback-access configuration file as a resource. Reference: http://jira.qos.ch/browse/LOGBACK-1069

All you have to do is:
logbackValve.setFilename("log-access.xml");

pires commented

LogbackValve works for Tomcat. Here's what I use for Jetty:

@Autowired
private ResourceLoader resourceLoader;

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
    if (container instanceof JettyEmbeddedServletContainerFactory) {
        final JettyEmbeddedServletContainerFactory containerFactory = (JettyEmbeddedServletContainerFactory) container;
        containerFactory.addServerCustomizers(new JettyServerCustomizer() {
            @Override
            public void customize(Server server) {
                // set-up request log handler
                final RequestLogImpl requestLog = new RequestLogImpl();
                // load from classpath or if it doesn't work, try the filesystem
                try {
                    final File logbackFile = resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + "logback-access.xml").getFile();
                    if (logbackFile != null) {
                        requestLog.setFileName(logbackFile.getCanonicalPath());
                    }
                } catch (IOException e) {
                    requestLog.setFileName("logback-access.xml");
                }
                final RequestLogHandler requestLogHandler = new RequestLogHandler();
                requestLogHandler.setHandler(server.getHandler());
                requestLogHandler.setRequestLog(requestLog);
                server.setHandler(requestLogHandler);
            }
        });
    }
}

Just to mention that when customising the container to create the logback Valve does not work with management endpoints when they are specified on a different port. (when management.port is different than server.port)
And i believe there is no way to configure the container for the management endpoints to add a valve.
From what i checked in the code, the problem is that for the management endpoints, a different container factory is created using reflection.

And i believe there is no way to configure the container for the management endpoints to add a valve

It should be possible using a @ManagementContextConfiguration class that's listed in spring.factories. If that class declares an EmbeddedServletContainerCustomizer bean, it should be called when the separate management container is being configured.

Even when configuring the LogbackValve manually using a costumizer, the <springProperty> will still not be available... Spring boot will also need to add a SpringBootJoranConfigurator of the logback-access type (ch.qos.logback.access.joran.JoranConfigurator)

Also adding support for MDC fields will help out a lot during tracing events in the log

When can we expect this feature? @wilkinsona

Thanks for keeping our dev engine running!

@ezraroi

I've re-purposed this issue to add a link to the 3rd-party starter.

izeye commented

@philwebb One was added in #9447 unless you meant another one.

Nope, that's the same one. Thanks, @izeye!