package com.getsentry.raven.log4j2; import com.getsentry.raven.environment.RavenEnvironment; import mockit.Injectable; import mockit.Tested; import mockit.Verifications; import com.getsentry.raven.Raven; import com.getsentry.raven.event.Event; import com.getsentry.raven.event.EventBuilder; import com.getsentry.raven.event.interfaces.ExceptionInterface; import com.getsentry.raven.event.interfaces.MessageInterface; import com.getsentry.raven.event.interfaces.SentryException; import com.getsentry.raven.event.interfaces.StackTraceInterface; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.FormattedMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.DefaultThreadContextStack; import org.hamcrest.Matchers; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; public class SentryAppenderEventBuildingTest { @Tested private SentryAppender sentryAppender = null; private MockUpErrorHandler mockUpErrorHandler; @Injectable private Raven mockRaven = null; private String mockExtraTag = "d421627f-7a25-4d43-8210-140dfe73ff10"; @BeforeMethod public void setUp() throws Exception { sentryAppender = new SentryAppender(mockRaven); mockUpErrorHandler = new MockUpErrorHandler(); sentryAppender.setHandler(mockUpErrorHandler.getMockInstance()); sentryAppender.setExtraTags(mockExtraTag); } private void assertNoErrorsInErrorHandler() throws Exception { assertThat(mockUpErrorHandler.getErrorCount(), is(0)); } @Test public void testSimpleMessageLogging() throws Exception { final String loggerName = "0a05c9ff-45ef-45cf-9595-9307b0729a0d"; final String message = "6ff10df4-2e27-43f5-b4e9-a957f8678176"; final String threadName = "f891f3c4-c619-4441-9c47-f5c8564d3c0a"; final Date date = new Date(1373883196416L); sentryAppender.append(new Log4jLogEvent(loggerName, null, null, Level.INFO, new SimpleMessage(message), null, null, null, threadName, null, date.getTime())); new Verifications() {{ Event event; mockRaven.runBuilderHelpers((EventBuilder) any); mockRaven.sendEvent(event = withCapture()); assertThat(event.getMessage(), is(message)); assertThat(event.getLogger(), is(loggerName)); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(SentryAppender.THREAD_NAME, threadName)); assertThat(event.getTimestamp(), is(date)); assertThat(event.getSdkName(), is(RavenEnvironment.SDK_NAME + ":log4j2")); }}; assertNoErrorsInErrorHandler(); } @DataProvider(name = "levels") private Object[][] levelConversions() { return new Object[][]{ {Event.Level.DEBUG, Level.TRACE}, {Event.Level.DEBUG, Level.DEBUG}, {Event.Level.INFO, Level.INFO}, {Event.Level.WARNING, Level.WARN}, {Event.Level.ERROR, Level.ERROR}, {Event.Level.FATAL, Level.FATAL}}; } @Test(dataProvider = "levels") public void testLevelConversion(final Event.Level expectedLevel, Level level) throws Exception { sentryAppender.append(new Log4jLogEvent(null, null, null, level, new SimpleMessage(""), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getLevel(), is(expectedLevel)); }}; assertNoErrorsInErrorHandler(); } @Test public void testExceptionLogging() throws Exception { final Exception exception = new Exception("d0d1b31f-e885-42e3-aac6-48c500f10ed1"); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage(""), exception)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); ExceptionInterface exceptionInterface = (ExceptionInterface) event.getSentryInterfaces() .get(ExceptionInterface.EXCEPTION_INTERFACE); SentryException sentryException = exceptionInterface.getExceptions().getFirst(); assertThat(sentryException.getExceptionMessage(), is(exception.getMessage())); assertThat(sentryException.getStackTraceInterface().getStackTrace(), is(exception.getStackTrace())); }}; assertNoErrorsInErrorHandler(); } @Test public void testLogParametrisedMessage() throws Exception { final String messagePattern = "Formatted message {} {} {}"; final Object[] parameters = {"first parameter", new Object[0], null}; sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new FormattedMessage(messagePattern, parameters), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); MessageInterface messageInterface = (MessageInterface) event.getSentryInterfaces() .get(MessageInterface.MESSAGE_INTERFACE); assertThat(event.getMessage(), is("Formatted message first parameter [] null")); assertThat(messageInterface.getMessage(), is(messagePattern)); assertThat(messageInterface.getParameters(), is(Arrays.asList(parameters[0].toString(), parameters[1].toString(), null))); }}; assertNoErrorsInErrorHandler(); } @Test public void testMarkerAddedToTag() throws Exception { final String markerName = "c97e1fc0-9fff-41b3-8d0d-c24b54c670bb"; sentryAppender.append(new Log4jLogEvent(null, MarkerManager.getMarker(markerName), null, Level.INFO, new SimpleMessage(""), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getTags(), Matchers.<String, Object>hasEntry(SentryAppender.LOG4J_MARKER, markerName)); }}; assertNoErrorsInErrorHandler(); } @Test public void testMdcAddedToExtra() throws Exception { final String extraKey = "a4ce2632-8d9c-471d-8b06-1744be2ae8e9"; final String extraValue = "6dbeb494-197e-4f57-939a-613e2c16607d"; sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new SimpleMessage(""), null, Collections.singletonMap(extraKey, extraValue), null, null, null, 0)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(extraKey, extraValue)); }}; assertNoErrorsInErrorHandler(); } @Test @SuppressWarnings("unchecked") public void testNdcAddedToExtra() throws Exception { final ThreadContext.ContextStack contextStack = new DefaultThreadContextStack(true); contextStack.push("444af01f-fb80-414f-b035-15bdb91cb8b2"); contextStack.push("a1cb5e08-480a-4b32-b675-212f00c44e05"); contextStack.push("0aa5db14-1579-46ef-aae2-350d974e7fb8"); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new SimpleMessage(""), null, null, contextStack, null, null, 0)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat((List<String>) event.getExtra().get(SentryAppender.LOG4J_NDC), equalTo(contextStack.asList())); }}; assertNoErrorsInErrorHandler(); } @Test public void testSourceUsedAsStacktrace() throws Exception { final StackTraceElement location = new StackTraceElement("7039c1f7-21e3-4134-8ced-524281633224", "c68f3af9-1618-4d80-ad1b-ea0701568153", "f87a8821-1c70-44b8-81c3-271d454e4b08", 42); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new SimpleMessage(""), null, null, null, null, location, 0)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); StackTraceInterface stackTraceInterface = (StackTraceInterface) event.getSentryInterfaces() .get(StackTraceInterface.STACKTRACE_INTERFACE); assertThat(stackTraceInterface.getStackTrace(), arrayWithSize(1)); assertThat(stackTraceInterface.getStackTrace()[0], is(location)); }}; assertNoErrorsInErrorHandler(); } @Test public void testCulpritWithSource() throws Exception { final StackTraceElement location = new StackTraceElement("a", "b", "c", 42); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new SimpleMessage(""), null, null, null, null, location, 0)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getCulprit(), is("a.b(c:42)")); }}; assertNoErrorsInErrorHandler(); } @Test public void testCulpritWithoutSource() throws Exception { final String loggerName = "150bbbfa-f729-460e-921b-a0fe1f7ab392 "; sentryAppender.append(new Log4jLogEvent(loggerName, null, null, Level.INFO, new SimpleMessage(""), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getCulprit(), is(loggerName)); }}; assertNoErrorsInErrorHandler(); } @Test public void testExtraTagObtainedFromMdc() throws Exception { Map<String, String> mdc = new HashMap<>(); mdc.put(mockExtraTag, "565940d2-f4a4-42f6-9496-42e3c7c85c43"); mdc.put("other_property", "395856e8-fa1d-474f-8fa9-c062b4886527"); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.INFO, new SimpleMessage(""), null, mdc, null, null, null, 0)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getTags().entrySet(), hasSize(1)); assertThat(event.getTags(), hasEntry(mockExtraTag, "565940d2-f4a4-42f6-9496-42e3c7c85c43")); assertThat(event.getExtra(), not(hasKey(mockExtraTag))); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry("other_property", "395856e8-fa1d-474f-8fa9-c062b4886527")); }}; assertNoErrorsInErrorHandler(); } @Test public void testReleaseAddedToEvent() throws Exception { final String release = "d7b4a6a0-1a0a-4381-a519-e2ccab609003"; sentryAppender.setRelease(release); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage(""), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getRelease(), is(release)); }}; assertNoErrorsInErrorHandler(); } @Test public void testEnvironmentAddedToEvent() throws Exception { final String environment = "d7b4a6a0-1a0a-4381-a519-e2ccab609003"; sentryAppender.setEnvironment(environment); sentryAppender.append(new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage(""), null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getEnvironment(), is(environment)); }}; assertNoErrorsInErrorHandler(); } }