diff --git a/src/main/java/com/tradier/raven/logging/HostnameEventBuilderHelper.java b/src/main/java/com/tradier/raven/logging/HostnameEventBuilderHelper.java new file mode 100644 index 0000000..344cdfa --- /dev/null +++ b/src/main/java/com/tradier/raven/logging/HostnameEventBuilderHelper.java @@ -0,0 +1,45 @@ +package com.tradier.raven.logging; + +import net.kencochrane.raven.event.EventBuilder; +import net.kencochrane.raven.event.helper.EventBuilderHelper; + +/** + * Helper that sets the {@link net.kencochrane.raven.event.EventBuilder#setServerName(String)} from a + * Environment or System property {@value #SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME}. The System Property takes + * precedence. + * + * The System property or Environment variable is sourced in the Constructor (which is created when raven initialises + * itself). + */ +public class HostnameEventBuilderHelper implements EventBuilderHelper { + + public static final String SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME = "RavenLogbackEventHostname"; + + // null so that the default hostname via {@link EventBuilder} does the default action + // At the time of writing this: https://github.com/getsentry/raven-java/issues/139 + public static final String UNAVAILABLE_HOSTNAME_VALUE = null; + + public final String hostname; + + public HostnameEventBuilderHelper() { + hostname = getSystemPropertyOrEnvVar(SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME,UNAVAILABLE_HOSTNAME_VALUE); + } + + public static String getSystemPropertyOrEnvVar(String property,String defaultValue) { + String hostName = System.getProperty(property,System.getenv(property)); + + if(hostName == null || hostName.trim().length()==0) { + return defaultValue; + } else { + return hostName; + } + } + + @Override + public void helpBuildingEvent(EventBuilder eventBuilder) { + eventBuilder.setServerName(hostname); + } + + + +} diff --git a/src/main/java/com/tradier/raven/logging/HostnameRavenFactory.java b/src/main/java/com/tradier/raven/logging/HostnameRavenFactory.java new file mode 100644 index 0000000..0e40193 --- /dev/null +++ b/src/main/java/com/tradier/raven/logging/HostnameRavenFactory.java @@ -0,0 +1,39 @@ +package com.tradier.raven.logging; + + +import net.kencochrane.raven.DefaultRavenFactory; +import net.kencochrane.raven.Raven; +import net.kencochrane.raven.dsn.Dsn; +import net.kencochrane.raven.event.helper.EventBuilderHelper; +import net.kencochrane.raven.event.helper.HttpEventBuilderHelper; + +/** + * RavenFactory in order to add the EventBuilder : {@link com.tradier.raven.logging.HostnameEventBuilderHelper} + * This is so that the Hostname can be source from a environment variable or system property. + */ +public class HostnameRavenFactory extends DefaultRavenFactory { + + + @Override + public Raven createRavenInstance(Dsn dsn) { + Raven raven = super.createRavenInstance(dsn); + try { + Class.forName("javax.servlet.Servlet", false, this.getClass().getClassLoader()); + raven.addBuilderHelper(new HttpEventBuilderHelper()); + } catch (ClassNotFoundException e) { + // + // DO NOT logger anything here. It can cause a recursive logging call to logback + // and deadlock. see: https://github.com/getsentry/raven-java/issues/139 + // + + } + raven.addBuilderHelper(createHostnameEventBuilderHelper()); + return raven; + } + + + public EventBuilderHelper createHostnameEventBuilderHelper() { + return new HostnameEventBuilderHelper(); + } + +} diff --git a/src/main/resources/META-INF/services/net.kencochrane.raven.RavenFactory b/src/main/resources/META-INF/services/net.kencochrane.raven.RavenFactory new file mode 100644 index 0000000..e397947 --- /dev/null +++ b/src/main/resources/META-INF/services/net.kencochrane.raven.RavenFactory @@ -0,0 +1 @@ +com.tradier.raven.logging.HostnameRavenFactory diff --git a/src/test/java/com/tradier/raven/logging/HostnameRavenFactoryTest.java b/src/test/java/com/tradier/raven/logging/HostnameRavenFactoryTest.java new file mode 100644 index 0000000..0876954 --- /dev/null +++ b/src/test/java/com/tradier/raven/logging/HostnameRavenFactoryTest.java @@ -0,0 +1,197 @@ +package com.tradier.raven.logging; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggingEvent; +import net.kencochrane.raven.Raven; +import net.kencochrane.raven.RavenFactory; +import net.kencochrane.raven.event.EventBuilder; +import net.kencochrane.raven.logback.SentryAppender; +import org.junit.*; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.UUID; + + +import static org.junit.Assert.*; + +public class HostnameRavenFactoryTest { + + private String previousHostname; + private String currentHostname; + + @BeforeClass + public static void recordEvents() { + MemoryPersistentHostnameEventBuilderHelper.withEventCollecting(); + } + + @AfterClass + public static void stopRecordingEvents() { + MemoryPersistentHostnameEventBuilderHelper.withoutEventCollecting(); + } + + @Before + public void setUp() { + previousHostname = System.getProperty(HostnameEventBuilderHelper.SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME); + currentHostname = UUID.randomUUID().toString(); + System.setProperty(HostnameEventBuilderHelper.SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME,currentHostname); + } + + @After + public void tearDown() { + clearHostnameProperty(); + } + + private void clearHostnameProperty() { + if(previousHostname!=null) { + System.setProperty(HostnameEventBuilderHelper.SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME, previousHostname); + } else { + System.clearProperty(HostnameEventBuilderHelper.SYSTEM_PROPERTY_OR_ENV_VAR_FOR_HOSTNAME); + } + } + + /** + * Check that the HostnameEventBuilderHelper is called + * and the Hostname on the EventBuilder is set by the helper to + * the value of the currentHostname set in the before + */ + @Test + public void checkHostnameIsSetWithinTheEvent() { + final String dsn = "https://user:pass@app.getsentry.com/id"; + try { + SentryAppender appender1 = new OurAppender(RavenFactory.ravenInstance(dsn)); + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + + ILoggingEvent event = new LoggingEvent("com.tradier.raven.logback.LogBackRavenFactoryTest", context.getLogger(this.getClass()), Level.ERROR, "hey", null, null); + appender1.start(); + appender1.doAppend(event); + } finally { + assertTrue("Hostname should have been set on event to: " + currentHostname,findEvent(currentHostname)); + } + } + + public static class OurAppender extends SentryAppender { + + + + public OurAppender() { + + } + + /** + * Creates an instance of SentryAppender. + * + * @param raven instance of Raven to use with this appender. + */ + public OurAppender(Raven raven) { + super(raven); + } + /** + * {@inheritDoc} + *
+ * The raven instance is started in this method instead of {@link #start()} in order to avoid substitute loggers
+ * being generated during the instantiation of {@link net.kencochrane.raven.Raven}.
+ * More on www.slf4j.org/codes.html#substituteLogger
+ *