Created
April 22, 2019 22:56
-
-
Save estebanefi/6fd2fbc963ce5e4538a57e0fe5a6036e to your computer and use it in GitHub Desktop.
sentry-apex1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author efigenio.esteban@corp.sysco.com | |
* @date 11/28/2018 | |
* | |
* @description Log class for Sentry | |
*/ | |
public class Sentry { | |
/** | |
* @description Init method for Sentry log | |
* @param log - dsn of form https://{SECRET}.sentry.io/{PROJECT_ID}?option1=value1&option2=value2 | |
* Accepted options (environment) | |
* @example | |
* LogUtility.log(log); | |
*/ | |
public Sentry(String dsn){ | |
dsn = dsn; | |
Url dsnUrl = new Url(dsn); | |
project_id = dsnUrl.getPath().replaceAll('/',''); | |
sentry_key = dsnUrl.getAuthority().replaceAll('@sentry.io',''); | |
PageReference pageReference = new PageReference(dsn); | |
options = pageReference.getParameters(); | |
} | |
public String sentry_key { | |
get { | |
return sentry_key; | |
} | |
set { | |
sentry_key = value; | |
} | |
} | |
public Map<String, String> options { | |
get { | |
return options; | |
} | |
set { | |
options = value; | |
} | |
} | |
public String project_id { | |
get { | |
return project_id; | |
} | |
set { | |
project_id = value; | |
} | |
} | |
/** | |
* captureException logs exception to sentry | |
* @param ex ex Exception object | |
*/ | |
public void captureException(Exception ex) { | |
SentryLog sentryLog = createSentryLog(ex, null); | |
sentryCallout(JSON.serialize(sentryLog,true)); | |
} | |
/** | |
* captureException logs exception to sentry with tags | |
* @param ex ex Exception object | |
* @param tags tags SentryTag - application, sObject | |
*/ | |
public void captureException(Exception ex, SentryTag tags){ | |
SentryLog sentryLog = createSentryLog(ex, tags.typeName); | |
sentryLog.tags = tags; | |
if(!String.isBlank(tags.user_id)){ | |
sentryLog.user = createSentryUser(tags.user_id); | |
} | |
sentryCallout(JSON.serialize(sentryLog,true)); | |
} | |
/** | |
* sentryCallout method to do callout to sentry api | |
* @param jsonBody jsonBody string | |
*/ | |
private void sentryCallout(String jsonBody){ | |
sentryAsyncRequest(jsonBody, project_id, sentry_key); | |
} | |
/** | |
* sentryAsyncRequest async method to make callout to post to sentry | |
* @param jsonBody jsonBody description | |
* @param project_id project_id project id | |
* @param sentry_key sentry_key sentry key | |
*/ | |
@future(callout=true) | |
private static void sentryAsyncRequest(String jsonBody, String project_id, String sentry_key){ | |
// rename exceptionSentry ro reserved word 'exception' required by Sentry API... | |
jsonBody = jsonBody.replaceAll('"exceptionSentry":','"exception":'); | |
HttpRequest req = new HttpRequest(); | |
req.setEndpoint('callout:Sentry/'+ project_id +'/store/?sentry_key='+sentry_key + '&sentry_version=7'); | |
req.setMethod('POST'); | |
req.setBody(jsonBody); | |
// Create a new http object to send the request object | |
// A response object is generated as a result of the request | |
System.debug(jsonBody); | |
Http http = new Http(); | |
HTTPResponse res = http.send(req); | |
System.debug('Sentry request:' + res.getBody()); | |
} | |
/** | |
* @description Maps the Log object to the Sentry Log object | |
* @param log - Log object | |
* @example | |
* LogUtility.createSentryLog(log); | |
*/ | |
private SentryLog createSentryLog(Exception ex, String typeName){ | |
SentryLog sentryLog = new SentryLog(); | |
if(options.containsKey('environment')){ | |
sentryLog.environment = options.get('environment'); | |
} | |
sentryLog.user.id = UserInfo.getUserId(); | |
sentryLog.user.email = UserInfo.getUserEmail(); | |
// create exception value | |
SentryExceptionValue exValue = new SentryExceptionValue(); | |
exValue.type = 'Error'; | |
if(typeName != null){ | |
exValue.value = typeName + ': ' + ex.getMessage(); | |
}else { | |
exValue.value = ex.getTypeName() + ': ' + ex.getMessage(); | |
} | |
if(ex.getMessage().contains('Error Fields:')){ | |
exValue.type = 'Error'; | |
exValue.value = ex.getMessage(); | |
exValue.stacktrace = new SentryExceptionStackTrace(); | |
SentryExceptionStackFrame frame = new SentryExceptionStackFrame(); | |
exValue.stacktrace.frames.add(frame); | |
}else{ | |
exValue.stacktrace = getStackTrace(ex); | |
} | |
sentryLog.exceptionSentry.values.add(exValue); | |
return sentryLog; | |
} | |
private SentryUser createSentryUser(String id){ | |
User user = [SELECT ID, EMAIL FROM USER WHERE ID = :id LIMIT 1]; | |
SentryUser sentryUser = new SentryUser(); | |
sentryUser.email = user.email; | |
sentryUser.id = user.id; | |
return sentryUser; | |
} | |
private SentryExceptionStackTrace getStackTrace(Exception ex){ | |
SentryExceptionStackTrace stacktrace = new SentryExceptionStackTrace(); | |
List<String> exceptionList = splitString(ex.getStackTraceString(), '(([^,])+,([column \\d])+)'); | |
for(String exc: exceptionList) { | |
SentryExceptionStackFrame frame = new SentryExceptionStackFrame(); | |
List<String> exceptionBreakdown = splitString(exc, '([^:)+,(^,])+'); | |
for(String exb: exceptionBreakdown) { | |
exb = exb.trim(); | |
if(exb.contains('Class')) { | |
List<String> fileBreakdown = exb.split('\\.'); | |
frame.filename = fileBreakdown[1]; | |
frame.function = fileBreakdown[2]; | |
} else if(exb.contains('line')) { | |
String line = exb.remove('line '); | |
frame.lineno = line; | |
} else if(exb.contains('column')) { | |
String column = exb.remove('column '); | |
frame.colno = column; | |
} else if(exb.contains('Trigger')){ | |
List<String> fileBreakdown = exb.split('\\.'); | |
frame.filename = fileBreakdown[0]; | |
frame.function = fileBreakdown[1]; | |
} | |
} | |
stacktrace.frames.add(frame); | |
} | |
return stacktrace; | |
} | |
/** | |
* splitString helper method to split a string based on a regex when String.split(regex) does nothing | |
* @param message message description | |
* @param regex regex description | |
* @return return return is a List<String> | |
*/ | |
public static List<String> splitString(String message, String regex){ | |
List<String> regexedString = new List<String>(); | |
Pattern pattern = Pattern.compile(regex); | |
Matcher match = pattern.matcher(message); | |
while (match.find() == true) { | |
regexedString.add(match.group()); | |
} | |
return regexedString; | |
} | |
public class SentryEx { | |
public List<SentryExceptionValue> values; | |
public SentryEx(){ | |
values = new List<SentryExceptionValue>(); | |
} | |
} | |
public class SentryExceptionValue { | |
public SentryExceptionStackTrace stacktrace; | |
public String type; | |
public String value; | |
public SentryExceptionValue(){ | |
stacktrace = new SentryExceptionStackTrace(); | |
} | |
} | |
public class SentryExceptionStackTrace { | |
public List<SentryExceptionStackFrame> frames; | |
public SentryExceptionStackTrace() { | |
frames = new List<SentryExceptionStackFrame>(); | |
} | |
} | |
public class SentryExceptionStackFrame { | |
public String filename; | |
public String function; | |
public String lineno; | |
public String colno; | |
public Boolean in_app; | |
public SentryExceptionStackFrame(){ | |
in_app = true; | |
} | |
} | |
public class SentryTag { | |
public String application; | |
public String obj; | |
public String obj_id; | |
public transient String user_id; | |
public transient String typeName; | |
} | |
public class SentryUser { | |
public String id; | |
public String email; | |
public SentryUser(){} | |
} | |
public class SentryRequest { | |
public String url; | |
public String method; | |
public SentryRequest(){} | |
} | |
public class SentryLog { | |
public SentryEx exceptionSentry; | |
public String platform; | |
public String environment; | |
public SentryUser user; | |
public SentryRequest request; | |
public SentryTag tags; | |
public SentryLog() { | |
user = new SentryUser(); | |
exceptionSentry = new SentryEx(); | |
request = new SentryRequest(); | |
platform = 'Apex'; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment