From f5b03faefa4c78c28aef10179b9c08a2035ba2f2 Mon Sep 17 00:00:00 2001 From: Nikita Sokolov Date: Thu, 1 May 2025 17:54:16 +0200 Subject: [PATCH] JSONEventLayoutV1 should be thread-safe ``` ERROR StatusConsoleListener An exception occurred processing Appender console java.util.ConcurrentModificationException at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1511) at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1544) at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1542) at net.minidev.json.JSONObject.writeJSON(JSONObject.java:162) at net.minidev.json.JSONObject.toJSONString(JSONObject.java:72) at net.minidev.json.JSONObject.toString(JSONObject.java:261) at net.logstash.log4j.JSONEventLayoutV1.format(JSONEventLayoutV1.java:137) at org.apache.log4j.bridge.LayoutAdapter.toByteArray(LayoutAdapter.java:71) at org.apache.log4j.bridge.LayoutAdapter.encode(LayoutAdapter.java:92) at org.apache.log4j.bridge.LayoutAdapter.encode(LayoutAdapter.java:29) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:215) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:208) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:199) 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:683) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:641) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:624) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:560) at org.apache.logging.log4j.core.config.DefaultReliabilityStrategy.log(DefaultReliabilityStrategy.java:63) at org.apache.logging.log4j.core.Logger.log(Logger.java:163) at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2168) at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2122) at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2105) at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1985) at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1838) at org.apache.logging.slf4j.Log4jLogger.info(Log4jLogger.java:175) at org.apache.spark.internal.Logging.logInfo(Logging.scala:60) at org.apache.spark.internal.Logging.logInfo$(Logging.scala:59) at org.apache.spark.scheduler.DAGScheduler.logInfo(DAGScheduler.scala:121) at org.apache.spark.scheduler.DAGScheduler.handleMapStageSubmitted(DAGScheduler.scala:1365) at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.doOnReceive(DAGScheduler.scala:3007) at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:2994) at org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:2983) at org.apache.spark.util.EventLoop$$anon$1.run(EventLoop.scala:49) ``` --- .../net/logstash/log4j/JSONEventLayoutV1.java | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/src/main/java/net/logstash/log4j/JSONEventLayoutV1.java b/src/main/java/net/logstash/log4j/JSONEventLayoutV1.java index aaf3228..0de5398 100644 --- a/src/main/java/net/logstash/log4j/JSONEventLayoutV1.java +++ b/src/main/java/net/logstash/log4j/JSONEventLayoutV1.java @@ -15,24 +15,10 @@ import java.util.TimeZone; public class JSONEventLayoutV1 extends Layout { - private boolean locationInfo = false; private String customUserFields; - private boolean ignoreThrowable = false; - - private boolean activeIgnoreThrowable = ignoreThrowable; - private String hostname = new HostData().getHostName(); - private String threadName; - private long timestamp; - private String ndc; - private Map mdc; - private LocationInfo info; - private HashMap exceptionInformation; - private static Integer version = 1; - - - private JSONObject logstashEvent; + private final String hostname = new HostData().getHostName(); public static final TimeZone UTC = TimeZone.getTimeZone("UTC"); public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", UTC); @@ -60,13 +46,13 @@ public JSONEventLayoutV1(boolean locationInfo) { } public String format(LoggingEvent loggingEvent) { - threadName = loggingEvent.getThreadName(); - timestamp = loggingEvent.getTimeStamp(); - exceptionInformation = new HashMap(); - mdc = loggingEvent.getProperties(); - ndc = loggingEvent.getNDC(); + String threadName = loggingEvent.getThreadName(); + long timestamp = loggingEvent.getTimeStamp(); + HashMap exceptionInformation = new HashMap(); + Map mdc = loggingEvent.getProperties(); + String ndc = loggingEvent.getNDC(); - logstashEvent = new JSONObject(); + JSONObject logstashEvent = new JSONObject(); String whoami = this.getClass().getSimpleName(); /** @@ -74,6 +60,7 @@ public String format(LoggingEvent loggingEvent) { * "@timestamp" and "@version" * Every other field is arbitrary */ + Integer version = 1; logstashEvent.put("@version", version); logstashEvent.put("@timestamp", dateFormat(timestamp)); @@ -83,7 +70,7 @@ public String format(LoggingEvent loggingEvent) { if (getUserFields() != null) { String userFlds = getUserFields(); LogLog.debug("["+whoami+"] Got user data from log4j property: "+ userFlds); - addUserFields(userFlds); + addUserFields(logstashEvent, userFlds); } /** @@ -96,7 +83,7 @@ public String format(LoggingEvent loggingEvent) { } String userFieldsProperty = System.getProperty(ADDITIONAL_DATA_PROPERTY); LogLog.debug("["+whoami+"] Got user data from system property: " + userFieldsProperty); - addUserFields(userFieldsProperty); + addUserFields(logstashEvent, userFieldsProperty); } /** @@ -117,28 +104,28 @@ public String format(LoggingEvent loggingEvent) { String stackTrace = StringUtils.join(throwableInformation.getThrowableStrRep(), "\n"); exceptionInformation.put("stacktrace", stackTrace); } - addEventData("exception", exceptionInformation); + addEventData(logstashEvent, "exception", exceptionInformation); } if (locationInfo) { - info = loggingEvent.getLocationInformation(); - addEventData("file", info.getFileName()); - addEventData("line_number", info.getLineNumber()); - addEventData("class", info.getClassName()); - addEventData("method", info.getMethodName()); + LocationInfo info = loggingEvent.getLocationInformation(); + addEventData(logstashEvent, "file", info.getFileName()); + addEventData(logstashEvent, "line_number", info.getLineNumber()); + addEventData(logstashEvent, "class", info.getClassName()); + addEventData(logstashEvent, "method", info.getMethodName()); } - addEventData("logger_name", loggingEvent.getLoggerName()); - addEventData("mdc", mdc); - addEventData("ndc", ndc); - addEventData("level", loggingEvent.getLevel().toString()); - addEventData("thread_name", threadName); + addEventData(logstashEvent, "logger_name", loggingEvent.getLoggerName()); + addEventData(logstashEvent, "mdc", mdc); + addEventData(logstashEvent, "ndc", ndc); + addEventData(logstashEvent, "level", loggingEvent.getLevel().toString()); + addEventData(logstashEvent, "thread_name", threadName); return logstashEvent.toString() + "\n"; } public boolean ignoresThrowable() { - return ignoreThrowable; + return false; } /** @@ -163,10 +150,9 @@ public void setLocationInfo(boolean locationInfo) { public void setUserFields(String userFields) { this.customUserFields = userFields; } public void activateOptions() { - activeIgnoreThrowable = ignoreThrowable; } - private void addUserFields(String data) { + private void addUserFields(JSONObject logstashEvent, String data) { if (null != data) { String[] pairs = data.split(","); for (String pair : pairs) { @@ -174,12 +160,12 @@ private void addUserFields(String data) { if (userField[0] != null) { String key = userField[0]; String val = userField[1]; - addEventData(key, val); + addEventData(logstashEvent, key, val); } } } } - private void addEventData(String keyname, Object keyval) { + private static void addEventData(JSONObject logstashEvent, String keyname, Object keyval) { if (null != keyval) { logstashEvent.put(keyname, keyval); }