TCPNetSyslogConfig多setter导致Logback配置facility启动异常求解决方案
问题
使用Logback版本1.5.6,配置如下:
<configuration> <appender name="SYSLOG-DEFAULT-APPENDER" class="com.papertrailapp.logback.Syslog4jAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>IRC: %m%n%xEx</pattern> </layout> <syslogConfig class="org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig"> <host>127.0.0.1</host> <port>514</port> <ident>guacamole_client</ident> <facility>local0</facility> <maxMessageLength>128000</maxMessageLength> </syslogConfig> </appender> <!-- Log at INFO level --> <root level="info"> <appender-ref ref="SYSLOG-DEFAULT-APPENDER" /> </root> </configuration>
启动应用时偶尔触发错误,核心异常为*java.lang.NumberFormatException: For input string: "local0"*,完整错误栈如下:
11:10:40,478 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 11:10:40,564 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [SYSLOG-DEFAULT-APPENDER] 11:10:40,564 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [com.papertrailapp.logback.Syslog4jAppender] 11:10:40,586 |-WARN in ch.qos.logback.core.joran.util.beans.BeanDescriptionFactory@1c5d2f51 - Class 'org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig' contains multiple setters for the same property 'delimiterSequence'. 11:10:40,586 |-WARN in ch.qos.logback.core.joran.util.beans.BeanDescriptionFactory@1c5d2f51 - Class 'org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig' contains multiple setters for the same property 'facility'. 11:10:40,586 |-WARN in ch.qos.logback.core.joran.util.beans.BeanDescriptionFactory@1c5d2f51 - Class 'org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig' contains multiple setters for the same property 'splitMessageEndText'. 11:10:40,586 |-WARN in ch.qos.logback.core.joran.util.beans.BeanDescriptionFactory@1c5d2f51 - Class 'org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig' contains multiple setters for the same property 'splitMessageBeginText'. 11:10:40,587 |-WARN in ch.qos.logback.core.joran.util.PropertySetter@6a7d70b0 - Failed to set property [facility] to value "local0". ch.qos.logback.core.util.PropertySetterException: Conversion to type [int] failed. at ch.qos.logback.core.util.PropertySetterException: Conversion to type [int] failed. at at ch.qos.logback.core.joran.util.PropertySetter.setProperty(PropertySetter.java:119) at at ch.qos.logback.core.joran.util.PropertySetter.setProperty(PropertySetter.java:96) at at ch.qos.logback.core.model.processor.ImplicitModelHandler.doBasicProperty(ImplicitModelHandler.java:111) at at ch.qos.logback.core.model.processor.ImplicitModelHandler.handle(ImplicitModelHandler.java:86) at at ch.qos.logback.core.model.processor.DefaultProcessor.secondPhaseTraverse(DefaultProcessor.java:241) at at ch.qos.logback.core.model.processor.DefaultProcessor.secondPhaseTraverse(DefaultProcessor.java:253) at at ch.qos.logback.core.model.processor.DefaultProcessor.secondPhaseTraverse(DefaultProcessor.java:253) at at ch.qos.logback.core.model.processor.DefaultProcessor.secondPhaseTraverse(DefaultProcessor.java:253) at at ch.qos.logback.core.model.processor.DefaultProcessor.traversalLoop(DefaultProcessor.java:90) at at ch.qos.logback.core.model.processor.DefaultProcessor.process(DefaultProcessor.java:106) at at ch.qos.logback.core.joran.GenericXMLConfigurator.processModel(GenericXMLConfigurator.java:208) at at ch.qos.logback.core.joran.GenericXMLConfigurator.doConfigure(GenericXMLConfigurator.java:170) at at ch.qos.logback.core.joran.GenericXMLConfigurator.doConfigure(GenericXMLConfigurator.java:122) at at ch.qos.logback.core.joran.GenericXMLConfigurator.doConfigure(GenericXMLConfigurator.java:65) at at ch.qos.logback.classic.util.DefaultJoranConfigurator.configureByResource(DefaultJoranConfigurator.java:68) at at ch.qos.logback.classic.util.DefaultJoranConfigurator.configure(DefaultJoranConfigurator.java:35) at at ch.qos.logback.classic.util.ContextInitializer.invokeConfigure(ContextInitializer.java:128) at at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:103) at at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:66) at at ch.qos.logback.classic.spi.LogbackServiceProvider.initializeLoggerContext(LogbackServiceProvider.java:52) at at ch.qos.logback.classic.spi.LogbackServiceProvider.initialize(LogbackServiceProvider.java:41) at at org.slf4j.LoggerFactory.bind(LoggerFactory.java:196) at at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:183) at at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:486) at at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:472) at at ch.qos.logback.classic.util.StatusViaSLF4JLoggerFactory.addStatus(StatusViaSLF4JLoggerFactory.java:34) at at ch.qos.logback.classic.util.StatusViaSLF4JLoggerFactory.addInfo(StatusViaSLF4JLoggerFactory.java:22) at at ch.qos.logback.classic.servlet.LogbackServletContainerInitializer.onStartup(LogbackServletContainerInitializer.java:33) at at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4438) at at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:599) at at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:571) at at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:603) at at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1751) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at at java.base/java.lang.reflect.Method.invoke(Method.java:568) at at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:264) at at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:814) at at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:802) at at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:453) at at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:407) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at at java.base/java.lang.reflect.Method.invoke(Method.java:568) at at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:264) at at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:814) at at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:802) at at java.management/com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:472) at at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1472) at at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1310) at at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) at at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1412) at at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at at java.base/java.lang.reflect.Method.invoke(Method.java:568) at at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360) at at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) at at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) at at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) at at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) at at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587) at at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828) at at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705) at at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704) at at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at at java.base/java.lang.Thread.run(Thread.java:833) Caused by: java.lang.NumberFormatException: For input string: "local0" at at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at at java.base/java.lang.Integer.parseInt(Integer.java:668) at at java.base/java.lang.Integer.valueOf(Integer.java:999) at at ch.qos.logback.core.joran.util.StringToObjectConverter.convertArg(StringToObjectConverter.java:62) at at ch.qos.logback.core.joran.util.PropertySetter.setProperty(PropertySetter.java:117) at ... 72 common frames omitted
问题根源:org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig类的facility属性存在两个重载的setter方法:
public void setFacility(int facility) { this.facility = facility; } public void setFacility(String facilityName) { this.facility = SyslogUtility.getFacility(facilityName); }
Logback的属性赋值逻辑偶尔会选择int类型的setter,导致无法将字符串"local0"转换为int类型,触发上述异常。已提交相关GitHub Issue但未收到反馈,求可行解决办法。
可行解决办法
- 直接使用facility对应的int值:查询
SyslogUtility.getFacility("local0")返回的int数值(比如local0对应16),将配置中的<facility>local0</facility>改为<facility>16</facility>,这样无论Logback选择哪个setter,都能完成赋值。 - 自定义TCPNetSyslogConfig子类:创建继承自
TCPNetSyslogConfig的子类,重写setter方法确保优先处理字符串参数。示例代码:
public class CustomTCPNetSyslogConfig extends TCPNetSyslogConfig { @Override public void setFacility(int facility) { // 调用字符串版本的setter,避免int类型赋值冲突 super.setFacility(SyslogUtility.getFacilityName(facility)); } @Override public void setFacility(String facilityName) { super.setFacility(facilityName); } }
然后修改Logback配置中的syslogConfig类:
<syslogConfig class="com.yourpackage.CustomTCPNetSyslogConfig"> <!-- 原有配置项保持不变 --> </syslogConfig>
- 替换为Logback官方Syslog Appender:放弃使用第三方的
com.papertrailapp.logback.Syslog4jAppender,改用Logback自带的ch.qos.logback.classic.net.SyslogAppender,该组件对facility的字符串配置支持更稳定,无需担心重载setter的冲突问题。
内容的提问来源于stack exchange,提问作者gstackoverflow
相关产品推荐
相关产品推荐

