@Override protected Object newEvent(LogDetails logDetails) { final Message message = new SimpleMessage(logDetails.getLogMessage()); final StringMap contextData; if (!logDetails.getMdc().isEmpty()) { contextData = ContextDataFactory.createContextData(); logDetails.getMdc().entrySet().forEach(it -> contextData.putValue(it.getKey(), it.getValue())); } else { contextData = null; } Log4jLogEvent.Builder builder = Log4jLogEvent.newBuilder().setLoggerName(logDetails.getClassName()) .setTimeMillis(logDetails.getTimeMillis()).setLevel(Level.DEBUG).setContextData(contextData) .setIncludeLocation(logDetails.isLocationInfo()).setLoggerFqcn(logDetails.getClassName()).setMessage(message); if (logDetails.isLocationInfo()) { builder.setSource(new StackTraceElement(logDetails.getClassName(), logDetails.getMethodName(), logDetails.getFileName(), logDetails.getLineNumber())); } if (logDetails.getException() != null) { builder.setThrown(logDetails.getException()); } return builder.build(); }
@Override public ReadOnlyStringMap convertToEntityAttribute(final String s) { if (Strings.isEmpty(s)) { return null; } try { final StringMap result = ContextDataFactory.createContextData(); final ObjectNode root = (ObjectNode) OBJECT_MAPPER.readTree(s); final Iterator<Map.Entry<String, JsonNode>> entries = root.fields(); while (entries.hasNext()) { final Map.Entry<String, JsonNode> entry = entries.next(); // Don't know what to do with non-text values. // Maybe users who need this need to provide custom converter? final Object value = entry.getValue().textValue(); result.putValue(entry.getKey(), value); } return result; } catch (final IOException e) { throw new PersistenceException("Failed to convert JSON string to map.", e); } }
@Override public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException { // Sanity check: verify that we got "Json Object": // JsonToken tok = jp.nextToken(); // if (tok != JsonToken.START_OBJECT) { // throw new IOException("Expected data to start with an Object"); // } final StringMap contextData = ContextDataFactory.createContextData(); // Iterate over object fields: while (jp.nextToken() != JsonToken.END_OBJECT) { final String fieldName = jp.getCurrentName(); // move to value jp.nextToken(); contextData.putValue(fieldName, jp.getText()); } return contextData; }
@SuppressWarnings("deprecation") static void assertEqualLogEvents(final LogEvent expected, final LogEvent actual, final boolean includeSource, final boolean includeContext, final boolean includeStacktrace) { assertEquals(expected.getClass(), actual.getClass()); assertEquals(includeContext ? expected.getContextData() : ContextDataFactory.createContextData(), actual.getContextData()); assertEquals(includeContext ? expected.getContextMap() : Collections.EMPTY_MAP, actual.getContextMap()); assertEquals(expected.getContextStack(), actual.getContextStack()); assertEquals(expected.getLevel(), actual.getLevel()); assertEquals(expected.getLoggerName(), actual.getLoggerName()); assertEquals(expected.getLoggerFqcn(), actual.getLoggerFqcn()); assertEquals(expected.getMarker(), actual.getMarker()); assertEquals(expected.getMessage(), actual.getMessage()); assertEquals(expected.getTimeMillis(), actual.getTimeMillis()); assertEquals(includeSource ? expected.getSource() : null, actual.getSource()); assertEquals(expected.getThreadName(), actual.getThreadName()); assertNotNull("original should have an exception", expected.getThrown()); assertNull("exception should not be serialized", actual.getThrown()); if (includeStacktrace) { // TODO should compare the rest of the ThrowableProxy assertEquals(expected.getThrownProxy(), actual.getThrownProxy()); } assertEquals(expected.isEndOfBatch(), actual.isEndOfBatch()); assertEquals(expected.isIncludeLocation(), actual.isIncludeLocation()); // original: non-null thrown & null thrownProxy // deserialized: null thrown & non-null thrownProxy assertNotEquals(expected.hashCode(), actual.hashCode()); assertNotEquals(expected, actual); }
@Test public void testConverter1() { final StringMap contextMap = ContextDataFactory.createContextData(1); contextMap.putValue("key1", "value1"); final String expected = "{{key1,value1}}"; test(contextMap, expected, null); }
@Test public void testConverter2() { final StringMap contextMap = ContextDataFactory.createContextData(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); final String expected = "{{key1,value1}{key2,value2}}"; test(contextMap, expected, null); }
@Test public void testConverterWithKey() { final StringMap contextMap = ContextDataFactory.createContextData(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); final String expected = "value1"; test(contextMap, expected, new String[] {"key1"}); }
@Test public void testWithPropertiesAndLocationInfo() { final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(true, true); final StringMap contextMap = ContextDataFactory.createContextData(2); contextMap.putValue("key1", "value1"); contextMap.putValue("key2", "value2"); final Log4jLogEvent event = Log4jLogEvent.newBuilder() .setLoggerName("a.B") .setLevel(Level.INFO) .setMessage(new SimpleMessage("Hello, World")) .setTimeMillis(System.currentTimeMillis() + 17) .setIncludeLocation(true) .setSource(new StackTraceElement("pack.MyClass", "myMethod", "MyClass.java", 17)) .setContextData(contextMap) .build(); final String result = layout.toSerializable(event); final String expected = "<log4j:event logger=\"a.B\" timestamp=\"" + event.getTimeMillis() + "\" level=\"INFO\" thread=\"main\">\r\n" + "<log4j:message><![CDATA[Hello, World]]></log4j:message>\r\n" + "<log4j:locationInfo class=\"pack.MyClass\" method=\"myMethod\" file=\"MyClass.java\" line=\"17\"/>\r\n" + "<log4j:properties>\r\n" + "<log4j:data name=\"key1\" value=\"value1\"/>\r\n" + "<log4j:data name=\"key2\" value=\"value2\"/>\r\n" + "</log4j:properties>\r\n"+ "</log4j:event>\r\n\r\n"; assertEquals(expected, result); }
@Override public StringMap deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException { final List<MapEntry> list = jp.readValueAs(new TypeReference<List<MapEntry>>() { // empty }); final StringMap contextData = new ContextDataFactory().createContextData(); for (final MapEntry mapEntry : list) { contextData.putValue(mapEntry.getKey(), mapEntry.getValue()); } return contextData; }
/** * Rewrites the event. * @param source a logging event that may be returned or * used to create a new logging event. * @return The LogEvent after rewriting. */ @Override public LogEvent rewrite(final LogEvent source) { final StringMap newContextData = ContextDataFactory.createContextData(source.getContextData()); for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) { final Property prop = entry.getKey(); newContextData.putValue(prop.getName(), entry.getValue().booleanValue() ? config.getStrSubstitutor().replace(prop.getValue()) : prop.getValue()); } return new Log4jLogEvent.Builder(source).setContextData(newContextData).build(); }
/** * This method is called by the EventHandler that processes the RingBufferLogEvent in a separate thread. * Merges the contents of the configuration map into the contextData, after replacing any variables in the property * values with the StrSubstitutor-supplied actual values. * * @param event the event to log */ public void actualAsyncLog(final RingBufferLogEvent event) { final List<Property> properties = privateConfig.loggerConfig.getPropertyList(); if (properties != null) { StringMap contextData = (StringMap) event.getContextData(); if (contextData.isFrozen()) { final StringMap temp = ContextDataFactory.createContextData(); temp.putAll(contextData); contextData = temp; } for (int i = 0; i < properties.size(); i++) { final Property prop = properties.get(i); if (contextData.getValue(prop.getName()) != null) { continue; // contextMap overrides config properties } final String value = prop.isValueNeedsLookup() // ? privateConfig.config.getStrSubstitutor().replace(event, prop.getValue()) // : prop.getValue(); contextData.putValue(prop.getName(), value); } event.setContextData(contextData); } final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy(); strategy.log(this, event); }
/** * Test the custom pattern */ @Test public void testCustomPattern() { final List<PatternFormatter> formatters = parser.parse(customPattern); assertNotNull(formatters); final StringMap mdc = ContextDataFactory.createContextData(); mdc.putValue("loginId", "Fred"); final Throwable t = new Throwable(); final StackTraceElement[] elements = t.getStackTrace(); final Log4jLogEvent event = Log4jLogEvent.newBuilder() // .setLoggerName("org.apache.logging.log4j.PatternParserTest") // .setMarker(MarkerManager.getMarker("TEST")) // .setLoggerFqcn(Logger.class.getName()) // .setLevel(Level.INFO) // .setMessage(new SimpleMessage("Hello, world")) // .setContextData(mdc) // .setThreadName("Thread1") // .setSource(elements[0]) .setTimeMillis(System.currentTimeMillis()).build(); final StringBuilder buf = new StringBuilder(); for (final PatternFormatter formatter : formatters) { formatter.format(event, buf); } final String str = buf.toString(); final String expected = "INFO [PatternParserTest :104 ] - Hello, world" + Strings.LINE_SEPARATOR; assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected)); }
@Test public void testDeeplyNestedPattern() { final List<PatternFormatter> formatters = parser.parse(deeplyNestedPattern); assertNotNull(formatters); assertEquals(1, formatters.size()); final StringMap mdc = ContextDataFactory.createContextData(); mdc.putValue("var", "1234"); final Log4jLogEvent event = Log4jLogEvent.newBuilder() // .setContextData(mdc).build(); final StringBuilder buf = new StringBuilder(); formatters.get(0).format(event, buf); final String expected = " 123 "; assertEquals(expected, buf.toString()); }
@Test public void testConverter0() { final StringMap contextMap = ContextDataFactory.createContextData(0); final String expected = "{}"; test(contextMap, expected, null); }
/** * @return a log event that uses all the bells and whistles, features, nooks and crannies */ static Log4jLogEvent createLogEvent() { final Marker cMarker = MarkerManager.getMarker("Marker1"); final Marker pMarker1 = MarkerManager.getMarker("ParentMarker1"); final Marker pMarker2 = MarkerManager.getMarker("ParentMarker2"); final Marker gfMarker = MarkerManager.getMarker("GrandFatherMarker"); final Marker gmMarker = MarkerManager.getMarker("GrandMotherMarker"); cMarker.addParents(pMarker1); cMarker.addParents(pMarker2); pMarker1.addParents(gmMarker); pMarker1.addParents(gfMarker); final Exception sourceHelper = new Exception(); sourceHelper.fillInStackTrace(); final Exception cause = new NullPointerException("testNPEx"); sourceHelper.fillInStackTrace(); final StackTraceElement source = sourceHelper.getStackTrace()[0]; final IOException ioException = new IOException("testIOEx", cause); ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 1")); ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 2")); final ThrowableProxy throwableProxy = new ThrowableProxy(ioException); final StringMap contextData = ContextDataFactory.createContextData(); contextData.putValue("MDC.A", "A_Value"); contextData.putValue("MDC.B", "B_Value"); final DefaultThreadContextStack contextStack = new DefaultThreadContextStack(true); contextStack.clear(); contextStack.push("stack_msg1"); contextStack.add("stack_msg2"); final Log4jLogEvent expected = Log4jLogEvent.newBuilder() // .setLoggerName("a.B") // .setMarker(cMarker) // .setLoggerFqcn("f.q.c.n") // .setLevel(Level.DEBUG) // .setMessage(new SimpleMessage("Msg")) // .setThrown(ioException) // .setThrownProxy(throwableProxy) // .setContextData(contextData) // .setContextStack(contextStack) // .setThreadName("MyThreadName") // .setSource(source) // .setTimeMillis(1).build(); // validate event? return expected; }