如何以编程方式将 AccessLogValve 添加到 Tomcat?

sch*_*tek 5 java logging spring tomcat

我正在开发一个 Spring boot 应用程序,我想通过我的 slf4j 日志系统将 Tomcat 的访问日志路由到远程系统日志。

由于是 Spring,我想避免接触 tomcat 的 server.xml 文件。

我的 AccessLogValve 非常简单:

import java.io.CharArrayWriter;
import org.apache.catalina.valves.AccessLogValve;

public class Log4JAccessLogValve extends AccessLogValve {
    @Override
    public void log(CharArrayWriter message) {
        log.info(message.toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望可以使用这样的东西将其连接到 Tomcat:

@Component
public class LogConfig {

    @Autowired
    private ServletContext servletContext;

    @PostConstruct
    public void setAccessLogValve() {
        ((ApplicationContextFacade)servletContext).addValve(new Log4JAccessLogValve());
    }

}
Run Code Online (Sandbox Code Playgroud)

除了 addValve() 方法不存在......

那么...有人知道如何连接我的 AccessLogValve 吗?


我也愿意接受完全不同的建议,将访问日志放入远程系统日志中,但我们正在制作数十个微服务,因此它必须是一种非常标准化的方法,易于为每个微服务实现。

pbi*_*nie 4

将这些答案组合成适用于 springboot 2.0 的东西

import org.apache.catalina.valves.AbstractAccessLogValve;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

import java.io.CharArrayWriter;

/**
 * see https://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot
 * 
*/
@Component
@Slf4j
public class CustomizeEmbeddedTomcatContainer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        log.info("configuring embedded Tomcat");
        TomcatSlf4jAccessValve accessLogValve = new TomcatSlf4jAccessValve();
        accessLogValve.setEnabled(true);

        /**
         * for pattern format see https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/valves/AccessLogValve.html
         */
        accessLogValve.setPattern("request: method=%m uri=\"%U\" response: statuscode=%s bytes=%b duration=%D(ms) client: remoteip=%a user=%u useragent=\"%{User-Agent}i\"");

        factory.addContextValves(accessLogValve);
    }


    public static class TomcatSlf4jAccessValve extends AbstractAccessLogValve {

        Logger httpAccessLogLogger = LoggerFactory.getLogger("http_access_log");

        @Override
        protected void log(CharArrayWriter message) {
            httpAccessLogLogger.info(message.toString());
        }

    }
}
Run Code Online (Sandbox Code Playgroud)