| /* |
| * 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.jackson.json.layout; |
| |
| import static org.hamcrest.CoreMatchers.containsString; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.nio.charset.Charset; |
| import java.nio.charset.StandardCharsets; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.logging.log4j.Level; |
| import org.apache.logging.log4j.ThreadContext; |
| import org.apache.logging.log4j.core.test.categories.Layouts; |
| import org.apache.logging.log4j.core.Appender; |
| import org.apache.logging.log4j.core.Logger; |
| import org.apache.logging.log4j.core.LoggerContext; |
| import org.apache.logging.log4j.core.async.RingBufferLogEvent; |
| import org.apache.logging.log4j.core.config.Configuration; |
| import org.apache.logging.log4j.core.config.ConfigurationFactory; |
| import org.apache.logging.log4j.core.impl.Log4jLogEvent; |
| import org.apache.logging.log4j.core.impl.MutableLogEvent; |
| import org.apache.logging.log4j.core.lookup.JavaLookup; |
| import org.apache.logging.log4j.core.test.BasicConfigurationFactory; |
| import org.apache.logging.log4j.core.test.layout.LogEventFixtures; |
| import org.apache.logging.log4j.core.time.internal.DummyNanoClock; |
| import org.apache.logging.log4j.core.time.internal.SystemClock; |
| import org.apache.logging.log4j.core.util.KeyValuePair; |
| import org.apache.logging.log4j.jackson.AbstractJacksonLayout; |
| import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; |
| import org.apache.logging.log4j.message.Message; |
| import org.apache.logging.log4j.message.ObjectMessage; |
| import org.apache.logging.log4j.message.ParameterizedMessage; |
| import org.apache.logging.log4j.message.ReusableMessageFactory; |
| import org.apache.logging.log4j.message.SimpleMessage; |
| import org.apache.logging.log4j.spi.AbstractLogger; |
| import org.apache.logging.log4j.core.test.appender.ListAppender; |
| import org.apache.logging.log4j.util.SortedArrayStringMap; |
| import org.apache.logging.log4j.util.Strings; |
| import org.junit.AfterClass; |
| import org.junit.Assert; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| /** |
| * Tests the JsonLayout class. |
| */ |
| @Category(Layouts.Json.class) |
| public class JsonLayoutTest { |
| private static class TestClass { |
| private int value; |
| |
| public int getValue() { |
| return value; |
| } |
| |
| public void setValue(final int value) { |
| this.value = value; |
| } |
| } |
| |
| static ConfigurationFactory cf = new BasicConfigurationFactory(); |
| |
| private static final String DQUOTE = "\""; |
| |
| @AfterClass |
| public static void cleanupClass() { |
| ConfigurationFactory.removeConfigurationFactory(cf); |
| ThreadContext.clearAll(); |
| } |
| |
| @BeforeClass |
| public static void setupClass() { |
| ThreadContext.clearAll(); |
| ConfigurationFactory.setConfigurationFactory(cf); |
| final LoggerContext ctx = LoggerContext.getContext(); |
| ctx.reconfigure(); |
| } |
| |
| LoggerContext ctx = LoggerContext.getContext(); |
| |
| Logger rootLogger = this.ctx.getRootLogger(); |
| |
| private void checkAt(final String expected, final int lineIndex, final List<String> list) { |
| final String trimedLine = list.get(lineIndex).trim(); |
| assertTrue("Incorrect line index " + lineIndex + ": " + Strings.dquote(trimedLine), trimedLine.equals(expected)); |
| } |
| |
| private void checkContains(final String expected, final List<String> list) { |
| for (final String string : list) { |
| final String trimedLine = string.trim(); |
| if (trimedLine.equals(expected)) { |
| return; |
| } |
| } |
| Assert.fail("Cannot find " + expected + " in " + list); |
| } |
| |
| private void checkMapEntry(final String key, final String value, final boolean compact, final String str, |
| final boolean contextMapAslist) { |
| this.toPropertySeparator(compact); |
| if (contextMapAslist) { |
| // {"key":"KEY", "value":"VALUE"} |
| final String expected = String.format("{\"key\":\"%s\",\"value\":\"%s\"}", key, value); |
| assertTrue("Cannot find contextMapAslist " + expected + " in " + str, str.contains(expected)); |
| } else { |
| // "KEY":"VALUE" |
| final String expected = String.format("\"%s\":\"%s\"", key, value); |
| assertTrue("Cannot find contextMap " + expected + " in " + str, str.contains(expected)); |
| } |
| } |
| |
| private void checkProperty(final String key, final String value, final boolean compact, final String str) { |
| final String propSep = this.toPropertySeparator(compact); |
| // {"key":"MDC.B","value":"B_Value"} |
| final String expected = String.format("\"%s\"%s\"%s\"", key, propSep, value); |
| assertTrue("Cannot find " + expected + " in " + str, str.contains(expected)); |
| } |
| |
| private void checkPropertyName(final String name, final boolean compact, final String str) { |
| final String propSep = this.toPropertySeparator(compact); |
| assertTrue(str, str.contains(DQUOTE + name + DQUOTE + propSep)); |
| } |
| |
| private void checkPropertyNameAbsent(final String name, final boolean compact, final String str) { |
| final String propSep = this.toPropertySeparator(compact); |
| assertFalse(str, str.contains(DQUOTE + name + DQUOTE + propSep)); |
| } |
| |
| private String prepareJsonForObjectMessageAsJsonObjectTests(final int value, final boolean objectMessageAsJsonObject) { |
| final TestClass testClass = new TestClass(); |
| testClass.setValue(value); |
| // @formatter:off |
| final Log4jLogEvent expected = Log4jLogEvent.newBuilder() |
| .setLoggerName("a.B") |
| .setLoggerFqcn("f.q.c.n") |
| .setLevel(Level.DEBUG) |
| .setMessage(new ObjectMessage(testClass)) |
| .setThreadName("threadName") |
| .setTimeMillis(1).build(); |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setCompact(true) |
| .setObjectMessageAsJsonObject(objectMessageAsJsonObject) |
| .build(); |
| // @formatter:off |
| return layout.toSerializable(expected); |
| } |
| |
| private String prepareJsonForStacktraceTests(final boolean stacktraceAsString) { |
| final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setCompact(true) |
| .setIncludeStacktrace(true) |
| .setStacktraceAsString(stacktraceAsString) |
| .build(); |
| // @formatter:off |
| return layout.toSerializable(expected); |
| } |
| |
| @Test |
| public void testAdditionalFields() throws Exception { |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setIncludeStacktrace(false) |
| .setAdditionalFields(new KeyValuePair[] { |
| new KeyValuePair("KEY1", "VALUE1"), |
| new KeyValuePair("KEY2", "${java:runtime}"), }) |
| .setCharset(StandardCharsets.UTF_8) |
| .setConfiguration(ctx.getConfiguration()) |
| .build(); |
| final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); |
| assertTrue(str, str.contains("\"KEY1\":\"VALUE1\"")); |
| assertTrue(str, str.contains("\"KEY2\":\"" + new JavaLookup().getRuntime() + "\"")); |
| } |
| |
| @Test |
| public void testMutableLogEvent() throws Exception { |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setIncludeStacktrace(false) |
| .setAdditionalFields(new KeyValuePair[] { |
| new KeyValuePair("KEY1", "VALUE1"), |
| new KeyValuePair("KEY2", "${java:runtime}"), }) |
| .setCharset(StandardCharsets.UTF_8) |
| .setConfiguration(ctx.getConfiguration()) |
| .build(); |
| Log4jLogEvent logEvent = LogEventFixtures.createLogEvent(); |
| final MutableLogEvent mutableEvent = new MutableLogEvent(); |
| mutableEvent.initFrom(logEvent); |
| final String strLogEvent = layout.toSerializable(logEvent); |
| final String strMutableEvent = layout.toSerializable(mutableEvent); |
| assertEquals(strMutableEvent, strLogEvent, strMutableEvent); |
| } |
| |
| private void testAllFeatures(final boolean locationInfo, final boolean compact, final boolean eventEol, |
| final String endOfLine, final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) |
| throws Exception { |
| final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(locationInfo) |
| .setProperties(includeContext) |
| .setPropertiesAsList(contextMapAslist) |
| .setComplete(false) |
| .setCompact(compact) |
| .setEventEol(eventEol) |
| .setEndOfLine(endOfLine) |
| .setCharset(StandardCharsets.UTF_8) |
| .setIncludeStacktrace(includeStacktrace) |
| .build(); |
| // @formatter:off |
| final String str = layout.toSerializable(expected); |
| this.toPropertySeparator(compact); |
| if (endOfLine == null) { |
| // Just check for \n since \r might or might not be there. |
| assertEquals(str, !compact || eventEol, str.contains("\n")); |
| } |
| else { |
| assertEquals(str, !compact || eventEol, str.contains(endOfLine)); |
| assertEquals(str, compact && eventEol, str.endsWith(endOfLine)); |
| } |
| assertEquals(str, locationInfo, str.contains("source")); |
| assertEquals(str, includeContext, str.contains("contextMap")); |
| final Log4jLogEvent actual = new Log4jJsonObjectMapper(contextMapAslist, includeStacktrace, false, false).readValue(str, Log4jLogEvent.class); |
| LogEventFixtures.assertEqualLogEvents(expected, actual, locationInfo, includeContext, includeStacktrace); |
| if (includeContext) { |
| this.checkMapEntry("MDC.A", "A_Value", compact, str, contextMapAslist); |
| this.checkMapEntry("MDC.B", "B_Value", compact, str, contextMapAslist); |
| } |
| // |
| assertNull(actual.getThrown()); |
| // make sure the names we want are used |
| this.checkPropertyName("instant", compact, str); |
| this.checkPropertyName("thread", compact, str); // and not threadName |
| this.checkPropertyName("level", compact, str); |
| this.checkPropertyName("loggerName", compact, str); |
| this.checkPropertyName("marker", compact, str); |
| this.checkPropertyName("name", compact, str); |
| this.checkPropertyName("parents", compact, str); |
| this.checkPropertyName("message", compact, str); |
| this.checkPropertyName("thrown", compact, str); |
| this.checkPropertyName("cause", compact, str); |
| this.checkPropertyName("commonElementCount", compact, str); |
| this.checkPropertyName("localizedMessage", compact, str); |
| if (includeStacktrace) { |
| this.checkPropertyName("extendedStackTrace", compact, str); |
| this.checkPropertyName("class", compact, str); |
| this.checkPropertyName("method", compact, str); |
| this.checkPropertyName("file", compact, str); |
| this.checkPropertyName("line", compact, str); |
| this.checkPropertyName("exact", compact, str); |
| this.checkPropertyName("location", compact, str); |
| this.checkPropertyName("version", compact, str); |
| } else { |
| this.checkPropertyNameAbsent("extendedStackTrace", compact, str); |
| } |
| this.checkPropertyName("suppressed", compact, str); |
| this.checkPropertyName("loggerFqcn", compact, str); |
| this.checkPropertyName("endOfBatch", compact, str); |
| if (includeContext) { |
| this.checkPropertyName("contextMap", compact, str); |
| } else { |
| this.checkPropertyNameAbsent("contextMap", compact, str); |
| } |
| this.checkPropertyName("contextStack", compact, str); |
| if (locationInfo) { |
| this.checkPropertyName("source", compact, str); |
| } else { |
| this.checkPropertyNameAbsent("source", compact, str); |
| } |
| // check some attrs |
| this.checkProperty("loggerFqcn", "f.q.c.n", compact, str); |
| this.checkProperty("loggerName", "a.B", compact, str); |
| } |
| |
| @Test |
| public void testContentType() { |
| final AbstractJacksonLayout layout = JsonLayout.createDefaultLayout(); |
| assertEquals("application/json; charset=UTF-8", layout.getContentType()); |
| } |
| |
| @Test |
| public void testDefaultCharset() { |
| final AbstractJacksonLayout layout = JsonLayout.createDefaultLayout(); |
| assertEquals(StandardCharsets.UTF_8, layout.getCharset()); |
| } |
| |
| @Test |
| public void testEscapeLayout() throws Exception { |
| final Map<String, Appender> appenders = this.rootLogger.getAppenders(); |
| for (final Appender appender : appenders.values()) { |
| this.rootLogger.removeAppender(appender); |
| } |
| final Configuration configuration = rootLogger.getContext().getConfiguration(); |
| // set up appender |
| final boolean propertiesAsList = false; |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setConfiguration(configuration) |
| .setLocationInfo(true) |
| .setProperties(true) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(true) |
| .setCompact(false) |
| .setEventEol(false) |
| .setIncludeStacktrace(true) |
| .build(); |
| // @formatter:on |
| final ListAppender appender = new ListAppender("List", null, layout, true, false); |
| appender.start(); |
| |
| // set appender on root and set level to debug |
| this.rootLogger.addAppender(appender); |
| this.rootLogger.setLevel(Level.DEBUG); |
| |
| // output starting message |
| this.rootLogger.debug("Here is a quote ' and then a double quote \""); |
| |
| appender.stop(); |
| |
| final List<String> list = appender.getMessages(); |
| |
| this.checkAt("[", 0, list); |
| this.checkAt("{", 1, list); |
| this.checkContains("\"level\" : \"DEBUG\",", list); |
| this.checkContains("\"message\" : \"Here is a quote ' and then a double quote \\\"\",", list); |
| this.checkContains("\"loggerFqcn\" : \"" + AbstractLogger.class.getName() + "\",", list); |
| for (final Appender app : appenders.values()) { |
| this.rootLogger.addAppender(app); |
| } |
| } |
| |
| @Test |
| public void testExcludeStacktrace() throws Exception { |
| this.testAllFeatures(false, false, false, null, false, false, false); |
| } |
| |
| @Test |
| public void testLocationOnCustomEndOfLine() throws Exception { |
| this.testAllFeatures(true, true, true, "CUSTOM_END_OF_LINE", true, false, true); |
| } |
| |
| @Test |
| public void testIncludeNullDelimiterFalse() throws Exception { |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setCompact(true) |
| .setIncludeNullDelimiter(false) |
| .build(); |
| final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); |
| assertFalse(str.endsWith("\0")); |
| } |
| |
| @Test |
| public void testIncludeNullDelimiterTrue() throws Exception { |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setCompact(true) |
| .setIncludeNullDelimiter(true) |
| .build(); |
| final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); |
| assertTrue(str.endsWith("\0")); |
| } |
| |
| /** |
| * Test case for MDC conversion pattern. |
| */ |
| @Test |
| public void testLayout() throws Exception { |
| final Map<String, Appender> appenders = this.rootLogger.getAppenders(); |
| for (final Appender appender : appenders.values()) { |
| this.rootLogger.removeAppender(appender); |
| } |
| final Configuration configuration = rootLogger.getContext().getConfiguration(); |
| // set up appender |
| // Use [[ and ]] to test header and footer (instead of [ and ]) |
| final boolean propertiesAsList = false; |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setConfiguration(configuration) |
| .setLocationInfo(true) |
| .setProperties(true) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(true) |
| .setCompact(false) |
| .setEventEol(false) |
| .setHeader("[[".getBytes(Charset.defaultCharset())) |
| .setFooter("]]".getBytes(Charset.defaultCharset())) |
| .setIncludeStacktrace(true) |
| .build(); |
| // @formatter:on |
| final ListAppender appender = new ListAppender("List", null, layout, true, false); |
| appender.start(); |
| |
| // set appender on root and set level to debug |
| this.rootLogger.addAppender(appender); |
| this.rootLogger.setLevel(Level.DEBUG); |
| |
| // output starting message |
| this.rootLogger.debug("starting mdc pattern test"); |
| |
| this.rootLogger.debug("empty mdc"); |
| |
| ThreadContext.put("key1", "value1"); |
| ThreadContext.put("key2", "value2"); |
| |
| this.rootLogger.debug("filled mdc"); |
| |
| ThreadContext.remove("key1"); |
| ThreadContext.remove("key2"); |
| |
| this.rootLogger.error("finished mdc pattern test", new NullPointerException("test")); |
| |
| appender.stop(); |
| |
| final List<String> list = appender.getMessages(); |
| |
| this.checkAt("[[", 0, list); |
| this.checkAt("{", 1, list); |
| this.checkContains("\"loggerFqcn\" : \"" + AbstractLogger.class.getName() + "\",", list); |
| this.checkContains("\"level\" : \"DEBUG\",", list); |
| this.checkContains("\"message\" : \"starting mdc pattern test\",", list); |
| for (final Appender app : appenders.values()) { |
| this.rootLogger.addAppender(app); |
| } |
| } |
| |
| @Test |
| public void testLayoutLoggerName() throws Exception { |
| final boolean propertiesAsList = false; |
| // @formatter:off |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setCharset(StandardCharsets.UTF_8) |
| .setIncludeStacktrace(true) |
| .build(); |
| // @formatter:on |
| // @formatter:off |
| final Log4jLogEvent expected = Log4jLogEvent.newBuilder() |
| .setLoggerName("a.B") |
| .setLoggerFqcn("f.q.c.n") |
| .setLevel(Level.DEBUG) |
| .setMessage(new SimpleMessage("M")) |
| .setThreadName("threadName") |
| .setTimeMillis(1).build(); |
| // @formatter:on |
| final String str = layout.toSerializable(expected); |
| assertTrue(str, str.contains("\"loggerName\":\"a.B\"")); |
| final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); |
| assertEquals(expected.getLoggerName(), actual.getLoggerName()); |
| assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testLayoutMessageWithCurlyBraces() throws Exception { |
| final boolean propertiesAsList = false; |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setCharset(StandardCharsets.UTF_8) |
| .setIncludeStacktrace(true) |
| .build(); |
| final Log4jLogEvent expected = Log4jLogEvent.newBuilder() |
| .setLoggerName("a.B") |
| .setLoggerFqcn("f.q.c.n") |
| .setLevel(Level.DEBUG) |
| .setMessage(new ParameterizedMessage("Testing {}", new TestObj())) |
| .setThreadName("threadName") |
| .setTimeMillis(1).build(); |
| final String str = layout.toSerializable(expected); |
| final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; |
| assertTrue(str, str.contains("\"message\":\"" + expectedMessage + '"')); |
| final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); |
| assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); |
| } |
| |
| // Test for LOG4J2-2345 |
| @Test |
| public void testReusableLayoutMessageWithCurlyBraces() throws Exception { |
| final boolean propertiesAsList = false; |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setCharset(StandardCharsets.UTF_8) |
| .setIncludeStacktrace(true) |
| .build(); |
| Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj()); |
| try { |
| final Log4jLogEvent expected = Log4jLogEvent.newBuilder() |
| .setLoggerName("a.B") |
| .setLoggerFqcn("f.q.c.n") |
| .setLevel(Level.DEBUG) |
| .setMessage(message) |
| .setThreadName("threadName") |
| .setTimeMillis(1).build(); |
| MutableLogEvent mutableLogEvent = new MutableLogEvent(); |
| mutableLogEvent.initFrom(expected); |
| final String str = layout.toSerializable(mutableLogEvent); |
| final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; |
| assertTrue(str, str.contains("\"message\":\"" + expectedMessage + '"')); |
| final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); |
| assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); |
| } finally { |
| ReusableMessageFactory.release(message); |
| } |
| } |
| |
| // Test for LOG4J2-2312 LOG4J2-2341 |
| @Test |
| public void testLayoutRingBufferEventReusableMessageWithCurlyBraces() throws Exception { |
| final boolean propertiesAsList = false; |
| final AbstractJacksonLayout layout = JsonLayout.newBuilder() |
| .setLocationInfo(false) |
| .setProperties(false) |
| .setPropertiesAsList(propertiesAsList) |
| .setComplete(false) |
| .setCompact(true) |
| .setEventEol(false) |
| .setCharset(StandardCharsets.UTF_8) |
| .setIncludeStacktrace(true) |
| .build(); |
| Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj()); |
| try { |
| RingBufferLogEvent ringBufferEvent = new RingBufferLogEvent(); |
| ringBufferEvent.setValues( |
| null, "a.B", null, "f.q.c.n", Level.DEBUG, message, |
| null, new SortedArrayStringMap(), ThreadContext.EMPTY_STACK, 1L, |
| "threadName", 1, null, new SystemClock(), new DummyNanoClock()); |
| final String str = layout.toSerializable(ringBufferEvent); |
| final String expectedMessage = "Testing " + TestObj.TO_STRING_VALUE; |
| assertThat(str, containsString("\"message\":\"" + expectedMessage + '"')); |
| final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class); |
| assertEquals(expectedMessage, actual.getMessage().getFormattedMessage()); |
| } finally { |
| ReusableMessageFactory.release(message); |
| } |
| } |
| |
| static class TestObj { |
| static final String TO_STRING_VALUE = "This is my toString {} with curly braces"; |
| @Override |
| public String toString() { |
| return TO_STRING_VALUE; |
| } |
| } |
| |
| @Test |
| public void testLocationOffCompactOffMdcOff() throws Exception { |
| this.testAllFeatures(false, false, false, null, false, false, true); |
| } |
| |
| @Test |
| public void testLocationOnCompactOnEventEolOnMdcOn() throws Exception { |
| this.testAllFeatures(true, true, true, null, true, false, true); |
| } |
| |
| @Test |
| public void testLocationOnCompactOnEventEolOnMdcOnMdcAsList() throws Exception { |
| this.testAllFeatures(true, true, true, null, true, true, true); |
| } |
| |
| @Test |
| public void testLocationOnCompactOnMdcOn() throws Exception { |
| this.testAllFeatures(true, true, false, null, true, false, true); |
| } |
| |
| @Test |
| public void testObjectMessageAsJsonObject() { |
| final String str = prepareJsonForObjectMessageAsJsonObjectTests(1234, true); |
| assertTrue(str, str.contains("\"message\":{\"value\":1234}")); |
| } |
| |
| @Test |
| public void testObjectMessageAsJsonString() { |
| final String str = prepareJsonForObjectMessageAsJsonObjectTests(1234, false); |
| assertTrue(str, str.contains("\"message\":\"" + this.getClass().getCanonicalName() + "$TestClass@")); |
| } |
| |
| @Test |
| public void testStacktraceAsNonString() throws Exception { |
| final String str = prepareJsonForStacktraceTests(false); |
| assertTrue(str, str.contains("\"extendedStackTrace\":[")); |
| } |
| |
| @Test |
| public void testStacktraceAsString() throws Exception { |
| final String str = prepareJsonForStacktraceTests(true); |
| assertTrue(str, str.contains("\"extendedStackTrace\":\"java.lang.NullPointerException")); |
| } |
| |
| private String toPropertySeparator(final boolean compact) { |
| return compact ? ":" : " : "; |
| } |
| |
| @Test // LOG4J2-2749 (#362) |
| public void testEmptyValuesAreIgnored() { |
| final AbstractJacksonLayout layout = JsonLayout |
| .newBuilder() |
| .setAdditionalFields(new KeyValuePair[] { |
| new KeyValuePair("empty", "${ctx:empty:-}") |
| }) |
| .setConfiguration(ctx.getConfiguration()) |
| .build(); |
| final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); |
| assertFalse(str, str.contains("\"empty\"")); |
| } |
| |
| } |