Log4j2 TcpSocketManager spam



我在Log4j2配置文件中设置了一个TCP套接字附加程序,但是远程接收器可以定期脱机。如果远程接收器已启动并运行,则可以正常工作,但当远程接收器离线时,它会启动控制台错误垃圾邮件。在我的设置中,如果远程接收器不可用是正常情况。

如何配置Log4j以在TCP远程接收器不可用的情况下停止错误消息垃圾?

log4j.xml的相关部分为:

<Socket name="ROLLING_SOCKET" host="127.0.0.1" port="18585">
<JsonLayout />
</Socket>

错误垃圾邮件看起来像这样:

2023-04-11 18:50:37,152 main ERROR TcpSocketManager (TCP:127.0.0.1:18585) caught exception and will continue: java.io.IOException: Unable to create socket for 127.0.0.1 at port 18585
at org.apache.logging.log4j.core.net.TcpSocketManager$TcpSocketManagerFactory.createSocket(TcpSocketManager.java:509)
at org.apache.logging.log4j.core.net.TcpSocketManager$TcpSocketManagerFactory.createManager(TcpSocketManager.java:478)
at org.apache.logging.log4j.core.net.TcpSocketManager$TcpSocketManagerFactory.createManager(TcpSocketManager.java:459)
at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:114)
at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
at org.apache.logging.log4j.core.net.TcpSocketManager.getSocketManager(TcpSocketManager.java:202)
at org.apache.logging.log4j.core.appender.SocketAppender.createSocketManager(SocketAppender.java:443)
at org.apache.logging.log4j.core.appender.SocketAppender$Builder.build(SocketAppender.java:221)
at org.apache.logging.log4j.core.appender.SocketAppender$Builder.build(SocketAppender.java:195)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:122)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1120)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1045)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1037)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:651)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:247)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:293)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:626)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:699)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:716)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:270)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:599)
at com.zzz.test.ServerModuleUnitTest.main(ServerModuleUnitTest.java:543)
Caused by: java.net.ConnectException: Connection refused: connect
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:588)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:633)
at org.apache.logging.log4j.core.net.TcpSocketManager.createSocket(TcpSocketManager.java:409)
at org.apache.logging.log4j.core.net.TcpSocketManager$TcpSocketManagerFactory.createSocket(TcpSocketManager.java:504)
... 27 more
2023-04-11 18:50:37,333 main ERROR Unable to write to stream TCP:127.0.0.1:18585 for appender ROLLING_SOCKET org.apache.logging.log4j.core.appender.AppenderLoggingException: Error writing to TCP:127.0.0.1:18585: socket not available
at org.apache.logging.log4j.core.net.TcpSocketManager.write(TcpSocketManager.java:214)
at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.writeByteArrayToManager(AbstractOutputStreamAppender.java:206)
at org.apache.logging.log4j.core.appender.SocketAppender.directEncodeEvent(SocketAppender.java:459)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:161)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:134)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:125)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:89)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:542)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:500)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:483)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
at org.apache.logging.log4j.core.Logger.log(Logger.java:161)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2205)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2159)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2142)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2017)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1983)
at org.apache.logging.log4j.spi.AbstractLogger.warn(AbstractLogger.java:2661)
at com.zzz.test.ServerModuleUnitTest.main(ServerModuleUnitTest.java:547)
2023-04-11 18:50:37,334 main ERROR An exception occurred processing Appender ROLLING_SOCKET org.apache.logging.log4j.core.appender.AppenderLoggingException: Error writing to TCP:127.0.0.1:18585: socket not available
at org.apache.logging.log4j.core.net.TcpSocketManager.write(TcpSocketManager.java:214)
at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.writeByteArrayToManager(AbstractOutputStreamAppender.java:206)
at org.apache.logging.log4j.core.appender.SocketAppender.directEncodeEvent(SocketAppender.java:459)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:161)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:134)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:125)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:89)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:542)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:500)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:483)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
at org.apache.logging.log4j.core.Logger.log(Logger.java:161)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2205)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2159)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2142)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2017)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1983)
at org.apache.logging.log4j.spi.AbstractLogger.warn(AbstractLogger.java:2661)
at com.zzz.test.ServerModuleUnitTest.main(ServerModuleUnitTest.java:547)

所以我能遇到的最好的解决方案是基于已经删除的评论的解决方案。这并不能解决问题,因为我在开始时仍然得到单个堆栈跟踪,但没有更多的周期性垃圾信息。

需要自定义错误处理程序:

