Skip to content

Instantly share code, notes, and snippets.

@estebanefi
Created April 22, 2019 22:56
Show Gist options
  • Save estebanefi/6fd2fbc963ce5e4538a57e0fe5a6036e to your computer and use it in GitHub Desktop.
Save estebanefi/6fd2fbc963ce5e4538a57e0fe5a6036e to your computer and use it in GitHub Desktop.
sentry-apex1
/**
* @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