From bbbf5e5dfbe3a6560ab5f5fd3fa120fb22b57fab Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 22 Mar 2025 21:06:02 -0300 Subject: [PATCH 01/37] fix: typos --- .../src/main/java/com/rollbar/notifier/Rollbar.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java index a3214e61..d62ee8e7 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java @@ -553,7 +553,7 @@ public void log(String message, Map custom, Level level) { } /** - * Record an error or message with extra data at the level specified. At least ene of `error` or + * Record an error or message with extra data at the level specified. At least one of `error` or * `description` must be non-null. If error is null, `description` will be sent as a message. If * error is non-null, description will be sent as the description of the error. Custom data will * be attached to message if the error is null. Custom data will extend whatever {@link @@ -569,7 +569,7 @@ public void log(Throwable error, Map custom, String description, } /** - * Record an error or message with extra data at the level specified. At least ene of `error` or + * Record an error or message with extra data at the level specified. At least one of `error` or * `description` must be non-null. If error is null, `description` will be sent as a message. If * error is non-null, description will be sent as the description of the error. Custom data will * be attached to message if the error is null. Custom data will extend whatever {@link @@ -579,7 +579,7 @@ public void log(Throwable error, Map custom, String description, * @param custom the custom data (if any). * @param description the description of the error, or the message to send. * @param level the level to send it at. - * @param isUncaught whether or not this data comes from an uncaught exception. + * @param isUncaught whether this data comes from an uncaught exception. */ public void log(Throwable error, Map custom, String description, Level level, boolean isUncaught) { From 08e1d608daf79e54a66c3a202019920e577a72da Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Mar 2025 18:31:46 -0300 Subject: [PATCH 02/37] feat: add new class RollbarThread --- .../api/payload/data/body/RollbarThread.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java new file mode 100644 index 00000000..298d5b5a --- /dev/null +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -0,0 +1,73 @@ +package com.rollbar.api.payload.data.body; + +import com.rollbar.api.json.JsonSerializable; +import com.rollbar.api.truncation.StringTruncatable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class RollbarThread implements JsonSerializable, StringTruncatable { + + private final String name; + private final String id; + private final String priority; + private final String state; + private final BodyContent bodyContent; + + public RollbarThread(Thread thread, BodyContent bodyContent) { + name = thread.getName(); + id = String.valueOf(thread.getId()); + priority = String.valueOf(thread.getPriority()); + state = thread.getState().toString(); + this.bodyContent = bodyContent; + } + + @Override + public Object asJson() { + Map values = new HashMap<>(); + values.put("name", name); + values.put("id", id); + values.put("priority", priority); + values.put("state", state); + if (bodyContent != null) { + values.put(bodyContent.getKeyName(), bodyContent); + } + return values; + } + + @Override + public RollbarThread truncateStrings(int maxLength) { + return null; + } + + @Override + public String toString() { + return "RollbarThread{" + + "name='" + name + '\'' + + ", id='" + id + '\'' + + ", priority='" + priority + '\'' + + ", state='" + state + '\'' + + ", " + bodyContent.getKeyName() + "=" + bodyContent + + '}'; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RollbarThread)) return false; + RollbarThread that = (RollbarThread) o; + return Objects.equals(name, that.name) && Objects.equals(id, that.id) && Objects.equals(priority, that.priority) && Objects.equals(state, that.state) && Objects.equals(bodyContent, that.bodyContent); + } + + @Override + public int hashCode() { + return Objects.hash(name, id, priority, state, bodyContent); + } + + /** + * Builder class for {@link RollbarThread RollbarThread}. + */ + public static final class Builder { + + } +} From 337a1f132c2397e1e50dd3b4bd205d81393064d4 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Mar 2025 18:32:22 -0300 Subject: [PATCH 03/37] feat: set thread information from RollbarUncaughtExceptionHandler --- .../uncaughtexception/RollbarUncaughtExceptionHandler.java | 2 +- .../RollbarUncaughtExceptionHandlerTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandler.java b/rollbar-java/src/main/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandler.java index 829dbe3a..99993285 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandler.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandler.java @@ -26,7 +26,7 @@ public RollbarUncaughtExceptionHandler(Rollbar rollbar, UncaughtExceptionHandler @Override public void uncaughtException(Thread thread, Throwable throwable) { - rollbar.log(throwable, null, null, null, true); + rollbar.log(throwable, thread, null, null, null, true); if (delegate != null) { delegate.uncaughtException(thread, throwable); diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandlerTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandlerTest.java index 1c27ad69..0f7dd373 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandlerTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/uncaughtexception/RollbarUncaughtExceptionHandlerTest.java @@ -34,7 +34,7 @@ public void shouldLogThrowableToRollbar() { sut.uncaughtException(thread, throwable); - verify(rollbar).log(throwable, null, null, null, true); + verify(rollbar).log(throwable, thread, null, null, null, true); verify(uncaughtExceptionHandler, never()).uncaughtException(thread, throwable); } @@ -45,7 +45,7 @@ public void shouldLogThrowableToRollbarAndDelegate() { sut.uncaughtException(thread, throwable); - verify(rollbar).log(throwable, null, null, null, true); + verify(rollbar).log(throwable, thread, null, null, null, true); verify(uncaughtExceptionHandler).uncaughtException(thread, throwable); } From c3ee843b03504782b024b6a99b6199301071daf3 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Mar 2025 18:33:12 -0300 Subject: [PATCH 04/37] feat: add Exception Thread and other threads information --- .../wrapper/RollbarThrowableWrapper.java | 111 +++++++++++++++--- .../notifier/wrapper/ThrowableWrapper.java | 6 + .../wrapper/RollbarThrowableWrapperTest.java | 17 ++- 3 files changed, 113 insertions(+), 21 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java index 128049d5..0cc5b88f 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java @@ -1,6 +1,8 @@ package com.rollbar.notifier.wrapper; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; /** * Implementation of the {@link ThrowableWrapper throwable wrapper}. @@ -17,38 +19,99 @@ public class RollbarThrowableWrapper implements ThrowableWrapper { private final Throwable throwable; + private final Thread thread; + + private final Map allStackTraces; + /** * Constructor. * * @param throwable the throwable. */ public RollbarThrowableWrapper(Throwable throwable) { - this(throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, - throwable); + this( + throwable.getClass().getName(), + throwable.getMessage(), + throwable.getStackTrace(), + throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, + throwable, + null, + null + ); } /** * Constructor. * - * @param className the class name. - * @param message the message. + * @param throwable the throwable. + */ + public RollbarThrowableWrapper(Throwable throwable, Thread thread) { + this( + throwable.getClass().getName(), + throwable.getMessage(), + throwable.getStackTrace(), + throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, + throwable, + thread, + getAllStackTraces(thread) + ); + } + + private static Map getAllStackTraces(Thread thread) { + if (thread == null) { + return null; + } + + return filter(thread, Thread.getAllStackTraces()); + } + + private static Map filter(Thread thread, Map allStackTraces) { + HashMap filteredStackTraces = new HashMap<>(); + + for (Map.Entry entry : allStackTraces.entrySet()) { + Thread entryThread = entry.getKey(); + + if (!thread.equals(entryThread)) { + filteredStackTraces.put(entryThread, entry.getValue()); + } + } + + return filteredStackTraces; + } + + /** + * Constructor. + * + * @param className the class name. + * @param message the message. * @param stackTraceElements the stack trace elements. - * @param cause the cause. + * @param cause the cause. */ - public RollbarThrowableWrapper(String className, String message, - StackTraceElement[] stackTraceElements, - ThrowableWrapper cause) { - this(className, message, stackTraceElements, cause, null); + public RollbarThrowableWrapper( + String className, + String message, + StackTraceElement[] stackTraceElements, + ThrowableWrapper cause + ) { + this(className, message, stackTraceElements, cause, null, null, null); } - private RollbarThrowableWrapper(String className, String message, - StackTraceElement[] stackTraceElements, ThrowableWrapper cause, Throwable throwable) { + private RollbarThrowableWrapper( + String className, + String message, + StackTraceElement[] stackTraceElements, + ThrowableWrapper cause, + Throwable throwable, + Thread thread, + Map allStackTraces + ) { this.className = className; this.message = message; this.stackTraceElements = stackTraceElements; this.cause = cause; this.throwable = throwable; + this.thread = thread; + this.allStackTraces = allStackTraces; } @Override @@ -76,15 +139,27 @@ public Throwable getThrowable() { return this.throwable; } + @Override + public Thread getThread() { + return thread; + } + + @Override + public Map getAllStackTraces() { + return allStackTraces; + } + @Override public String toString() { return "RollbarThrowableWrapper{" - + "className='" + className + '\'' - + ", message='" + message + '\'' - + ", stackTraceElements=" + Arrays.toString(stackTraceElements) - + ", cause=" + cause - + ", throwable=" + throwable - + '}'; + + "className='" + className + '\'' + + ", message='" + message + '\'' + + ", stackTraceElements=" + Arrays.toString(stackTraceElements) + + ", cause=" + cause + + ", throwable=" + throwable + + ", thread=" + thread + + ", threads=" + allStackTraces + + '}'; } @Override diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java index a195c108..6a5cd8c9 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java @@ -1,5 +1,7 @@ package com.rollbar.notifier.wrapper; +import java.util.Map; + /** * Throwable wrapper to wrap a {@link Throwable thowable} or to represent a not available one. */ @@ -39,4 +41,8 @@ public interface ThrowableWrapper { * @return the throwable. */ Throwable getThrowable(); + + Thread getThread(); + + Map getAllStackTraces(); } diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java index 3456cfcd..e6f36df0 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java @@ -2,13 +2,20 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import org.junit.Test; public class RollbarThrowableWrapperTest { + @Test + public void shouldCollectThreads() { + RollbarThrowableWrapper sut = new RollbarThrowableWrapper(new Exception("Any"), Thread.currentThread()); + + assertNotNull(sut.getAllStackTraces()); + assertNotNull(sut.getThread()); + } + @Test public void shouldBeCreatedByThrowable() { Throwable nestedThrowable = new IllegalStateException("This is the nested throwable message"); @@ -22,6 +29,8 @@ public void shouldBeCreatedByThrowable() { assertThat(sut.getStackTrace(), is(throwable.getStackTrace())); assertThat(sut.getCause(), is(nested)); assertThat(sut.getThrowable(), is(throwable)); + assertNull(sut.getAllStackTraces()); + assertNull(sut.getThread()); } @Test @@ -40,6 +49,8 @@ public void shouldBeCreatedByThrowableParams() { assertThat(sut.getStackTrace(), is(elements)); assertThat(sut.getCause(), is(cause)); assertThat(sut.getThrowable(), is(nullValue())); + assertNull(sut.getAllStackTraces()); + assertNull(sut.getThread()); } @Test @@ -49,6 +60,6 @@ public void shouldBeEqual() { RollbarThrowableWrapper sut1 = new RollbarThrowableWrapper(throwable); RollbarThrowableWrapper sut2 = new RollbarThrowableWrapper(throwable); - assertTrue(sut1.equals(sut2)); + assertEquals(sut1, sut2); } } \ No newline at end of file From e73ab61472c627d619afd7d81936c5231dad233c Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Mar 2025 18:33:40 -0300 Subject: [PATCH 05/37] feat: add Threads to body --- .../rollbar/api/payload/data/body/Body.java | 26 ++++- .../rollbar/notifier/util/BodyFactory.java | 104 +++++++++++++----- .../notifier/util/BodyFactoryTest.java | 27 ++++- 3 files changed, 129 insertions(+), 28 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 2ba983de..d6de3ae8 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -19,9 +19,12 @@ public class Body implements JsonSerializable, StringTruncatable { private final List telemetryEvents; + private final List rollbarThreads; + private Body(Builder builder) { this.bodyContent = builder.bodyContent; this.telemetryEvents = builder.telemetryEvents; + this.rollbarThreads = builder.rollbarThreads; } /** @@ -44,6 +47,10 @@ public Object asJson() { values.put("telemetry", telemetryEvents); } + if (rollbarThreads != null) { + values.put("threads", rollbarThreads); + } + return values; } @@ -83,6 +90,7 @@ public String toString() { return "Body{" + "bodyContent=" + bodyContent + ", telemetry=" + telemetryEvents + + ", threads=" + rollbarThreads + '}'; } @@ -95,6 +103,8 @@ public static final class Builder { private List telemetryEvents; + private List rollbarThreads; + /** * Constructor. */ @@ -108,8 +118,9 @@ public Builder() { * @param body the {@link Body body} to initialize a new builder instance. */ public Builder(Body body) { - this.bodyContent = body.bodyContent; - this.telemetryEvents = body.telemetryEvents; + bodyContent = body.bodyContent; + telemetryEvents = body.telemetryEvents; + rollbarThreads = body.rollbarThreads; } /** @@ -135,6 +146,17 @@ public Builder telemetryEvents(List telemetryEvents) { return this; } + /** + * Information from other threads. + * + * @param rollbarThreads a list of threads without the thread where the Exception occurred; + * @return the builder instance. + */ + public Builder rollbarThreads(List rollbarThreads) { + this.rollbarThreads = rollbarThreads; + return this; + } + /** * Builds the {@link Body body}. * diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index 50a847c0..2827dfea 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -1,18 +1,14 @@ package com.rollbar.notifier.util; import com.rollbar.api.payload.data.TelemetryEvent; -import com.rollbar.api.payload.data.body.Body; -import com.rollbar.api.payload.data.body.ExceptionInfo; -import com.rollbar.api.payload.data.body.Frame; -import com.rollbar.api.payload.data.body.Message; -import com.rollbar.api.payload.data.body.Trace; -import com.rollbar.api.payload.data.body.TraceChain; +import com.rollbar.api.payload.data.body.*; import com.rollbar.jvmti.CacheFrame; import com.rollbar.jvmti.ThrowableCache; import com.rollbar.notifier.wrapper.RollbarThrowableWrapper; import com.rollbar.notifier.wrapper.ThrowableWrapper; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -60,22 +56,70 @@ public Body from(ThrowableWrapper throwableWrapper, String description) { * @return the body. */ public Body from( - ThrowableWrapper throwableWrapper, - String description, - List telemetryEvents + ThrowableWrapper throwableWrapper, + String description, + List telemetryEvents ) { Body.Builder builder = new Body.Builder().telemetryEvents(telemetryEvents); return from(throwableWrapper, description, builder); } - private Body from(ThrowableWrapper throwableWrapper, String description, Body.Builder builder) { + private Body from( + ThrowableWrapper throwableWrapper, + String description, + Body.Builder builder + ) { + return builder + .bodyContent(makeBodyContent(throwableWrapper, description)) + .rollbarThreads(makeRollbarThreads(throwableWrapper, description)) + .build(); + } + + private List makeRollbarThreads( + ThrowableWrapper throwableWrapper, + String description + ) { + if (throwableWrapper == null) { + return null; + } + + Map allStackTraces = throwableWrapper.getAllStackTraces(); + if (allStackTraces == null) { + return null; + } + + ArrayList rollbarThreads = new ArrayList<>(); + rollbarThreads.add(makeInitialRollbarThread(throwableWrapper, description)); + return addOtherThreads(rollbarThreads, allStackTraces); + } + + private RollbarThread makeInitialRollbarThread(ThrowableWrapper throwableWrapper, String description) { + BodyContent bodyContent = makeBodyContent(throwableWrapper, description); + return new RollbarThread(throwableWrapper.getThread(), bodyContent); + } + + private ArrayList addOtherThreads( + ArrayList rollbarThreads, + Map allStackTraces + ) { + for (Map.Entry entry : allStackTraces.entrySet()) { + List frames = frames(entry.getValue()); + Trace trace = new Trace.Builder().frames(frames).build(); + rollbarThreads.add(new RollbarThread(entry.getKey(), trace)); + } + return rollbarThreads; + } + + private BodyContent makeBodyContent(ThrowableWrapper throwableWrapper, String description) { if (throwableWrapper == null) { - return builder.bodyContent(message(description)).build(); + return message(description); } + if (throwableWrapper.getCause() == null) { - return builder.bodyContent(trace(throwableWrapper, description)).build(); + return trace(throwableWrapper, description); } - return builder.bodyContent(traceChain(throwableWrapper, description)).build(); + + return traceChain(throwableWrapper, description); } private static Message message(String description) { @@ -99,8 +143,8 @@ private static TraceChain traceChain(ThrowableWrapper throwableWrapper, String d throwableWrapper = throwableWrapper.getCause(); } while (throwableWrapper != null); return new TraceChain.Builder() - .traces(chain) - .build(); + .traces(chain) + .build(); } private static List frames(ThrowableWrapper throwableWrapper) { @@ -129,14 +173,24 @@ private static List frames(ThrowableWrapper throwableWrapper) { return result; } + private static List frames(StackTraceElement[] stackTraceElements) { + + ArrayList result = new ArrayList<>(); + for (int i = stackTraceElements.length - 1; i >= 0; i--) { + result.add(frame(stackTraceElements[i], Collections.emptyMap())); + } + + return result; + } + private static ExceptionInfo info(ThrowableWrapper throwableWrapper, String description) { String className = throwableWrapper.getClassName(); String message = throwableWrapper.getMessage(); return new ExceptionInfo.Builder() - .className(className) - .message(message) - .description(description) - .build(); + .className(className) + .message(message) + .description(description) + .build(); } private static Frame frame(StackTraceElement element, Map locals) { @@ -146,11 +200,11 @@ private static Frame frame(StackTraceElement element, Map locals String className = element.getClassName(); return new Frame.Builder() - .filename(filename) - .lineNumber(lineNumber) - .method(method) - .className(className) - .locals(locals) - .build(); + .filename(filename) + .lineNumber(lineNumber) + .method(method) + .className(className) + .locals(locals) + .build(); } } diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java index 37090686..b40755a4 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java @@ -3,7 +3,8 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.mockito.Mockito.verify; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import com.rollbar.api.payload.data.body.Body; import com.rollbar.api.payload.data.body.ExceptionInfo; @@ -15,6 +16,7 @@ import com.rollbar.notifier.wrapper.ThrowableWrapper; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import org.junit.Before; import org.junit.Test; @@ -47,6 +49,29 @@ public void shouldBuildBodyWithDescription() { assertThat(((Message) body2.getContents()).getBody(), is(DESCRIPTION)); } + @Test + public void shouldBuildBodyWithDescriptionAndTelemetryEvents() { + Body body = sut.from(null, DESCRIPTION, new ArrayList<>()); + + assertThat(body.getContents(), is(instanceOf(Message.class))); + assertThat(((Message) body.getContents()).getBody(), is(DESCRIPTION)); + HashMap map = (HashMap) body.asJson(); + assertNotNull(map.get("telemetry")); + assertNull(map.get("threads")); + } + + @Test + public void shouldBuildBodyWithThreads() { + Throwable throwable = buildSimpleThrowable(); + ThrowableWrapper throwableWrapper = new RollbarThrowableWrapper(throwable, Thread.currentThread()); + Body body = sut.from(throwableWrapper, DESCRIPTION); + + assertThat(body.getContents(), is(instanceOf(Trace.class))); + HashMap map = (HashMap) body.asJson(); + assertNull(map.get("telemetry")); + assertNotNull(map.get("threads")); + } + @Test public void shouldBuildBodyWithTraceAsContent() { Throwable throwable = buildSimpleThrowable(); From 2bfb85dcb4d36a4ea58e0c8e45e659dd4440348b Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Mar 2025 18:34:06 -0300 Subject: [PATCH 06/37] feat: add Threads to throwable wrapper in notifier --- .../java/com/rollbar/notifier/Rollbar.java | 29 +++++++++++++++++-- .../com/rollbar/notifier/RollbarBase.java | 16 ++++++---- .../com/rollbar/notifier/RollbarTest.java | 7 ----- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java index d62ee8e7..04bd4808 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java @@ -587,17 +587,42 @@ public void log(Throwable error, Map custom, String description, } /** - * Record an error or message with extra data at the level specified. At least ene of `error` or + * Record an error or message with extra data at the level specified. At least one of `error` or * `description` must be non-null. If error is null, `description` will be sent as a message. If * error is non-null, description will be sent as the description of the error. Custom data will * be attached to message if the error is null. Custom data will extend whatever {@link * Config#custom} returns. * * @param error the error (if any). + * @param thread the thread where the error happened (if any). * @param custom the custom data (if any). * @param description the description of the error, or the message to send. * @param level the level to send it at. - * @param isUncaught whether or not this data comes from an uncaught exception. + * @param isUncaught whether this data comes from an uncaught exception. + */ + public void log( + Throwable error, + Thread thread, + Map custom, + String description, + Level level, + boolean isUncaught + ) { + this.log(wrapThrowable(error, thread), custom, description, level, isUncaught); + } + + /** + * Record an error or message with extra data at the level specified. At least one of `error` or + * `description` must be non-null. If error is null, `description` will be sent as a message. If + * error is non-null, description will be sent as the description of the error. Custom data will + * be attached to message if the error is null. Custom data will extend whatever {@link + * Config#custom} returns. + * + * @param error the error (if any). + * @param custom the custom data (if any). + * @param description the description of the error, or the message to send. + * @param level the level to send it at. + * @param isUncaught whether this data comes from an uncaught exception. */ public void log(ThrowableWrapper error, Map custom, String description, Level level, boolean isUncaught) { diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/RollbarBase.java b/rollbar-java/src/main/java/com/rollbar/notifier/RollbarBase.java index 15f458be..cc61f94c 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/RollbarBase.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/RollbarBase.java @@ -326,14 +326,20 @@ private Payload truncateIfNecessary(C config, Payload payload) { return payload; } - protected RollbarThrowableWrapper wrapThrowable(Throwable error) { - RollbarThrowableWrapper rollbarThrowableWrapper = null; + protected RollbarThrowableWrapper wrapThrowable(Throwable error, Thread thread) { + if (error != null && thread != null) { + return new RollbarThrowableWrapper(error, thread); + } else { + return wrapThrowable(error); + } + } - if (error != null) { - rollbarThrowableWrapper = new RollbarThrowableWrapper(error); + protected RollbarThrowableWrapper wrapThrowable(Throwable error) { + if (error == null) { + return null; } - return rollbarThrowableWrapper; + return new RollbarThrowableWrapper(error); } protected abstract RESULT sendPayload(C config, Payload payload); diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/RollbarTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/RollbarTest.java index 1141f946..fe29202b 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/RollbarTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/RollbarTest.java @@ -4,18 +4,13 @@ import static com.rollbar.notifier.config.ConfigBuilder.withConfig; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.Is.isA; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.hamcrest.MockitoHamcrest.argThat; import com.rollbar.api.payload.Payload; import com.rollbar.api.payload.data.Client; @@ -42,10 +37,8 @@ import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; -import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import org.mockito.stubbing.Answer; public class RollbarTest { From bdb79d5ffe23168b4bfa6660ed27fe78abcbd41e Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 28 Mar 2025 17:33:34 -0300 Subject: [PATCH 07/37] refactor: a Thread should only contain trace_chain, not trace --- .../com/rollbar/notifier/util/BodyFactory.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index 2827dfea..f8d4eed1 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -94,7 +94,7 @@ private List makeRollbarThreads( } private RollbarThread makeInitialRollbarThread(ThrowableWrapper throwableWrapper, String description) { - BodyContent bodyContent = makeBodyContent(throwableWrapper, description); + BodyContent bodyContent = traceChain(throwableWrapper, description); return new RollbarThread(throwableWrapper.getThread(), bodyContent); } @@ -103,9 +103,9 @@ private ArrayList addOtherThreads( Map allStackTraces ) { for (Map.Entry entry : allStackTraces.entrySet()) { - List frames = frames(entry.getValue()); - Trace trace = new Trace.Builder().frames(frames).build(); - rollbarThreads.add(new RollbarThread(entry.getKey(), trace)); + TraceChain traceChain = traceChain(entry.getValue()); + RollbarThread rollbarThread = new RollbarThread(entry.getKey(), traceChain); + rollbarThreads.add(rollbarThread); } return rollbarThreads; } @@ -135,6 +135,14 @@ private static Trace trace(ThrowableWrapper throwableWrapper, String description .build(); } + private TraceChain traceChain(StackTraceElement[] stackTraceElements) { + List frames = frames(stackTraceElements); + Trace trace = new Trace.Builder().frames(frames).build(); + ArrayList chain = new ArrayList<>(); + chain.add(trace); + return new TraceChain.Builder().traces(chain).build(); + } + private static TraceChain traceChain(ThrowableWrapper throwableWrapper, String description) { ArrayList chain = new ArrayList<>(); do { From a645a62df4c10d8d66e51defd127105e073ea988 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 29 Mar 2025 15:23:45 -0300 Subject: [PATCH 08/37] refactor: add a list of groups before threads in payload --- .../rollbar/api/payload/data/body/Body.java | 22 ++++++------- .../rollbar/api/payload/data/body/Group.java | 31 +++++++++++++++++++ .../rollbar/notifier/util/BodyFactory.java | 8 +++-- .../notifier/util/BodyFactoryTest.java | 4 +-- 4 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index d6de3ae8..5295e920 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -19,12 +19,12 @@ public class Body implements JsonSerializable, StringTruncatable { private final List telemetryEvents; - private final List rollbarThreads; + private final List groups; private Body(Builder builder) { this.bodyContent = builder.bodyContent; this.telemetryEvents = builder.telemetryEvents; - this.rollbarThreads = builder.rollbarThreads; + this.groups = builder.groups; } /** @@ -47,8 +47,8 @@ public Object asJson() { values.put("telemetry", telemetryEvents); } - if (rollbarThreads != null) { - values.put("threads", rollbarThreads); + if (groups != null) { + values.put("group", groups); } return values; @@ -90,7 +90,7 @@ public String toString() { return "Body{" + "bodyContent=" + bodyContent + ", telemetry=" + telemetryEvents - + ", threads=" + rollbarThreads + + ", group=" + groups + '}'; } @@ -103,7 +103,7 @@ public static final class Builder { private List telemetryEvents; - private List rollbarThreads; + private List groups; /** * Constructor. @@ -120,7 +120,7 @@ public Builder() { public Builder(Body body) { bodyContent = body.bodyContent; telemetryEvents = body.telemetryEvents; - rollbarThreads = body.rollbarThreads; + groups = body.groups; } /** @@ -147,13 +147,13 @@ public Builder telemetryEvents(List telemetryEvents) { } /** - * Information from other threads. + * Information from a group of threads. * - * @param rollbarThreads a list of threads without the thread where the Exception occurred; + * @param groups a group with a list of threads; * @return the builder instance. */ - public Builder rollbarThreads(List rollbarThreads) { - this.rollbarThreads = rollbarThreads; + public Builder groups(List groups) { + this.groups = groups; return this; } diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java new file mode 100644 index 00000000..4133cdc2 --- /dev/null +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -0,0 +1,31 @@ +package com.rollbar.api.payload.data.body; + +import com.rollbar.api.json.JsonSerializable; +import com.rollbar.api.truncation.StringTruncatable; + +import java.util.HashMap; +import java.util.List; + +public class Group implements JsonSerializable, StringTruncatable { + private final List rollbarThreads; + + public Group(List threads) { + rollbarThreads = threads; + } + + @Override + public Object asJson() { + HashMap values = new HashMap<>(); + + if (rollbarThreads != null) { + values.put("threads", rollbarThreads); + } + + return values; + } + + @Override + public Group truncateStrings(int maxLength) { + return null; + } +} diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index f8d4eed1..c45369b5 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -71,11 +71,11 @@ private Body from( ) { return builder .bodyContent(makeBodyContent(throwableWrapper, description)) - .rollbarThreads(makeRollbarThreads(throwableWrapper, description)) + .groups(makeGroups(throwableWrapper, description)) .build(); } - private List makeRollbarThreads( + private List makeGroups( ThrowableWrapper throwableWrapper, String description ) { @@ -90,7 +90,9 @@ private List makeRollbarThreads( ArrayList rollbarThreads = new ArrayList<>(); rollbarThreads.add(makeInitialRollbarThread(throwableWrapper, description)); - return addOtherThreads(rollbarThreads, allStackTraces); + ArrayList groups = new ArrayList<>(); + groups.add(new Group(addOtherThreads(rollbarThreads, allStackTraces))); + return groups; } private RollbarThread makeInitialRollbarThread(ThrowableWrapper throwableWrapper, String description) { diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java index b40755a4..e12f5025 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java @@ -57,7 +57,7 @@ public void shouldBuildBodyWithDescriptionAndTelemetryEvents() { assertThat(((Message) body.getContents()).getBody(), is(DESCRIPTION)); HashMap map = (HashMap) body.asJson(); assertNotNull(map.get("telemetry")); - assertNull(map.get("threads")); + assertNull(map.get("group")); } @Test @@ -69,7 +69,7 @@ public void shouldBuildBodyWithThreads() { assertThat(body.getContents(), is(instanceOf(Trace.class))); HashMap map = (HashMap) body.asJson(); assertNull(map.get("telemetry")); - assertNotNull(map.get("threads")); + assertNotNull(map.get("group")); } @Test From 1889b0f1873900e9827e91f4148af462dd95c6ef Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 29 Mar 2025 15:36:44 -0300 Subject: [PATCH 09/37] refactor: simplify truncation in TelemetryEvents --- .../api/payload/data/TelemetryEvent.java | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java index 37209f64..c60adbd0 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java @@ -30,11 +30,11 @@ public class TelemetryEvent implements JsonSerializable, StringTruncatable body + TelemetryType telemetryType, + Level level, + Long timestamp, + Source source, + Map body ) { type = telemetryType; this.timestamp = timestamp; @@ -56,29 +56,24 @@ public Map asJson() { @Override public TelemetryEvent truncateStrings(int maxLength) { - Map truncatedMap = new HashMap<>(); - for (Map.Entry entry : body.entrySet()) { - String truncatedValue = TruncationHelper.truncateString(entry.getValue(), maxLength); - truncatedMap.put(entry.getKey(), truncatedValue); - } return new TelemetryEvent( - this.type, - this.level, - this.timestamp, - this.source, - truncatedMap + this.type, + this.level, + this.timestamp, + this.source, + TruncationHelper.truncateStringsInStringMap(body, maxLength) ); } @Override public String toString() { return "TelemetryEvent{" - + "type='" + type.asJson() + '\'' - + ", level='" + level.asJson() + '\'' - + ", source='" + source + '\'' - + ", timestamp_ms=" + timestamp - + ", body=" + body - + '}'; + + "type='" + type.asJson() + '\'' + + ", level='" + level.asJson() + '\'' + + ", source='" + source + '\'' + + ", timestamp_ms=" + timestamp + + ", body=" + body + + '}'; } @Override @@ -91,7 +86,7 @@ public boolean equals(Object o) { } TelemetryEvent that = (TelemetryEvent) o; return type == that.type && level == that.level && Objects.equals(timestamp, that.timestamp) - && Objects.equals(body, that.body) && Objects.equals(source, that.source); + && Objects.equals(body, that.body) && Objects.equals(source, that.source); } @Override From 9953f08a4c2169b7c914db5c5d816f006ff60064 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 29 Mar 2025 16:01:27 -0300 Subject: [PATCH 10/37] refactor: add truncation to TelemetryEvents in body --- .../rollbar/api/payload/data/body/Body.java | 32 +++++++++++------ .../notifier/util/BodyFactoryTest.java | 35 +++++++++++++++---- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 5295e920..cb326de7 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -4,9 +4,7 @@ import com.rollbar.api.payload.data.TelemetryEvent; import com.rollbar.api.truncation.StringTruncatable; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; +import java.util.*; /** * A container for the actual error(s), message, or crash report that caused this error. @@ -29,6 +27,7 @@ private Body(Builder builder) { /** * Getter. + * * @return the contents. */ public BodyContent getContents() { @@ -58,8 +57,9 @@ public Object asJson() { public Body truncateStrings(int maxSize) { if (bodyContent != null) { return new Body.Builder(this) - .bodyContent(bodyContent.truncateStrings(maxSize)) - .build(); + .bodyContent(bodyContent.truncateStrings(maxSize)) + .telemetryEvents(truncatedTelemetryEvents(maxSize)) + .build(); } else { return this; } @@ -77,7 +77,7 @@ public boolean equals(Object o) { Body body = (Body) o; return Objects.equals(bodyContent, body.bodyContent) - && Objects.equals(telemetryEvents, body.telemetryEvents); + && Objects.equals(telemetryEvents, body.telemetryEvents); } @Override @@ -88,10 +88,22 @@ public int hashCode() { @Override public String toString() { return "Body{" - + "bodyContent=" + bodyContent - + ", telemetry=" + telemetryEvents - + ", group=" + groups - + '}'; + + "bodyContent=" + bodyContent + + ", telemetry=" + telemetryEvents + + ", group=" + groups + + '}'; + } + + private List truncatedTelemetryEvents(int maxSize) { + if (telemetryEvents == null) { + return null; + } + + List truncatedTelemetryEvents = new ArrayList<>(); + for (TelemetryEvent telemetryEvent : telemetryEvents) { + truncatedTelemetryEvents.add(telemetryEvent.truncateStrings(maxSize)); + } + return truncatedTelemetryEvents; } /** diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java index e12f5025..aeeea9ff 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java @@ -3,9 +3,12 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; +import com.rollbar.api.payload.data.Level; +import com.rollbar.api.payload.data.Source; +import com.rollbar.api.payload.data.TelemetryEvent; +import com.rollbar.api.payload.data.TelemetryType; import com.rollbar.api.payload.data.body.Body; import com.rollbar.api.payload.data.body.ExceptionInfo; import com.rollbar.api.payload.data.body.Frame; @@ -14,10 +17,9 @@ import com.rollbar.api.payload.data.body.TraceChain; import com.rollbar.notifier.wrapper.RollbarThrowableWrapper; import com.rollbar.notifier.wrapper.ThrowableWrapper; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; + +import java.util.*; + import org.junit.Before; import org.junit.Test; @@ -60,6 +62,23 @@ public void shouldBuildBodyWithDescriptionAndTelemetryEvents() { assertNull(map.get("group")); } + @Test + public void shouldTruncateTelemetryEvents() { + Map telemetryBody = new HashMap<>(); + telemetryBody.put("message", "1234567890"); + TelemetryEvent telemetryEvent = makeTelemetryEvent(telemetryBody); + ArrayList telemetryEvents = new ArrayList<>(); + telemetryEvents.add(telemetryEvent); + + Body body = sut.from(null, DESCRIPTION, telemetryEvents).truncateStrings(5); + + HashMap map = (HashMap) body.asJson(); + List truncatedTelemetryEvents = (List) map.get("telemetry"); + telemetryBody.put("message", "12345"); + TelemetryEvent expected = makeTelemetryEvent(telemetryBody); + assertEquals(expected, truncatedTelemetryEvents.get(0)); + } + @Test public void shouldBuildBodyWithThreads() { Throwable throwable = buildSimpleThrowable(); @@ -113,6 +132,10 @@ public void shouldBuildBodyWithTraceChainAsContentFromThrowableWrapper() { verifyTraceChain((TraceChain) body.getContents(), throwable); } + private TelemetryEvent makeTelemetryEvent( Map body) { + return new TelemetryEvent(TelemetryType.LOG, Level.DEBUG, 12L, Source.CLIENT, body); + } + private void verifyTrace(Trace trace, Throwable throwable, String description) { verifyFrames(trace.getFrames(), throwable); verifyExceptionInfo(trace.getException(), throwable, description); From 34e252f15f22a58dc614de01efb90518df7ddcc3 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 29 Mar 2025 16:15:30 -0300 Subject: [PATCH 11/37] refactor: add truncation helper method for a list with Truncatable objects --- .../rollbar/api/payload/data/body/Body.java | 15 ++------------- .../api/truncation/TruncationHelper.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index cb326de7..e5b3545f 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -3,6 +3,7 @@ import com.rollbar.api.json.JsonSerializable; import com.rollbar.api.payload.data.TelemetryEvent; import com.rollbar.api.truncation.StringTruncatable; +import com.rollbar.api.truncation.TruncationHelper; import java.util.*; @@ -58,7 +59,7 @@ public Body truncateStrings(int maxSize) { if (bodyContent != null) { return new Body.Builder(this) .bodyContent(bodyContent.truncateStrings(maxSize)) - .telemetryEvents(truncatedTelemetryEvents(maxSize)) + .telemetryEvents(TruncationHelper.truncate(telemetryEvents, maxSize)) .build(); } else { return this; @@ -94,18 +95,6 @@ public String toString() { + '}'; } - private List truncatedTelemetryEvents(int maxSize) { - if (telemetryEvents == null) { - return null; - } - - List truncatedTelemetryEvents = new ArrayList<>(); - for (TelemetryEvent telemetryEvent : telemetryEvents) { - truncatedTelemetryEvents.add(telemetryEvent.truncateStrings(maxSize)); - } - return truncatedTelemetryEvents; - } - /** * Builder class for {@link Body body}. */ diff --git a/rollbar-api/src/main/java/com/rollbar/api/truncation/TruncationHelper.java b/rollbar-api/src/main/java/com/rollbar/api/truncation/TruncationHelper.java index b197cc7a..8463f62e 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/truncation/TruncationHelper.java +++ b/rollbar-api/src/main/java/com/rollbar/api/truncation/TruncationHelper.java @@ -28,6 +28,25 @@ public static List truncateStringsInList(List values, int maxLen return result; } + /** + * Truncates all the StringTruncatable in the list to the specified maximum length. + * @param values The StringTruncatables to be truncated. + * @param maxLength Maximum length of each string. + * @return A list containing the truncated StringTruncatables. + */ + public static > List truncate(List values, int maxLength) { + if (values == null) { + return null; + } + + List result = new ArrayList<>(values.size()); + for (T value : values) { + result.add(value.truncateStrings(maxLength)); + } + + return result; + } + /** * Truncates any strings in the list to the specified maximum length. * @param values The list of objects which might contain strings to be truncated. From 62c038b2c6ce27ace5eaf631cb30505090357e76 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 30 Mar 2025 02:16:25 -0300 Subject: [PATCH 12/37] refactor: truncate Group in body --- .../rollbar/api/payload/data/body/Body.java | 1 + .../rollbar/api/payload/data/body/Group.java | 16 +++++- .../api/payload/data/body/RollbarThread.java | 56 ++++++++++--------- .../notifier/util/BodyFactoryTest.java | 44 ++++++++++++--- 4 files changed, 80 insertions(+), 37 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index e5b3545f..41612679 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -60,6 +60,7 @@ public Body truncateStrings(int maxSize) { return new Body.Builder(this) .bodyContent(bodyContent.truncateStrings(maxSize)) .telemetryEvents(TruncationHelper.truncate(telemetryEvents, maxSize)) + .groups(TruncationHelper.truncate(groups, maxSize)) .build(); } else { return this; diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index 4133cdc2..ecd3a410 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -2,9 +2,11 @@ import com.rollbar.api.json.JsonSerializable; import com.rollbar.api.truncation.StringTruncatable; +import com.rollbar.api.truncation.TruncationHelper; import java.util.HashMap; import java.util.List; +import java.util.Objects; public class Group implements JsonSerializable, StringTruncatable { private final List rollbarThreads; @@ -26,6 +28,18 @@ public Object asJson() { @Override public Group truncateStrings(int maxLength) { - return null; + return new Group(TruncationHelper.truncate(rollbarThreads, maxLength)); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Group)) return false; + Group group = (Group) o; + return Objects.equals(rollbarThreads, group.rollbarThreads); + } + + @Override + public int hashCode() { + return Objects.hashCode(rollbarThreads); } } diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 298d5b5a..ab682db4 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -8,28 +8,21 @@ import java.util.Objects; public class RollbarThread implements JsonSerializable, StringTruncatable { - - private final String name; - private final String id; - private final String priority; - private final String state; + private final Thread thread; private final BodyContent bodyContent; public RollbarThread(Thread thread, BodyContent bodyContent) { - name = thread.getName(); - id = String.valueOf(thread.getId()); - priority = String.valueOf(thread.getPriority()); - state = thread.getState().toString(); + this.thread = thread; this.bodyContent = bodyContent; } @Override public Object asJson() { Map values = new HashMap<>(); - values.put("name", name); - values.put("id", id); - values.put("priority", priority); - values.put("state", state); + values.put("name", getThreadName()); + values.put("id", getThreadId()); + values.put("priority", getThreadPriority()); + values.put("state", getThreadState()); if (bodyContent != null) { values.put(bodyContent.getKeyName(), bodyContent); } @@ -38,36 +31,45 @@ public Object asJson() { @Override public RollbarThread truncateStrings(int maxLength) { - return null; + return new RollbarThread(thread, bodyContent.truncateStrings(maxLength)); } @Override public String toString() { return "RollbarThread{" + - "name='" + name + '\'' + - ", id='" + id + '\'' + - ", priority='" + priority + '\'' + - ", state='" + state + '\'' + + "name='" + getThreadName() + '\'' + + ", id='" + getThreadId() + '\'' + + ", priority='" + getThreadPriority() + '\'' + + ", state='" + getThreadState() + '\'' + ", " + bodyContent.getKeyName() + "=" + bodyContent + '}'; } + private String getThreadName() { + return thread.getName(); + } + + private String getThreadId() { + return String.valueOf(thread.getId()); + } + + private String getThreadPriority() { + return String.valueOf(thread.getPriority()); + } + + private String getThreadState() { + return thread.getState().toString(); + } + @Override public boolean equals(Object o) { if (!(o instanceof RollbarThread)) return false; RollbarThread that = (RollbarThread) o; - return Objects.equals(name, that.name) && Objects.equals(id, that.id) && Objects.equals(priority, that.priority) && Objects.equals(state, that.state) && Objects.equals(bodyContent, that.bodyContent); + return Objects.equals(thread, that.thread) && Objects.equals(bodyContent, that.bodyContent); } @Override public int hashCode() { - return Objects.hash(name, id, priority, state, bodyContent); - } - - /** - * Builder class for {@link RollbarThread RollbarThread}. - */ - public static final class Builder { - + return Objects.hash(thread, bodyContent); } } diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java index aeeea9ff..5708029d 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java @@ -9,12 +9,7 @@ import com.rollbar.api.payload.data.Source; import com.rollbar.api.payload.data.TelemetryEvent; import com.rollbar.api.payload.data.TelemetryType; -import com.rollbar.api.payload.data.body.Body; -import com.rollbar.api.payload.data.body.ExceptionInfo; -import com.rollbar.api.payload.data.body.Frame; -import com.rollbar.api.payload.data.body.Message; -import com.rollbar.api.payload.data.body.Trace; -import com.rollbar.api.payload.data.body.TraceChain; +import com.rollbar.api.payload.data.body.*; import com.rollbar.notifier.wrapper.RollbarThrowableWrapper; import com.rollbar.notifier.wrapper.ThrowableWrapper; @@ -72,11 +67,24 @@ public void shouldTruncateTelemetryEvents() { Body body = sut.from(null, DESCRIPTION, telemetryEvents).truncateStrings(5); - HashMap map = (HashMap) body.asJson(); - List truncatedTelemetryEvents = (List) map.get("telemetry"); telemetryBody.put("message", "12345"); TelemetryEvent expected = makeTelemetryEvent(telemetryBody); - assertEquals(expected, truncatedTelemetryEvents.get(0)); + assertEquals(expected, getFirstTelemetryEvent(body)); + } + + @Test + public void shouldTruncateGroups() { + int expectedLength = 5; + Throwable throwable = buildSimpleThrowable(); + ThrowableWrapper throwableWrapper = new RollbarThrowableWrapper(throwable, Thread.currentThread()); + + Body truncatedBody = sut.from(throwableWrapper, DESCRIPTION).truncateStrings(expectedLength); + + Trace trace = getFirstTraceFromGroup(truncatedBody); + assertEquals(expectedLength, trace.getException().getMessage().length()); + assertEquals(expectedLength, trace.getException().getClassName().length()); + assertEquals(expectedLength, trace.getException().getDescription().length()); + assertEquals(expectedLength, trace.getFrames().get(0).getClassName().length()); } @Test @@ -136,6 +144,24 @@ private TelemetryEvent makeTelemetryEvent( Map body) { return new TelemetryEvent(TelemetryType.LOG, Level.DEBUG, 12L, Source.CLIENT, body); } + private TelemetryEvent getFirstTelemetryEvent(Body body) { + HashMap map = (HashMap) body.asJson(); + List telemetryEvents = (List) map.get("telemetry"); + return telemetryEvents.get(0); + } + + private Trace getFirstTraceFromGroup(Body body) { + HashMap bodyJson = (HashMap) body.asJson(); + List groups = (List) bodyJson.get("group"); + + HashMap groupJson = (HashMap) groups.get(0).asJson(); + List rollbarThreads = (List) groupJson.get("threads"); + + HashMap rollbarThreadJson = (HashMap) rollbarThreads.get(0).asJson(); + TraceChain traceChain = (TraceChain) rollbarThreadJson.get("trace_chain"); + return traceChain.getTraces().get(0); + } + private void verifyTrace(Trace trace, Throwable throwable, String description) { verifyFrames(trace.getFrames(), throwable); verifyExceptionInfo(trace.getException(), throwable, description); From 162c25388a8dcd3e6bba7f5ecfd01a90a812bd52 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 30 Mar 2025 18:31:35 -0300 Subject: [PATCH 13/37] refactor: set expected payload, first threads, with a group of trace_chains inside every thread --- .../rollbar/api/payload/data/body/Body.java | 24 +++--- .../rollbar/api/payload/data/body/Group.java | 27 +++--- .../api/payload/data/body/RollbarThread.java | 85 +++++++++++-------- .../rollbar/notifier/util/BodyFactory.java | 15 ++-- .../notifier/util/BodyFactoryTest.java | 12 +-- 5 files changed, 84 insertions(+), 79 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 41612679..4e4f2c4c 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -18,12 +18,12 @@ public class Body implements JsonSerializable, StringTruncatable { private final List telemetryEvents; - private final List groups; + private final List rollbarThreads; private Body(Builder builder) { this.bodyContent = builder.bodyContent; this.telemetryEvents = builder.telemetryEvents; - this.groups = builder.groups; + this.rollbarThreads = builder.rollbarThreads; } /** @@ -47,8 +47,8 @@ public Object asJson() { values.put("telemetry", telemetryEvents); } - if (groups != null) { - values.put("group", groups); + if (rollbarThreads != null) { + values.put("threads", rollbarThreads); } return values; @@ -60,7 +60,7 @@ public Body truncateStrings(int maxSize) { return new Body.Builder(this) .bodyContent(bodyContent.truncateStrings(maxSize)) .telemetryEvents(TruncationHelper.truncate(telemetryEvents, maxSize)) - .groups(TruncationHelper.truncate(groups, maxSize)) + .rollbarThreads(TruncationHelper.truncate(rollbarThreads, maxSize)) .build(); } else { return this; @@ -92,7 +92,7 @@ public String toString() { return "Body{" + "bodyContent=" + bodyContent + ", telemetry=" + telemetryEvents - + ", group=" + groups + + ", threads=" + rollbarThreads + '}'; } @@ -105,7 +105,7 @@ public static final class Builder { private List telemetryEvents; - private List groups; + private List rollbarThreads; /** * Constructor. @@ -122,7 +122,7 @@ public Builder() { public Builder(Body body) { bodyContent = body.bodyContent; telemetryEvents = body.telemetryEvents; - groups = body.groups; + rollbarThreads = body.rollbarThreads; } /** @@ -149,13 +149,13 @@ public Builder telemetryEvents(List telemetryEvents) { } /** - * Information from a group of threads. + * Information from threads. * - * @param groups a group with a list of threads; + * @param rollbarThreads a list of threads; * @return the builder instance. */ - public Builder groups(List groups) { - this.groups = groups; + public Builder rollbarThreads(List rollbarThreads) { + this.rollbarThreads = rollbarThreads; return this; } diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index ecd3a410..2a5d0ca4 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -2,44 +2,41 @@ import com.rollbar.api.json.JsonSerializable; import com.rollbar.api.truncation.StringTruncatable; -import com.rollbar.api.truncation.TruncationHelper; +import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Objects; public class Group implements JsonSerializable, StringTruncatable { - private final List rollbarThreads; + private final BodyContent traceChain; - public Group(List threads) { - rollbarThreads = threads; + public Group(BodyContent traceChain) { + this.traceChain = traceChain; } @Override public Object asJson() { HashMap values = new HashMap<>(); - - if (rollbarThreads != null) { - values.put("threads", rollbarThreads); - } - - return values; + values.put("trace_chain", traceChain); + ArrayList> traceChains = new ArrayList<>(); + traceChains.add(values); + return traceChains; } @Override public Group truncateStrings(int maxLength) { - return new Group(TruncationHelper.truncate(rollbarThreads, maxLength)); + return new Group(traceChain.truncateStrings(maxLength)); } @Override public boolean equals(Object o) { - if (!(o instanceof Group)) return false; + if (o == null || getClass() != o.getClass()) return false; Group group = (Group) o; - return Objects.equals(rollbarThreads, group.rollbarThreads); + return Objects.equals(traceChain, group.traceChain); } @Override public int hashCode() { - return Objects.hashCode(rollbarThreads); + return Objects.hashCode(traceChain); } } diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index ab682db4..85f48762 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -2,74 +2,85 @@ import com.rollbar.api.json.JsonSerializable; import com.rollbar.api.truncation.StringTruncatable; +import com.rollbar.api.truncation.TruncationHelper; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; public class RollbarThread implements JsonSerializable, StringTruncatable { - private final Thread thread; - private final BodyContent bodyContent; + private final String name; + private final String id; + private final String priority; + private final String state; + private final Group group; - public RollbarThread(Thread thread, BodyContent bodyContent) { - this.thread = thread; - this.bodyContent = bodyContent; + public RollbarThread(Thread thread, Group group) { + name = thread.getName(); + id = String.valueOf(thread.getId()); + priority = String.valueOf(thread.getPriority()); + state = thread.getState().toString(); + this.group = group; + } + + private RollbarThread( + String name, + String id, + String priority, + String state, + Group group + ) { + this.name = name; + this.id = id; + this.priority = priority; + this.state = state; + this.group = group; } @Override public Object asJson() { Map values = new HashMap<>(); - values.put("name", getThreadName()); - values.put("id", getThreadId()); - values.put("priority", getThreadPriority()); - values.put("state", getThreadState()); - if (bodyContent != null) { - values.put(bodyContent.getKeyName(), bodyContent); - } + values.put("name", name); + values.put("id", id); + values.put("priority", priority); + values.put("state", state); + values.put("group", group); return values; } @Override public RollbarThread truncateStrings(int maxLength) { - return new RollbarThread(thread, bodyContent.truncateStrings(maxLength)); + return new RollbarThread( + name, + id, + priority, + state, + group.truncateStrings(maxLength) + ); } @Override public String toString() { return "RollbarThread{" + - "name='" + getThreadName() + '\'' + - ", id='" + getThreadId() + '\'' + - ", priority='" + getThreadPriority() + '\'' + - ", state='" + getThreadState() + '\'' + - ", " + bodyContent.getKeyName() + "=" + bodyContent + - '}'; + "name='" + name + '\'' + + ", id='" + id + '\'' + + ", priority='" + priority + '\'' + + ", state='" + state + '\'' + + ", group='" + group + + '}'; } - private String getThreadName() { - return thread.getName(); - } - - private String getThreadId() { - return String.valueOf(thread.getId()); - } - - private String getThreadPriority() { - return String.valueOf(thread.getPriority()); - } - - private String getThreadState() { - return thread.getState().toString(); - } @Override public boolean equals(Object o) { - if (!(o instanceof RollbarThread)) return false; + if (o == null || getClass() != o.getClass()) return false; RollbarThread that = (RollbarThread) o; - return Objects.equals(thread, that.thread) && Objects.equals(bodyContent, that.bodyContent); + return Objects.equals(name, that.name) && Objects.equals(id, that.id) && Objects.equals(priority, that.priority) && Objects.equals(state, that.state) && Objects.equals(group, that.group); } @Override public int hashCode() { - return Objects.hash(thread, bodyContent); + return Objects.hash(name, id, priority, state, group); } } diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index c45369b5..a7e57910 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -71,18 +71,17 @@ private Body from( ) { return builder .bodyContent(makeBodyContent(throwableWrapper, description)) - .groups(makeGroups(throwableWrapper, description)) + .rollbarThreads(makeRollbarThreads(throwableWrapper, description)) .build(); } - private List makeGroups( + private List makeRollbarThreads( ThrowableWrapper throwableWrapper, String description ) { if (throwableWrapper == null) { return null; } - Map allStackTraces = throwableWrapper.getAllStackTraces(); if (allStackTraces == null) { return null; @@ -90,14 +89,12 @@ private List makeGroups( ArrayList rollbarThreads = new ArrayList<>(); rollbarThreads.add(makeInitialRollbarThread(throwableWrapper, description)); - ArrayList groups = new ArrayList<>(); - groups.add(new Group(addOtherThreads(rollbarThreads, allStackTraces))); - return groups; + return addOtherThreads(rollbarThreads, allStackTraces); } private RollbarThread makeInitialRollbarThread(ThrowableWrapper throwableWrapper, String description) { - BodyContent bodyContent = traceChain(throwableWrapper, description); - return new RollbarThread(throwableWrapper.getThread(), bodyContent); + TraceChain traceChain = traceChain(throwableWrapper, description); + return new RollbarThread(throwableWrapper.getThread(), new Group(traceChain)); } private ArrayList addOtherThreads( @@ -106,7 +103,7 @@ private ArrayList addOtherThreads( ) { for (Map.Entry entry : allStackTraces.entrySet()) { TraceChain traceChain = traceChain(entry.getValue()); - RollbarThread rollbarThread = new RollbarThread(entry.getKey(), traceChain); + RollbarThread rollbarThread = new RollbarThread(entry.getKey(), new Group(traceChain)); rollbarThreads.add(rollbarThread); } return rollbarThreads; diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java index 5708029d..6808aab0 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/util/BodyFactoryTest.java @@ -96,7 +96,7 @@ public void shouldBuildBodyWithThreads() { assertThat(body.getContents(), is(instanceOf(Trace.class))); HashMap map = (HashMap) body.asJson(); assertNull(map.get("telemetry")); - assertNotNull(map.get("group")); + assertNotNull(map.get("threads")); } @Test @@ -152,13 +152,13 @@ private TelemetryEvent getFirstTelemetryEvent(Body body) { private Trace getFirstTraceFromGroup(Body body) { HashMap bodyJson = (HashMap) body.asJson(); - List groups = (List) bodyJson.get("group"); + List rollbarThreads = (List) bodyJson.get("threads"); - HashMap groupJson = (HashMap) groups.get(0).asJson(); - List rollbarThreads = (List) groupJson.get("threads"); + HashMap groupJson = (HashMap) rollbarThreads.get(0).asJson(); + Group group = (Group) groupJson.get("group"); - HashMap rollbarThreadJson = (HashMap) rollbarThreads.get(0).asJson(); - TraceChain traceChain = (TraceChain) rollbarThreadJson.get("trace_chain"); + List> rollbarThreadJson = (List>) group.asJson(); + TraceChain traceChain = (TraceChain) rollbarThreadJson.get(0).get("trace_chain"); return traceChain.getTraces().get(0); } From 68659a97f113c9119e492b90f83c88181bd1ecd3 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 01:50:59 -0300 Subject: [PATCH 14/37] refactor: remove locals field in a Trace from a non exception thread --- .../src/main/java/com/rollbar/notifier/util/BodyFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index a7e57910..14f35ac9 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -184,7 +184,7 @@ private static List frames(StackTraceElement[] stackTraceElements) { ArrayList result = new ArrayList<>(); for (int i = stackTraceElements.length - 1; i >= 0; i--) { - result.add(frame(stackTraceElements[i], Collections.emptyMap())); + result.add(frame(stackTraceElements[i], null)); } return result; From 1090987732344a9502f49468214ddec29c86af80 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 02:03:02 -0300 Subject: [PATCH 15/37] chore: fix indentation --- .../api/payload/data/TelemetryEvent.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java index c60adbd0..b8a81b10 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/TelemetryEvent.java @@ -30,11 +30,11 @@ public class TelemetryEvent implements JsonSerializable, StringTruncatable body + TelemetryType telemetryType, + Level level, + Long timestamp, + Source source, + Map body ) { type = telemetryType; this.timestamp = timestamp; @@ -57,23 +57,23 @@ public Map asJson() { @Override public TelemetryEvent truncateStrings(int maxLength) { return new TelemetryEvent( - this.type, - this.level, - this.timestamp, - this.source, - TruncationHelper.truncateStringsInStringMap(body, maxLength) + this.type, + this.level, + this.timestamp, + this.source, + TruncationHelper.truncateStringsInStringMap(body, maxLength) ); } @Override public String toString() { return "TelemetryEvent{" - + "type='" + type.asJson() + '\'' - + ", level='" + level.asJson() + '\'' - + ", source='" + source + '\'' - + ", timestamp_ms=" + timestamp - + ", body=" + body - + '}'; + + "type='" + type.asJson() + '\'' + + ", level='" + level.asJson() + '\'' + + ", source='" + source + '\'' + + ", timestamp_ms=" + timestamp + + ", body=" + body + + '}'; } @Override @@ -86,7 +86,7 @@ public boolean equals(Object o) { } TelemetryEvent that = (TelemetryEvent) o; return type == that.type && level == that.level && Objects.equals(timestamp, that.timestamp) - && Objects.equals(body, that.body) && Objects.equals(source, that.source); + && Objects.equals(body, that.body) && Objects.equals(source, that.source); } @Override From c9384a78ffbb4f18776606b640e561707159d0b7 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 02:03:38 -0300 Subject: [PATCH 16/37] chore: remove * from import --- .../src/main/java/com/rollbar/api/payload/data/body/Body.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 4e4f2c4c..d29e3f6a 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -5,7 +5,9 @@ import com.rollbar.api.truncation.StringTruncatable; import com.rollbar.api.truncation.TruncationHelper; -import java.util.*; +import java.util.HashMap; +import java.util.Objects; +import java.util.List; /** * A container for the actual error(s), message, or crash report that caused this error. From 2bc8148c4c37e7df5b7b549a38f3ffd6e7d6d76f Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 02:04:09 -0300 Subject: [PATCH 17/37] chore: add Java doc and fix indentations --- .../api/payload/data/body/RollbarThread.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 85f48762..f7db2bf1 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -2,13 +2,14 @@ import com.rollbar.api.json.JsonSerializable; import com.rollbar.api.truncation.StringTruncatable; -import com.rollbar.api.truncation.TruncationHelper; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; +/** + * Represents Thread information + */ public class RollbarThread implements JsonSerializable, StringTruncatable { private final String name; private final String id; @@ -62,21 +63,27 @@ public RollbarThread truncateStrings(int maxLength) { @Override public String toString() { - return "RollbarThread{" + - "name='" + name + '\'' + - ", id='" + id + '\'' + - ", priority='" + priority + '\'' + - ", state='" + state + '\'' + - ", group='" + group + - '}'; + return "RollbarThread{" + + "name='" + name + '\'' + + ", id='" + id + '\'' + + ", priority='" + priority + '\'' + + ", state='" + state + '\'' + + ", group='" + group + + '}'; } @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } RollbarThread that = (RollbarThread) o; - return Objects.equals(name, that.name) && Objects.equals(id, that.id) && Objects.equals(priority, that.priority) && Objects.equals(state, that.state) && Objects.equals(group, that.group); + return Objects.equals(name, that.name) + && Objects.equals(id, that.id) + && Objects.equals(priority, that.priority) + && Objects.equals(state, that.state) + && Objects.equals(group, that.group); } @Override From f191a898774bbc35189b9b6739180ee3225a72b0 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 02:04:33 -0300 Subject: [PATCH 18/37] chore: add Java doc and fix indentations --- .../java/com/rollbar/api/payload/data/body/Group.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index 2a5d0ca4..eeca09a2 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -7,6 +7,11 @@ import java.util.HashMap; import java.util.Objects; +/** + * This represent a Group of trace chains in a Thread. + * In Java we only send 1 TraceChain per Group, in other languages like Python (ExceptionGroup) or + * JS (AggregatorError), it may be more TraceChains per group. + */ public class Group implements JsonSerializable, StringTruncatable { private final BodyContent traceChain; @@ -30,7 +35,9 @@ public Group truncateStrings(int maxLength) { @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } Group group = (Group) o; return Objects.equals(traceChain, group.traceChain); } From a7e5a2d6d015a81a0de6fe62bfff3a5b052f3229 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 31 Mar 2025 02:10:44 -0300 Subject: [PATCH 19/37] chore: fix lint --- .../main/java/com/rollbar/api/payload/data/body/Body.java | 2 +- .../com/rollbar/api/payload/data/body/RollbarThread.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index d29e3f6a..3e8b3cfd 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -6,8 +6,8 @@ import com.rollbar.api.truncation.TruncationHelper; import java.util.HashMap; -import java.util.Objects; import java.util.List; +import java.util.Objects; /** * A container for the actual error(s), message, or crash report that caused this error. diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index f7db2bf1..05e41b5c 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -8,7 +8,7 @@ import java.util.Objects; /** - * Represents Thread information + * Represents Thread information. */ public class RollbarThread implements JsonSerializable, StringTruncatable { private final String name; @@ -17,6 +17,11 @@ public class RollbarThread implements JsonSerializable, StringTruncatable Date: Sun, 6 Apr 2025 14:12:50 -0300 Subject: [PATCH 20/37] chore: fix lint --- .../java/com/rollbar/notifier/Rollbar.java | 12 +++---- .../rollbar/notifier/util/BodyFactory.java | 36 ++++++++++++------- .../wrapper/RollbarThrowableWrapper.java | 31 ++++++++-------- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java index 04bd4808..e59b95e3 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/Rollbar.java @@ -601,12 +601,12 @@ public void log(Throwable error, Map custom, String description, * @param isUncaught whether this data comes from an uncaught exception. */ public void log( - Throwable error, - Thread thread, - Map custom, - String description, - Level level, - boolean isUncaught + Throwable error, + Thread thread, + Map custom, + String description, + Level level, + boolean isUncaught ) { this.log(wrapThrowable(error, thread), custom, description, level, isUncaught); } diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index 14f35ac9..8c6f36e3 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -1,14 +1,21 @@ package com.rollbar.notifier.util; import com.rollbar.api.payload.data.TelemetryEvent; -import com.rollbar.api.payload.data.body.*; +import com.rollbar.api.payload.data.body.Body; +import com.rollbar.api.payload.data.body.BodyContent; +import com.rollbar.api.payload.data.body.ExceptionInfo; +import com.rollbar.api.payload.data.body.Frame; +import com.rollbar.api.payload.data.body.Group; +import com.rollbar.api.payload.data.body.Message; +import com.rollbar.api.payload.data.body.RollbarThread; +import com.rollbar.api.payload.data.body.Trace; +import com.rollbar.api.payload.data.body.TraceChain; import com.rollbar.jvmti.CacheFrame; import com.rollbar.jvmti.ThrowableCache; import com.rollbar.notifier.wrapper.RollbarThrowableWrapper; import com.rollbar.notifier.wrapper.ThrowableWrapper; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -56,18 +63,18 @@ public Body from(ThrowableWrapper throwableWrapper, String description) { * @return the body. */ public Body from( - ThrowableWrapper throwableWrapper, - String description, - List telemetryEvents + ThrowableWrapper throwableWrapper, + String description, + List telemetryEvents ) { Body.Builder builder = new Body.Builder().telemetryEvents(telemetryEvents); return from(throwableWrapper, description, builder); } private Body from( - ThrowableWrapper throwableWrapper, - String description, - Body.Builder builder + ThrowableWrapper throwableWrapper, + String description, + Body.Builder builder ) { return builder .bodyContent(makeBodyContent(throwableWrapper, description)) @@ -76,8 +83,8 @@ private Body from( } private List makeRollbarThreads( - ThrowableWrapper throwableWrapper, - String description + ThrowableWrapper throwableWrapper, + String description ) { if (throwableWrapper == null) { return null; @@ -92,14 +99,17 @@ private List makeRollbarThreads( return addOtherThreads(rollbarThreads, allStackTraces); } - private RollbarThread makeInitialRollbarThread(ThrowableWrapper throwableWrapper, String description) { + private RollbarThread makeInitialRollbarThread( + ThrowableWrapper throwableWrapper, + String description + ) { TraceChain traceChain = traceChain(throwableWrapper, description); return new RollbarThread(throwableWrapper.getThread(), new Group(traceChain)); } private ArrayList addOtherThreads( - ArrayList rollbarThreads, - Map allStackTraces + ArrayList rollbarThreads, + Map allStackTraces ) { for (Map.Entry entry : allStackTraces.entrySet()) { TraceChain traceChain = traceChain(entry.getValue()); diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java index 0cc5b88f..a2bb21d7 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java @@ -53,11 +53,11 @@ public RollbarThrowableWrapper(Throwable throwable, Thread thread) { throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, throwable, thread, - getAllStackTraces(thread) + captureAllStackTraces(thread) ); } - private static Map getAllStackTraces(Thread thread) { + private static Map captureAllStackTraces(Thread thread) { if (thread == null) { return null; } @@ -65,7 +65,10 @@ private static Map getAllStackTraces(Thread thread) return filter(thread, Thread.getAllStackTraces()); } - private static Map filter(Thread thread, Map allStackTraces) { + private static Map filter( + Thread thread, Map allStackTraces + ) { HashMap filteredStackTraces = new HashMap<>(); for (Map.Entry entry : allStackTraces.entrySet()) { @@ -88,22 +91,22 @@ private static Map filter(Thread thread, Map allStackTraces + String className, + String message, + StackTraceElement[] stackTraceElements, + ThrowableWrapper cause, + Throwable throwable, + Thread thread, + Map allStackTraces ) { this.className = className; this.message = message; From 315f7c463758fd7a803f713ca7f9b58d75712f91 Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 6 Apr 2025 14:21:56 -0300 Subject: [PATCH 21/37] chore: add revapi info --- .palantir/revapi.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.palantir/revapi.yml b/.palantir/revapi.yml index 1c1ab03c..451ee479 100644 --- a/.palantir/revapi.yml +++ b/.palantir/revapi.yml @@ -33,3 +33,15 @@ acceptedBreaks: - code: "java.method.addedToInterface" new: "method int com.rollbar.notifier.config.CommonConfig::maximumTelemetryData()" justification: "This is going to be added in a major version" + "2.1.0": + com.rollbar:rollbar-java: + - code: "java.method.addedToInterface" + new: "method java.util.Map com.rollbar.notifier.wrapper.ThrowableWrapper::getAllStackTraces()" + justification: "This is a binary compatible change, which could only break custom\ + \ implementations of our config interfaces, but those interfaces are not meant\ + \ to be implemented by users" + - code: "java.method.addedToInterface" + new: "method java.lang.Thread com.rollbar.notifier.wrapper.ThrowableWrapper::getThread()" + justification: "This is a binary compatible change, which could only break custom\ + \ implementations of our config interfaces, but those interfaces are not meant\ + \ to be implemented by users" From 5363108c02accd5f8db81616f43d520b8bc971f8 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 7 Apr 2025 13:55:19 -0300 Subject: [PATCH 22/37] feat: add threads to a catch exception log --- .../wrapper/RollbarThrowableWrapper.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java index a2bb21d7..df9cd4df 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java @@ -33,10 +33,10 @@ public RollbarThrowableWrapper(Throwable throwable) { throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, + throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, throwable, - null, - null + Thread.currentThread(), + captureAllStackTraces(Thread.currentThread()) ); } @@ -50,13 +50,32 @@ public RollbarThrowableWrapper(Throwable throwable, Thread thread) { throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause()) : null, + throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, throwable, thread, captureAllStackTraces(thread) ); } + /** + * Private constructor used to not capture all stack traces in a trace chain + * The unused parameter is used to have a method overload. + * + * @param throwable the throwable. + * @param unusedParameter used to differentiate signatures. + */ + private RollbarThrowableWrapper(Throwable throwable, boolean unusedParameter) { + this( + throwable.getClass().getName(), + throwable.getMessage(), + throwable.getStackTrace(), + throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, + throwable, + null, + null + ); + } + private static Map captureAllStackTraces(Thread thread) { if (thread == null) { return null; From e95f99156061de265ab2fa3b09388534e6aa9595 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 7 Apr 2025 14:07:50 -0300 Subject: [PATCH 23/37] chore: fix lint, line max size exceeded --- .../notifier/wrapper/RollbarThrowableWrapper.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java index df9cd4df..1139a1b6 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java @@ -33,7 +33,7 @@ public RollbarThrowableWrapper(Throwable throwable) { throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, + getInnerThrowableWrapper(throwable), throwable, Thread.currentThread(), captureAllStackTraces(Thread.currentThread()) @@ -50,7 +50,7 @@ public RollbarThrowableWrapper(Throwable throwable, Thread thread) { throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, + getInnerThrowableWrapper(throwable), throwable, thread, captureAllStackTraces(thread) @@ -69,13 +69,20 @@ private RollbarThrowableWrapper(Throwable throwable, boolean unusedParameter) { throwable.getClass().getName(), throwable.getMessage(), throwable.getStackTrace(), - throwable.getCause() != null ? new RollbarThrowableWrapper(throwable.getCause(), false) : null, + getInnerThrowableWrapper(throwable), throwable, null, null ); } + private static ThrowableWrapper getInnerThrowableWrapper(Throwable throwable) { + if (throwable.getCause() == null) { + return null; + } + return new RollbarThrowableWrapper(throwable.getCause(), false); + } + private static Map captureAllStackTraces(Thread thread) { if (thread == null) { return null; From 3fb1840dfdf4b1352b416de235b6ec06f741ba7d Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 7 Apr 2025 14:13:23 -0300 Subject: [PATCH 24/37] test: now we capture threads info using the current thread --- .../rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java index e6f36df0..eecd6a03 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java @@ -29,8 +29,8 @@ public void shouldBeCreatedByThrowable() { assertThat(sut.getStackTrace(), is(throwable.getStackTrace())); assertThat(sut.getCause(), is(nested)); assertThat(sut.getThrowable(), is(throwable)); - assertNull(sut.getAllStackTraces()); - assertNull(sut.getThread()); + assertNotNull(sut.getAllStackTraces()); + assertNotNull(sut.getThread()); } @Test From f0c48d7d42b358ad9a657b99fdc8e105bf1da5ea Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:09:01 -0300 Subject: [PATCH 25/37] refactor(FramesStrategy): set truncateTraceChain with default visibility to use it in RollbarThreadStrategy --- .../java/com/rollbar/notifier/truncation/FramesStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/FramesStrategy.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/FramesStrategy.java index 2a89c0f5..253f55b6 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/FramesStrategy.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/FramesStrategy.java @@ -42,7 +42,7 @@ public TruncationResult truncate(Payload payload) { return TruncationResult.none(); } - private TruncationResult truncateTraceChain(TraceChain chain) { + TruncationResult truncateTraceChain(TraceChain chain) { boolean truncated = false; ArrayList updated = new ArrayList<>(); From c3e547b1e8183cfccd53ad9ad765aa0794098986 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:10:23 -0300 Subject: [PATCH 26/37] refactor(Group): set property as type TraceChain and add getter --- .../com/rollbar/api/payload/data/body/Group.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index eeca09a2..d1d14abb 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -13,12 +13,21 @@ * JS (AggregatorError), it may be more TraceChains per group. */ public class Group implements JsonSerializable, StringTruncatable { - private final BodyContent traceChain; + private final TraceChain traceChain; - public Group(BodyContent traceChain) { + public Group(TraceChain traceChain) { this.traceChain = traceChain; } + /** + * Getter. + * + * @return the trace chain. + */ + public TraceChain getTraceChain() { + return traceChain; + } + @Override public Object asJson() { HashMap values = new HashMap<>(); From eb0b6e100a321d3ee1e78f32110b0256162b8191 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:16:58 -0300 Subject: [PATCH 27/37] feat(RollbarThreadStrategy): add truncation strategy for RollbarThread --- .../rollbar/api/payload/data/body/Body.java | 14 ++- .../api/payload/data/body/RollbarThread.java | 90 +++++++++++++++++++ .../notifier/truncation/PayloadTruncator.java | 1 + .../truncation/RollbarThreadStrategy.java | 65 ++++++++++++++ .../truncation/RollbarThreadStrategyTest.java | 83 +++++++++++++++++ .../truncation/TestPayloadBuilder.java | 37 +++++--- 6 files changed, 278 insertions(+), 12 deletions(-) create mode 100644 rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java create mode 100644 rollbar-java/src/test/java/com/rollbar/notifier/truncation/RollbarThreadStrategyTest.java diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 3e8b3cfd..0e5122ad 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -37,6 +37,15 @@ public BodyContent getContents() { return bodyContent; } + /** + * Getter. + * + * @return the rollbar threads. + */ + public List getRollbarThreads() { + return rollbarThreads; + } + @Override public Object asJson() { HashMap values = new HashMap<>(); @@ -81,12 +90,13 @@ public boolean equals(Object o) { Body body = (Body) o; return Objects.equals(bodyContent, body.bodyContent) - && Objects.equals(telemetryEvents, body.telemetryEvents); + && Objects.equals(telemetryEvents, body.telemetryEvents) + && Objects.equals(rollbarThreads, body.rollbarThreads); } @Override public int hashCode() { - return Objects.hash(bodyContent, telemetryEvents); + return Objects.hash(bodyContent, telemetryEvents, rollbarThreads); } @Override diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 05e41b5c..3e0a0c3e 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -44,6 +44,51 @@ private RollbarThread( this.group = group; } + /** + * Getter + * + * @return the group for this Thread + */ + public Group getGroup() { + return group; + } + + /** + * Getter + * + * @return the state of this Thread + */ + public String getState() { + return state; + } + + /** + * Getter + * + * @return the priority of this Thread + */ + public String getPriority() { + return priority; + } + + /** + * Getter + * + * @return the id of this Thread + */ + public String getId() { + return id; + } + + /** + * Getter + * + * @return the name of this Thread + */ + public String getName() { + return name; + } + @Override public Object asJson() { Map values = new HashMap<>(); @@ -95,4 +140,49 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name, id, priority, state, group); } + + /** + * Builder class for {@link RollbarThread RollbarThread}. + */ + public static final class Builder { + private String name; + private String id; + private String priority; + private String state; + private Group group; + + public Builder(RollbarThread rollbarThread) { + name = rollbarThread.name; + id = rollbarThread.id; + priority = rollbarThread.priority; + state = rollbarThread.state; + group = rollbarThread.group; + } + + /** + * The group for this thread. + * + * @param group an updated version of group; + * @return the builder instance. + */ + public Builder group(Group group) { + this.group = group; + return this; + } + + /** + * Builds the {@link RollbarThread RollbarThread}. + * + * @return the RollbarThread. + */ + public RollbarThread build() { + return new RollbarThread( + name, + id, + priority, + state, + group + ); + } + } } diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java index d475a23c..45fb394e 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java @@ -11,6 +11,7 @@ public class PayloadTruncator { private static final Charset TRANSPORT_CHARSET = Charset.forName("UTF-8"); private static final TruncationStrategy[] STRATEGIES = { + new RollbarThreadStrategy(), new FramesStrategy(), new StringsStrategy(1024), new StringsStrategy(512), diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java new file mode 100644 index 00000000..7aa95027 --- /dev/null +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java @@ -0,0 +1,65 @@ +package com.rollbar.notifier.truncation; + +import com.rollbar.api.payload.Payload; +import com.rollbar.api.payload.data.Data; +import com.rollbar.api.payload.data.body.Body; +import com.rollbar.api.payload.data.body.Group; +import com.rollbar.api.payload.data.body.RollbarThread; +import com.rollbar.api.payload.data.body.TraceChain; + +import java.util.ArrayList; +import java.util.List; + +public class RollbarThreadStrategy implements TruncationStrategy { + private static final FramesStrategy FRAMES_STRATEGY = new FramesStrategy(); + + @Override + public TruncationResult truncate(Payload payload) { + if (payload == null || payload.getData() == null || payload.getData().getBody() == null) { + return TruncationResult.none(); + } + + Body body = payload.getData().getBody(); + List rollbarThreads = body.getRollbarThreads(); + if (rollbarThreads == null) { + return TruncationResult.none(); + } + + TruncationResult> truncationResult = truncateRollbarThreads(rollbarThreads); + if (!truncationResult.wasTruncated) { + return TruncationResult.none(); + } + + Payload newPayload = new Payload.Builder(payload).data( + new Data.Builder(payload.getData()).body( + new Body.Builder(payload.getData().getBody()) + .rollbarThreads(truncationResult.value).build() + ).build() + ).build(); + + return TruncationResult.truncated(newPayload); + } + + private TruncationResult> truncateRollbarThreads(List rollbarThreads) { + boolean truncated = false; + ArrayList truncatedThreads = new ArrayList<>(); + for(RollbarThread rollbarThread: rollbarThreads) { + TraceChain traceChain = rollbarThread.getGroup().getTraceChain(); + + TruncationResult result = FRAMES_STRATEGY.truncateTraceChain(traceChain); + if (result.wasTruncated) { + truncated = true; + traceChain = result.value; + } + + RollbarThread truncatedThread = new RollbarThread.Builder(rollbarThread).group(new Group(traceChain)).build(); + truncatedThreads.add(truncatedThread); + } + + if (truncated) { + return TruncationResult.truncated(truncatedThreads); + } else { + return TruncationResult.none(); + } + } +} diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/RollbarThreadStrategyTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/RollbarThreadStrategyTest.java new file mode 100644 index 00000000..8c2097d9 --- /dev/null +++ b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/RollbarThreadStrategyTest.java @@ -0,0 +1,83 @@ +package com.rollbar.notifier.truncation; + +import com.rollbar.api.payload.Payload; +import com.rollbar.api.payload.data.body.Body; +import com.rollbar.notifier.truncation.TruncationStrategy.TruncationResult; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RollbarThreadStrategyTest { + + private TestPayloadBuilder payloadBuilder; + private final RollbarThreadStrategy sut = new RollbarThreadStrategy(); + private static final int MAX_FRAMES = 20; + + @Before + public void setUp() { + payloadBuilder = new TestPayloadBuilder(); + } + + @Test + public void ifPayloadIsNullItShouldNotTruncate() { + TruncationResult result = sut.truncate(null); + + verifyNoTruncation(result); + } + + @Test + public void ifDataIsNullItShouldNotTruncate() { + Payload payload = new Payload.Builder(payloadBuilder.createTestPayload()) + .data(null) + .build(); + + TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifBodyIsNullItShouldNotTruncate() { + Payload payload = payloadBuilder.createTestPayload((Body) null); + + TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifRollbarThreadsIsNullItShouldNotTruncate() { + Payload payload = payloadBuilder.createTestPayload(); + + TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifRollbarThreadsContainsFramesEqualOrLessThanMaximumItShouldNotTruncate() { + Payload payload = payloadBuilder.createTestPayloadSingleTraceWithRollbarThreads(MAX_FRAMES); + + TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifRollbarThreadsContainsMoreFramesThanMaximumItShouldTruncate() { + Payload payload = payloadBuilder.createTestPayloadSingleTraceWithRollbarThreads(MAX_FRAMES + 1); + + TruncationResult result = sut.truncate(payload); + + assertTrue(result.wasTruncated); + assertNotNull(result.value); + assertNotEquals(payload, result.value); + } + + private void verifyNoTruncation(TruncationResult result) { + assertFalse(result.wasTruncated); + assertNull(result.value); + } + +} diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java index 7f4a0ac6..f033992f 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java @@ -32,6 +32,10 @@ public Payload createTestPayloadSingleTrace(int frameCount) { return createTestPayloadSingleTrace(createFrames(frameCount)); } + public Payload createTestPayloadSingleTraceWithRollbarThreads(int frameCount) { + return createTestPayload(Collections.singletonList(createFrames(frameCount)), true); + } + public Payload createTestPayloadSingleTrace(Trace trace) { return createTestPayload(new Body.Builder().bodyContent(trace).build()); } @@ -41,16 +45,20 @@ public Payload createTestPayloadSingleTrace(List frameList) { } public Payload createTestPayload(List> frameLists) { + return createTestPayload(frameLists, false); + } + + public Payload createTestPayload(List> frameLists, boolean addRollbarThreads) { List traces = frameLists.stream().map(frameList -> new Trace.Builder() - .exception( - new ExceptionInfo.Builder() - .message(makeString("Error")) - .description(makeString("some error")) - .className(makeString("com.example.TestException")) - .build() - ) - .frames(frameList) - .build()).collect(Collectors.toList()); + .exception( + new ExceptionInfo.Builder() + .message(makeString("Error")) + .description(makeString("some error")) + .className(makeString("com.example.TestException")) + .build() + ) + .frames(frameList) + .build()).collect(Collectors.toList()); BodyContent bodyContent; if (traces.size() == 1) { @@ -59,7 +67,16 @@ public Payload createTestPayload(List> frameLists) { bodyContent = new TraceChain.Builder().traces(traces).build(); } - return createTestPayload(new Body.Builder().bodyContent(bodyContent).build()); + ArrayList rollbarThreads = null; + if (addRollbarThreads) { + rollbarThreads = new ArrayList<>(); + TraceChain traceChain = new TraceChain.Builder().traces(traces).build(); + Group group = new Group(traceChain); + RollbarThread rollbarThread = new RollbarThread(Thread.currentThread(), group); + rollbarThreads.add(rollbarThread); + } + + return createTestPayload(new Body.Builder().bodyContent(bodyContent).rollbarThreads(rollbarThreads).build()); } public Payload createTestPayload(Body body) { From a757a2c779a9e8a0dfe28ffe099998a794494c9c Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:22:25 -0300 Subject: [PATCH 28/37] fix: lint --- .../api/payload/data/body/RollbarThread.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 3e0a0c3e..8f62fa36 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -45,45 +45,45 @@ private RollbarThread( } /** - * Getter + * Getter. * - * @return the group for this Thread + * @return the group for this Thread. */ public Group getGroup() { return group; } /** - * Getter + * Getter. * - * @return the state of this Thread + * @return the state of this Thread. */ public String getState() { return state; } /** - * Getter + * Getter. * - * @return the priority of this Thread + * @return the priority of this Thread. */ public String getPriority() { return priority; } /** - * Getter + * Getter. * - * @return the id of this Thread + * @return the id of this Thread. */ public String getId() { return id; } /** - * Getter + * Getter. * - * @return the name of this Thread + * @return the name of this Thread. */ public String getName() { return name; From eef19c6aa0798dce3493146308cf2a49603e6aa1 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:23:26 -0300 Subject: [PATCH 29/37] fix: lint --- .../com/rollbar/api/payload/data/body/RollbarThread.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 8f62fa36..33406da5 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -151,6 +151,11 @@ public static final class Builder { private String state; private Group group; + /** + * Constructor. + * + * @param rollbarThread the {@link RollbarThread rollbarThread} to initialize a new builder instance. + */ public Builder(RollbarThread rollbarThread) { name = rollbarThread.name; id = rollbarThread.id; From 4e1fce936e9736bc9b12e12076bc0582b7ad4e86 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:26:33 -0300 Subject: [PATCH 30/37] fix: lint --- .../java/com/rollbar/api/payload/data/body/RollbarThread.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 33406da5..687c4e6b 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -154,7 +154,8 @@ public static final class Builder { /** * Constructor. * - * @param rollbarThread the {@link RollbarThread rollbarThread} to initialize a new builder instance. + * @param rollbarThread the {@link RollbarThread rollbarThread} to initialize + * a new builder instance. */ public Builder(RollbarThread rollbarThread) { name = rollbarThread.name; From 6082a7048a35c106f8017ffc0dcb89c46b1a59d8 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 12 Apr 2025 17:30:33 -0300 Subject: [PATCH 31/37] fix(RollbarThreadStrategy): lint --- .../notifier/truncation/RollbarThreadStrategy.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java index 7aa95027..029d6330 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/RollbarThreadStrategy.java @@ -40,10 +40,12 @@ public TruncationResult truncate(Payload payload) { return TruncationResult.truncated(newPayload); } - private TruncationResult> truncateRollbarThreads(List rollbarThreads) { + private TruncationResult> truncateRollbarThreads( + List rollbarThreads + ) { boolean truncated = false; ArrayList truncatedThreads = new ArrayList<>(); - for(RollbarThread rollbarThread: rollbarThreads) { + for (RollbarThread rollbarThread: rollbarThreads) { TraceChain traceChain = rollbarThread.getGroup().getTraceChain(); TruncationResult result = FRAMES_STRATEGY.truncateTraceChain(traceChain); @@ -52,7 +54,9 @@ private TruncationResult> truncateRollbarThreads(List Date: Sat, 12 Apr 2025 18:08:40 -0300 Subject: [PATCH 32/37] feat: Add strategy for Telemetry events --- .../rollbar/api/payload/data/body/Body.java | 9 ++ .../notifier/truncation/PayloadTruncator.java | 1 + .../truncation/TelemetryEventsStrategy.java | 42 +++++++ .../TelemetryEventsStrategyTest.java | 106 ++++++++++++++++++ .../truncation/TestPayloadBuilder.java | 29 ++++- 5 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 rollbar-java/src/main/java/com/rollbar/notifier/truncation/TelemetryEventsStrategy.java create mode 100644 rollbar-java/src/test/java/com/rollbar/notifier/truncation/TelemetryEventsStrategyTest.java diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java index 0e5122ad..93fd471d 100755 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Body.java @@ -46,6 +46,15 @@ public List getRollbarThreads() { return rollbarThreads; } + /** + * Getter. + * + * @return the list of Telemetry events. + */ + public List getTelemetryEvents() { + return telemetryEvents; + } + @Override public Object asJson() { HashMap values = new HashMap<>(); diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java index 45fb394e..eb9d70b9 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/PayloadTruncator.java @@ -13,6 +13,7 @@ public class PayloadTruncator { private static final TruncationStrategy[] STRATEGIES = { new RollbarThreadStrategy(), new FramesStrategy(), + new TelemetryEventsStrategy(), new StringsStrategy(1024), new StringsStrategy(512), new StringsStrategy(256), diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/truncation/TelemetryEventsStrategy.java b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/TelemetryEventsStrategy.java new file mode 100644 index 00000000..e2260acd --- /dev/null +++ b/rollbar-java/src/main/java/com/rollbar/notifier/truncation/TelemetryEventsStrategy.java @@ -0,0 +1,42 @@ +package com.rollbar.notifier.truncation; + +import com.rollbar.api.payload.Payload; +import com.rollbar.api.payload.data.Data; +import com.rollbar.api.payload.data.TelemetryEvent; +import com.rollbar.api.payload.data.body.Body; + +import java.util.ArrayList; +import java.util.List; + +public class TelemetryEventsStrategy implements TruncationStrategy { + private static final int MAX_EVENTS = 10; + + @Override + public TruncationResult truncate(Payload payload) { + if (payload == null || payload.getData() == null || payload.getData().getBody() == null) { + return TruncationResult.none(); + } + + Body body = payload.getData().getBody(); + List telemetryEvents = body.getTelemetryEvents(); + if (telemetryEvents == null || telemetryEvents.size() <= MAX_EVENTS) { + return TruncationResult.none(); + } + + ArrayList truncatedTelemetryEvents = new ArrayList<>(); + for (int i = 0; i < MAX_EVENTS; i++) { + truncatedTelemetryEvents.add(telemetryEvents.get(i)); + } + + Payload newPayload = new Payload.Builder(payload).data( + new Data.Builder(payload.getData()).body( + new Body + .Builder(payload.getData().getBody()) + .telemetryEvents(truncatedTelemetryEvents) + .build() + ).build() + ).build(); + + return TruncationResult.truncated(newPayload); + } +} diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TelemetryEventsStrategyTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TelemetryEventsStrategyTest.java new file mode 100644 index 00000000..c98797d8 --- /dev/null +++ b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TelemetryEventsStrategyTest.java @@ -0,0 +1,106 @@ +package com.rollbar.notifier.truncation; + +import com.rollbar.api.payload.Payload; +import com.rollbar.api.payload.data.Level; +import com.rollbar.api.payload.data.Source; +import com.rollbar.api.payload.data.TelemetryEvent; +import com.rollbar.api.payload.data.TelemetryType; +import com.rollbar.api.payload.data.body.Body; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.junit.Assert.*; + +public class TelemetryEventsStrategyTest { + + private TestPayloadBuilder payloadBuilder; + private final TelemetryEventsStrategy sut = new TelemetryEventsStrategy(); + private static final int MAX_EVENTS = 10; + + @Before + public void setUp() { + payloadBuilder = new TestPayloadBuilder(); + } + + @Test + public void ifPayloadIsNullItShouldNotTruncate() { + TruncationStrategy.TruncationResult result = sut.truncate(null); + + verifyNoTruncation(result); + } + + @Test + public void ifDataIsNullItShouldNotTruncate() { + Payload payload = new Payload.Builder(payloadBuilder.createTestPayload()) + .data(null) + .build(); + + TruncationStrategy.TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifBodyIsNullItShouldNotTruncate() { + Payload payload = payloadBuilder.createTestPayload((Body) null); + + TruncationStrategy.TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifTelemetryEventsEqualOrLessThanMaximumItShouldTruncate() { + List telemetryEvents = createTelemetryEvents(MAX_EVENTS); + Payload payload = payloadBuilder.createTestPayloadSingleTraceWithTelemetryEvents( + 1, + telemetryEvents + ); + + TruncationStrategy.TruncationResult result = sut.truncate(payload); + + verifyNoTruncation(result); + } + + @Test + public void ifTelemetryEventsAreAboveMaximumItShouldTruncate() { + List telemetryEvents = createTelemetryEvents(MAX_EVENTS + 1); + Payload payload = payloadBuilder.createTestPayloadSingleTraceWithTelemetryEvents( + 1, + telemetryEvents + ); + + TruncationStrategy.TruncationResult result = sut.truncate(payload); + + assertTrue(result.wasTruncated); + assertNotNull(result.value); + assertNotEquals(payload, result.value); + } + + private void verifyNoTruncation(TruncationStrategy.TruncationResult result) { + assertFalse(result.wasTruncated); + assertNull(result.value); + } + + private List createTelemetryEvents(int quantity) { + ArrayList telemetryEvents = new ArrayList<>(); + for (int i = 0; i < quantity; i++) { + telemetryEvents.add(creteTelemetryEvent()); + } + return telemetryEvents; + } + + private TelemetryEvent creteTelemetryEvent() { + return new TelemetryEvent( + TelemetryType.MANUAL, + Level.DEBUG, + 1L, + Source.CLIENT, + new HashMap<>() + ); + } +} diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java index f033992f..aaffc758 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/truncation/TestPayloadBuilder.java @@ -33,7 +33,17 @@ public Payload createTestPayloadSingleTrace(int frameCount) { } public Payload createTestPayloadSingleTraceWithRollbarThreads(int frameCount) { - return createTestPayload(Collections.singletonList(createFrames(frameCount)), true); + return createTestPayload(Collections.singletonList(createFrames(frameCount)), true, null); + } + + public Payload createTestPayloadSingleTraceWithTelemetryEvents( + int frameCount, + List telemetryEvents + ) { + return createTestPayload( + Collections.singletonList(createFrames(frameCount)), + true, + telemetryEvents); } public Payload createTestPayloadSingleTrace(Trace trace) { @@ -45,10 +55,14 @@ public Payload createTestPayloadSingleTrace(List frameList) { } public Payload createTestPayload(List> frameLists) { - return createTestPayload(frameLists, false); + return createTestPayload(frameLists, false, null); } - public Payload createTestPayload(List> frameLists, boolean addRollbarThreads) { + public Payload createTestPayload( + List> frameLists, + boolean addRollbarThreads, + List telemetryEvents + ) { List traces = frameLists.stream().map(frameList -> new Trace.Builder() .exception( new ExceptionInfo.Builder() @@ -76,7 +90,14 @@ public Payload createTestPayload(List> frameLists, boolean addRollba rollbarThreads.add(rollbarThread); } - return createTestPayload(new Body.Builder().bodyContent(bodyContent).rollbarThreads(rollbarThreads).build()); + return createTestPayload( + new Body + .Builder() + .bodyContent(bodyContent) + .rollbarThreads(rollbarThreads) + .telemetryEvents(telemetryEvents) + .build() + ); } public Payload createTestPayload(Body body) { From 5a8bc02a162c8d89b877a9b00a5a8866b4768aaf Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 14 Apr 2025 02:42:32 -0300 Subject: [PATCH 33/37] feat: Add is_main field --- .../api/payload/data/body/RollbarThread.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java index 687c4e6b..efff8f00 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/RollbarThread.java @@ -15,6 +15,7 @@ public class RollbarThread implements JsonSerializable, StringTruncatable Date: Mon, 12 May 2025 01:16:49 -0300 Subject: [PATCH 34/37] refactor: replace Thread by RollbarThread in ThrowableWrapper --- .../rollbar/api/payload/data/body/Group.java | 7 +++++ .../rollbar/notifier/util/BodyFactory.java | 28 +++++++++++++++++-- .../wrapper/RollbarThrowableWrapper.java | 16 ++++++----- .../notifier/wrapper/ThrowableWrapper.java | 14 +++++++++- .../wrapper/RollbarThrowableWrapperTest.java | 6 ++-- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index d1d14abb..8a7c1b4b 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -55,4 +55,11 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hashCode(traceChain); } + + @Override + public String toString() { + return "Group{" + + "traceChain=" + traceChain + + '}'; + } } diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java index 8c6f36e3..103d3ed0 100755 --- a/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/util/BodyFactory.java @@ -71,6 +71,22 @@ public Body from( return from(throwableWrapper, description, builder); } + /** + * Builds a RollbarThread from a Thread. + * + * @param thread the thread. + * @return the RollbarThread. + */ + public RollbarThread from( + Thread thread + ) { + if (thread == null) { + return null; + } + TraceChain traceChain = traceChain(thread.getStackTrace()); + return new RollbarThread(thread, new Group(traceChain)); + } + private Body from( ThrowableWrapper throwableWrapper, String description, @@ -94,17 +110,23 @@ private List makeRollbarThreads( return null; } + RollbarThread rollbarThread = throwableWrapper.getRollbarThread(); + if (rollbarThread == null) { + return null; + } + ArrayList rollbarThreads = new ArrayList<>(); - rollbarThreads.add(makeInitialRollbarThread(throwableWrapper, description)); + rollbarThreads.add(updateInitialRollbarThread(rollbarThread, throwableWrapper, description)); return addOtherThreads(rollbarThreads, allStackTraces); } - private RollbarThread makeInitialRollbarThread( + private RollbarThread updateInitialRollbarThread( + RollbarThread rollbarThread, ThrowableWrapper throwableWrapper, String description ) { TraceChain traceChain = traceChain(throwableWrapper, description); - return new RollbarThread(throwableWrapper.getThread(), new Group(traceChain)); + return new RollbarThread.Builder(rollbarThread).group(new Group(traceChain)).build(); } private ArrayList addOtherThreads( diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java index 1139a1b6..7eee3ba2 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapper.java @@ -1,5 +1,8 @@ package com.rollbar.notifier.wrapper; +import com.rollbar.api.payload.data.body.RollbarThread; +import com.rollbar.notifier.util.BodyFactory; + import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -19,7 +22,7 @@ public class RollbarThrowableWrapper implements ThrowableWrapper { private final Throwable throwable; - private final Thread thread; + private final RollbarThread rollbarThread; private final Map allStackTraces; @@ -36,7 +39,7 @@ public RollbarThrowableWrapper(Throwable throwable) { getInnerThrowableWrapper(throwable), throwable, Thread.currentThread(), - captureAllStackTraces(Thread.currentThread()) + captureAllStackTraces(Thread.currentThread()) ); } @@ -139,7 +142,7 @@ private RollbarThrowableWrapper( this.stackTraceElements = stackTraceElements; this.cause = cause; this.throwable = throwable; - this.thread = thread; + this.rollbarThread = new BodyFactory().from(thread); this.allStackTraces = allStackTraces; } @@ -169,8 +172,8 @@ public Throwable getThrowable() { } @Override - public Thread getThread() { - return thread; + public RollbarThread getRollbarThread() { + return rollbarThread; } @Override @@ -186,8 +189,7 @@ public String toString() { + ", stackTraceElements=" + Arrays.toString(stackTraceElements) + ", cause=" + cause + ", throwable=" + throwable - + ", thread=" + thread - + ", threads=" + allStackTraces + + ", rollbarThread=" + rollbarThread + '}'; } diff --git a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java index 6a5cd8c9..480de92e 100644 --- a/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java +++ b/rollbar-java/src/main/java/com/rollbar/notifier/wrapper/ThrowableWrapper.java @@ -1,5 +1,7 @@ package com.rollbar.notifier.wrapper; +import com.rollbar.api.payload.data.body.RollbarThread; + import java.util.Map; /** @@ -42,7 +44,17 @@ public interface ThrowableWrapper { */ Throwable getThrowable(); - Thread getThread(); + /** + * Get the RollbarThread {@link RollbarThread rollbarThread}. + * + * @return the rollbarThread. + */ + RollbarThread getRollbarThread(); + /** + * Get a map of stack traces for all live threads in the moment of the Exception. + * + * @return the map. + */ Map getAllStackTraces(); } diff --git a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java index eecd6a03..4c752a4e 100644 --- a/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java +++ b/rollbar-java/src/test/java/com/rollbar/notifier/wrapper/RollbarThrowableWrapperTest.java @@ -13,7 +13,7 @@ public void shouldCollectThreads() { RollbarThrowableWrapper sut = new RollbarThrowableWrapper(new Exception("Any"), Thread.currentThread()); assertNotNull(sut.getAllStackTraces()); - assertNotNull(sut.getThread()); + assertNotNull(sut.getRollbarThread()); } @Test @@ -30,7 +30,7 @@ public void shouldBeCreatedByThrowable() { assertThat(sut.getCause(), is(nested)); assertThat(sut.getThrowable(), is(throwable)); assertNotNull(sut.getAllStackTraces()); - assertNotNull(sut.getThread()); + assertNotNull(sut.getRollbarThread()); } @Test @@ -50,7 +50,7 @@ public void shouldBeCreatedByThrowableParams() { assertThat(sut.getCause(), is(cause)); assertThat(sut.getThrowable(), is(nullValue())); assertNull(sut.getAllStackTraces()); - assertNull(sut.getThread()); + assertNull(sut.getRollbarThread()); } @Test From bdfab2f152903a426bfe0a5e9a92838349e6a034 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 12 May 2025 01:28:53 -0300 Subject: [PATCH 35/37] CI: bump ubuntu image to 22.04 Ref. actions/runner-images#11101 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85459fbf..2272a299 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,13 +19,13 @@ on: jobs: validation: name: Gradle wrapper validation - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - uses: gradle/actions/wrapper-validation@v3 build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: Build with Java ${{ matrix.java }} needs: [ validation ] strategy: @@ -71,7 +71,7 @@ jobs: **/build/reports/* release: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: Release # It would be nice to run this as part of the build job, since it would be # faster and have less duplicated Yaml, it would not be possible to check From 9eb1e67b7f621ebd0dcd504d72d1f24e41412bbe Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 12 May 2025 01:34:43 -0300 Subject: [PATCH 36/37] fix: lint --- .../main/java/com/rollbar/api/payload/data/body/Group.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java index 8a7c1b4b..2808229f 100644 --- a/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java +++ b/rollbar-api/src/main/java/com/rollbar/api/payload/data/body/Group.java @@ -58,8 +58,6 @@ public int hashCode() { @Override public String toString() { - return "Group{" + - "traceChain=" + traceChain + - '}'; + return "Group{traceChain=" + traceChain + '}'; } } From 7c096eb198fc5bf29f96f2ec1f480439afa430ce Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 12 May 2025 01:45:30 -0300 Subject: [PATCH 37/37] fix: update revapi.yml replacing getThread with getRollbarThread --- .palantir/revapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.palantir/revapi.yml b/.palantir/revapi.yml index 451ee479..24ca338e 100644 --- a/.palantir/revapi.yml +++ b/.palantir/revapi.yml @@ -41,7 +41,7 @@ acceptedBreaks: \ implementations of our config interfaces, but those interfaces are not meant\ \ to be implemented by users" - code: "java.method.addedToInterface" - new: "method java.lang.Thread com.rollbar.notifier.wrapper.ThrowableWrapper::getThread()" + new: "method com.rollbar.api.payload.data.body.RollbarThread com.rollbar.notifier.wrapper.ThrowableWrapper::getRollbarThread()" justification: "This is a binary compatible change, which could only break custom\ \ implementations of our config interfaces, but those interfaces are not meant\ \ to be implemented by users"