blob: 058b9978fd43a3a3458db885de0bb4a0e1ad80be [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.util.Clock;
import org.apache.logging.log4j.core.util.ClockFactory;
import org.apache.logging.log4j.core.util.ClockFactoryTest;
import org.apache.logging.log4j.core.util.DummyNanoClock;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.util.ArrayContextData;
import org.apache.logging.log4j.spi.MutableContextData;
import org.apache.logging.log4j.util.Strings;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class Log4jLogEventTest {
/** Helper class */
public static class FixedTimeClock implements Clock {
public static final long FIXED_TIME = 1234567890L;
/*
* (non-Javadoc)
*
* @see org.apache.logging.log4j.core.helpers.Clock#currentTimeMillis()
*/
@Override
public long currentTimeMillis() {
return FIXED_TIME;
}
}
@BeforeClass
public static void beforeClass() {
System.setProperty(ClockFactory.PROPERTY_NAME, FixedTimeClock.class.getName());
}
@AfterClass
public static void afterClass() throws IllegalAccessException {
ClockFactoryTest.resetClocks();
}
@Test
public void testJavaIoSerializable() throws Exception {
final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
.setLoggerName("some.test") //
.setLoggerFqcn(Strings.EMPTY) //
.setLevel(Level.INFO) //
.setMessage(new SimpleMessage("abc")) //
.build();
final byte[] binary = serialize(evt);
final Log4jLogEvent evt2 = deserialize(binary);
assertEquals(evt.getTimeMillis(), evt2.getTimeMillis());
assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn());
assertEquals(evt.getLevel(), evt2.getLevel());
assertEquals(evt.getLoggerName(), evt2.getLoggerName());
assertEquals(evt.getMarker(), evt2.getMarker());
assertEquals(evt.getContextMap(), evt2.getContextMap());
assertEquals(evt.getContextStack(), evt2.getContextStack());
assertEquals(evt.getMessage(), evt2.getMessage());
assertEquals(evt.getSource(), evt2.getSource());
assertEquals(evt.getThreadName(), evt2.getThreadName());
assertEquals(evt.getThrown(), evt2.getThrown());
assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch());
assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation());
}
@Test
public void testJavaIoSerializableWithThrown() throws Exception {
final Error thrown = new InternalError("test error");
final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
.setLoggerName("some.test") //
.setLoggerFqcn(Strings.EMPTY) //
.setLevel(Level.INFO) //
.setMessage(new SimpleMessage("abc")) //
.setThrown(thrown) //
.build();
final byte[] binary = serialize(evt);
final Log4jLogEvent evt2 = deserialize(binary);
assertEquals(evt.getTimeMillis(), evt2.getTimeMillis());
assertEquals(evt.getLoggerFqcn(), evt2.getLoggerFqcn());
assertEquals(evt.getLevel(), evt2.getLevel());
assertEquals(evt.getLoggerName(), evt2.getLoggerName());
assertEquals(evt.getMarker(), evt2.getMarker());
assertEquals(evt.getContextMap(), evt2.getContextMap());
assertEquals(evt.getContextStack(), evt2.getContextStack());
assertEquals(evt.getMessage(), evt2.getMessage());
assertEquals(evt.getSource(), evt2.getSource());
assertEquals(evt.getThreadName(), evt2.getThreadName());
assertNull(evt2.getThrown());
assertNotNull(evt2.getThrownProxy());
assertEquals(evt.getThrownProxy(), evt2.getThrownProxy());
assertEquals(evt.isEndOfBatch(), evt2.isEndOfBatch());
assertEquals(evt.isIncludeLocation(), evt2.isIncludeLocation());
}
private byte[] serialize(final Log4jLogEvent event) throws IOException {
final ByteArrayOutputStream arr = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(arr);
out.writeObject(event);
return arr.toByteArray();
}
private Log4jLogEvent deserialize(final byte[] binary) throws IOException, ClassNotFoundException {
final ByteArrayInputStream inArr = new ByteArrayInputStream(binary);
final ObjectInputStream in = new ObjectInputStream(inArr);
final Log4jLogEvent result = (Log4jLogEvent) in.readObject();
return result;
}
// DO NOT REMOVE THIS COMMENT:
// UNCOMMENT WHEN GENERATING SERIALIZED EVENT FOR #testJavaIoSerializableWithUnknownThrowable
// public static class DeletedException extends Exception {
// private static final long serialVersionUID = 1L;
// public DeletedException(String msg) {
// super(msg);
// }
// };
@Test
public void testJavaIoSerializableWithUnknownThrowable() throws Exception {
final String loggerName = "some.test";
final Marker marker = null;
final String loggerFQN = Strings.EMPTY;
final Level level = Level.INFO;
final Message msg = new SimpleMessage("abc");
final String threadName = Thread.currentThread().getName();
final String errorMessage = "OMG I've been deleted!";
// DO NOT DELETE THIS COMMENT:
// UNCOMMENT TO RE-GENERATE SERIALIZED EVENT WHEN UPDATING THIS TEST.
// final Exception thrown = new DeletedException(errorMessage);
// final Log4jLogEvent evt = new Log4jLogEvent(loggerName, marker, loggerFQN, level, msg, thrown);
// final byte[] binary = serialize(evt);
// String base64Str = DatatypeConverter.printBase64Binary(binary);
// System.out.println("final String base64 = \"" + base64Str.replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") +
// "\";");
final String base64 = "rO0ABXNyAD5vcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkxvZzRqTG9nRXZlbnQkTG9nRXZlbnRQcm94eYgtmn+yXsP9AgAPWgAMaXNFbmRPZkJhdGNoWgASaXNMb2NhdGlvblJlcXVpcmVkSgAIdGhyZWFkSWRJAA50aHJlYWRQcmlvcml0eUoACnRpbWVNaWxsaXNMAApjb250ZXh0TWFwdAAPTGphdmEvdXRpbC9NYXA7TAAMY29udGV4dFN0YWNrdAA1TG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9UaHJlYWRDb250ZXh0JENvbnRleHRTdGFjaztMAAVsZXZlbHQAIExvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovTGV2ZWw7TAAKbG9nZ2VyRlFDTnQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACmxvZ2dlck5hbWVxAH4ABEwABm1hcmtlcnQAIUxvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovTWFya2VyO0wAB21lc3NhZ2V0ACpMb3JnL2FwYWNoZS9sb2dnaW5nL2xvZzRqL21lc3NhZ2UvTWVzc2FnZTtMAAZzb3VyY2V0AB1MamF2YS9sYW5nL1N0YWNrVHJhY2VFbGVtZW50O0wACnRocmVhZE5hbWVxAH4ABEwAC3Rocm93blByb3h5dAAzTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvVGhyb3dhYmxlUHJveHk7eHAAAAAAAAAAAAABAAAABQAAAABJlgLSc3IAHmphdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eU1hcFk2FIVa3OfQAgAAeHBzcgA+b3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLlRocmVhZENvbnRleHQkRW1wdHlUaHJlYWRDb250ZXh0U3RhY2sAAAAAAAAAAQIAAHhwc3IAHm9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5MZXZlbAAAAAAAGCAaAgADSQAIaW50TGV2ZWxMAARuYW1lcQB+AARMAA1zdGFuZGFyZExldmVsdAAsTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9zcGkvU3RhbmRhcmRMZXZlbDt4cAAAAZB0AARJTkZPfnIAKm9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5zcGkuU3RhbmRhcmRMZXZlbAAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQABElORk90AAB0AAlzb21lLnRlc3Rwc3IALm9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5tZXNzYWdlLlNpbXBsZU1lc3NhZ2WLdE0wYLeiqAMAAUwAB21lc3NhZ2VxAH4ABHhwdAADYWJjcQB+ABp4cHQABG1haW5zcgAxb3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5UaHJvd2FibGVQcm94ednMMNWae6z6AgAHSQASY29tbW9uRWxlbWVudENvdW50TAAKY2F1c2VQcm94eXEAfgAIWwASZXh0ZW5kZWRTdGFja1RyYWNldAA/W0xvcmcvYXBhY2hlL2xvZ2dpbmcvbG9nNGovY29yZS9pbXBsL0V4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnQ7TAAQbG9jYWxpemVkTWVzc2FnZXEAfgAETAAHbWVzc2FnZXEAfgAETAAEbmFtZXEAfgAEWwARc3VwcHJlc3NlZFByb3hpZXN0ADRbTG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvVGhyb3dhYmxlUHJveHk7eHAAAAAAcHVyAD9bTG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuRXh0ZW5kZWRTdGFja1RyYWNlRWxlbWVudDvKz4gjpcfPvAIAAHhwAAAAHXNyADxvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkV4dGVuZGVkU3RhY2tUcmFjZUVsZW1lbnTh3s+6xraQBwIAAkwADmV4dHJhQ2xhc3NJbmZvdAA2TG9yZy9hcGFjaGUvbG9nZ2luZy9sb2c0ai9jb3JlL2ltcGwvRXh0ZW5kZWRDbGFzc0luZm87TAARc3RhY2tUcmFjZUVsZW1lbnRxAH4AB3hwc3IANG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuRXh0ZW5kZWRDbGFzc0luZm8AAAAAAAAAAQIAA1oABWV4YWN0TAAIbG9jYXRpb25xAH4ABEwAB3ZlcnNpb25xAH4ABHhwAXQADXRlc3QtY2xhc3Nlcy90AAE/c3IAG2phdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudGEJxZomNt2FAgAESQAKbGluZU51bWJlckwADmRlY2xhcmluZ0NsYXNzcQB+AARMAAhmaWxlTmFtZXEAfgAETAAKbWV0aG9kTmFtZXEAfgAEeHAAAACqdAA0b3JnLmFwYWNoZS5sb2dnaW5nLmxvZzRqLmNvcmUuaW1wbC5Mb2c0akxvZ0V2ZW50VGVzdHQAFkxvZzRqTG9nRXZlbnRUZXN0LmphdmF0ACp0ZXN0SmF2YUlvU2VyaWFsaXphYmxlV2l0aFVua25vd25UaHJvd2FibGVzcQB+ACJzcQB+ACUAcQB+ACh0AAgxLjcuMF81NXNxAH4AKf////50ACRzdW4ucmVmbGVjdC5OYXRpdmVNZXRob2RBY2Nlc3NvckltcGx0AB1OYXRpdmVNZXRob2RBY2Nlc3NvckltcGwuamF2YXQAB2ludm9rZTBzcQB+ACJzcQB+ACUAcQB+AChxAH4AMHNxAH4AKQAAADlxAH4AMnEAfgAzdAAGaW52b2tlc3EAfgAic3EAfgAlAHEAfgAocQB+ADBzcQB+ACkAAAArdAAoc3VuLnJlZmxlY3QuRGVsZWdhdGluZ01ldGhvZEFjY2Vzc29ySW1wbHQAIURlbGVnYXRpbmdNZXRob2RBY2Nlc3NvckltcGwuamF2YXEAfgA4c3EAfgAic3EAfgAlAHEAfgAocQB+ADBzcQB+ACkAAAJedAAYamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kdAALTWV0aG9kLmphdmFxAH4AOHNxAH4AInNxAH4AJQF0AA5qdW5pdC00LjEyLmphcnQABDQuMTJzcQB+ACkAAAAydAApb3JnLmp1bml0LnJ1bm5lcnMubW9kZWwuRnJhbWV3b3JrTWV0aG9kJDF0ABRGcmFtZXdvcmtNZXRob2QuamF2YXQAEXJ1blJlZmxlY3RpdmVDYWxsc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAAMdAAzb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMubW9kZWwuUmVmbGVjdGl2ZUNhbGxhYmxldAAXUmVmbGVjdGl2ZUNhbGxhYmxlLmphdmF0AANydW5zcQB+ACJzcQB+ACUBdAAOanVuaXQtNC4xMi5qYXJxAH4ARnNxAH4AKQAAAC90ACdvcmcuanVuaXQucnVubmVycy5tb2RlbC5GcmFtZXdvcmtNZXRob2RxAH4ASXQAEWludm9rZUV4cGxvc2l2ZWx5c3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAARdAAyb3JnLmp1bml0LmludGVybmFsLnJ1bm5lcnMuc3RhdGVtZW50cy5JbnZva2VNZXRob2R0ABFJbnZva2VNZXRob2QuamF2YXQACGV2YWx1YXRlc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAFFdAAeb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVydAARUGFyZW50UnVubmVyLmphdmF0AAdydW5MZWFmc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAABOdAAob3JnLmp1bml0LnJ1bm5lcnMuQmxvY2tKVW5pdDRDbGFzc1J1bm5lcnQAG0Jsb2NrSlVuaXQ0Q2xhc3NSdW5uZXIuamF2YXQACHJ1bkNoaWxkc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAA5cQB+AGpxAH4Aa3EAfgBsc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAEidAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDNxAH4AZHEAfgBRc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAABHdAAgb3JnLmp1bml0LnJ1bm5lcnMuUGFyZW50UnVubmVyJDFxAH4AZHQACHNjaGVkdWxlc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAEgcQB+AGNxAH4AZHQAC3J1bkNoaWxkcmVuc3EAfgAic3EAfgAlAXQADmp1bml0LTQuMTIuamFycQB+AEZzcQB+ACkAAAA6cQB+AGNxAH4AZHQACmFjY2VzcyQwMDBzcQB+ACJzcQB+ACUBdAAOanVuaXQtNC4xMi5qYXJxAH4ARnNxAH4AKQAAAQx0ACBvcmcuanVuaXQucnVubmVycy5QYXJlbnRSdW5uZXIkMnEAfgBkcQB+AF5zcQB+ACJzcQB+ACUBdAAOanVuaXQtNC4xMi5qYXJxAH4ARnNxAH4AKQAAABp0ADBvcmcuanVuaXQuaW50ZXJuYWwucnVubmVycy5zdGF0ZW1lbnRzLlJ1bkJlZm9yZXN0AA9SdW5CZWZvcmVzLmphdmFxAH4AXnNxAH4AInNxAH4AJQF0AA5qdW5pdC00LjEyLmphcnEAfgBGc3EAfgApAAAAG3QAL29yZy5qdW5pdC5pbnRlcm5hbC5ydW5uZXJzLnN0YXRlbWVudHMuUnVuQWZ0ZXJzdAAOUnVuQWZ0ZXJzLmphdmFxAH4AXnNxAH4AInNxAH4AJQF0AA5qdW5pdC00LjEyLmphcnEAfgBGc3EAfgApAAABa3EAfgBjcQB+AGRxAH4AUXNxAH4AInNxAH4AJQF0AA5qdW5pdC00LjEyLmphcnEAfgBGc3EAfgApAAAAiXQAGm9yZy5qdW5pdC5ydW5uZXIuSlVuaXRDb3JldAAOSlVuaXRDb3JlLmphdmFxAH4AUXNxAH4AInNxAH4AJQF0AAxqdW5pdC1ydC5qYXJxAH4AKHNxAH4AKQAAAEV0AChjb20uaW50ZWxsaWouanVuaXQ0LkpVbml0NElkZWFUZXN0UnVubmVydAAZSlVuaXQ0SWRlYVRlc3RSdW5uZXIuamF2YXQAE3N0YXJ0UnVubmVyV2l0aEFyZ3NzcQB+ACJzcQB+ACUBdAAManVuaXQtcnQuamFycQB+AChzcQB+ACkAAADqdAAsY29tLmludGVsbGlqLnJ0LmV4ZWN1dGlvbi5qdW5pdC5KVW5pdFN0YXJ0ZXJ0ABFKVW5pdFN0YXJ0ZXIuamF2YXQAFnByZXBhcmVTdHJlYW1zQW5kU3RhcnRzcQB+ACJzcQB+ACUBdAAManVuaXQtcnQuamFycQB+AChzcQB+ACkAAABKcQB+AKxxAH4ArXQABG1haW5zcQB+ACJzcQB+ACUAcQB+AChxAH4AMHNxAH4AKf////5xAH4AMnEAfgAzcQB+ADRzcQB+ACJzcQB+ACUAcQB+AChxAH4AMHNxAH4AKQAAADlxAH4AMnEAfgAzcQB+ADhzcQB+ACJzcQB+ACUAcQB+AChxAH4AMHNxAH4AKQAAACtxAH4APHEAfgA9cQB+ADhzcQB+ACJzcQB+ACUAcQB+AChxAH4AMHNxAH4AKQAAAl5xAH4AQXEAfgBCcQB+ADhzcQB+ACJzcQB+ACUBdAALaWRlYV9ydC5qYXJxAH4AKHNxAH4AKQAAAJB0AC1jb20uaW50ZWxsaWoucnQuZXhlY3V0aW9uLmFwcGxpY2F0aW9uLkFwcE1haW50AAxBcHBNYWluLmphdmFxAH4As3QAFk9NRyBJJ3ZlIGJlZW4gZGVsZXRlZCFxAH4AxnQARW9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuTG9nNGpMb2dFdmVudFRlc3QkRGVsZXRlZEV4Y2VwdGlvbnVyADRbTG9yZy5hcGFjaGUubG9nZ2luZy5sb2c0ai5jb3JlLmltcGwuVGhyb3dhYmxlUHJveHk7+u0B4IWi6zkCAAB4cAAAAAA=";
final byte[] binaryDecoded = DatatypeConverter.parseBase64Binary(base64);
final Log4jLogEvent evt2 = deserialize(binaryDecoded);
assertEquals(loggerFQN, evt2.getLoggerFqcn());
assertEquals(level, evt2.getLevel());
assertEquals(loggerName, evt2.getLoggerName());
assertEquals(marker, evt2.getMarker());
assertEquals(msg, evt2.getMessage());
assertEquals(threadName, evt2.getThreadName());
assertEquals(null, evt2.getThrown());
assertEquals(this.getClass().getName() + "$DeletedException", evt2.getThrownProxy().getName());
assertEquals(errorMessage, evt2.getThrownProxy().getMessage());
}
@Test
public void testNullLevelReplacedWithOFF() throws Exception {
final Level NULL_LEVEL = null;
final Log4jLogEvent evt = Log4jLogEvent.newBuilder().setLevel(NULL_LEVEL).build();
assertEquals(Level.OFF, evt.getLevel());
}
@Test
public void testTimestampGeneratedByClock() {
final LogEvent evt = Log4jLogEvent.newBuilder().build();
assertEquals(FixedTimeClock.FIXED_TIME, evt.getTimeMillis());
}
@Test
public void testInitiallyDummyNanoClock() {
assertTrue(Log4jLogEvent.getNanoClock() instanceof DummyNanoClock);
assertEquals("initial dummy nanotime", 0, Log4jLogEvent.getNanoClock().nanoTime());
}
@Test
public void testNanoTimeGeneratedByNanoClock() {
Log4jLogEvent.setNanoClock(new DummyNanoClock(123));
verifyNanoTimeWithAllConstructors(123);
Log4jLogEvent.setNanoClock(new DummyNanoClock(87654));
verifyNanoTimeWithAllConstructors(87654);
}
@SuppressWarnings("deprecation")
private void verifyNanoTimeWithAllConstructors(final long expected) {
assertEquals(expected, Log4jLogEvent.getNanoClock().nanoTime());
assertEquals("No-arg constructor", expected, new Log4jLogEvent().getNanoTime());
assertEquals("1-arg constructor", expected, new Log4jLogEvent(98).getNanoTime());
assertEquals("6-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null).getNanoTime());
assertEquals("7-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null)
.getNanoTime());
assertEquals("11-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null, null,
null, null, 0).getNanoTime());
assertEquals("12-arg factory method", expected, Log4jLogEvent.createEvent("l", null, "a", null, null, null,
null, null, null, null, null, 0).getNanoTime());
}
@Test
public void testBuilderCorrectlyCopiesAllEventAttributes() {
final Map<String, String> contextMap = new HashMap<>();
contextMap.put("A", "B");
final ContextStack contextStack = ThreadContext.getImmutableStack();
final Exception exception = new Exception("test");
final Marker marker = MarkerManager.getMarker("EVENTTEST");
final Message message = new SimpleMessage("foo");
final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
final String fqcn = "qualified";
final String name = "Ceci n'est pas une pipe";
final String threadName = "threadName";
final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
.setContextMap(contextMap) //
.setContextStack(contextStack) //
.setEndOfBatch(true) //
.setIncludeLocation(true) //
.setLevel(Level.FATAL) //
.setLoggerFqcn(fqcn) //
.setLoggerName(name) //
.setMarker(marker) //
.setMessage(message) //
.setNanoTime(1234567890L) //
.setSource(stackTraceElement) //
.setThreadName(threadName) //
.setThrown(exception) //
.setTimeMillis(987654321L)
.build();
assertEquals(contextMap, event.getContextMap());
assertSame(contextStack, event.getContextStack());
assertEquals(true, event.isEndOfBatch());
assertEquals(true, event.isIncludeLocation());
assertSame(Level.FATAL, event.getLevel());
assertSame(fqcn, event.getLoggerFqcn());
assertSame(name, event.getLoggerName());
assertSame(marker, event.getMarker());
assertSame(message, event.getMessage());
assertEquals(1234567890L, event.getNanoTime());
assertSame(stackTraceElement, event.getSource());
assertSame(threadName, event.getThreadName());
assertSame(exception, event.getThrown());
assertEquals(987654321L, event.getTimeMillis());
final LogEvent event2 = new Log4jLogEvent.Builder(event).build();
assertEquals("copy constructor builder", event2, event);
assertEquals("same hashCode", event2.hashCode(), event.hashCode());
}
@Test
public void testBuilderCorrectlyCopiesAllEventAttributesInclContextData() {
final MutableContextData contextData = new ArrayContextData();
contextData.putValue("A", "B");
final ContextStack contextStack = ThreadContext.getImmutableStack();
final Exception exception = new Exception("test");
final Marker marker = MarkerManager.getMarker("EVENTTEST");
final Message message = new SimpleMessage("foo");
final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
final String fqcn = "qualified";
final String name = "Ceci n'est pas une pipe";
final String threadName = "threadName";
final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
.setContextData(contextData) //
.setContextStack(contextStack) //
.setEndOfBatch(true) //
.setIncludeLocation(true) //
.setLevel(Level.FATAL) //
.setLoggerFqcn(fqcn) //
.setLoggerName(name) //
.setMarker(marker) //
.setMessage(message) //
.setNanoTime(1234567890L) //
.setSource(stackTraceElement) //
.setThreadName(threadName) //
.setThrown(exception) //
.setTimeMillis(987654321L)
.build();
assertSame(contextData, event.getContextData());
assertSame(contextStack, event.getContextStack());
assertEquals(true, event.isEndOfBatch());
assertEquals(true, event.isIncludeLocation());
assertSame(Level.FATAL, event.getLevel());
assertSame(fqcn, event.getLoggerFqcn());
assertSame(name, event.getLoggerName());
assertSame(marker, event.getMarker());
assertSame(message, event.getMessage());
assertEquals(1234567890L, event.getNanoTime());
assertSame(stackTraceElement, event.getSource());
assertSame(threadName, event.getThreadName());
assertSame(exception, event.getThrown());
assertEquals(987654321L, event.getTimeMillis());
final LogEvent event2 = new Log4jLogEvent.Builder(event).build();
assertEquals("copy constructor builder", event2, event);
assertEquals("same hashCode", event2.hashCode(), event.hashCode());
}
@Test
public void testBuilderCorrectlyCopiesMutableLogEvent() throws Exception {
final MutableContextData contextData = new ArrayContextData();
contextData.putValue("A", "B");
final ContextStack contextStack = ThreadContext.getImmutableStack();
final Exception exception = new Exception("test");
final Marker marker = MarkerManager.getMarker("EVENTTEST");
final Message message = new SimpleMessage("foo");
new StackTraceElement("A", "B", "file", 123);
final String fqcn = "qualified";
final String name = "Ceci n'est pas une pipe";
final String threadName = "threadName";
final MutableLogEvent event = new MutableLogEvent();
event.setContextData(contextData);
event.setContextStack(contextStack);
event.setEndOfBatch(true);
event.setIncludeLocation(true);
//event.setSource(stackTraceElement); // cannot be explicitly set
event.setLevel(Level.FATAL);
event.setLoggerFqcn(fqcn);
event.setLoggerName(name);
event.setMarker(marker);
event.setMessage(message);
event.setNanoTime(1234567890L);
event.setThreadName(threadName);
event.setThrown(exception);
event.setTimeMillis(987654321L);
assertSame(contextData, event.getContextData());
assertSame(contextStack, event.getContextStack());
assertEquals(true, event.isEndOfBatch());
assertEquals(true, event.isIncludeLocation());
assertSame(Level.FATAL, event.getLevel());
assertSame(fqcn, event.getLoggerFqcn());
assertSame(name, event.getLoggerName());
assertSame(marker, event.getMarker());
assertSame(message, event.getMessage());
assertEquals(1234567890L, event.getNanoTime());
//assertSame(stackTraceElement, event.getSource()); // don't invoke
assertSame(threadName, event.getThreadName());
assertSame(exception, event.getThrown());
assertEquals(987654321L, event.getTimeMillis());
final LogEvent e2 = new Log4jLogEvent.Builder(event).build();
assertEquals(contextData, e2.getContextData());
assertSame(contextStack, e2.getContextStack());
assertEquals(true, e2.isEndOfBatch());
assertEquals(true, e2.isIncludeLocation());
assertSame(Level.FATAL, e2.getLevel());
assertSame(fqcn, e2.getLoggerFqcn());
assertSame(name, e2.getLoggerName());
assertSame(marker, e2.getMarker());
assertSame(message, e2.getMessage());
assertEquals(1234567890L, e2.getNanoTime());
//assertSame(stackTraceElement, e2.getSource()); // don't invoke
assertSame(threadName, e2.getThreadName());
assertSame(exception, e2.getThrown());
assertEquals(987654321L, e2.getTimeMillis());
// use reflection to get value of source field in log event copy:
// invoking the getSource() method would initialize the field
final Field fieldSource = Log4jLogEvent.class.getDeclaredField("source");
fieldSource.setAccessible(true);
final Object value = fieldSource.get(e2);
assertNull("source in copy", value);
}
@Test
public void testEquals() {
final Map<String, String> contextMap = new HashMap<>();
contextMap.put("A", "B");
ThreadContext.push("first");
final ContextStack contextStack = ThreadContext.getImmutableStack();
final Exception exception = new Exception("test");
final Marker marker = MarkerManager.getMarker("EVENTTEST");
final Message message = new SimpleMessage("foo");
final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
final String fqcn = "qualified";
final String name = "Ceci n'est pas une pipe";
final String threadName = "threadName";
final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
.setContextMap(contextMap) //
.setContextStack(contextStack) //
.setEndOfBatch(true) //
.setIncludeLocation(true) //
.setLevel(Level.FATAL) //
.setLoggerFqcn(fqcn) //
.setLoggerName(name) //
.setMarker(marker) //
.setMessage(message) //
.setNanoTime(1234567890L) //
.setSource(stackTraceElement) //
.setThreadName(threadName) //
.setThrown(exception) //
.setTimeMillis(987654321L)
.build();
assertEquals(contextMap, event.getContextMap());
assertSame(contextStack, event.getContextStack());
assertEquals(true, event.isEndOfBatch());
assertEquals(true, event.isIncludeLocation());
assertSame(Level.FATAL, event.getLevel());
assertSame(fqcn, event.getLoggerFqcn());
assertSame(name, event.getLoggerName());
assertSame(marker, event.getMarker());
assertSame(message, event.getMessage());
assertEquals(1234567890L, event.getNanoTime());
assertSame(stackTraceElement, event.getSource());
assertSame(threadName, event.getThreadName());
assertSame(exception, event.getThrown());
assertEquals(987654321L, event.getTimeMillis());
final LogEvent event2 = builder(event).build();
assertEquals("copy constructor builder", event2, event);
assertEquals("same hashCode", event2.hashCode(), event.hashCode());
assertEquals(contextMap, event2.getContextMap());
assertSame(contextStack, event2.getContextStack());
assertEquals(true, event2.isEndOfBatch());
assertEquals(true, event2.isIncludeLocation());
assertSame(Level.FATAL, event2.getLevel());
assertSame(fqcn, event2.getLoggerFqcn());
assertSame(name, event2.getLoggerName());
assertSame(marker, event2.getMarker());
assertSame(message, event2.getMessage());
assertEquals(1234567890L, event2.getNanoTime());
assertSame(stackTraceElement, event2.getSource());
assertSame(threadName, event2.getThreadName());
assertSame(exception, event2.getThrown());
assertEquals(987654321L, event2.getTimeMillis());
final Map<String, String> differentMap = Collections.emptyMap();
different("different contextMap", builder(event).setContextMap(differentMap), event);
different("null contextMap", builder(event).setContextMap(null), event);
ThreadContext.push("abc");
final ContextStack contextStack2 = ThreadContext.getImmutableStack();
different("different contextStack", builder(event).setContextStack(contextStack2), event);
different("null contextStack", builder(event).setContextStack(null), event);
different("different EndOfBatch", builder(event).setEndOfBatch(false), event);
different("different IncludeLocation", builder(event).setIncludeLocation(false), event);
different("different level", builder(event).setLevel(Level.INFO), event);
different("null level", builder(event).setLevel(null), event);
different("different fqcn", builder(event).setLoggerFqcn("different"), event);
different("null fqcn", builder(event).setLoggerFqcn(null), event);
different("different name", builder(event).setLoggerName("different"), event);
try { // TODO null logger name throws NPE in equals. Use Objects.requireNonNull in constructor?
different("null name", builder(event).setLoggerName(null), event);
fail("Expected NullPointerException");
} catch (final NullPointerException ok) {
}
different("different marker", builder(event).setMarker(MarkerManager.getMarker("different")), event);
different("null marker", builder(event).setMarker(null), event);
different("different message", builder(event).setMessage(new ObjectMessage("different")), event);
try { // TODO null message throws NPE in equals(). Use Objects.requireNonNull in constructor?
different("null message", builder(event).setMessage(null), event);
fail("Expected NullPointerException");
} catch (final NullPointerException ok) {
}
different("different nanoTime", builder(event).setNanoTime(135), event);
different("different milliTime", builder(event).setTimeMillis(137), event);
final StackTraceElement stack2 = new StackTraceElement("XXX", "YYY", "file", 123);
different("different source", builder(event).setSource(stack2), event);
different("null source", builder(event).setSource(null), event);
different("different threadname", builder(event).setThreadName("different"), event);
different("null threadname", builder(event).setThreadName(null), event);
different("different exception", builder(event).setThrown(new Error("Boo!")), event);
different("null exception", builder(event).setThrown(null), event);
}
private static Log4jLogEvent.Builder builder(final LogEvent event) {
return new Log4jLogEvent.Builder(event);
}
private void different(final String reason, final Log4jLogEvent.Builder builder, final LogEvent event) {
final LogEvent other = builder.build();
assertNotEquals(reason, other, event);
assertNotEquals(reason + " hashCode", other.hashCode(), event.hashCode());
}
}