Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c6839bd
feat: Add App_Logs_Home dashboard page for unified logging view
Dec 3, 2024
f4d9996
feat: Add @AuraEnabled to logging methods for LWC support
Dec 3, 2024
786971d
Delete force-app/main/default/flexipages/App_Logs_Home.flexipage-meta…
RyanSchierholz Dec 19, 2024
d43a899
Merge pull request #1 from RyanSchierholz/fix/aura-enabled-methods
RyanSchierholz Dec 23, 2024
fab7b37
Feature/app log writer clean (#3)
RyanSchierholz Dec 23, 2024
9efd726
Feature/log reader toolbar improvements (#4)
RyanSchierholz Dec 23, 2024
79244e3
feat: add refresh button and filter; improved table, delete option (#5)
RyanSchierholz Dec 23, 2024
6487e88
feat:Add Config Properties to XML; Update the info line and use Toast…
RyanSchierholz Dec 24, 2024
969befe
feat: Add LogEntryItem LWC and update LogReader" (#7)
RyanSchierholz Dec 26, 2024
1515ca2
docs: add author credits (#8)
RyanSchierholz Dec 26, 2024
11e59ae
Feat/add credits (#9)
RyanSchierholz Dec 26, 2024
ca44ba6
fix: Add test setup for Logger_Test (#10)
RyanSchierholz Dec 26, 2024
55cc615
fix: update test for correct assertions (#11)
RyanSchierholz Dec 26, 2024
32393d8
test: Add comprehensive tests for LogUiController with 95% coverage (…
RyanSchierholz Dec 26, 2024
6ea6c6c
feat:Dedicated Home page for the app (#13)
RyanSchierholz Dec 26, 2024
479b9e5
Delete force-app/main/default/objects/Account/validationRules directory
RyanSchierholz Dec 26, 2024
d59b129
feat: Improved UI on refresh, icons, and alignment (#14)
RyanSchierholz Dec 27, 2024
6ba91e2
Ignore local package.xml
RyanSchierholz Dec 27, 2024
2759000
Revert "feat: Improved UI on refresh, icons, and alignment"
RyanSchierholz Dec 27, 2024
3ab2c54
feat/read-improvements
RyanSchierholz Dec 27, 2024
1de4321
feat:Add Home page to app (#15)
RyanSchierholz Dec 27, 2024
e3fb33c
feat:Improved icons, refreshing, and alignment (#16)
RyanSchierholz Dec 27, 2024
9a49795
Add Chart and more (#17)
RyanSchierholz Dec 29, 2024
99d00ef
Card icon, Error logging added, enabled for utility bar (#18)
RyanSchierholz Dec 29, 2024
57e657a
Card icon, Error logging added, enabled for utility bar (#19)
RyanSchierholz Dec 29, 2024
f53b413
feat/log-storage: Update logChart and related files (#20)
RyanSchierholz Dec 29, 2024
4f744a3
Enhanced chart visualization: added empty dates, fixed line charts, i…
RyanSchierholz Dec 30, 2024
2e35ffc
Fix/package requirements (#22)
RyanSchierholz Dec 31, 2024
88205df
Fix/package requirements (#23)
RyanSchierholz Dec 31, 2024
6b1570c
Enhancements for Log Writer (#24)
RyanSchierholz Jan 2, 2025
c4dc4cc
Include custom resizer to workaround the LockerService (#25)
RyanSchierholz Jan 2, 2025
3b29f60
Update README.md
RyanSchierholz Jan 3, 2025
17c444d
Create post-install.txt (#26)
RyanSchierholz Jan 3, 2025
40cf4d4
use dedicated static resource to avoid conflicts (#27)
RyanSchierholz Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ IlluminatedCloud
**/profileSessionSettings/**.*

force-app/main/default/settings/
force-app/main/default/profiles/
force-app/main/default/profiles/.localdevserver/
.localdevserver/
force-app/main/default/lwc/jsconfig.json
force-app/main/default/package.xml
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ to log INFO,DEBUG,WARN,ERROR. It might be desirable to reduce this for productio

[![Deploy](https://raw.githubusercontent.com/afawcett/githubsfdeploy/master/src/main/webapp/resources/img/deploy.png)](https://githubsfdeploy.herokuapp.com/app/githubdeploy/mlockett/ApexLogger)

After deploying:
### After deploying:

* Ensure users that should be able to read the logs are assigned the AppLogReader permission set.
* Add an assignment on the _App Logs_ application to the profiles of users that should read logs.
Expand Down
9 changes: 9 additions & 0 deletions force-app/main/default/applications/App_Logs.app-meta.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
<actionOverrides>
<actionName>Tab</actionName>
<content>App_Log_Home</content>
<formFactor>Large</formFactor>
<skipRecordTypeSelect>false</skipRecordTypeSelect>
<type>Flexipage</type>
<pageOrSobjectType>standard-home</pageOrSobjectType>
</actionOverrides>
<brand>
<headerColor>#0070D2</headerColor>
<shouldOverrideOrgTheme>false</shouldOverrideOrgTheme>
Expand All @@ -12,6 +20,7 @@
<isNavTabPersistenceDisabled>false</isNavTabPersistenceDisabled>
<label>App Logs</label>
<navType>Standard</navType>
<tabs>standard-home</tabs>
<tabs>Log_List</tabs>
<tabs>Log_Reader</tabs>
<tabs>Log_Tester</tabs>
Expand Down
5 changes: 4 additions & 1 deletion force-app/main/default/classes/LogService.cls
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ global without sharing class LogService {
* @param message message to be logged
* @param className <class>.<method> if applicable
*/
@AuraEnabled(cacheable=false)
global static void debug(String message, String className) {
logger.debug(message, className);
}
Expand All @@ -30,6 +31,7 @@ global without sharing class LogService {
* @param message message to be logged
* @param className <class>.<method> if applicable
*/
@AuraEnabled(cacheable=false)
global static void info(String message, String className) {
logger.info(message, className);
}
Expand All @@ -40,6 +42,7 @@ global without sharing class LogService {
* @param message message to be logged
* @param className <class>.<method> if applicable
*/
@AuraEnabled(cacheable=false)
global static void warn(String message, String className) {
logger.warn(message, className);
}
Expand Down Expand Up @@ -124,4 +127,4 @@ global without sharing class LogService {
@InvocableVariable(Label='Object Id' Description='Id of object error occurred on')
global String affectedId;
}
}
}
165 changes: 147 additions & 18 deletions force-app/main/default/classes/LogUiController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,14 @@ public without sharing class LogUiController {
String query = 'SELECT AffectedId__c, Class__c, CreatedDate, '
+ 'Id, LogLevel__c, Message__c, Name, ShortMessage__c '
+ 'FROM AppLog__c '
+ 'WHERE LogLevel__c IN :params.logLevels '
+ ' ORDER BY CreatedDate DESC '
+ ' LIMIT = ' + params.logsPerPage;
List<AppLog__c> retVal = [
SELECT AffectedId__c,
Class__c,
CreatedDate,
Id,
LogLevel__c,
Message__c,
Name,
ShortMessage__c
FROM AppLog__c
WHERE LogLevel__c IN :params.logLevels
ORDER BY CreatedDate DESC
LIMIT :params.logsPerPage
];
return retVal;
+ 'WHERE LogLevel__c IN (\'' + String.join(params.logLevels, '\',\'') + '\')';
if (params.newLogsOnly == true && params.tailTimestamp != null) {
query += ' AND CreatedDate > ' + params.tailTimestamp;
}

query += ' ORDER BY CreatedDate DESC LIMIT ' + params.logsPerPage;

return Database.query(query);
}

@AuraEnabled
Expand All @@ -42,11 +32,150 @@ public without sharing class LogUiController {
return results;
}

@AuraEnabled
public static void insertLog(String level,String message,String cls){

AppLog__c log = new AppLog__c();
log.LogLevel__c = level;
log.Message__c = message;
log.ShortMessage__c = message.left(255);
log.Class__c = cls;
insert log;
}

// insert a lot platform event
@AuraEnabled
public static void insertLogPe(String level,String message,String cls){

EventBus.publish(new AppLogEvent__e(
LogLevel__c = level,
Message__c = message,
Class__c = cls
));
}

@AuraEnabled
public static List<AggregateResult> getLogCountByLevelDate(String relDateFilter){
// Valid filters list
Set<String> validFilters = new Set<String>{
'TODAY',
'YESTERDAY',
'THIS_WEEK',
'LAST_WEEK',
'THIS_MONTH',
'LAST_MONTH',
'THIS_YEAR',
'LAST_YEAR'
};

// Validate input
if (relDateFilter != null && !validFilters.contains(relDateFilter.toUpperCase())) {
throw new AuraHandledException('Invalid date filter provided');
}

String query = 'SELECT COUNT(Id) LogCount, MIN(CreatedDate) FirstCreatedDate, LogLevel__c '
+ 'FROM AppLog__c ';

// Add date filter if provided (null means ALL TIME)
if (validFilters.contains(relDateFilter)) {
query += ' WHERE CreatedDate = ' + relDateFilter; // Use the literal directly in SOQL
}
// Order by custom order: INFO, DEBUG, WARN, ERROR
query += ' GROUP BY LogLevel__c '
+ 'ORDER BY LogLevel__c ';

return Database.query(query);
}

@AuraEnabled
public static List<AggregateResult> getLogsByDateLevel(String relDateFilter) {
system.debug('relDateFilter: ' + relDateFilter);
// Valid filters list
Set<String> validFilters = new Set<String>{
'TODAY',
'YESTERDAY',
'THIS_WEEK',
'LAST_WEEK',
'THIS_MONTH',
'LAST_MONTH',
'THIS_YEAR',
'LAST_YEAR'
};

// Validate input
if (relDateFilter != null && !validFilters.contains(relDateFilter.toUpperCase())) {
throw new AuraHandledException('Invalid date filter provided');
}

String query = 'SELECT DAY_ONLY(convertTimezone(CreatedDate)) CreatedDate, LogLevel__c level, COUNT(Id) logCount '
+ 'FROM AppLog__c ';
// Add date filter if provided (null means ALL TIME)
if (validFilters.contains(relDateFilter)) {
query += ' WHERE CreatedDate = ' + relDateFilter; // Use the literal directly in SOQL
}
query += ' GROUP BY DAY_ONLY(convertTimezone(CreatedDate)), LogLevel__c '
+ 'ORDER BY DAY_ONLY(convertTimezone(CreatedDate))';

system.debug('Query: ' + query);
return Database.query(query);
}

@AuraEnabled
public static void deleteLog(String logId) {
try {
delete new AppLog__c(Id = logId);
} catch (Exception e) {
throw new AuraHandledException('Error deleting log: ' + e.getMessage());
}
}

@AuraEnabled
public static void deleteLogsByLevel(String logLevel, String relDateFilter) {
system.debug('Deleting logs with log level: ' + logLevel + ' and date filter: ' + relDateFilter);
// Valid filters list
Set<String> validFilters = new Set<String>{
'TODAY',
'YESTERDAY',
'THIS_WEEK',
'LAST_WEEK',
'THIS_MONTH',
'LAST_MONTH',
'THIS_YEAR',
'LAST_YEAR'
};

// Validate inputs
if (String.isBlank(logLevel)) {
throw new AuraHandledException('Log level must be specified');
}
if (relDateFilter != null && !validFilters.contains(relDateFilter.toUpperCase())) {
throw new AuraHandledException('Invalid date filter provided');
}

String query = 'SELECT Id FROM AppLog__c WHERE LogLevel__c = :logLevel';

// Add date filter if provided (null means ALL TIME)
if (relDateFilter != null) {
query += ' AND CreatedDate = ' + relDateFilter;
}
try {
List<AppLog__c> logsToDelete = Database.query(query);
delete logsToDelete;
} catch (Exception e) {
throw new AuraHandledException('Error deleting logs: ' + e.getMessage());
}
}

public class LogParamWrapper {
@AuraEnabled
public List<String> logLevels { get; set; }
@AuraEnabled
public String cacheBuster { get; set; }
@AuraEnabled
public Integer logsPerPage { get; set; }
@AuraEnabled
public Boolean newLogsOnly { get; set; }
@AuraEnabled
public String tailTimestamp { get; set; }
}
}
65 changes: 49 additions & 16 deletions force-app/main/default/classes/LogUiController_Test.cls
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@

@IsTest
public with sharing class LogUiController_Test {

@TestSetup
static void setup() {
List<AppLog__c> logs = new List<AppLog__c>();
logs.add(new AppLog__c(LogLevel__c = 'DEBUG', Message__c = 'Test Debug'));
logs.add(new AppLog__c(LogLevel__c = 'ERROR', Message__c = 'Test Error'));
logs.add(new AppLog__c(LogLevel__c = 'WARN', Message__c = 'Test Warning'));
insert logs;
}

@IsTest
static void getReturnsRecords() {
LogService_Test.testSetup();
// insert a log
insert new AppLog__c(Message__c = 'My error', LogLevel__c = 'Error');


// create params
LogUiController.LogParamWrapper params = new LogUiController.LogParamWrapper();
params.logLevels = new List<String>{
Expand All @@ -28,30 +36,55 @@ public with sharing class LogUiController_Test {
static void getLogCountByLevelReturnCorrectValues() {
LogService_Test.testSetup();

// insert a few logs
insert new List<AppLog__c>{
new AppLog__c(Message__c = 'My error', LogLevel__c = 'Error'),
new AppLog__c(Message__c = 'My warning', LogLevel__c = 'Warn')
};

// call system under test
List<AggregateResult> results = LogUiController.getLogCountByLevel();

// expect 2 results
Assert.areEqual(2, results.size());
Assert.areEqual(3, results.size());

// expect 1 error log
Integer logCount = Integer.valueOf(results[0].get('LogCount'));
String logLevel = String.valueOf(results[0].get('LogLevel__c'));
Integer logCount = Integer.valueOf(results[1].get('LogCount'));
String logLevel = String.valueOf(results[1].get('LogLevel__c'));

Assert.areEqual('Error', logLevel);
Assert.areEqual('ERROR', logLevel.toUpperCase());
Assert.areEqual(1, logCount);

// expect 1 warn log
Integer logCount2 = Integer.valueOf(results[1].get('LogCount'));
String logLevel2 = String.valueOf(results[1].get('LogLevel__c'));
Integer logCount2 = Integer.valueOf(results[2].get('LogCount'));
String logLevel2 = String.valueOf(results[2].get('LogLevel__c'));

Assert.areEqual('Warn', logLevel2);
Assert.areEqual('WARN', logLevel2.toUpperCase());
Assert.areEqual(1, logCount2);
}

@IsTest
static void testDeleteLog() {
AppLog__c log = [SELECT Id FROM AppLog__c LIMIT 1];

Test.startTest();
LogUiController.deleteLog(log.Id);
Test.stopTest();

List<AppLog__c> remainingLogs = [SELECT Id FROM AppLog__c WHERE Id = :log.Id];
System.assertEquals(0, remainingLogs.size());
}

@IsTest
static void testDeleteLogsByLevel() {
Test.startTest();
LogUiController.deleteLogsByLevel('DEBUG', 'TODAY');
Test.stopTest();

List<AppLog__c> remainingLogs = [SELECT Id FROM AppLog__c WHERE LogLevel__c = 'DEBUG'];
System.assertEquals(0, remainingLogs.size());
}

@IsTest
static void testGetLogCountByLevelDate() {
Test.startTest();
List<AggregateResult> results = LogUiController.getLogCountByLevelDate('TODAY');
Test.stopTest();

System.assertNotEquals(0, results.size());
}
}
22 changes: 22 additions & 0 deletions force-app/main/default/classes/Logger_Test.cls
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,28 @@
public with sharing class Logger_Test {
static Logger sut = new Logger();

@TestSetup
static void setup() {
Logger.ignoreTestMode = true;
sut.debug('My message', 'myClass');
sut.debug('My message', 'myClass', 'my id');
sut.warn('My message', 'myClass');
sut.warn('My message', 'myClass', 'my id');
sut.error('My message', 'myClass');
try {
//noinspection ApexUnusedDeclaration
Double badNumber = 1 / 0; // force MathException
} catch (Exception ex) {
sut.error(ex, 'myClass');
}
try {
//noinspection ApexUnusedDeclaration
Double badNumber = 1 / 0; // force MathException
} catch (Exception ex) {
sut.error(ex, 'myClass', 'idValue');
}
}

@IsTest
static void debugWritesCorrectValues() {

Expand Down
Loading