From 8f0fff263006ffac0401a9c9c3ab4ccf77b66329 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Tue, 7 Aug 2018 11:17:40 +0100 Subject: [PATCH 01/10] fix: move thread capture to report construction rather than serialisation --- src/main/java/com/bugsnag/Bugsnag.java | 6 ++-- .../java/com/bugsnag/ExceptionHandler.java | 2 +- src/main/java/com/bugsnag/Report.java | 8 +++-- src/main/java/com/bugsnag/ThreadState.java | 4 +-- .../com/bugsnag/HandledStatePayloadTest.java | 2 +- .../java/com/bugsnag/ThreadStateTest.java | 35 ++++++++++++++++--- 6 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bugsnag/Bugsnag.java b/src/main/java/com/bugsnag/Bugsnag.java index 9e6eb515..e8237087 100644 --- a/src/main/java/com/bugsnag/Bugsnag.java +++ b/src/main/java/com/bugsnag/Bugsnag.java @@ -354,7 +354,7 @@ public boolean notify(Throwable throwable, Severity severity, Callback callback) HandledState handledState = HandledState.newInstance( HandledState.SeverityReasonType.REASON_USER_SPECIFIED, severity); - Report report = new Report(config, throwable, handledState); + Report report = new Report(config, throwable, handledState, Thread.currentThread()); return notify(report, callback); } @@ -372,8 +372,8 @@ public boolean notify(Report report) { } - boolean notify(Throwable throwable, HandledState handledState) { - Report report = new Report(config, throwable, handledState); + boolean notify(Throwable throwable, HandledState handledState, Thread currentThread) { + Report report = new Report(config, throwable, handledState, currentThread); return notify(report, null); } diff --git a/src/main/java/com/bugsnag/ExceptionHandler.java b/src/main/java/com/bugsnag/ExceptionHandler.java index 510ce861..d7eb5ab0 100644 --- a/src/main/java/com/bugsnag/ExceptionHandler.java +++ b/src/main/java/com/bugsnag/ExceptionHandler.java @@ -55,7 +55,7 @@ public void uncaughtException(Thread thread, Throwable throwable) { HandledState handledState = HandledState.newInstance( HandledState.SeverityReasonType.REASON_UNHANDLED_EXCEPTION, Severity.ERROR); - bugsnag.notify(throwable, handledState); + bugsnag.notify(throwable, handledState, thread); } // Pass exception on to original exception handler diff --git a/src/main/java/com/bugsnag/Report.java b/src/main/java/com/bugsnag/Report.java index 64adfac7..6967bdd6 100644 --- a/src/main/java/com/bugsnag/Report.java +++ b/src/main/java/com/bugsnag/Report.java @@ -24,6 +24,7 @@ public class Report { private Diagnostics diagnostics; private boolean shouldCancel = false; private Session session; + private final List threadStates; /** * Create a report for the error. @@ -33,15 +34,16 @@ public class Report { */ protected Report(Configuration config, Throwable throwable) { this(config, throwable, HandledState.newInstance( - HandledState.SeverityReasonType.REASON_HANDLED_EXCEPTION)); + HandledState.SeverityReasonType.REASON_HANDLED_EXCEPTION), Thread.currentThread()); } - Report(Configuration config, Throwable throwable, HandledState handledState) { + Report(Configuration config, Throwable throwable, HandledState handledState, Thread currentThread) { this.config = config; this.exception = new Exception(config, throwable); this.handledState = handledState; this.severity = handledState.getOriginalSeverity(); diagnostics = new Diagnostics(this.config); + threadStates = config.sendThreads ? ThreadState.getLiveThreads(config, currentThread) : null; } @Expose @@ -80,7 +82,7 @@ SeverityReason getSeverityReason() { @Expose protected List getThreads() { - return config.sendThreads ? ThreadState.getLiveThreads(config) : null; + return threadStates; } @Expose diff --git a/src/main/java/com/bugsnag/ThreadState.java b/src/main/java/com/bugsnag/ThreadState.java index 8a0fb04f..5b4b329a 100644 --- a/src/main/java/com/bugsnag/ThreadState.java +++ b/src/main/java/com/bugsnag/ThreadState.java @@ -22,9 +22,9 @@ class ThreadState { this.stackTraceElements = stackTraceElements; } - static List getLiveThreads(Configuration config) { + static List getLiveThreads(Configuration config, Thread currentThread) { // Get current thread id (the crashing thread) and stacktraces for all live threads - long crashingThreadId = Thread.currentThread().getId(); + long crashingThreadId = currentThread.getId(); Map liveThreads = Thread.getAllStackTraces(); // Sort threads by thread-id diff --git a/src/test/java/com/bugsnag/HandledStatePayloadTest.java b/src/test/java/com/bugsnag/HandledStatePayloadTest.java index 23d06bcd..0b86f80f 100644 --- a/src/test/java/com/bugsnag/HandledStatePayloadTest.java +++ b/src/test/java/com/bugsnag/HandledStatePayloadTest.java @@ -107,7 +107,7 @@ public void testCallbackSpecified() throws Exception { } private Report reportFromHandledState(HandledState handledState) { - return new Report(config, new RuntimeException(), handledState); + return new Report(config, new RuntimeException(), handledState, Thread.currentThread()); } private JsonNode getJsonPayloadFromReport(Report report) throws IOException { diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index 5cd93430..1564b784 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; @@ -15,6 +14,7 @@ import java.io.IOException; import java.lang.Exception; import java.util.List; +import java.util.Map; public class ThreadStateTest { @@ -27,7 +27,7 @@ public class ThreadStateTest { */ @Before public void setUp() throws Exception { - threadStates = ThreadState.getLiveThreads(new Configuration("apikey")); + threadStates = ThreadState.getLiveThreads(new Configuration("apikey"), Thread.currentThread()); } @Test @@ -62,7 +62,7 @@ public void testThreadStacktrace() { */ @Test public void testSerialisation() throws Exception { - JsonNode root = serialiseThreadStateToJson(); + JsonNode root = serialiseThreadStateToJson(threadStates); for (JsonNode jsonNode : root) { assertNotNull(jsonNode.get("id").asText()); @@ -77,7 +77,7 @@ public void testSerialisation() throws Exception { */ @Test public void testCurrentThread() throws Exception { - JsonNode root = serialiseThreadStateToJson(); + JsonNode root = serialiseThreadStateToJson(threadStates); long currentThreadId = Thread.currentThread().getId(); int currentThreadCount = 0; @@ -92,7 +92,32 @@ public void testCurrentThread() throws Exception { assertEquals(1, currentThreadCount); } - private JsonNode serialiseThreadStateToJson() throws IOException { + /** + * Verifies that a thread different from the current thread is serialised as an object, + * and that only this value contains the errorReportingThread boolean flag + */ + @Test + public void testDifferentThread() throws Exception { + Map threads = Thread.getAllStackTraces(); + threads.remove(Thread.currentThread()); + Thread otherThread = threads.keySet().iterator().next(); + List state = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread); + + JsonNode root = serialiseThreadStateToJson(state); + int currentThreadCount = 0; + + for (JsonNode jsonNode : root) { + if (otherThread.getId() == jsonNode.get("id").asLong()) { + assertTrue(jsonNode.get("errorReportingThread").asBoolean()); + currentThreadCount++; + } else { + assertFalse(jsonNode.has("errorReportingThread")); + } + } + assertEquals(1, currentThreadCount); + } + + private JsonNode serialiseThreadStateToJson(List threadStates) throws IOException { ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(threadStates); return mapper.readTree(json); From 447b11183d3340d05950eb198b78be9cc3f7c6d6 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Tue, 7 Aug 2018 13:23:40 +0100 Subject: [PATCH 02/10] style: pass checkstyle --- src/main/java/com/bugsnag/Report.java | 6 ++++-- src/test/java/com/bugsnag/ThreadStateTest.java | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bugsnag/Report.java b/src/main/java/com/bugsnag/Report.java index 6967bdd6..f8dfea33 100644 --- a/src/main/java/com/bugsnag/Report.java +++ b/src/main/java/com/bugsnag/Report.java @@ -37,13 +37,15 @@ protected Report(Configuration config, Throwable throwable) { HandledState.SeverityReasonType.REASON_HANDLED_EXCEPTION), Thread.currentThread()); } - Report(Configuration config, Throwable throwable, HandledState handledState, Thread currentThread) { + Report(Configuration config, Throwable throwable, + HandledState handledState, Thread currentThread) { this.config = config; this.exception = new Exception(config, throwable); this.handledState = handledState; this.severity = handledState.getOriginalSeverity(); diagnostics = new Diagnostics(this.config); - threadStates = config.sendThreads ? ThreadState.getLiveThreads(config, currentThread) : null; + threadStates = config.sendThreads + ? ThreadState.getLiveThreads(config, currentThread) : null; } @Expose diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index 1564b784..b92e813c 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -27,7 +27,8 @@ public class ThreadStateTest { */ @Before public void setUp() throws Exception { - threadStates = ThreadState.getLiveThreads(new Configuration("apikey"), Thread.currentThread()); + Configuration config = new Configuration("apikey"); + threadStates = ThreadState.getLiveThreads(config, Thread.currentThread()); } @Test @@ -101,7 +102,8 @@ public void testDifferentThread() throws Exception { Map threads = Thread.getAllStackTraces(); threads.remove(Thread.currentThread()); Thread otherThread = threads.keySet().iterator().next(); - List state = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread); + List state + = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; From 6b265efe884398fe2a34aa599372812547ff6f23 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Fri, 10 Aug 2018 09:47:06 +0100 Subject: [PATCH 03/10] feat: if thread trace missing for current thread, add a trace within threadstate --- src/main/java/com/bugsnag/Report.java | 2 +- src/main/java/com/bugsnag/ThreadState.java | 12 ++++++-- .../java/com/bugsnag/ThreadStateTest.java | 30 +++++++++++++++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bugsnag/Report.java b/src/main/java/com/bugsnag/Report.java index f8dfea33..1b724702 100644 --- a/src/main/java/com/bugsnag/Report.java +++ b/src/main/java/com/bugsnag/Report.java @@ -45,7 +45,7 @@ protected Report(Configuration config, Throwable throwable) { this.severity = handledState.getOriginalSeverity(); diagnostics = new Diagnostics(this.config); threadStates = config.sendThreads - ? ThreadState.getLiveThreads(config, currentThread) : null; + ? ThreadState.getLiveThreads(config, currentThread, Thread.getAllStackTraces()) : null; } @Expose diff --git a/src/main/java/com/bugsnag/ThreadState.java b/src/main/java/com/bugsnag/ThreadState.java index 5b4b329a..f764b695 100644 --- a/src/main/java/com/bugsnag/ThreadState.java +++ b/src/main/java/com/bugsnag/ThreadState.java @@ -22,10 +22,18 @@ class ThreadState { this.stackTraceElements = stackTraceElements; } - static List getLiveThreads(Configuration config, Thread currentThread) { + static List getLiveThreads(Configuration config, + Thread currentThread, + Map liveThreads) { // Get current thread id (the crashing thread) and stacktraces for all live threads long crashingThreadId = currentThread.getId(); - Map liveThreads = Thread.getAllStackTraces(); + + // if thread is not present for any reason, add the current stacktrace to the map + // so that the errorReportingThread will always be reported + if (!liveThreads.containsKey(currentThread)) { + liveThreads.put(currentThread, currentThread.getStackTrace()); + } + // Sort threads by thread-id Object[] keys = liveThreads.keySet().toArray(); diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index b92e813c..a73febef 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -28,7 +28,7 @@ public class ThreadStateTest { @Before public void setUp() throws Exception { Configuration config = new Configuration("apikey"); - threadStates = ThreadState.getLiveThreads(config, Thread.currentThread()); + threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), Thread.getAllStackTraces()); } @Test @@ -103,7 +103,7 @@ public void testDifferentThread() throws Exception { threads.remove(Thread.currentThread()); Thread otherThread = threads.keySet().iterator().next(); List state - = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread); + = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread, Thread.getAllStackTraces()); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; @@ -119,6 +119,32 @@ public void testDifferentThread() throws Exception { assertEquals(1, currentThreadCount); } + /** + * Verifies that if the current thread is missing from the available traces as reported by + * {@link Thread#getAllStackTraces()}, its stacktrace will still be serialised + */ + @Test + public void testMissingCurrentThread() throws Exception { + Map threads = Thread.getAllStackTraces(); + Thread currentThread = Thread.currentThread(); + threads.remove(currentThread); + + List state + = ThreadState.getLiveThreads(new Configuration("apikey"), currentThread, threads); + + JsonNode root = serialiseThreadStateToJson(state); + int currentThreadCount = 0; + + for (JsonNode jsonNode : root) { + if (currentThread.getId() == jsonNode.get("id").asLong()) { + assertTrue(jsonNode.get("errorReportingThread").asBoolean()); + assertTrue(jsonNode.get("stacktrace").size() > 0); + currentThreadCount++; + } + } + assertEquals(1, currentThreadCount); + } + private JsonNode serialiseThreadStateToJson(List threadStates) throws IOException { ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(threadStates); From 110364b50c3d7c2a37408cd0619711290a068860 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Fri, 10 Aug 2018 10:08:44 +0100 Subject: [PATCH 04/10] style: pass checkstyle --- src/main/java/com/bugsnag/Report.java | 9 +++++++-- src/test/java/com/bugsnag/ThreadStateTest.java | 12 +++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bugsnag/Report.java b/src/main/java/com/bugsnag/Report.java index 1b724702..3e7d7cd8 100644 --- a/src/main/java/com/bugsnag/Report.java +++ b/src/main/java/com/bugsnag/Report.java @@ -44,8 +44,13 @@ protected Report(Configuration config, Throwable throwable) { this.handledState = handledState; this.severity = handledState.getOriginalSeverity(); diagnostics = new Diagnostics(this.config); - threadStates = config.sendThreads - ? ThreadState.getLiveThreads(config, currentThread, Thread.getAllStackTraces()) : null; + + if (config.sendThreads) { + Map allStackTraces = Thread.getAllStackTraces(); + threadStates = ThreadState.getLiveThreads(config, currentThread, allStackTraces); + } else { + threadStates = null; + } } @Expose diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index a73febef..8c513bd2 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -19,6 +19,7 @@ public class ThreadStateTest { private List threadStates; + private Configuration config; /** * Generates a list of current thread states @@ -27,8 +28,9 @@ public class ThreadStateTest { */ @Before public void setUp() throws Exception { - Configuration config = new Configuration("apikey"); - threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), Thread.getAllStackTraces()); + config = new Configuration("apikey"); + Map stackTraces = Thread.getAllStackTraces(); + threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), stackTraces); } @Test @@ -102,8 +104,8 @@ public void testDifferentThread() throws Exception { Map threads = Thread.getAllStackTraces(); threads.remove(Thread.currentThread()); Thread otherThread = threads.keySet().iterator().next(); - List state - = ThreadState.getLiveThreads(new Configuration("apikey"), otherThread, Thread.getAllStackTraces()); + Map allStackTraces = Thread.getAllStackTraces(); + List state = ThreadState.getLiveThreads(config, otherThread, allStackTraces); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; @@ -130,7 +132,7 @@ public void testMissingCurrentThread() throws Exception { threads.remove(currentThread); List state - = ThreadState.getLiveThreads(new Configuration("apikey"), currentThread, threads); + = ThreadState.getLiveThreads(config, currentThread, threads); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; From 7ede3e8a91b4e8d1c299e334f6c8b5668d3226e6 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Tue, 14 Aug 2018 14:43:33 +0100 Subject: [PATCH 05/10] feat: if a throwable is unhandled, serialise the exception rather than thread stacktrace if thread c --- src/main/java/com/bugsnag/Report.java | 3 +- src/main/java/com/bugsnag/ThreadState.java | 7 +- .../java/com/bugsnag/ThreadStateTest.java | 79 ++++++++++++++++++- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bugsnag/Report.java b/src/main/java/com/bugsnag/Report.java index 3e7d7cd8..edbbf4c5 100644 --- a/src/main/java/com/bugsnag/Report.java +++ b/src/main/java/com/bugsnag/Report.java @@ -46,8 +46,9 @@ protected Report(Configuration config, Throwable throwable) { diagnostics = new Diagnostics(this.config); if (config.sendThreads) { + Throwable exc = handledState.isUnhandled() ? throwable : null; Map allStackTraces = Thread.getAllStackTraces(); - threadStates = ThreadState.getLiveThreads(config, currentThread, allStackTraces); + threadStates = ThreadState.getLiveThreads(config, currentThread, allStackTraces, exc); } else { threadStates = null; } diff --git a/src/main/java/com/bugsnag/ThreadState.java b/src/main/java/com/bugsnag/ThreadState.java index f764b695..3525538b 100644 --- a/src/main/java/com/bugsnag/ThreadState.java +++ b/src/main/java/com/bugsnag/ThreadState.java @@ -24,7 +24,8 @@ class ThreadState { static List getLiveThreads(Configuration config, Thread currentThread, - Map liveThreads) { + Map liveThreads, + Throwable exc) { // Get current thread id (the crashing thread) and stacktraces for all live threads long crashingThreadId = currentThread.getId(); @@ -33,7 +34,9 @@ static List getLiveThreads(Configuration config, if (!liveThreads.containsKey(currentThread)) { liveThreads.put(currentThread, currentThread.getStackTrace()); } - + if (exc != null) { // unhandled errors use the exception trace + liveThreads.put(currentThread, exc.getStackTrace()); + } // Sort threads by thread-id Object[] keys = liveThreads.keySet().toArray(); diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index 8c513bd2..58157011 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -30,7 +30,7 @@ public class ThreadStateTest { public void setUp() throws Exception { config = new Configuration("apikey"); Map stackTraces = Thread.getAllStackTraces(); - threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), stackTraces); + threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), stackTraces, null); } @Test @@ -105,7 +105,7 @@ public void testDifferentThread() throws Exception { threads.remove(Thread.currentThread()); Thread otherThread = threads.keySet().iterator().next(); Map allStackTraces = Thread.getAllStackTraces(); - List state = ThreadState.getLiveThreads(config, otherThread, allStackTraces); + List state = ThreadState.getLiveThreads(config, otherThread, allStackTraces, null); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; @@ -132,7 +132,7 @@ public void testMissingCurrentThread() throws Exception { threads.remove(currentThread); List state - = ThreadState.getLiveThreads(config, currentThread, threads); + = ThreadState.getLiveThreads(config, currentThread, threads, null); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; @@ -147,6 +147,79 @@ public void testMissingCurrentThread() throws Exception { assertEquals(1, currentThreadCount); } + + /** + * Verifies that a handled error uses {@link Thread#getAllStackTraces()} for the reporting thread stacktrace + */ + @Test + public void testHandledStacktrace() throws Exception { + Map threads = Thread.getAllStackTraces(); + Thread currentThread = Thread.currentThread(); + StackTraceElement[] expectedTrace = threads.get(currentThread); + + List state + = ThreadState.getLiveThreads(config, currentThread, threads, null); + + JsonNode root = serialiseThreadStateToJson(state); + int currentThreadCount = 0; + + for (JsonNode jsonNode : root) { + if (currentThread.getId() == jsonNode.get("id").asLong()) { + currentThreadCount++; + + // the thread id + name should always be used + assertEquals(currentThread.getName(), jsonNode.get("name").asText()); + + // stacktrace should come from the thread (check same length and line numbers) + JsonNode stacktrace = jsonNode.get("stacktrace"); + assertEquals(expectedTrace.length, stacktrace.size()); + + for (int k = 0; k < expectedTrace.length; k++) { + JsonNode obj = stacktrace.get(k); + assertEquals(expectedTrace[k].getLineNumber(), obj.get("lineNumber").intValue()); + } + } + } + assertEquals(1, currentThreadCount); + } + + /** + * Verifies that an unhandled error uses {@link com.bugsnag.Exception#getStacktrace()} + * for the reporting thread stacktrace + */ + @Test + public void testUnhandledStacktrace() throws Exception { + Map threads = Thread.getAllStackTraces(); + Thread currentThread = Thread.currentThread(); + RuntimeException exc = new RuntimeException("Whoops"); + StackTraceElement[] expectedTrace = exc.getStackTrace(); + + List state + = ThreadState.getLiveThreads(config, currentThread, threads, exc); + + JsonNode root = serialiseThreadStateToJson(state); + int currentThreadCount = 0; + + for (JsonNode jsonNode : root) { + if (currentThread.getId() == jsonNode.get("id").asLong()) { + currentThreadCount++; + + // the thread id + name should always be used + assertEquals(currentThread.getName(), jsonNode.get("name").asText()); + + // stacktrace should come from the thread (check same length and line numbers) + JsonNode stacktrace = jsonNode.get("stacktrace"); + assertEquals(expectedTrace.length, stacktrace.size()); + + for (int k = 0; k < expectedTrace.length; k++) { + JsonNode obj = stacktrace.get(k); + assertEquals(expectedTrace[k].getLineNumber(), obj.get("lineNumber").intValue()); + } + } + } + assertEquals(1, currentThreadCount); + } + private JsonNode serialiseThreadStateToJson(List threadStates) throws IOException { ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(threadStates); From 249c5f649ab855902caa20fb89e3664efd2e1cd7 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Tue, 14 Aug 2018 14:45:51 +0100 Subject: [PATCH 06/10] style: pass checkstyle --- src/test/java/com/bugsnag/ThreadStateTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index 58157011..889c212f 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -30,7 +30,8 @@ public class ThreadStateTest { public void setUp() throws Exception { config = new Configuration("apikey"); Map stackTraces = Thread.getAllStackTraces(); - threadStates = ThreadState.getLiveThreads(config, Thread.currentThread(), stackTraces, null); + Thread currentThread = Thread.currentThread(); + threadStates = ThreadState.getLiveThreads(config, currentThread, stackTraces, null); } @Test @@ -105,7 +106,8 @@ public void testDifferentThread() throws Exception { threads.remove(Thread.currentThread()); Thread otherThread = threads.keySet().iterator().next(); Map allStackTraces = Thread.getAllStackTraces(); - List state = ThreadState.getLiveThreads(config, otherThread, allStackTraces, null); + List state + = ThreadState.getLiveThreads(config, otherThread, allStackTraces, null); JsonNode root = serialiseThreadStateToJson(state); int currentThreadCount = 0; @@ -149,7 +151,8 @@ public void testMissingCurrentThread() throws Exception { /** - * Verifies that a handled error uses {@link Thread#getAllStackTraces()} for the reporting thread stacktrace + * Verifies that a handled error uses {@link Thread#getAllStackTraces()} + * for the reporting thread stacktrace */ @Test public void testHandledStacktrace() throws Exception { @@ -176,7 +179,8 @@ public void testHandledStacktrace() throws Exception { for (int k = 0; k < expectedTrace.length; k++) { JsonNode obj = stacktrace.get(k); - assertEquals(expectedTrace[k].getLineNumber(), obj.get("lineNumber").intValue()); + JsonNode lineNumber = obj.get("lineNumber"); + assertEquals(expectedTrace[k].getLineNumber(), lineNumber.intValue()); } } } @@ -213,7 +217,8 @@ public void testUnhandledStacktrace() throws Exception { for (int k = 0; k < expectedTrace.length; k++) { JsonNode obj = stacktrace.get(k); - assertEquals(expectedTrace[k].getLineNumber(), obj.get("lineNumber").intValue()); + JsonNode lineNumber = obj.get("lineNumber"); + assertEquals(expectedTrace[k].getLineNumber(), lineNumber.intValue()); } } } From 1d7d9edd951b31ccba409aa3483787b87570941c Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Mon, 3 Sep 2018 14:41:42 +0100 Subject: [PATCH 07/10] style: remove unnecessary jsoninclude annotation - serialisation is non-empty by default --- src/main/java/com/bugsnag/ThreadState.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/bugsnag/ThreadState.java b/src/main/java/com/bugsnag/ThreadState.java index 3525538b..a6876dd8 100644 --- a/src/main/java/com/bugsnag/ThreadState.java +++ b/src/main/java/com/bugsnag/ThreadState.java @@ -76,7 +76,6 @@ public List getStacktrace() { } @JsonProperty("errorReportingThread") - @JsonInclude(JsonInclude.Include.NON_NULL) public Boolean isErrorReportingThread() { return errorReportingThread; } From 334768d67d196c9886ff0f6331ad417890486e90 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Mon, 3 Sep 2018 14:49:59 +0100 Subject: [PATCH 08/10] remove unused import --- src/main/java/com/bugsnag/ThreadState.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/bugsnag/ThreadState.java b/src/main/java/com/bugsnag/ThreadState.java index a6876dd8..87ca3ec5 100644 --- a/src/main/java/com/bugsnag/ThreadState.java +++ b/src/main/java/com/bugsnag/ThreadState.java @@ -1,6 +1,5 @@ package com.bugsnag; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; From 5d7850fe0445fbb3d28a0a3c0d9a163477295025 Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Mon, 3 Sep 2018 14:59:06 +0100 Subject: [PATCH 09/10] test: update ThreadStateTest to use same objectmapper configuration as bugsnag Updates the ThreadStateTest ObjectMapper to ignore non-empty values when serialising JSON. This means the stacktrace node can be null for some threads, as it is not guaranteed by the language that a trace can be captured for each thread. --- src/test/java/com/bugsnag/ThreadStateTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/bugsnag/ThreadStateTest.java b/src/test/java/com/bugsnag/ThreadStateTest.java index 889c212f..94526508 100644 --- a/src/test/java/com/bugsnag/ThreadStateTest.java +++ b/src/test/java/com/bugsnag/ThreadStateTest.java @@ -4,8 +4,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; @@ -71,7 +72,6 @@ public void testSerialisation() throws Exception { for (JsonNode jsonNode : root) { assertNotNull(jsonNode.get("id").asText()); assertNotNull(jsonNode.get("name").asText()); - assertNotNull(jsonNode.get("stacktrace")); } } @@ -225,8 +225,14 @@ public void testUnhandledStacktrace() throws Exception { assertEquals(1, currentThreadCount); } + @SuppressWarnings("deprecation") private JsonNode serialiseThreadStateToJson(List threadStates) throws IOException { ObjectMapper mapper = new ObjectMapper(); + mapper + .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) + .setVisibilityChecker(mapper.getVisibilityChecker() + .with(JsonAutoDetect.Visibility.NONE)); + String json = mapper.writeValueAsString(threadStates); return mapper.readTree(json); } From 1f3ed1867c97da295e114b80fce8440ca4965a2a Mon Sep 17 00:00:00 2001 From: fractalwrench Date: Tue, 25 Sep 2018 15:05:39 +0100 Subject: [PATCH 10/10] v3.3.0 --- CHANGELOG.md | 2 +- gradle.properties | 2 +- src/main/java/com/bugsnag/Notifier.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 961c2edc..c73a14da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 3.X.X (TBD) +## 3.3.0 (2018-09-26) * Capture trace of error reporting thread and identify with boolean flag [#87](https://github.com/bugsnag/bugsnag-java/pull/87) diff --git a/gradle.properties b/gradle.properties index eb470999..de200631 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.2.1 +version=3.3.0 group=com.bugsnag # Default properties diff --git a/src/main/java/com/bugsnag/Notifier.java b/src/main/java/com/bugsnag/Notifier.java index 5a616a35..cb4f57f2 100644 --- a/src/main/java/com/bugsnag/Notifier.java +++ b/src/main/java/com/bugsnag/Notifier.java @@ -4,7 +4,7 @@ class Notifier { private static final String NOTIFIER_NAME = "Bugsnag Java"; - private static final String NOTIFIER_VERSION = "3.2.1"; + private static final String NOTIFIER_VERSION = "3.3.0"; private static final String NOTIFIER_URL = "https://github.com/bugsnag/bugsnag-java"; @Expose