Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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);
}



}
39 changes: 39 additions & 0 deletions src/main/java/com/tradier/raven/logging/HostnameRavenFactory.java
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.tradier.raven.logging.HostnameRavenFactory
197 changes: 197 additions & 0 deletions src/test/java/com/tradier/raven/logging/HostnameRavenFactoryTest.java
Original file line number Diff line number Diff line change
@@ -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}
* <p>
* 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}.<br />
* More on <a href="http://www.slf4j.org/codes.html#substituteLogger">www.slf4j.org/codes.html#substituteLogger</a>
* </p>
*/
@Override
protected void append(ILoggingEvent iLoggingEvent) {
System.out.println(iLoggingEvent.getLoggerName().startsWith("net.kencochrane.raven"));

super.append(iLoggingEvent);
}
}

/**
* Check that the HostnameEventBuilderHelper is called for each append call
* and that the Hostname on the EventBuilder is set by the helper to
* the value of the currentHostname set in the before
*/
@Test
public void checkHostnameIsSetForEachAppend() {
final String dsn = "https://user:pass@app.getsentry.com/id";
int numberOfEventsToGenerate = 3;
try {
SentryAppender appender1 = new SentryAppender(RavenFactory.ravenInstance(dsn));
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
appender1.start();

for(int i=0;i<numberOfEventsToGenerate;i++) {
ILoggingEvent event = new LoggingEvent("com.tradier.raven.logback.LogBackRavenFactoryTest", context.getLogger("dynamic_logger"), Level.ERROR, "hey", null, null);
appender1.doAppend(event);
}
} finally {
assertTrue("Hostname should have been set on event to: " + currentHostname,findEvent(currentHostname));
assertEquals("Hostname should have been set on " + numberOfEventsToGenerate +" events.", numberOfEventsToGenerate,countMatchingEvent(currentHostname));
}
}

/**
* 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.
*
* This tests that the default raven builder logic is in place.
*/
@Test
public void checkHostnameIsNotSetWithinTheEvent() {
clearHostnameProperty();
final String dsn = "https://user:pass@app.getsentry.com/id";
try {
SentryAppender appender1 = new SentryAppender(RavenFactory.ravenInstance(dsn));
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

ILoggingEvent event = new LoggingEvent("com.tradier.raven.logback.LogBackRavenFactoryTest", context.getLogger("dynamic_logger"), Level.ERROR, "hey", null, null);
appender1.start();
appender1.doAppend(event);
} finally {
assertFalse("Hostname should not have been set on event to: " + currentHostname, findEvent(currentHostname));
}
}


/**
* Returns true if a matching event was found
* @param hostname
* @return true is a matching event was found, false if not
*/
private boolean findEvent(String hostname) {
List<EventBuilder> events = MemoryPersistentHostnameEventBuilderHelper.getEventsHelped();

for(EventBuilder builder : events) {
if(builder instanceof MemoryPersistentHostnameEventBuilderHelper.WrappedEventBuilder) {
String setEventHostname = ((MemoryPersistentHostnameEventBuilderHelper.WrappedEventBuilder)builder).hostname;
if(setEventHostname!=null && setEventHostname.equals(hostname)){
return true;
}
}

}

return false;
}

/**
* Returns the number of matching events that were found, that had the given hostname set
* @param hostname
* @return The number of EventBuilder objects that had the given hostname
*/
private int countMatchingEvent(String hostname) {
List<EventBuilder> events = MemoryPersistentHostnameEventBuilderHelper.getEventsHelped();

int count = 0;
for(EventBuilder builder : events) {
if(builder instanceof MemoryPersistentHostnameEventBuilderHelper.WrappedEventBuilder) {
String setEventHostname = ((MemoryPersistentHostnameEventBuilderHelper.WrappedEventBuilder)builder).hostname;
if(setEventHostname!=null && setEventHostname.equals(hostname)){
count++;
}
}
}

return count;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.tradier.raven.logging;

import net.kencochrane.raven.event.EventBuilder;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

/**
*
*/
public class MemoryPersistentHostnameEventBuilderHelper extends HostnameEventBuilderHelper {

private final static List<EventBuilder> eventsHelped = new CopyOnWriteArrayList<EventBuilder>();
private final static AtomicBoolean collectEvents = new AtomicBoolean(false);

@Override
public void helpBuildingEvent(EventBuilder eventBuilder) {
EventBuilder eventBuilder1 = new WrappedEventBuilder(eventBuilder);
super.helpBuildingEvent(eventBuilder1);
if(collectEvents.get()) {
eventsHelped.add(eventBuilder1);
}
}


public static List<EventBuilder> getEventsHelped() {
return eventsHelped;
}

public static void withEventCollecting() {
collectEvents.set(true);
}

public static void withoutEventCollecting() {
eventsHelped.clear();
collectEvents.set(false);
}


public static class WrappedEventBuilder extends EventBuilder {
public volatile String hostname;
public final EventBuilder wrapped;

public WrappedEventBuilder(EventBuilder delegate) {
this.wrapped = delegate;
}

@Override
public EventBuilder setServerName(String name) {
wrapped.setServerName(name);
hostname = name;
return wrapped;

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tradier.raven.logging;


import net.kencochrane.raven.event.helper.EventBuilderHelper;

/**
* RavenFactory in order to add the EventBuilder : {@link HostnameEventBuilderHelper}
* This is so that the Hostname can be source from a environment variable or system property.
*/
public class MemoryPersistentHostnameRavenFactory extends HostnameRavenFactory {


public EventBuilderHelper createHostnameEventBuilderHelper() {
return new MemoryPersistentHostnameEventBuilderHelper();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.tradier.raven.logging.RavenAppenderFactory
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.tradier.raven.logging.MemoryPersistentHostnameRavenFactory