[ https://issues.apache.org/jira/browse/LOG4J2-3680?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17813612#comment-17813612 ]
Piotr Karwasz commented on LOG4J2-3680: --------------------------------------- Hi [~peterdm], The problem is due to the hardening of the deserialization of Log4j classes in version 2.22.0 (cf. [apache/logging-log4j2#1906|http://example.com|https://github.com/apache/logging-log4j2/pull/1906]). Only a limited number of classes can be deserialized (e.g. those in {{java.lang}}), but the filter does not work correctly with arrays (e.g. it denies {{java.lang.StackTraceElement[]}}). We'll fix this in the next release. > Some log events are no longer serialized correctly > -------------------------------------------------- > > Key: LOG4J2-3680 > URL: https://issues.apache.org/jira/browse/LOG4J2-3680 > Project: Log4j 2 > Issue Type: Bug > Components: Core > Affects Versions: 2.22.0 > Reporter: Peter De Maeyer > Assignee: Piotr Karwasz > Priority: Major > > We noticed a regression between 2.21.1 and 2.22.0 in the serilialization of > log events. The below test succeeds with 2.21.1, but fails with 2.22.0. I had > a look at the source code, and I think it's because of changes in the > {{ObjectMessage.read/writeObject}} implementation. > {code:java} > import static org.apache.logging.log4j.LogManager.getLogger; > import static org.junit.jupiter.api.Assertions.assertEquals; > import java.io.ByteArrayInputStream; > import java.io.ByteArrayOutputStream; > import java.io.IOException; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; > import java.io.Serializable; > import java.util.ArrayList; > import java.util.List; > import org.apache.logging.log4j.core.Appender; > import org.apache.logging.log4j.core.ErrorHandler; > import org.apache.logging.log4j.core.Layout; > import org.apache.logging.log4j.core.LogEvent; > import org.apache.logging.log4j.core.Logger; > import org.junit.jupiter.api.AfterEach; > import org.junit.jupiter.api.BeforeEach; > import org.junit.jupiter.api.Test; > class Log4jSerializationTest { > private final Logger logger = (Logger) > getLogger(Log4jSerializationTest.class); > private final RecordingAppender appender = new > RecordingAppender(Log4jSerializationTest.class.getName()); > @BeforeEach > void addRecordingAppender() { > appender.start(); > logger.addAppender(appender); > } > @AfterEach > void removeRecordingAppender() { > logger.removeAppender(appender); > appender.stop(); > } > @Test > void logEventSerialization() { > RuntimeException exception = new RuntimeException("induced by test"); > logger.error(exception, exception); > LogEvent event = appender.getEvents().get(0); > assertEquals(RuntimeException.class.getName() + ": induced by test", > event.getMessage().getFormattedMessage()); > } > static class RecordingAppender implements Appender { > private final List<LogEvent> events = new ArrayList(); > private State state = State.STOPPED; > private final String name; > private ErrorHandler handler; > public RecordingAppender(String name) { > this.name = name; > } > @Override > public State getState() { > return state; > } > @Override > public void initialize() { > state = State.INITIALIZED; > } > @Override > public boolean isStarted() { > return state == State.STARTED; > } > @Override > public boolean isStopped() { > return !isStarted(); > } > @Override > public void start() { > events.clear(); > state = State.STARTED; > } > @Override > public void stop() { > events.clear(); > state = State.STOPPED; > } > @Override > public synchronized void append(LogEvent event) { > // The event is a mutable one, Log4j2 emits the same event > instance but changes the message each time. > // If we want to hold on to the event details, we need to clone > the event. > // LogEvent is not an instance of Cloneable, but it IS an > instance of Serializable. > // So we clone by serializing and deserializing. > ByteArrayOutputStream out = new ByteArrayOutputStream(); > try (ObjectOutputStream objectOut = new ObjectOutputStream(out)) { > objectOut.writeObject(event); > } catch (IOException e) { > throw new RuntimeException(e); > } > LogEvent clone; > try (ObjectInputStream objectInput = new ObjectInputStream(new > ByteArrayInputStream(out.toByteArray()))) { > clone = (LogEvent) objectInput.readObject(); > } catch (IOException | ClassNotFoundException e) { > throw new RuntimeException(e); > } > events.add(clone); > } > @Override > public ErrorHandler getHandler() { > return handler; > } > @Override > public Layout<? extends Serializable> getLayout() { > return null; > } > @Override > public String getName() { > return name; > } > @Override > public boolean ignoreExceptions() { > return true; > } > @Override > public void setHandler(ErrorHandler handler) { > this.handler = handler; > } > public synchronized List<LogEvent> getEvents() { > return events; > } > } > } > {code} -- This message was sent by Atlassian Jira (v8.20.10#820010)