package com.getsentry.raven.log4j; import com.getsentry.raven.environment.RavenEnvironment; import mockit.*; 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.SentryException; import com.getsentry.raven.event.interfaces.StackTraceInterface; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.spi.LocationInfo; import org.apache.log4j.spi.LoggingEvent; import org.hamcrest.Matchers; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; import static mockit.Deencapsulation.setField; 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; @Injectable private Logger mockLogger = null; private String mockExtraTag = "a8e0ad33-3c11-4899-b8c7-c99926c6d7b8"; @BeforeMethod public void setUp() throws Exception { sentryAppender = new SentryAppender(mockRaven); mockUpErrorHandler = new MockUpErrorHandler(); sentryAppender.setErrorHandler(mockUpErrorHandler.getMockInstance()); sentryAppender.setExtraTags(mockExtraTag); sentryAppender.activateOptions(); } private void assertNoErrorsInErrorHandler() throws Exception { assertThat(mockUpErrorHandler.getErrorCount(), is(0)); } @Test public void testSimpleMessageLogging() throws Exception { final String loggerName = "cdc23028-9b1f-485d-90bf-853d2f5f52d6"; final String message = "fae94de0-0df3-4f96-92d5-a3fb66e714f3"; final String threadName = "78ecbf4d-aa61-4dd7-8ef4-b1c49232e8f4"; final Date date = new Date(1373883196416L); new Expectations() {{ mockLogger.getName(); result = loggerName; }}; sentryAppender.append(new LoggingEvent(null, mockLogger, date.getTime(), Level.INFO, message, threadName, null, null, null, null)); 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 + ":log4j")); }}; 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 LoggingEvent(null, mockLogger, 0, level, null, 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("027a0db3-fb98-4377-bafb-fe5a49f067e8"); sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, 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 testMdcAddedToExtra() throws Exception { final String extraKey = "1aeb7253-6e0d-4902-86d6-7e4b36571cfd"; final String extraValue = "b2e19866-08a2-4611-b72c-150fa6aa3394"; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, null, null, Collections.singletonMap(extraKey, extraValue))); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(extraKey, extraValue)); }}; assertNoErrorsInErrorHandler(); } @Test public void testNdcAddedToExtra() throws Exception { final String ndcEntries = "930580ba-f92f-4893-855b-ac24efa1a6c2 fa32ad74-a015-492a-991f-c6a0e04accaf be9dd914-3690-4781-97b2-fe14aedb4cbd"; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, ndcEntries, null, null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(SentryAppender.LOG4J_NDC, ndcEntries)); }}; assertNoErrorsInErrorHandler(); } @Test public void testSourceUsedAsStacktrace(@Injectable final LocationInfo locationInfo) throws Exception { final String className = "8004ac1e-8bd3-4762-abe0-2d0d79ae4e40"; final String methodName = "ce7cd195-9e6d-4315-b883-12951be3da6e"; final String fileName = "1ab50f43-f11c-4439-a05c-d089281411fa"; final int line = 42; new NonStrictExpectations() {{ locationInfo.getClassName(); result = className; locationInfo.getMethodName(); result = methodName; locationInfo.getFileName(); result = fileName; locationInfo.getLineNumber(); result = Integer.toString(line); setField(locationInfo, "fullInfo", ""); }}; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, null, locationInfo, null)); 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(new StackTraceElement(className, methodName, fileName, line))); }}; assertNoErrorsInErrorHandler(); } @Test public void testCulpritWithSource(@Injectable final LocationInfo locationInfo) throws Exception { final String className = "a"; final String methodName = "b"; final String fileName = "c"; final int line = 42; new NonStrictExpectations() {{ locationInfo.getClassName(); result = className; locationInfo.getMethodName(); result = methodName; locationInfo.getFileName(); result = fileName; locationInfo.getLineNumber(); result = Integer.toString(line); setField(locationInfo, "fullInfo", ""); }}; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, null, locationInfo, null)); 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 = "2b27da1d-e03a-4292-9a81-78be5491a7e1"; new Expectations() {{ mockLogger.getName(); result = loggerName; }}; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getCulprit(), is(loggerName)); }}; assertNoErrorsInErrorHandler(); } @Test public void testExtraTagObtainedFromMdc() throws Exception { Map<String, Object> properties = new HashMap<>(); properties.put(mockExtraTag, "ac84f38a-3889-41ed-9519-201402688abb"); properties.put("other_property", "10ebc4f6-a915-46d0-bb60-75bc9bd71371"); sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, null, null, properties)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getTags().entrySet(), hasSize(1)); assertThat(event.getTags(), hasEntry(mockExtraTag, "ac84f38a-3889-41ed-9519-201402688abb")); assertThat(event.getExtra(), not(hasKey(mockExtraTag))); assertThat(event.getExtra(), Matchers.<String, Object>hasEntry("other_property", "10ebc4f6-a915-46d0-bb60-75bc9bd71371")); }}; assertNoErrorsInErrorHandler(); } @Test public void testExtraTagObtainedFromMdcConvertedToString(@Injectable final Object extraTagValue) throws Exception { Map<String, Object> properties = Collections.singletonMap(mockExtraTag, extraTagValue); new NonStrictExpectations() {{ extraTagValue.toString(); result = "3c8981b4-01ad-47ec-8a3a-77a0bbcb42e2"; }}; sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null, null, null, null, properties)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getTags().entrySet(), hasSize(1)); assertThat(event.getTags(), hasEntry(mockExtraTag, "3c8981b4-01ad-47ec-8a3a-77a0bbcb42e2")); assertThat(event.getExtra(), not(hasKey(mockExtraTag))); }}; assertNoErrorsInErrorHandler(); } @Test public void testReleaseAddedToEvent() throws Exception { final String release = "d7b4a6a0-1a0a-4381-a519-e2ccab609003"; sentryAppender.setRelease(release); sentryAppender.append(new LoggingEvent(null, mockLogger, 0, Level.ERROR, null, 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 LoggingEvent(null, mockLogger, 0, Level.ERROR, null, null)); new Verifications() {{ Event event; mockRaven.sendEvent(event = withCapture()); assertThat(event.getEnvironment(), is(environment)); }}; assertNoErrorsInErrorHandler(); } }