From 91beb7a46863bf90ab69d4afc063685644ea9717 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 21 May 2019 00:49:10 +0200 Subject: [PATCH] feat(exception email): add raw email body when reporting parsin failure Closes #2 --- .../main/default/classes/DataBuilder.cls | 57 ++++++++++++------- force-app/main/default/classes/Notifier.cls | 6 ++ force-app/main/default/classes/Rollbar.cls | 5 ++ .../classes/RollbarExceptionEmailHandler.cls | 7 ++- .../main/default/tests/DataBuilderTest.cls | 16 ++++++ 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/force-app/main/default/classes/DataBuilder.cls b/force-app/main/default/classes/DataBuilder.cls index 3029146..a8376b3 100644 --- a/force-app/main/default/classes/DataBuilder.cls +++ b/force-app/main/default/classes/DataBuilder.cls @@ -5,37 +5,37 @@ public with sharing class DataBuilder { public Map buildPayload(String level, String message) { - return buildPayloadStructure(level, this.buildMessageBody(message)); + return buildPayloadStructure(level, buildMessageBody(message), null); } public Map buildPayload(Exception exc) { - if (exc.getCause() != null) { - return buildTraceChainPayload(exc); - } else { - return buildExceptionPayload(exc); - } + return buildPayloadStructure('error', buildExceptionBody(exc), null); } - public Map buildPayload(ExceptionData exData) + public Map buildPayload(Exception exc, Map custom) { - Map payload = buildPayloadStructure('error', this.buildTraceBody(exData)); + return buildPayloadStructure('error', buildExceptionBody(exc), custom); + } + public Map buildPayload(ExceptionData exData) + { Map custom = new Map(); custom.put('context', exData.context()); - Map data = (Map)payload.get('data'); - data.put('custom', custom); - - return payload; + return buildPayloadStructure('error', buildTraceBody(exData), custom); } - private Map buildExceptionPayload(Exception exc) + private Map buildExceptionBody(Exception exc) { - return buildPayloadStructure('error', this.buildTraceBody(exc)); + if (exc.getCause() == null) { + return buildTraceBody(exc); + } else { + return buildTraceChainBody(exc); + } } - private Map buildTraceChainPayload(Exception exc) + private Map buildTraceChainBody(Exception exc) { Map outterExTrace = (Map)this.buildTraceBody(exc).get('trace'); Map innerExTrace = (Map)this.buildTraceBody(exc.getCause()).get('trace'); @@ -48,12 +48,20 @@ public with sharing class DataBuilder { Map body = new Map(); body.put('trace_chain', traceChainList); - return buildPayloadStructure('error', body); + return body; } - private Map buildPayloadStructure(String level, Map body) - { - Map data = this.buildDataStructure(level, this.config.environment(), body); + private Map buildPayloadStructure( + String level, + Map body, + Map custom + ) { + Map data = this.buildDataStructure( + level, + this.config.environment(), + body, + custom + ); Map structure = new Map(); structure.put('access_token', this.config.accessToken()); @@ -61,8 +69,13 @@ public with sharing class DataBuilder { return structure; } - private Map buildDataStructure(String level, String environment, Map body) - { + private Map buildDataStructure( + String level, + String environment, + Map body, + Map custom + ) { + Map notifierMap = new Map(); notifierMap.put('name', Notifier.NAME); notifierMap.put('version', Notifier.VERSION); @@ -73,6 +86,8 @@ public with sharing class DataBuilder { structure.put('environment', environment); structure.put('framework', 'apex'); structure.put('body', body); + structure.put('custom', custom); + return structure; } diff --git a/force-app/main/default/classes/Notifier.cls b/force-app/main/default/classes/Notifier.cls index 4363474..68f3db2 100644 --- a/force-app/main/default/classes/Notifier.cls +++ b/force-app/main/default/classes/Notifier.cls @@ -21,6 +21,12 @@ public with sharing class Notifier return reportPayload(payload); } + public HttpResponse log(Exception exc, Map custom) + { + String payload = JSON.serialize(this.dataBuilder.buildPayload(exc, custom)); + return reportPayload(payload); + } + public HttpResponse log(ExceptionData exData) { String payload = JSON.serialize(this.dataBuilder.buildPayload(exData)); diff --git a/force-app/main/default/classes/Rollbar.cls b/force-app/main/default/classes/Rollbar.cls index 577589c..2c0a8a4 100644 --- a/force-app/main/default/classes/Rollbar.cls +++ b/force-app/main/default/classes/Rollbar.cls @@ -36,6 +36,11 @@ public with sharing class Rollbar { return instance.notifier.log(exc); } + public static HttpResponse log(Exception exc, Map custom) { + Rollbar instance = initializedInstance(); + return instance.notifier.log(exc, custom); + } + public static HttpResponse log(ExceptionData exData) { Rollbar instance = initializedInstance(); return instance.notifier.log(exData); diff --git a/force-app/main/default/classes/RollbarExceptionEmailHandler.cls b/force-app/main/default/classes/RollbarExceptionEmailHandler.cls index 15ea001..34f3980 100644 --- a/force-app/main/default/classes/RollbarExceptionEmailHandler.cls +++ b/force-app/main/default/classes/RollbarExceptionEmailHandler.cls @@ -23,9 +23,12 @@ global class RollbarExceptionEmailHandler implements Messaging.InboundEmailHandl throw new ExceptionEmailParsingException('Unable to process unhandled email', exc); } } catch(ExceptionEmailParsingException wrapper) { - // TODO: add full email body in case we can't process exception email wrapper.getStackTraceString(); // without those calls strack trace string is not populated - Rollbar.log(wrapper); + + Map custom = new Map(); + custom.put('email_body', emailBody); + + Rollbar.log(wrapper, custom); } // Set the result to true. No need to send an email back to the user diff --git a/force-app/main/default/tests/DataBuilderTest.cls b/force-app/main/default/tests/DataBuilderTest.cls index 7cc59fc..8670e7d 100644 --- a/force-app/main/default/tests/DataBuilderTest.cls +++ b/force-app/main/default/tests/DataBuilderTest.cls @@ -55,6 +55,22 @@ public class DataBuilderTest } } + @isTest + static void testBuildExceptionPayloadWithCustom() + { + DataBuilder subject = new DataBuilder(new Config('foo', 'bar')); + Map expectedCustom = new Map(); + expectedCustom.put('foo', 'bar'); + + DataBuilderTestException exc = new DataBuilderTestException('foobar'); + + Map result = subject.buildPayload(exc, expectedCustom); + Map data = (Map)result.get('data'); + Map custom = (Map)data.get('custom'); + + System.assertEquals(expectedCustom.get('foo'), (String)custom.get('foo')); + } + @isTest static void testBuildTraceChainPayload() {