Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions nebula-logger/core.package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@
<members>LoggerParameter.EnableLoggerSystemMessages</members>
<members>LoggerParameter.EnableStackTraceParsing</members>
<members>LoggerParameter.EnableTagging</members>
<members>LoggerParameter.IgnoredApexOrigins</members>
<members>LoggerParameter.LogBatchPurgerDefaultBatchSize</members>
<members>LoggerParameter.LogEntryEventStreamDisplayFields</members>
<members>LoggerParameter.NormalizeScenarioData</members>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ public class LoggerParameter {
private set;
}

/**
* @description A list of Apex class names that should be ignored when parsing stack traces.
* Any stack trace lines containing these class names will be removed from the parsed stack trace.
* This is useful for filtering out utility or framework classes from stack traces.
* Controlled by the custom metadata record `LoggerParameter.IgnoredApexOrigins`, or an empty list as the default
*/
public static final List<String> IGNORED_APEX_ORIGINS {
get {
if (IGNORED_APEX_ORIGINS == null) {
IGNORED_APEX_ORIGINS = getStringList('IgnoredApexOrigins', new List<String>());
}
return IGNORED_APEX_ORIGINS;
}
private set;
}

/**
* @description Indicates if Nebula Logger will append its own log entries about the logging system.
* Controlled by the custom metadata record `LoggerParameter.EnableLoggerSystemMessages`, or `false` as the default
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<label>Ignored Apex Origins</label>
<protected>false</protected>
<values>
<field>Comments__c</field>
<value xsi:nil="true"/>
</values>
<values>
<field>Description__c</field>
<value xsi:type="xsd:string">A list of Apex class names that should be ignored when parsing stack traces. Any stack trace lines containing these class names will be removed from the parsed stack trace. This is useful for filtering out utility or framework classes from stack traces. The value should be a JSON array of strings, e.g., [&quot;MyUtilityClass&quot;, &quot;AnotherFrameworkClass&quot;].</value>
</values>
<values>
<field>Value__c</field>
<value xsi:type="xsd:string">[]</value>
</values>
</CustomMetadata>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
'PMD.ApexDoc, PMD.AvoidDeeplyNestedIfStmts, PMD.CognitiveComplexity, PMD.CyclomaticComplexity, PMD.ExcessivePublicCount, PMD.NcssMethodCount, PMD.PropertyNamingConventions, PMD.StdCyclomaticComplexity'
)
public without sharing class LoggerStackTrace {
private static final Set<String> IGNORED_APEX_ORIGINS = new Set<String>{ LoggerStackTrace.class.getName() };
private static final String NEW_LINE_DELIMITER = '\n';

private static final System.Pattern INVALID_NAMESPACED_STACK_TRACE_PATTERN {
Expand All @@ -27,6 +26,17 @@ public without sharing class LoggerStackTrace {
set;
}

private static Set<String> IGNORED_APEX_ORIGINS {
get {
if (IGNORED_APEX_ORIGINS == null) {
Set<String> ignoredOrigins = new Set<String>{ LoggerStackTrace.class.getName() };
ignoredOrigins.addAll(LoggerParameter.IGNORED_APEX_ORIGINS);
IGNORED_APEX_ORIGINS = ignoredOrigins;
}
return IGNORED_APEX_ORIGINS;
}
private set;
}
@SuppressWarnings('PMD.FieldNamingConventions')
public enum SourceLanguage {
Apex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,38 @@ private class LoggerStackTrace_Tests {
System.Assert.isTrue(stackTrace.ParsedStackTraceString.contains(externalEntryPointStackTrace));
}

@IsTest
static void it_should_ignore_stack_trace_line_when_matching_class_name_has_been_declaratively_ignored() {
String ignoredClassName = 'SomeIgnoredUtilityClass';
String ignoredStackTraceLine = 'Class.' + ignoredClassName + '.someMethod: line 99999, column 1';
String nonIgnoredTopLevelClassName = 'TheNextClassNameInTheStack';
Integer nonIgnoredTopLevelClassLineNumber = 987;
String nonIgnoredMethodName = 'doSomething';
String expectedOriginLocation = nonIgnoredTopLevelClassName + '.' + nonIgnoredMethodName;
String relevantStackTraceLines =
'Class.' +
expectedOriginLocation +
': line ' +
nonIgnoredTopLevelClassLineNumber +
', column 1' +
'\nAnonymousBlock: line 1, column 1';
String mockStackTrace = ignoredStackTraceLine + '\n' + relevantStackTraceLines;

LoggerConfigurationSelector.useMocks();
LoggerParameter__mdt ignoredOriginsParameter = new LoggerParameter__mdt(DeveloperName = 'IgnoredApexOrigins', Value__c = '["' + ignoredClassName + '"]');
LoggerConfigurationSelector.mockLoggerParameters.put(ignoredOriginsParameter.DeveloperName, ignoredOriginsParameter);

LoggerStackTrace stackTrace = new LoggerStackTrace(mockStackTrace);

System.Assert.areEqual(LoggerStackTrace.SourceLanguage.Apex, stackTrace.Language);
System.Assert.areEqual(expectedOriginLocation, stackTrace.Location);
System.Assert.areEqual(relevantStackTraceLines, stackTrace.ParsedStackTraceString);
System.Assert.areEqual(nonIgnoredTopLevelClassName, stackTrace.Source.ApiName);
System.Assert.areEqual(nonIgnoredMethodName, stackTrace.Source.ActionName);
System.Assert.areEqual(nonIgnoredTopLevelClassLineNumber, stackTrace.Source.LineNumber);
System.Assert.areEqual(LoggerStackTrace.SourceMetadataType.ApexClass, stackTrace.Source.MetadataType);
}

private class DebugStringExample {
private System.Exception constructorStackTraceGenerator;
private System.Exception methodStackTraceGenerator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,16 @@ private class CMDT_LoggerParameter_Tests {
System.Assert.areEqual('false', bundledRecord.Value__c);
}

@IsTest
static void it_has_correct_record_for_ignored_apex_origins() {
LoggerParameter__mdt bundledRecord = LoggerParameter__mdt.getInstance('IgnoredApexOrigins');

System.Assert.isNotNull(bundledRecord, 'Record is missing');
System.Assert.isNull(bundledRecord.Comments__c, 'Comments should be null/blank');
System.Assert.isNotNull(bundledRecord.Description__c, 'Description is missing');
System.Assert.areEqual('Ignored Apex Origins', bundledRecord.Label);
}

/*
// LoggerParameter__mdt checks
// The field LoggerParameter__mdt.Description__c is a long textarea field, so it can't be marked as required - but every record
Expand Down