Skip to content

Commit

Permalink
feat(exception email): nest exception email parsing exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
ArturMoczulski committed May 20, 2019
1 parent f7d3501 commit f6b4172
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 5 deletions.
29 changes: 28 additions & 1 deletion force-app/main/default/classes/DataBuilder.cls
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ public with sharing class DataBuilder {

public Map<String, Object> buildPayload(Exception exc)
{
return buildPayloadStructure('error', this.buildTraceBody(exc));
if (exc.getCause() != null) {
return buildTraceChainPayload(exc);
} else {
return buildExceptionPayload(exc);
}
}

public Map<String, Object> buildPayload(ExceptionData exData)
Expand All @@ -26,6 +30,27 @@ public with sharing class DataBuilder {
return payload;
}

private Map<String, Object> buildExceptionPayload(Exception exc)
{
return buildPayloadStructure('error', this.buildTraceBody(exc));
}

private Map<String, Object> buildTraceChainPayload(Exception exc)
{
Map<String, Object> outterExTrace = (Map<String, Object>)this.buildTraceBody(exc).get('trace');
Map<String, Object> innerExTrace = (Map<String, Object>)this.buildTraceBody(exc.getCause()).get('trace');

List<Map<String, Object>> traceChainList = new List<Map<String, Object>>();
traceChainList.add(outterExTrace);
traceChainList.add(innerExTrace);


Map<String, Object> body = new Map<String, Object>();
body.put('trace_chain', traceChainList);

return buildPayloadStructure('error', body);
}

private Map<String, Object> buildPayloadStructure(String level, Map<String, Object> body)
{
Map<String, Object> data = this.buildDataStructure(level, this.config.environment(), body);
Expand Down Expand Up @@ -90,6 +115,8 @@ public with sharing class DataBuilder {
for (String frameStr : frames) {
if (frameStr == '()') {
continue;
} else if (frameStr.toLowerCase() == 'caused by') {
break;
}

Map<String, Object> frameMap = new Map<String, Object>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public class ExceptionEmailParsingException extends Exception {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="urn:metadata.tooling.soap.sforce.com" fqn="ExceptionEmailParsingException">
<apiVersion>45.0</apiVersion>
<status>Active</status>
</ApexClass>
14 changes: 10 additions & 4 deletions force-app/main/default/classes/RollbarExceptionEmailHandler.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ global class RollbarExceptionEmailHandler implements Messaging.InboundEmailHandl
Rollbar.init('access-token', UserInfo.getOrganizationId());

try {
ExceptionData exData = ExceptionEmailParser.parse(emailBody);
Rollbar.log(exData);
} catch(Exception exc) {
try {
ExceptionData exData = ExceptionEmailParser.parse(emailBody);
Rollbar.log(exData);
} catch(Exception exc) {
exc.getStackTraceString(); // without those calls strack trace string is not populated
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
Rollbar.log(exc);
wrapper.getStackTraceString(); // without those calls strack trace string is not populated
Rollbar.log(wrapper);
}

// Set the result to true. No need to send an email back to the user
Expand Down
43 changes: 43 additions & 0 deletions force-app/main/default/tests/DataBuilderTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,49 @@ public class DataBuilderTest
}
}

@isTest
static void testBuildTraceChainPayload()
{
DataBuilder subject = new DataBuilder(new Config('foo', 'bar'));
String expectedMessage1 = 'Exception message in test 001';
String expectedClass1;
String expectedMessage2 = 'Exception message in test 002';
String expectedClass2;

try {
try {
DataBuilderTestException exc2 = new DataBuilderTestException(expectedMessage2);
expectedClass2 = exc2.getTypeName();
throw exc2;
} catch(Exception exc2) {
throw new ExceptionEmailParsingException(expectedMessage1, exc2);
}
} catch(Exception exc1) {
expectedClass1 = exc1.getTypeName();

Map<String, Object> result = subject.buildPayload(exc1);

Map<String, Object> data = (Map<String, Object>)result.get('data');

Map<String, Object> notifierMap = (Map<String, Object>)data.get('notifier');
System.assertEquals(Notifier.NAME, (String)notifierMap.get('name'));
System.assertEquals(Notifier.VERSION, (String)notifierMap.get('version'));

Map<String, Object> body = (Map<String, Object>)data.get('body');
List<Map<String, Object>> traceChain = (List<Map<String, Object>>)body.get('trace_chain');
Map<String, Object> trace1 = (Map<String, Object>)traceChain[0];
Map<String, Object> trace2 = (Map<String, Object>)traceChain[1];
Map<String, Object> exc1Map = (Map<String, Object>)trace1.get('exception');
Map<String, Object> exc2Map = (Map<String, Object>)trace2.get('exception');

System.assertEquals(expectedMessage1, exc1Map.get('message'));
System.assertEquals(expectedClass1, exc1Map.get('class'));

System.assertEquals(expectedMessage2, exc2Map.get('message'));
System.assertEquals(expectedClass2, exc2Map.get('class'));
}
}

@isTest
static void testBuildExceptionDataPayload()
{
Expand Down
1 change: 1 addition & 0 deletions manifest/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<members>DataBuilder</members>
<members>ExceptionData</members>
<members>ExceptionEmailParser</members>
<members>ExceptionEmailParsingException</members>
<members>Notifier</members>
<members>Rollbar</members>
<members>RollbarExceptionEmailHandler</members>
Expand Down

0 comments on commit f6b4172

Please sign in to comment.