Last active
July 25, 2024 21:55
-
-
Save jongpie/2e84dc855f128769ab826d3ea33734c6 to your computer and use it in GitHub Desktop.
Nebula Logger - managed package REST resource prototype
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
@RestResource(urlMapping='/logger/*') | |
global class LoggerRestResource { | |
public class LogRequest { | |
public String parentLogTransactionId; | |
public List<LogEntryRequest> logEntries = new List<LogEntryRequest>(); | |
} | |
public class LogEntryRequest { | |
public String loggingLevel; | |
public String message; | |
public String relatedRecordId; | |
public Datetime timestamp; | |
public List<String> tags = new List<String>(); | |
} | |
public class LogResponse { | |
public String transactionId; | |
} | |
@HttpPost | |
global static void handlePost() { | |
LogResponse logResponse = new LogRequestSaver(System.RestContext.request).saveLogRequest(); | |
System.RestContext.response = new System.RestResponse(); | |
System.RestContext.response.responseBody = System.Blob.valueOf(System.JSON.serialize(logResponse)); | |
} | |
private class LogRequestSaver { | |
private final LogRequest logRequest; | |
public LogRequestSaver(System.RestRequest restRequest) { | |
this.logRequest = this.deserializeLogRequest(restRequest); | |
} | |
public LogRequest getLogRequest() { | |
return this.logRequest; | |
} | |
public LogResponse saveLogRequest() { | |
Nebula.Logger.setParentLogTransactionId(this.getLogRequest().parentLogTransactionId); | |
for (LogEntryRequest logEntryRequest : this.getLogRequest().logEntries) { | |
System.LoggingLevel loggingLevel = Nebula.Logger.getLoggingLevel(logEntryRequest.loggingLevel); | |
Nebula.Logger.newEntry(loggingLevel, logEntryRequest.message).setRecord(logEntryRequest.relatedRecordId).addTags(logEntryRequest.tags); | |
// FIXME The managed package currently doesn't have the .setTimestamp() builder method, | |
// so there's not a great way to correctly set the Timestamp__c field yet | |
} | |
Nebula.Logger.saveLog(); | |
LogResponse logResponse = new LogResponse(); | |
logResponse.transactionId = Nebula.Logger.getTransactionId(); | |
return logResponse; | |
} | |
private LogRequest deserializeLogRequest(System.RestRequest restRequest) { | |
if (String.isBlank(restRequest?.requestBody?.toString())) { | |
throw new System.IllegalArgumentException('No data provided'); | |
} | |
LogRequest logRequest = (LogRequest) System.JSON.deserialize(restRequest.requestBody.toString(), LogRequest.class); | |
if (logRequest.logEntries == null || logRequest.logEntries.isEmpty()) { | |
throw new System.IllegalArgumentException('No log entries provided'); | |
} | |
return logRequest; | |
} | |
} | |
} |
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
@IsTest | |
private class LoggerRestResource_Tests { | |
private static final String REQUEST_URI = '/services/apexrest/logger'; | |
@IsTest | |
static void it_throws_an_exception_when_no_json_data_is_posted() { | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = null; | |
System.Exception thrownException = null; | |
try { | |
LoggerRestResource.handlePost(); | |
System.Assert.fail('Exception expected on previous line'); | |
} catch (System.IllegalArgumentException ex) { | |
thrownException = ex; | |
} | |
System.Assert.isNotNull(thrownException); | |
System.Assert.isInstanceOfType(thrownException, System.IllegalArgumentException.class); | |
System.Assert.areEqual('No data provided', thrownException.getMessage()); | |
} | |
@IsTest | |
static void it_throws_an_exception_when_log_entries_list_is_null() { | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
logRequest.logEntries = null; | |
System.Assert.isNull(logRequest.logEntries); | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
System.Exception thrownException = null; | |
try { | |
LoggerRestResource.handlePost(); | |
System.Assert.fail('Exception expected on previous line'); | |
} catch (System.IllegalArgumentException ex) { | |
thrownException = ex; | |
} | |
System.Assert.isNotNull(thrownException); | |
System.Assert.isInstanceOfType(thrownException, System.IllegalArgumentException.class); | |
System.Assert.areEqual('No log entries provided', thrownException.getMessage()); | |
} | |
@IsTest | |
static void it_throws_an_exception_when_log_entries_list_is_empty() { | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
System.Assert.isTrue(logRequest.logEntries.isEmpty()); | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
System.Exception thrownException = null; | |
try { | |
LoggerRestResource.handlePost(); | |
System.Assert.fail('Exception expected on previous line'); | |
} catch (System.IllegalArgumentException ex) { | |
thrownException = ex; | |
} | |
System.Assert.isNotNull(thrownException); | |
System.Assert.isInstanceOfType(thrownException, System.IllegalArgumentException.class); | |
System.Assert.areEqual('No log entries provided', thrownException.getMessage()); | |
} | |
@IsTest | |
static void it_should_successsfully_save_log_request_with_log_entries() { | |
LoggerRestResource.LogEntryRequest firstLogEntryRequest = new LoggerRestResource.LogEntryRequest(); | |
firstLogEntryRequest.loggingLevel = System.LoggingLevel.INFO.name(); | |
firstLogEntryRequest.message = 'some message for INFO'; | |
firstLogEntryRequest.timestamp = System.now().addDays(-1); | |
LoggerRestResource.LogEntryRequest secondLogEntryRequest = new LoggerRestResource.LogEntryRequest(); | |
secondLogEntryRequest.loggingLevel = System.LoggingLevel.WARN.name(); | |
secondLogEntryRequest.message = 'some message for WARN'; | |
secondLogEntryRequest.timestamp = System.now().addDays(-1); | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
logRequest.logEntries.add(firstLogEntryRequest); | |
logRequest.logEntries.add(secondLogEntryRequest); | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
LoggerRestResource.handlePost(); | |
System.Test.getEventBus().deliver(); | |
LoggerRestResource.LogResponse logResponse = (LoggerRestResource.LogResponse) System.JSON.deserialize( | |
System.RestContext.response.responseBody.toString(), | |
LoggerRestResource.LogResponse.class | |
); | |
System.Assert.areEqual(Nebula.Logger.getTransactionId(), logResponse.transactionId); | |
Nebula__Log__c log = [SELECT Id, Nebula__TransactionId__c FROM Nebula__Log__c]; | |
System.Assert.areEqual(Nebula.Logger.getTransactionId(), log.Nebula__TransactionId__c); | |
Nebula__LogEntry__c firstLogEntry = [ | |
SELECT Id, Nebula__LoggingLevel__c, Nebula__Message__c, Nebula__Timestamp__c, Nebula__TransactionEntryNumber__c | |
FROM Nebula__LogEntry__c | |
WHERE Nebula__Log__c = :log.Id AND Nebula__LoggingLevel__c = :firstLogEntryRequest.loggingLevel | |
]; | |
System.Assert.areEqual(firstLogEntryRequest.loggingLevel, firstLogEntry.Nebula__LoggingLevel__c); | |
System.Assert.areEqual(firstLogEntryRequest.message, firstLogEntry.Nebula__Message__c); | |
// System.Assert.areEqual(firstLogEntryRequest.timestamp, firstLogEntry.Nebula__Timestamp__c); | |
System.Assert.areEqual(1, firstLogEntry.Nebula__TransactionEntryNumber__c); | |
Nebula__LogEntry__c secondLogEntry = [ | |
SELECT Id, Nebula__LoggingLevel__c, Nebula__Message__c, Nebula__Timestamp__c, Nebula__TransactionEntryNumber__c | |
FROM Nebula__LogEntry__c | |
WHERE Nebula__Log__c = :log.Id AND Nebula__LoggingLevel__c = :secondLogEntryRequest.loggingLevel | |
]; | |
System.Assert.areEqual(secondLogEntryRequest.loggingLevel, secondLogEntry.Nebula__LoggingLevel__c); | |
System.Assert.areEqual(secondLogEntryRequest.message, secondLogEntry.Nebula__Message__c); | |
// System.Assert.areEqual(secondLogEntryRequest.timestamp, secondLogEntry.Nebula__Timestamp__c); | |
System.Assert.areEqual(2, secondLogEntry.Nebula__TransactionEntryNumber__c); | |
} | |
@IsTest | |
static void it_sets_parent_transaction_id_when_provided() { | |
Nebula__Log__c parentLog = new Nebula__Log__c(Nebula__TransactionId__c = 'some fake parent transaction id'); | |
insert parentLog; | |
LoggerRestResource.LogEntryRequest logEntryRequest = new LoggerRestResource.LogEntryRequest(); | |
logEntryRequest.loggingLevel = System.LoggingLevel.INFO.name(); | |
logEntryRequest.message = 'some message'; | |
logEntryRequest.timestamp = System.now().addDays(-1); | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
logRequest.logEntries.add(logEntryRequest); | |
logRequest.parentLogTransactionId = parentLog.Nebula__TransactionId__c; | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
LoggerRestResource.handlePost(); | |
System.Test.getEventBus().deliver(); | |
LoggerRestResource.LogResponse logResponse = (LoggerRestResource.LogResponse) System.JSON.deserialize( | |
System.RestContext.response.responseBody.toString(), | |
LoggerRestResource.LogResponse.class | |
); | |
System.Assert.areEqual(Nebula.Logger.getTransactionId(), logResponse.transactionId); | |
Nebula__Log__c log = [SELECT Id, Nebula__ParentLog__c, Nebula__TransactionId__c FROM Nebula__Log__c WHERE Id != :parentLog.Id]; | |
System.Assert.areEqual(parentLog.Id, log.Nebula__ParentLog__c); | |
System.Assert.areEqual(Nebula.Logger.getTransactionId(), log.Nebula__TransactionId__c); | |
} | |
@IsTest | |
static void it_sets_related_record_id_when_provided() { | |
String recordId = System.UserInfo.getUserId(); | |
LoggerRestResource.LogEntryRequest logEntryRequest = new LoggerRestResource.LogEntryRequest(); | |
logEntryRequest.loggingLevel = System.LoggingLevel.INFO.name(); | |
logEntryRequest.message = 'some message'; | |
logEntryRequest.relatedRecordId = recordId; | |
logEntryRequest.timestamp = System.now().addDays(-1); | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
logRequest.logEntries.add(logEntryRequest); | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
LoggerRestResource.handlePost(); | |
System.Test.getEventBus().deliver(); | |
LoggerRestResource.LogResponse logResponse = (LoggerRestResource.LogResponse) System.JSON.deserialize( | |
System.RestContext.response.responseBody.toString(), | |
LoggerRestResource.LogResponse.class | |
); | |
System.Assert.areEqual(Nebula.Logger.getTransactionId(), logResponse.transactionId); | |
Nebula__LogEntry__c logEntry = [ | |
SELECT Id, Nebula__RecordId__c | |
FROM Nebula__LogEntry__c | |
WHERE Nebula__Log__r.Nebula__TransactionId__c = :logResponse.transactionId | |
]; | |
System.Assert.areEqual(logEntryRequest.relatedRecordId, logEntry.Nebula__RecordId__c); | |
} | |
@IsTest | |
static void it_stores_tags_when_provided() { | |
LoggerRestResource.LogEntryRequest logEntryRequest = new LoggerRestResource.LogEntryRequest(); | |
logEntryRequest.loggingLevel = System.LoggingLevel.INFO.name(); | |
logEntryRequest.message = 'some message'; | |
logEntryRequest.timestamp = System.now().addDays(-1); | |
logEntryRequest.tags = new List<String>{'some tag', 'another tag'}; | |
LoggerRestResource.LogRequest logRequest = new LoggerRestResource.LogRequest(); | |
logRequest.logEntries.add(logEntryRequest); | |
System.RestContext.request = new System.RestRequest(); | |
System.RestContext.request.requestURI = REQUEST_URI; | |
System.RestContext.request.requestBody = System.Blob.valueOf(System.JSON.serialize(logRequest)); | |
LoggerRestResource.handlePost(); | |
System.Test.getEventBus().deliver(); | |
LoggerRestResource.LogResponse logResponse = (LoggerRestResource.LogResponse) System.JSON.deserialize( | |
System.RestContext.response.responseBody.toString(), | |
LoggerRestResource.LogResponse.class | |
); | |
Nebula__LogEntry__c logEntry = [ | |
SELECT Id, (SELECT Id, Nebula__Tag__r.Name FROM Nebula__LogEntryTags__r) | |
FROM Nebula__LogEntry__c | |
]; | |
System.Assert.areEqual(logEntryRequest.tags.size(), logEntry.Nebula__LogEntryTags__r.size()); | |
Set<String> providedTags = new Set<String>(logEntryRequest.tags); | |
for (Nebula__LogEntryTag__c logEntryTag : logEntry.Nebula__LogEntryTags__r) { | |
System.Assert.isTrue(providedTags.contains(logEntryTag.Nebula__Tag__r.Name)); | |
} | |
} | |
} |
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
{ | |
"parentLogTransactionId": "null-or-a-uuid-returned-from-nebula-logger", | |
"logEntries": [ | |
{ | |
"loggingLevel": "ERROR", | |
"message": "some log entry message" | |
}, | |
{ | |
"loggingLevel": "INFO", | |
"message": "another log entry message", | |
"relatedRecordId": "0058G0000072V5BQAU", | |
}, | |
{ | |
"loggingLevel": "FINEST", | |
"message": "yet another log entry message", | |
"tags": ["some tag", "another tag"] | |
} | |
] | |
} |
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
{ | |
"transactionId": "uuid-returned-from-nebula-logger" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment