From 1f55f5fb44bfffbf9d90a158c52268ad31db4382 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Fri, 22 Nov 2024 15:56:16 +0100 Subject: [PATCH] Start using reports to send inner exceptions --- .../library/BacktraceClientSendTest.java | 12 +++- .../backtraceio/library/BacktraceClient.java | 24 +------ .../library/base/BacktraceBase.java | 66 ++++++++++------- .../library/models/json/BacktraceReport.java | 27 ++++--- ...r.java => ReportExceptionTransformer.java} | 64 +++++++++++++---- ...va => ReportExceptionTransformerTest.java} | 70 +++++++++---------- 6 files changed, 153 insertions(+), 110 deletions(-) rename backtrace-library/src/main/java/backtraceio/library/services/{ExceptionTransformer.java => ReportExceptionTransformer.java} (54%) rename backtrace-library/src/test/java/backtraceio/library/{ExceptionTransformerTest.java => ReportExceptionTransformerTest.java} (61%) diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientSendTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientSendTest.java index 33897df2..dbd40595 100644 --- a/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientSendTest.java +++ b/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientSendTest.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.concurrent.TimeUnit; import backtraceio.library.common.BacktraceSerializeHelper; @@ -93,7 +94,12 @@ public void sendExceptionWithManyCause() { final BacktraceClient backtraceClient = new BacktraceClient(context, credentials); final Waiter waiter = new Waiter(); - final String mainExceptionExpectedMessage = "java.io.IOException: java.lang.IllegalArgumentException: New Exception"; + + final Stack expectedExceptionMessages = new Stack() {{ + add("java.lang.IllegalArgumentException: New Exception"); + add("java.io.IOException: java.lang.IllegalArgumentException: New Exception"); + }}; + RequestHandler rh = data -> { String jsonString = BacktraceSerializeHelper.toJson(data); @@ -102,7 +108,7 @@ public void sendExceptionWithManyCause() { final JSONObject jsonObject = new JSONObject(jsonString); final JSONObject exceptionProperties = jsonObject.getJSONObject("annotations").getJSONObject("Exception properties"); final String mainExceptionMessage = jsonObject.getJSONObject("annotations").getJSONObject("Exception").getString("message"); - + final String mainExceptionExpectedMessage = expectedExceptionMessages.pop(); assertEquals(mainExceptionExpectedMessage, mainExceptionMessage); assertTrue(exceptionProperties.getJSONArray("stack-trace").length() > 0); assertEquals(mainExceptionExpectedMessage, exceptionProperties.get("detail-message")); @@ -124,7 +130,7 @@ public void sendExceptionWithManyCause() { // WAIT FOR THE RESULT FROM ANOTHER THREAD try { - waiter.await(5, TimeUnit.SECONDS); + waiter.await(500, TimeUnit.SECONDS); } catch (Exception ex) { fail(ex.getMessage()); } diff --git a/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java b/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java index f163c593..d4ea119d 100644 --- a/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java +++ b/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java @@ -11,7 +11,6 @@ import backtraceio.library.interfaces.Database; import backtraceio.library.models.database.BacktraceDatabaseSettings; import backtraceio.library.models.json.BacktraceReport; -import backtraceio.library.services.ExceptionTransformer; import backtraceio.library.watchdog.BacktraceANRWatchdog; import backtraceio.library.watchdog.OnApplicationNotRespondingEvent; @@ -20,7 +19,6 @@ */ public class BacktraceClient extends BacktraceBase { - private final ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); /** * Backtrace ANR watchdog instance */ @@ -227,10 +225,7 @@ public void send(Throwable throwable, OnServerResponseEventListener */ public void send(Throwable throwable, Map attributes, OnServerResponseEventListener serverResponseEventListener) { - for (BacktraceReport report : - this.exceptionTransformer.transformExceptionIntoReports(throwable, attributes)) { - super.send(report, serverResponseEventListener); - } + super.send(new BacktraceReport(throwable, attributes), serverResponseEventListener); } /** @@ -310,21 +305,4 @@ public void disableAnr() { } } - /** - * Determine if Reports should be generated for inner exceptions. By default the value is set to true. - * - * @param sendInnerExceptions boolean flag that enabled/disable sending inner exceptions - */ - public void sendInnerExceptions(boolean sendInnerExceptions) { - this.exceptionTransformer.sendInnerExceptions(sendInnerExceptions); - } - - /** - * Determine if Reports should be generated for suppressed exceptions. By default the value is set to true. - * - * @param sendSuppressedExceptions boolean flag that enabled/disable sending suppressed exceptions - */ - public void sendSuppressedExceptions(boolean sendSuppressedExceptions) { - this.exceptionTransformer.sendSuppressedExceptions(sendSuppressedExceptions); - } } diff --git a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java index 4890637b..c73c38d2 100644 --- a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java +++ b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java @@ -29,13 +29,18 @@ import backtraceio.library.models.types.BacktraceResultStatus; import backtraceio.library.services.BacktraceApi; import backtraceio.library.services.BacktraceMetrics; +import backtraceio.library.services.ReportExceptionTransformer; /** * Base Backtrace Android client */ public class BacktraceBase implements Client { - private static final transient String LOG_TAG = BacktraceBase.class.getSimpleName(); + private static final String LOG_TAG = BacktraceBase.class.getSimpleName(); + /** + * Backtrace client version + */ + public static String version = backtraceio.library.BuildConfig.VERSION_NAME; static { System.loadLibrary("backtrace-native"); @@ -45,12 +50,6 @@ public class BacktraceBase implements Client { * Backtrace database instance */ public final Database database; - - /** - * Backtrace client version - */ - public static String version = backtraceio.library.BuildConfig.VERSION_NAME; - /** * Get custom client attributes. Every argument stored in dictionary will be send to Backtrace API */ @@ -61,27 +60,23 @@ public class BacktraceBase implements Client { */ public final List attachments; private final BacktraceCredentials credentials; - + private final ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); /** * Backtrace metrics instance */ public Metrics metrics = null; - /** * Application context */ protected Context context; - /** * Instance of BacktraceApi that allows to send data to Backtrace API */ private Api backtraceApi; - /** * Event which will be executed before sending data to Backtrace API */ private OnBeforeSendEventListener beforeSendEventListener = null; - /** * Is Proguard symbolication enabled? We have to inform the Backtrace API */ @@ -574,25 +569,28 @@ public void send(BacktraceReport report) { /** * Sending an exception to Backtrace API * - * @param report current BacktraceReport + * @param sourceReport current BacktraceReport */ - public void send(BacktraceReport report, final OnServerResponseEventListener callback) { + public void send(BacktraceReport sourceReport, final OnServerResponseEventListener callback) { Breadcrumbs breadcrumbs = this.database.getBreadcrumbs(); - if (breadcrumbs != null) { - breadcrumbs.processReportBreadcrumbs(report); - } - addReportAttachments(report); + for (BacktraceReport report : + this.reportExceptionTransformer.transformReportWithInnerExceptions(sourceReport)) { + if (breadcrumbs != null) { + breadcrumbs.processReportBreadcrumbs(report); + } + addReportAttachments(report); - BacktraceData backtraceData = new BacktraceData(this.context, report, this.attributes); - backtraceData.symbolication = this.isProguardEnabled ? "proguard" : null; + BacktraceData backtraceData = new BacktraceData(this.context, report, this.attributes); + backtraceData.symbolication = this.isProguardEnabled ? "proguard" : null; - final BacktraceDatabaseRecord record = this.database.add(report, this.attributes, this.isProguardEnabled); + final BacktraceDatabaseRecord record = this.database.add(report, this.attributes, this.isProguardEnabled); - if (this.beforeSendEventListener != null) { - backtraceData = this.beforeSendEventListener.onEvent(backtraceData); - } + if (this.beforeSendEventListener != null) { + backtraceData = this.beforeSendEventListener.onEvent(backtraceData); + } - this.backtraceApi.send(backtraceData, this.getDatabaseCallback(record, callback)); + this.backtraceApi.send(backtraceData, this.getDatabaseCallback(record, callback)); + } } private OnServerResponseEventListener getDatabaseCallback(final BacktraceDatabaseRecord record, final OnServerResponseEventListener customCallback) { @@ -624,4 +622,22 @@ private boolean isBreadcrumbsAvailable() { return database != null && database.getBreadcrumbs() != null; } + + /** + * Determine if Reports should be generated for inner exceptions. By default the value is set to true. + * + * @param sendInnerExceptions boolean flag that enabled/disable sending inner exceptions + */ + public void sendInnerExceptions(boolean sendInnerExceptions) { + this.reportExceptionTransformer.sendInnerExceptions(sendInnerExceptions); + } + + /** + * Determine if Reports should be generated for suppressed exceptions. By default the value is set to true. + * + * @param sendSuppressedExceptions boolean flag that enabled/disable sending suppressed exceptions + */ + public void sendSuppressedExceptions(boolean sendSuppressedExceptions) { + this.reportExceptionTransformer.sendSuppressedExceptions(sendSuppressedExceptions); + } } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceReport.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceReport.java index 8727c593..527c2371 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceReport.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceReport.java @@ -20,47 +20,43 @@ */ public class BacktraceReport { + /** + * Reference to the original exception. This field is internally used by the library. + */ + private final transient Throwable originalException; /** * 16 bytes of randomness in human readable UUID format * server will reject request if uuid is already found */ public UUID uuid = UUID.randomUUID(); - /** * UTC timestamp in seconds */ public long timestamp = BacktraceTimeHelper.getTimestampSeconds(); - /** * Get information about report type. If value is true the BacktraceReport has an error */ public Boolean exceptionTypeReport = false; - /** * Get a report classification */ public String classifier = ""; - /** * Get an report attributes */ - public Map attributes; - + public Map attributes = new HashMap<>(); /** * Get a custom client message */ public String message; - /** * Get a report exception */ public Exception exception; - /** * Get all paths to attachments */ - public List attachmentPaths; - + public List attachmentPaths = new ArrayList<>(); /** * Current report exception stack */ @@ -173,6 +169,7 @@ public BacktraceReport( public BacktraceReport(Throwable throwable, Map attributes, List attachmentPaths) { this.attributes = CollectionUtils.copyMap(attributes); this.attachmentPaths = CollectionUtils.copyList(attachmentPaths); + this.originalException = throwable; this.exception = this.prepareException(throwable); if (throwable != null) { this.classifier = getExceptionClassifier(throwable); @@ -237,6 +234,16 @@ private void setDefaultErrorTypeAttribute() { : BacktraceAttributeConsts.MessageAttributeType); } + /** + * Returns report exception - original exception if possible or serializable exception if + * the report was loaded from JSON. + * + * @return throwable object + */ + public Throwable getException() { + return this.originalException != null ? this.originalException : this.exception; + } + public BacktraceData toBacktraceData(Context context, Map clientAttributes) { return toBacktraceData(context, clientAttributes, false); } diff --git a/backtrace-library/src/main/java/backtraceio/library/services/ExceptionTransformer.java b/backtrace-library/src/main/java/backtraceio/library/services/ReportExceptionTransformer.java similarity index 54% rename from backtrace-library/src/main/java/backtraceio/library/services/ExceptionTransformer.java rename to backtrace-library/src/main/java/backtraceio/library/services/ReportExceptionTransformer.java index dfe45681..f7eb0b4e 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/ExceptionTransformer.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/ReportExceptionTransformer.java @@ -7,7 +7,7 @@ import backtraceio.library.models.json.BacktraceReport; -public class ExceptionTransformer { +public class ReportExceptionTransformer { /** * Error trace attribute key @@ -49,29 +49,42 @@ public void sendSuppressedExceptions(boolean sendSuppressedExceptions) { * Transforms throwable into an array of Backtrace reports. During the transformation, inner exception and suppressed exceptions * are being converted into Backtrace reports with a proper exception reference. * - * @param throwable throwable - * @param attributes report attributes - attributes will be included in each report + * @param sourceReport BacktraceReport * @return list of Backtrace reports */ - public List transformExceptionIntoReports(Throwable throwable, Map attributes) { + public List transformReportWithInnerExceptions(BacktraceReport sourceReport) { final String exceptionTrace = UUID.randomUUID().toString(); - final List reports = new ArrayList<>(); - String parentId = null; + final List reports = new ArrayList() {{ + add(sourceReport); + }}; + + if (!sourceReport.exceptionTypeReport) { + return reports; + } + Throwable throwable = sourceReport.getException(); + if (throwable == null) { + return reports; + } + /** + * To keep the original report, we're not re-creating it but rather, we copy all known possible values + * that should be also available in inner exceptions. We should keep the original report, in case of potential + * changes that could + */ + String parentId = sourceReport.uuid.toString(); + Map attributes = sourceReport.attributes; + List attachments = sourceReport.attachmentPaths; + reports.addAll(this.getSuppressedReports(throwable, attachments, attributes, exceptionTrace, parentId)); + + throwable = throwable.getCause(); while (throwable != null) { BacktraceReport report = new BacktraceReport(throwable, attributes); + report.attachmentPaths.addAll(attachments); this.extendReportWithNestedExceptionAttributes(report, exceptionTrace, parentId); reports.add(report); parentId = report.uuid.toString(); - if (sendSuppressedExceptions) { - for (Throwable suppressedException : - throwable.getSuppressed()) { - BacktraceReport suppressedExceptionReport = new BacktraceReport(suppressedException, attributes); - this.extendReportWithNestedExceptionAttributes(suppressedExceptionReport, exceptionTrace, parentId); - reports.add(suppressedExceptionReport); - } - } + reports.addAll(this.getSuppressedReports(throwable, attachments, attributes, exceptionTrace, parentId)); if (!sendInnerExceptions) { break; @@ -82,6 +95,29 @@ public List transformExceptionIntoReports(Throwable throwable, return reports; } + private List getSuppressedReports( + Throwable throwable, + List attachments, + Map attributes, + String exceptionTrace, + String parentId) { + List reports = new ArrayList<>(); + if (!this.sendSuppressedExceptions) { + return reports; + } + + for (Throwable suppressedException : + throwable.getSuppressed()) { + BacktraceReport suppressedExceptionReport = new BacktraceReport(suppressedException, attributes); + this.extendReportWithNestedExceptionAttributes(suppressedExceptionReport, exceptionTrace, parentId); + suppressedExceptionReport.attachmentPaths.addAll(attachments); + reports.add(suppressedExceptionReport); + } + + + return reports; + } + /** * Add exception trace attributes to the nested exception * diff --git a/backtrace-library/src/test/java/backtraceio/library/ExceptionTransformerTest.java b/backtrace-library/src/test/java/backtraceio/library/ReportExceptionTransformerTest.java similarity index 61% rename from backtrace-library/src/test/java/backtraceio/library/ExceptionTransformerTest.java rename to backtrace-library/src/test/java/backtraceio/library/ReportExceptionTransformerTest.java index e3d82dcc..9e755f9b 100644 --- a/backtrace-library/src/test/java/backtraceio/library/ExceptionTransformerTest.java +++ b/backtrace-library/src/test/java/backtraceio/library/ReportExceptionTransformerTest.java @@ -11,9 +11,9 @@ import java.util.Map; import backtraceio.library.models.json.BacktraceReport; -import backtraceio.library.services.ExceptionTransformer; +import backtraceio.library.services.ReportExceptionTransformer; -public class ExceptionTransformerTest { +public class ReportExceptionTransformerTest { final String innerExceptionMessage = "Inner exception message"; final String outerExceptionMessage = "Outer exception message"; @@ -26,15 +26,15 @@ public class ExceptionTransformerTest { @Test public void generateReportOnlyForExceptionWithoutInnerExceptions() { final Exception exception = new Exception("Exception without inner or suppressed exceptions"); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - List reports = exceptionTransformer.transformExceptionIntoReports(exception, attributes); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(exception, attributes)); BacktraceReport exceptionReport = reports.get(0); assertEquals(exception.getMessage(), exceptionReport.exception.getMessage()); - assertNull(exceptionReport.attributes.get(ExceptionTransformer.ErrorParentIdAttribute)); - assertEquals(exceptionReport.uuid.toString(), exceptionReport.attributes.get(ExceptionTransformer.ErrorIdAttribute)); - assertNotNull(exceptionReport.attributes.get(ExceptionTransformer.ErrorTraceAttribute)); + assertNull(exceptionReport.attributes.get(ReportExceptionTransformer.ErrorParentIdAttribute)); + assertEquals(exceptionReport.uuid.toString(), exceptionReport.attributes.get(ReportExceptionTransformer.ErrorIdAttribute)); + assertNotNull(exceptionReport.attributes.get(ReportExceptionTransformer.ErrorTraceAttribute)); } @Test @@ -42,10 +42,10 @@ public void generateReportForInnerAndOuterException() { final int expectedNumberOfReports = 2; Exception innerException = new Exception(innerExceptionMessage); Exception outerException = new Exception(outerExceptionMessage, innerException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendInnerExceptions(true); - List reports = exceptionTransformer.transformExceptionIntoReports(outerException, attributes); + reportExceptionTransformer.sendInnerExceptions(true); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(outerException, attributes)); assertEquals(expectedNumberOfReports, reports.size()); BacktraceReport outerExceptionReport = reports.get(0); @@ -53,23 +53,23 @@ public void generateReportForInnerAndOuterException() { assertEquals( outerExceptionReport.uuid.toString(), - innerExceptionReport.attributes.get(ExceptionTransformer.ErrorParentIdAttribute)); + innerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorParentIdAttribute)); assertEquals( outerExceptionReport.uuid.toString(), - outerExceptionReport.attributes.get(ExceptionTransformer.ErrorIdAttribute)); + outerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorIdAttribute)); assertEquals( - innerExceptionReport.attributes.get(ExceptionTransformer.ErrorTraceAttribute), - outerExceptionReport.attributes.get(ExceptionTransformer.ErrorTraceAttribute)); + innerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorTraceAttribute), + outerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorTraceAttribute)); } @Test public void DoNotGenerateInnerExceptionIfDisabled() { Exception innerException = new Exception(innerExceptionMessage); Exception outerException = new Exception(outerExceptionMessage, innerException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendInnerExceptions(false); - List reports = exceptionTransformer.transformExceptionIntoReports(outerException, attributes); + reportExceptionTransformer.sendInnerExceptions(false); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(outerException, attributes)); assertEquals(1, reports.size()); BacktraceReport outerExceptionReport = reports.get(0); @@ -82,10 +82,10 @@ public void generateReportForSuppressedException() { Exception suppressedException = new Exception(suppressedExceptionMessage); Exception exception = new Exception(outerExceptionMessage); exception.addSuppressed(suppressedException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendSuppressedExceptions(true); - List reports = exceptionTransformer.transformExceptionIntoReports(exception, attributes); + reportExceptionTransformer.sendSuppressedExceptions(true); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(exception, attributes)); assertEquals(expectedNumberOfReports, reports.size()); BacktraceReport outerExceptionReport = reports.get(0); @@ -94,13 +94,13 @@ public void generateReportForSuppressedException() { assertEquals(suppressedExceptionMessage, suppressedExceptionReport.exception.getMessage()); assertEquals( outerExceptionReport.uuid.toString(), - suppressedExceptionReport.attributes.get(ExceptionTransformer.ErrorParentIdAttribute)); + suppressedExceptionReport.attributes.get(ReportExceptionTransformer.ErrorParentIdAttribute)); assertEquals( outerExceptionReport.uuid.toString(), - outerExceptionReport.attributes.get(ExceptionTransformer.ErrorIdAttribute)); + outerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorIdAttribute)); assertEquals( - suppressedExceptionReport.attributes.get(ExceptionTransformer.ErrorTraceAttribute), - outerExceptionReport.attributes.get(ExceptionTransformer.ErrorTraceAttribute)); + suppressedExceptionReport.attributes.get(ReportExceptionTransformer.ErrorTraceAttribute), + outerExceptionReport.attributes.get(ReportExceptionTransformer.ErrorTraceAttribute)); } @Test @@ -108,10 +108,10 @@ public void DoNotGenerateSuppressedExceptionIfDisabled() { Exception suppressedException = new Exception(suppressedExceptionMessage); Exception exception = new Exception(outerExceptionMessage); exception.addSuppressed(suppressedException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendSuppressedExceptions(false); - List reports = exceptionTransformer.transformExceptionIntoReports(exception, attributes); + reportExceptionTransformer.sendSuppressedExceptions(false); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(exception, attributes)); assertEquals(1, reports.size()); BacktraceReport exceptionReport = reports.get(0); @@ -125,11 +125,11 @@ public void generateReportForInnerSuppressedAndOuterException() { Exception innerException = new Exception(innerExceptionMessage); innerException.addSuppressed(suppressedException); Exception outerException = new Exception(outerExceptionMessage, innerException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendInnerExceptions(true); - exceptionTransformer.sendSuppressedExceptions(true); - List reports = exceptionTransformer.transformExceptionIntoReports(outerException, attributes); + reportExceptionTransformer.sendInnerExceptions(true); + reportExceptionTransformer.sendSuppressedExceptions(true); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(outerException, attributes)); assertEquals(expectedNumberOfReports, reports.size()); BacktraceReport outerExceptionReport = reports.get(0); @@ -147,11 +147,11 @@ public void reportsHasCorrectlySetAttributes() { Exception innerException = new Exception(innerExceptionMessage); innerException.addSuppressed(suppressedException); Exception outerException = new Exception(outerExceptionMessage, innerException); - ExceptionTransformer exceptionTransformer = new ExceptionTransformer(); + ReportExceptionTransformer reportExceptionTransformer = new ReportExceptionTransformer(); - exceptionTransformer.sendInnerExceptions(true); - exceptionTransformer.sendSuppressedExceptions(true); - List reports = exceptionTransformer.transformExceptionIntoReports(outerException, attributes); + reportExceptionTransformer.sendInnerExceptions(true); + reportExceptionTransformer.sendSuppressedExceptions(true); + List reports = reportExceptionTransformer.transformReportWithInnerExceptions(new BacktraceReport(outerException, attributes)); assertEquals(expectedNumberOfReports, reports.size()); BacktraceReport outerExceptionReport = reports.get(0);