package com.getsentry.raven.logback;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.BasicStatusManager;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.status.OnConsoleStatusListener;
import com.getsentry.raven.environment.RavenEnvironment;
import mockit.Injectable;
import mockit.NonStrictExpectations;
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.hamcrest.Matchers;
import org.slf4j.MarkerFactory;
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;
@Injectable
private Raven mockRaven = null;
@Injectable
private Context mockContext = null;
private String mockExtraTag = "60f42409-c029-447d-816a-fb2722913c93";
private String mockMinLevel = "ALL";
@BeforeMethod
public void setUp() throws Exception {
new MockUpStatusPrinter();
sentryAppender = new SentryAppender(mockRaven);
sentryAppender.setContext(mockContext);
sentryAppender.setExtraTags(mockExtraTag);
sentryAppender.setMinLevel(mockMinLevel);
new NonStrictExpectations() {{
final BasicStatusManager statusManager = new BasicStatusManager();
final OnConsoleStatusListener listener = new OnConsoleStatusListener();
listener.start();
statusManager.add(listener);
mockContext.getStatusManager();
result = statusManager;
}};
}
private void assertNoErrorsInStatusManager() throws Exception {
assertThat(mockContext.getStatusManager().getCount(), is(0));
}
@Test
public void testSimpleMessageLogging() throws Exception {
final String message = "14a667c5-0de3-4b43-b62b-f9ccced7adf1";
final String loggerName = "2cc053ad-8c13-44a6-849f-11a9bf8ba646";
final String threadName = "a70e658d-f5fa-4707-b7ac-0d503429f1dd";
final Date date = new Date(1373883196416L);
ILoggingEvent loggingEvent = new MockUpLoggingEvent(loggerName, null, Level.INFO, message, null, null, null,
threadName, null, date.getTime()).getMockInstance();
sentryAppender.append(loggingEvent);
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 + ":logback"));
}};
assertNoErrorsInStatusManager();
}
@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}};
}
@Test(dataProvider = "levels")
public void testLevelConversion(final Event.Level expectedLevel, Level level) throws Exception {
sentryAppender.append(new MockUpLoggingEvent(null, null, level, null, null, null).getMockInstance());
new Verifications() {{
Event event;
mockRaven.sendEvent(event = withCapture());
assertThat(event.getLevel(), is(expectedLevel));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testExceptionLogging() throws Exception {
final Exception exception = new Exception();
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.ERROR, null, null, exception).getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
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()));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testLogParametrisedMessage() throws Exception {
final String messagePattern = "Formatted message {} {} {}";
final Object[] parameters = {"first parameter", new Object[0], null};
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, messagePattern, parameters, null)
.getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
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)));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testMarkerAddedToTag() throws Exception {
final String markerName = "d33e3927-ea6c-4a5a-b66c-8dcb2052e812";
sentryAppender.append(
new MockUpLoggingEvent(null, MarkerFactory.getMarker(markerName), Level.INFO, null, null, null)
.getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getTags(), Matchers.<String, Object>hasEntry(SentryAppender.LOGBACK_MARKER, markerName));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testMdcAddedToExtra() throws Exception {
final String extraKey = "10e09b11-546f-4c57-99b2-cf3c627c8737";
final String extraValue = "5f7a53b1-4354-4120-a368-78a615705540";
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null,
Collections.singletonMap(extraKey, extraValue), null, null, 0).getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(extraKey, extraValue));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testContextPropertiesAddedToExtra() throws Exception {
final String extraKey = "0489bc59-b4ba-4890-9a60-58e65624fe8c";
final String extraValue = "986adaa7-c0e4-4c09-9c5e-49edaf2e6d53";
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null,
null, null, null, 0, Collections.singletonMap(extraKey, extraValue)).getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(extraKey, extraValue));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testMdcTakesPrecedenceOverContextProperties() throws Exception {
final String mdcKey = "0aab006e-0128-42d7-84d5-aa88329beb19";
final String mdcValue = "8ba43697-7568-40e2-914b-4d2c3f12e70e";
final String contextKey = mdcKey;
final String contextValue = "66d123eb-7786-4f3d-86f1-a906039401d9";
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null,
Collections.singletonMap(mdcKey, mdcValue), null, null, 0,
Collections.singletonMap(contextKey, contextValue)).getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getExtra(), Matchers.<String, Object>hasEntry(mdcKey, mdcValue));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testSourceUsedAsStacktrace() throws Exception {
final StackTraceElement[] location = {new StackTraceElement("854de9b9-95ea-4dae-8e01-23b25c9bd271",
"49974348-1704-47cc-be5a-4e72f2e0db33",
"bf48ef03-657c-4924-844a-317743c4599b", 42)};
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null, null, null, location, 0)
.getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
StackTraceInterface stackTraceInterface = (StackTraceInterface) event.getSentryInterfaces()
.get(StackTraceInterface.STACKTRACE_INTERFACE);
assertThat(stackTraceInterface.getStackTrace(), is(location));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testCulpritWithSource() throws Exception {
final StackTraceElement[] location = {new StackTraceElement("a", "b", "c", 42),
new StackTraceElement("d", "e", "f", 69)};
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null, null, null, location, 0)
.getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getCulprit(), is("a.b(c:42)"));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testCulpritWithoutSource() throws Exception {
final String loggerName = "ee1c33e8-2f2e-4613-9c2c-2564624a9d4f";
sentryAppender.append(new MockUpLoggingEvent(loggerName, null, Level.INFO, null, null, null).getMockInstance());
new Verifications() {{
Event event;
mockRaven.runBuilderHelpers((EventBuilder) any);
mockRaven.sendEvent(event = withCapture());
assertThat(event.getCulprit(), is(loggerName));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testExtraTagObtainedFromMdc() throws Exception {
Map<String, String> mdcPropertyMap = new HashMap<>();
mdcPropertyMap.put(mockExtraTag, "47008f35-50c8-4e40-94ca-c8c1a3ddb729");
mdcPropertyMap.put("other_property", "cb9c92a1-0182-4e9c-866f-b06b271cd196");
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null, mdcPropertyMap, null,
null, 0).getMockInstance());
new Verifications() {{
Event event;
mockRaven.sendEvent(event = withCapture());
assertThat(event.getTags().entrySet(), hasSize(1));
assertThat(event.getTags(), hasEntry(mockExtraTag, "47008f35-50c8-4e40-94ca-c8c1a3ddb729"));
assertThat(event.getExtra(), not(hasKey(mockExtraTag)));
assertThat(event.getExtra(), Matchers.<String, Object>hasEntry("other_property", "cb9c92a1-0182-4e9c-866f-b06b271cd196"));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testReleaseAddedToEvent() throws Exception {
final String release = "d7b4a6a0-1a0a-4381-a519-e2ccab609003";
sentryAppender.setRelease(release);
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null).getMockInstance());
new Verifications() {{
Event event;
mockRaven.sendEvent(event = withCapture());
assertThat(event.getRelease(), is(release));
}};
assertNoErrorsInStatusManager();
}
@Test
public void testEnvironmentAddedToEvent() throws Exception {
final String environment = "d7b4a6a0-1a0a-4381-a519-e2ccab609003";
sentryAppender.setEnvironment(environment);
sentryAppender.append(new MockUpLoggingEvent(null, null, Level.INFO, null, null, null).getMockInstance());
new Verifications() {{
Event event;
mockRaven.sendEvent(event = withCapture());
assertThat(event.getEnvironment(), is(environment));
}};
assertNoErrorsInStatusManager();
}
}