如何配置Tomcat将访问日志发送至远程syslog-ng服务器
兄弟,你找对方向了——Log4j2AccessLogValve(适配log4j2的版本,对应你提到的Log4JAccessLogValve)确实是解决这个问题的核心,而且完全不用自己编译!Tomcat 8.5.x已经内置了这个Valve,只要把依赖、配置一步步弄好就行,下面给你详细拆解:
1. 先确保依赖Jar包到位
你的Tomcat lib目录需要包含这些log4j2相关Jar(如果还没放的话):
log4j-api.jar:log4j2的API基础包log4j-core.jar:log4j2的核心实现包log4j-jul.jar:用来把Tomcat默认的JUL(Java Util Logging)日志桥接到log4j2
注意:Tomcat自带的tomcat-juli.jar可以保留,不用替换,后面我们通过配置让日志流转向log4j2。
2. 修改server.xml,替换原有的AccessLogValve
把你原来的AccessLogValve替换成Log4j2AccessLogValve,核心是指定一个唯一的loggerName,这样log4j2能精准识别访问日志。示例配置如下:
<Valve className="org.apache.catalina.valves.Log4j2AccessLogValve" loggerName="tomcat.accesslog" pattern="%h %l %u %t "%r" %s %b" />
这里去掉了原来的本地文件相关参数(directory、prefix等),因为日志会交给log4j2处理,不再写入本地文件(如果需要同时保留本地日志,可以再加回这些参数)。
3. 扩展你的log4j.xml,单独处理访问日志
为了让syslog-ng能单独过滤访问日志,我们给它配置独立的Appender和Logger:
第一步:新增访问日志专属的Socket Appender
在Appenders节点里添加一个专门给访问日志的远程Appender,还可以加异步包装提升性能:
<!-- 访问日志专属远程Appender,加[ACCESSLOG]前缀方便syslog-ng识别 --> <Socket name="AccessLogRemoteAppender" host="__syslog_server_hostname_here__" port="###"> <PatternLayout pattern="[ACCESSLOG] %d{yyyy-MM-dd HH:mm:ss.SSS} %h %l %u %t "%r" %s %b%n"/> </Socket> <!-- 异步包装,避免日志发送阻塞Tomcat请求 --> <Async name="AsyncAccessLog"> <AppenderRef ref="AccessLogRemoteAppender"/> </Async>
第二步:新增访问日志专属Logger
在Loggers节点里添加一个Logger,专门处理tomcat.accesslog的日志,并且关闭additivity(防止日志重复输出到Root Logger):
<Logger name="tomcat.accesslog" level="info" additivity="false"> <AppenderRef ref="AsyncAccessLog"/> </Logger>
这样访问日志就会通过独立的异步通道发送到syslog-ng,而且[ACCESSLOG]前缀能让syslog-ng轻松区分它和你的应用日志。
4. 配置日志桥接(关键步骤!)
修改Tomcat的conf/logging.properties,把默认的JUL日志处理器换成log4j2的桥接器,确保Tomcat的访问日志能被log4j2接管:
handlers = org.apache.logging.log4j.jul.LogManager .level = INFO
如果跳过这一步,Tomcat的访问日志可能还是会走默认的本地文件输出,不会进入log4j2的远程发送流程。
做完这些后,重启Tomcat,访问几个测试页面,然后去syslog-ng服务器查看日志,应该就能看到带[ACCESSLOG]标记的访问日志,和你的应用日志完全分开,方便后续过滤处理。
备注:内容来源于stack exchange,提问作者Ed Sabol

