如何通过编程将AccessLogValve添加到Tomcat?

5
我正在开发一个Spring Boot应用程序,并希望通过我的slf4j日志系统并最终到达远程syslog来路由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());
    }
}

我希望能够使用类似以下内容将其连接到Tomcat:

而我希望能够使用类似以下内容将其连接到Tomcat:

@Component
public class LogConfig {

    @Autowired
    private ServletContext servletContext;

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

}

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

那么...有人知道我如何挂钩我的AccessLogValve吗?


我也愿意接受完全不同的建议,以将访问日志记录到远程syslog中,但我们正在创建数十个微服务,因此必须采用相当标准化的方法,对于每个微服务都很容易实现。

3个回答

4
将这些答案结合起来,使其与Spring Boot 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());
        }

    }
}

我从来没有找到一个合适的答案,所以我会给你这个问题的线索 :) 我已经远离Spring和Tomcat,因为像这样永无止境的废话 :) - schuttek

2
此外,我建议使用AbstractAccessLogValve来扩展Log4JAccessLogValve,而不是使用AccessLogValve。这样可以避免初始化与访问日志文件相关的功能。例如:
import java.io.CharArrayWriter;
import org.apache.catalina.valves.AbstractAccessLogValve;

public class Log4JAccessLogValve extends AbstractAccessLogValve {

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

}

1
使用EmbeddedServletContainerCustomizer接口。向嵌入式Tomcat添加自定义阀门。
例如:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter implements EmbeddedServletContainerCustomizer {

   @Override
   public void customize(ConfigurableEmbeddedServletContainer container) {
       if (container instanceof TomcatEmbeddedServletContainerFactory) {
           TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;
           AccessLogValve accessLogValve = new Log4JAccessLogValve();
           accessLogValve.setDirectory("/var/log/access_log");
           accessLogValve.setPattern("%h %u %t &quot;%r&quot; %s %b - %T");
           accessLogValve.setSuffix(".log");
           factory.addContextValves(accessLogValve);
       } else {
           logger.error("WARNING! this customizer does not support a custom configured container");
       }
   }

}

我已经尝试了很多不同版本的代码,但是我的log(CharArrayWriter message)方法从未运行过,根据我的分析器...我猜测Tomcat由于某种原因没有运行该阀门。 - schuttek
工厂.addContextValves()是否可能添加到与实际Tomcat服务器无关的内容? - schuttek
1
我的解决方案非常简单:放弃syslog...它只是一个过时的系统的hack...我只需要将日志转储到本地文件系统,并设置logstash来收集、集中和处理它们。我只需要想办法让Tomcat每30秒刷新一次其访问日志缓存,但这是另一回事了...感谢你的帮助Johnny,我希望它能帮助其他人 :) - schuttek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接