diff --git a/.gitignore b/.gitignore index b320ea0..ee1b0da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ */target/** */idea/** .idea -*.i?? \ No newline at end of file +*.i?? +out \ No newline at end of file diff --git a/honeybadger-client/pom.xml b/honeybadger-client/pom.xml index f018256..d7dce70 100644 --- a/honeybadger-client/pom.xml +++ b/honeybadger-client/pom.xml @@ -5,7 +5,7 @@ honeybadger-java com.workable.honeybadger - 1.5.1 + 1.5.2 4.0.0 diff --git a/honeybadger-log4j-appender/pom.xml b/honeybadger-log4j-appender/pom.xml index 7c33bd3..f38c4ad 100644 --- a/honeybadger-log4j-appender/pom.xml +++ b/honeybadger-log4j-appender/pom.xml @@ -5,7 +5,7 @@ honeybadger-java com.workable.honeybadger - 1.5.1 + 1.5.2 4.0.0 honeybadger-log4j-appender diff --git a/honeybadger-log4j2-appender/README.md b/honeybadger-log4j2-appender/README.md new file mode 100644 index 0000000..5ba7634 --- /dev/null +++ b/honeybadger-log4j2-appender/README.md @@ -0,0 +1,70 @@ +# honeybadger-log4j-appender +[log4j2](https://logging.apache.org/log4j/2.5/) support for honeybadger. +It provides an [`Appender`](https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Appender.html) +for log4j to send the logged events to honeybadger. + +## Usage +### Configuration +In the `log4j2.xml` file configure an appender named `HoneybadgerAppender`: + +```properties + + + + + + + +``` + +## Additional Options + +### Async mode +The error dispatching to honebadger.io is performed asynchronously via http in order to avoid performance impact. + +To disable the async mode simply set the `async` option to `false`: + +```properties +log4j.appender.HoneybadgerAppender.async=false +``` + +### Max Threads +By default the thread pool used for async dispatching contains one thread per +processor available to the JVM. + +It's possible to manually set the number of threads (for example if you want +only one thread) with the option `maxThreads`: + +```properties +log4j.appender.HoneybadgerAppender.maxThreads=1 +``` + +### Queue Size +The default queue used to store the not yet processed events doesn't have a +limit. +Depending on the environment (if the memory is sparse) it is important to be +able to control the size of that queue to avoid memory issues. + +It is possible to set a maximum with the option `queuesize`: + +```properties +log4j.appender.HoneybadgerAppender.queueSize=50000 +``` + +### Thread Priority +As in most cases sending error to Honebadger isn't as important as an application +running smoothly, the threads have a +[minimal priority](http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#MIN_PRIORITY). + +It is possible to customise this value to increase the priority of those threads +with the option `priority`: + +```properties +log4j.appender.HoneybadgerAppender.priority=1 +``` + +### Additional data and information +It's possible to add extra details to events captured by the Log4j module +thanks to [the MDC](https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html) +systems provided by Log4j are usable, allowing to attach extras information to the event. + diff --git a/honeybadger-log4j2-appender/pom.xml b/honeybadger-log4j2-appender/pom.xml new file mode 100644 index 0000000..da27128 --- /dev/null +++ b/honeybadger-log4j2-appender/pom.xml @@ -0,0 +1,49 @@ + + + + honeybadger-java + com.workable.honeybadger + 1.5.2 + + 4.0.0 + honeybadger-log4j2-appender + Honeybadger :: Java :: Log4j2 Appender + Log4j2 appender allowing to send logs to Honeybadger. + + + 2.5 + + + + + com.workable.honeybadger + honeybadger-client + ${project.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.slf4j + slf4j-log4j12 + 1.7.7 + + + + + junit + junit + 4.11 + + + + \ No newline at end of file diff --git a/honeybadger-log4j2-appender/src/main/java/META-INF/MANIFEST.MF b/honeybadger-log4j2-appender/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..be31cb1 --- /dev/null +++ b/honeybadger-log4j2-appender/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: com.workable.honeybadger.log4j2.HoneybadgerAppender + diff --git a/honeybadger-log4j2-appender/src/main/java/com/workable/honeybadger/log4j2/HoneybadgerAppender.java b/honeybadger-log4j2-appender/src/main/java/com/workable/honeybadger/log4j2/HoneybadgerAppender.java new file mode 100644 index 0000000..55d422d --- /dev/null +++ b/honeybadger-log4j2-appender/src/main/java/com/workable/honeybadger/log4j2/HoneybadgerAppender.java @@ -0,0 +1,85 @@ +package com.workable.honeybadger.log4j2; + +import com.workable.honeybadger.*; +import com.workable.honeybadger.Error; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.appender.AppenderLoggingException; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.layout.PatternLayout; + +import java.io.Serializable; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Appender for log4j responsible to send events carrying exceptions to Honeybadger + */ +@Plugin(name="HoneybadgerAppender", category="Core", elementType="appender", printObject=true) +public class HoneybadgerAppender extends AbstractAppender { + + private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + + /** + * The client to send errors to Honeybadger + */ + private static HoneybadgerClient client; + + protected HoneybadgerAppender(HoneybadgerClient client, String name, Filter filter, + Layout layout, final boolean ignoreExceptions) { + super(name, filter, layout, ignoreExceptions); + this.client = client; + } + + @Override + public void append(LogEvent event) { + readLock.lock(); + try { + Error error = new Error(getLayout().toByteArray(event).toString(), event.getThrown()); + error.setReporter(event.getLoggerName()); + client.reportError(error); + } catch (Exception ex) { + if (!ignoreExceptions()) { + throw new AppenderLoggingException(ex); + } + } finally { + readLock.unlock(); + } + } + + @PluginFactory + public static HoneybadgerAppender createAppender( + @PluginAttribute("name") String name, + @PluginElement("Layout") Layout layout, + @PluginElement("Filter") final Filter filter, + @PluginAttribute("apiKey") String apiKey, + @PluginAttribute("ignoredSystemProperties") String ignoredSystemProperties, + @PluginAttribute("ignoredExceptions") String ignoredExceptions, + @PluginAttribute("async") boolean async, + @PluginAttribute("maxThreads") int maxThreads, + @PluginAttribute("priority") int priority, + @PluginAttribute("queueSize") int queueSize) { + if (name == null) { + LOGGER.error("No name provided for HoneybadgerAppender"); + return null; + } + if (layout == null) { + layout = PatternLayout.createDefaultLayout(); + } + if (client == null) { + client = new HoneybadgerClient(apiKey, ignoredSystemProperties, ignoredExceptions); + client.setAsync(async); + client.setMaxThreads(maxThreads); + client.setPriority(priority); + client.setQueueSize(queueSize); + } + return new HoneybadgerAppender(client, name, filter, layout, true); + } +} diff --git a/honeybadger-log4j2-appender/src/test/java/AppenderIT.java b/honeybadger-log4j2-appender/src/test/java/AppenderIT.java new file mode 100644 index 0000000..3f2be46 --- /dev/null +++ b/honeybadger-log4j2-appender/src/test/java/AppenderIT.java @@ -0,0 +1,76 @@ +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Test; + +/** + * Created by kostas on 12/4/14. + */ +public class AppenderIT { + + public static final Logger log = LogManager.getLogger(AppenderIT.class); + + @Test + public void shouldLogErrorFromBuggy() throws Exception { + Buggy buggy = new Buggy(); + buggy.fail(); + } + + + @Test + public void testNestedException() throws Exception { + + try { + Delegate delegate = new Delegate(); + delegate.run(); + } + catch(Exception e){ + log.error("Exception while running", e); + } + + + } + + @Test + public void shouldLogError2() throws Exception { + + for (int i = 0; i < 25; i++){ + log.error("This is an error" + i, new IllegalStateException("Oups" + i)); + } + } + +// @Test +// public void shouldLogErrorWithMDC() throws Exception { +// MDC.put("MDC Entry", "MDC Value"); +// +// log.error("This is an error with MDC", new UnsupportedOperationException("Something went wrong...", new NullPointerException())); +// } + + private class Buggy { + + public final Logger log = LogManager.getLogger(Buggy.class); + + public void fail(){ + log.error("Error from buggy", new IllegalStateException("From buggy")); + } + } + + private class Delegate{ + + public void run(){ + try { + Failer failer = new Failer(); + failer.fail(); + } + catch (Exception e){ + throw new IllegalStateException("Error while running", e); + } + } + } + private class Failer { + + public void fail(){ + throw new NullPointerException("Point to null"); + } + } + +} diff --git a/honeybadger-log4j2-appender/src/test/resources/log4j2.xml b/honeybadger-log4j2-appender/src/test/resources/log4j2.xml new file mode 100644 index 0000000..9b431d7 --- /dev/null +++ b/honeybadger-log4j2-appender/src/test/resources/log4j2.xml @@ -0,0 +1,20 @@ + + + + [%-5p] %c - %m%n%throwable{none} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/honeybadger-logback-appender/pom.xml b/honeybadger-logback-appender/pom.xml index d8ad573..326a119 100644 --- a/honeybadger-logback-appender/pom.xml +++ b/honeybadger-logback-appender/pom.xml @@ -5,7 +5,7 @@ honeybadger-java com.workable.honeybadger - 1.5.1 + 1.5.2 4.0.0 diff --git a/pom.xml b/pom.xml index 8f1ca99..43b1577 100644 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,14 @@ 4.0.0 com.workable.honeybadger honeybadger-java - 1.5.1 + 1.5.2 Honeybadger :: Java Honeybadger Java parent project. https://github.com/Workable/honeybadger-java/wiki honeybadger-client honeybadger-log4j-appender + honeybadger-log4j2-appender honeybadger-logback-appender pom