import org.apache.logging.log4j.core.ErrorHandler;
import org.apache.logging.log4j.core.LogEvent;
public class TcpSocketErrorHandler implements ErrorHandler {
@Override
public void error(String msg) {
// Ignore errors silently
}
@Override
public void error(String msg, Throwable t) {
// Ignore errors silently
}
@Override
public void error(String msg, LogEvent event, Throwable t) {
// Ignore errors silently
}
}

在Log4j中。X中可以通过使用配置文件附加自定义错误处理程序,但在log4j 2中。需要一些更复杂的步骤。我创建了一个扩展SocketAppender的自定义Appender(下面的一些代码改编自Log4j 2)。x来源)。

import java.io.Serializable;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.SocketAppender;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.net.AbstractSocketManager;
import org.apache.logging.log4j.core.net.Advertiser;
import org.apache.logging.log4j.core.net.DatagramSocketManager;
import org.apache.logging.log4j.core.net.Protocol;
import org.apache.logging.log4j.core.net.SocketOptions;
import org.apache.logging.log4j.core.net.SslSocketManager;
import org.apache.logging.log4j.core.net.TcpSocketManager;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
@Plugin(name = "SocketNoLog", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
public class SocketNoLogAppender extends SocketAppender {

public SocketNoLogAppender(String name, Layout<? extends Serializable> layout, Filter filter,
AbstractSocketManager manager, boolean ignoreExceptions, boolean immediateFlush, Advertiser advertiser,
Property[] properties) {
super(name, layout, filter, manager, ignoreExceptions, immediateFlush, advertiser, properties);
this.setHandler(new TcpSocketErrorHandler());
}
@PluginBuilderFactory
public static SocketNoLogAppender.Builder newBuilder() {
SocketNoLogAppender.Builder bb = new SocketNoLogAppender.Builder();
return bb;
}

/**
* Creates an AbstractSocketManager for TCP, UDP, and SSL.
*
* @throws IllegalArgumentException
*             if the protocol cannot be handled.
*/
protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig,
final int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout,
final int bufferSize, final SocketOptions socketOptions) {
if (protocol == Protocol.TCP && sslConfig != null) {
// Upgrade TCP to SSL if an SSL config is specified.
protocol = Protocol.SSL;
}
if (protocol != Protocol.SSL && sslConfig != null) {
LOGGER.info("Appender {} ignoring SSL configuration for {} protocol", name, protocol);
}
switch (protocol) {
case TCP:
return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, reconnectDelayMillis,
immediateFail, layout, bufferSize, socketOptions);
case UDP:
return DatagramSocketManager.getSocketManager(host, port, layout, bufferSize);
case SSL:
return SslSocketManager.getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis,
immediateFail, layout, bufferSize, socketOptions);
default:
throw new IllegalArgumentException(protocol.toString());
}
}

public static class Builder extends SocketAppender.Builder {
org.apache.logging.log4j.core.appender.SocketAppender.Builder parent;
public SocketNoLogAppender build() {
boolean immediateFlush = isImmediateFlush();
final boolean bufferedIo = isBufferedIo();
final Layout<? extends Serializable> layout = getLayout();
if (layout == null) {
AbstractLifeCycle.LOGGER.error("No layout provided for SocketAppender");
return null;
}
final String name = getName();
if (name == null) {
AbstractLifeCycle.LOGGER.error("No name provided for SocketAppender");
return null;
}
final Protocol protocol = getProtocol();
final Protocol actualProtocol = protocol != null ? protocol : Protocol.TCP;
if (actualProtocol == Protocol.UDP) {
immediateFlush = true;
}
final AbstractSocketManager manager = SocketAppender.createSocketManager(name, actualProtocol, getHost(), getPort(),
getConnectTimeoutMillis(), getSslConfiguration(), getReconnectDelayMillis(), getImmediateFail(), layout, getBufferSize(), getSocketOptions());
return new SocketNoLogAppender(name, layout, getFilter(), manager, isIgnoreExceptions(),
!bufferedIo || immediateFlush, getAdvertise() ? getConfiguration().getAdvertiser() : null,
getPropertyArray());
}
}
}

并在我的log4j.xml配置中将默认Appender替换为自定义Appender:

<SocketNoLog name="ROLLING_SOCKET" host="127.0.0.1" port="18585" immediateFail="true">
<JsonLayout />
</SocketNoLog>

这并不能完全解决问题,但到目前为止,这是我能找到的最好的解决方案。

最新更新