Skip to content

Commit

Permalink
Added the ability to capture HttpRequest headers (#755)
Browse files Browse the repository at this point in the history
* Added instance method overload LogEntryEventBuilder.setHttpRequestDetails(System.HttpRequest request, List<String> headersToLog)
  * Any header keys provided in headersToLog will now be logged
  * The existing overload, setHttpRequestDetails(System.HttpRequest request), will not log any header information

* Added new LogEntryEvent__e fields HttpRequestHeaderKeys__c and HttpRequestHeaders__c to capture the specified list of header keys

* Added new LoggerParameter__mdt record StoreHttpRequestHeaderValues to globally control if HttpResponse header values are stored when calling setHttpRequestDetails(System.HttpRequest request, List<String> headersToLog)
  * This new record mimics the existing record StoreHttpResponseHeaderValues (used for responses)

* Added new LogEntry__c fields to store the HttpRequest header keys & values captured on LogEntryEvent__e, as well as some checkbox fields to aid with filtering in SOQL, list views, etc.
  * HttpRequestHeaderKeys__c
  * HasHttpRequestHeaderKeys__c - set to true when HttpRequestHeaderKeys__c is not null
  * HttpRequestHeaders__c
  * HasHttpRequestHeaders__c - set to true when HttpRequestHeaders__c is not null

* Updated the flexipage LogEntryRecordPage to add the 2 new LogEntry__c fields HttpRequestHeaderKeys__c and HttpRequestHeaders__c
  * Both fields are conditionally displayed when populated, based on their corresponding checkbox fields HasHttpRequestHeaderKeys__c and HasHttpRequestHeaders__c (respectively)

* Updated the existing list view AllHttpRequestLogEntries to include the new field HttpRequestHeaderKeys__c (HttpRequestHeader__c is intentionally not included at this time)

* Updated build.yml to fail the build if the codecov upload action fails in the pipeline
  • Loading branch information
jongpie authored Sep 2, 2024
1 parent 3c38ee8 commit 5c4e09e
Show file tree
Hide file tree
Showing 32 changed files with 467 additions and 32 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ jobs:
- name: 'Upload LWC code coverage to Codecov.io'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
flags: LWC
token: ${{ secrets.CODECOV_TOKEN }}

base-scratch-org-tests:
environment: 'Base Scratch Org'
Expand Down Expand Up @@ -318,8 +319,9 @@ jobs:
- name: 'Upload Apex test code coverage to Codecov.io'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
flags: Apex
token: ${{ secrets.CODECOV_TOKEN }}

- name: 'Delete Experience Cloud Scratch Org'
run: npx sf org delete scratch --no-prompt
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

The most robust observability solution for Salesforce experts. Built 100% natively on the platform, and designed to work seamlessly with Apex, Lightning Components, Flow, Process Builder & integrations.

## Unlocked Package - v4.14.7
## Unlocked Package - v4.14.8

[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRrQAI)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRrQAI)
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oS1QAI)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oS1QAI)
[![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/)

`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oRrQAI`
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oS1QAI`

`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oRrQAI`
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oS1QAI`

---

Expand Down
4 changes: 4 additions & 0 deletions docs/apex/Configuration/LoggerParameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ Indicates if Nebula Logger will send an error email notification if any internal

Indicates if Nebula Logger will store the transaction heap limits on `LogEntry__c`, retrieved from the class `System.Limits`. Controlled by the custom metadata record `LoggerParameter.StoreApexHeapSizeLimit`, or `true` as the default. Relies on `LoggerParameter.StoreTransactionLimits` to be true, as well.

#### `STORE_HTTP_REQUEST_HEADER_VALUES``Boolean`

Indicates if Nebula Logger will store the header values when logging an instance of `System.HttpRequest`. Controlled by the custom metadata record `LoggerParameter.StoreHttpRequestHeaderValues`, or `true` as the default. Regardless of how this parameter is configured, Nebula Logger will still log the specified list of header keys of any instance of `System.HttpRequest` that is logged - this parameter only controls if the header values are stored.

#### `STORE_HTTP_RESPONSE_HEADER_VALUES``Boolean`

Indicates if Nebula Logger will store the header values when logging an instance of `System.HttpResponse`. Controlled by the custom metadata record `LoggerParameter.StoreHttpResponseHeaderValues`, or `true` as the default. Regardless of how this parameter is configured, Nebula Logger will still log the header keys of any instance of `System.HttpResponse` that is logged - this parameter only controls if the header values are stored.
Expand Down
21 changes: 21 additions & 0 deletions docs/apex/Logger-Engine/LogEntryEventBuilder.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,27 @@ LogEntryEventBuilder

The same instance of `LogEntryEventBuilder`, useful for chaining methods

#### `setHttpRequestDetails(System.HttpRequest request, List<String> headersToLog)``LogEntryEventBuilder`

Sets the log entry event&apos;s HTTP Request fields

##### Parameters

| Param | Description |
| -------------- | --------------------------------------------------------------------- |
| `request` | The instance of `HttpRequest` to log |
| `headersToLog` | An instance of `List&lt;String&gt;` containing the header keys to log |

##### Return

**Type**

LogEntryEventBuilder

**Description**

The same instance of `LogEntryEventBuilder`, useful for chaining methods

#### `setHttpResponseDetails(System.HttpResponse response)``LogEntryEventBuilder`

Sets the log entry event&apos;s HTTP Response fields
Expand Down
16 changes: 16 additions & 0 deletions nebula-logger/core/main/configuration/classes/LoggerParameter.cls
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,22 @@ public class LoggerParameter {
private set;
}

/**
* @description Indicates if Nebula Logger will store the header values when logging an instance of `System.HttpRequest`.
* Controlled by the custom metadata record `LoggerParameter.StoreHttpRequestHeaderValues`, or `true` as the default.
* Regardless of how this parameter is configured, Nebula Logger will still log the specified list of header keys of any instance of
* `System.HttpRequest` that is logged - this parameter only controls if the header values are stored.
*/
public static final Boolean STORE_HTTP_REQUEST_HEADER_VALUES {
get {
if (STORE_HTTP_REQUEST_HEADER_VALUES == null) {
STORE_HTTP_REQUEST_HEADER_VALUES = getBoolean('StoreHttpRequestHeaderValues', true);
}
return STORE_HTTP_REQUEST_HEADER_VALUES;
}
private set;
}

/**
* @description Indicates if Nebula Logger will store the header values when logging an instance of `System.HttpResponse`.
* Controlled by the custom metadata record `LoggerParameter.StoreHttpResponseHeaderValues`, or `true` as the default.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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>Store HTTP Request Header Values</label>
<protected>false</protected>
<values>
<field>Comments__c</field>
<value xsi:nil="true"/>
</values>
<values>
<field>Description__c</field>
<value xsi:type="xsd:string">When set to &apos;true&apos; (default), Nebula Logger will store the header values of any instance of an HttpRequest that is logged using the instance method LogEntryEventBuilder.setHttpRequestDetails().

When set to &apos;false&apos;, the header values are not stored or referenced by Nebula Logger.

Regardless of how this parameter is configured, Nebula Logger will still log the specified list of header keys of any instance of an HttpRequest that is logged - this parameter only controls if the header values are stored.</value>
</values>
<values>
<field>Value__c</field>
<value xsi:type="xsd:string">true</value>
</values>
</CustomMetadata>
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler {
HttpRequestBodyMasked__c = logEntryEvent.HttpRequestBodyMasked__c,
HttpRequestCompressed__c = logEntryEvent.HttpRequestCompressed__c,
HttpRequestEndpoint__c = logEntryEvent.HttpRequestEndpoint__c,
HttpRequestHeaderKeys__c = logEntryEvent.HttpRequestHeaderKeys__c,
HttpRequestHeaders__c = logEntryEvent.HttpRequestHeaders__c,
HttpRequestMethod__c = logEntryEvent.HttpRequestMethod__c,
HttpResponseBody__c = logEntryEvent.HttpResponseBody__c,
HttpResponseBodyMasked__c = logEntryEvent.HttpResponseBodyMasked__c,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler {
logEntry.HasExceptionSourceSnippet__c = logEntry.ExceptionSourceSnippet__c != null;
logEntry.HasExceptionStackTrace__c = logEntry.ExceptionStackTrace__c != null;
logEntry.HasHttpRequestBody__c = logEntry.HttpRequestBody__c != null;
logEntry.HasHttpRequestHeaderKeys__c = logEntry.HttpRequestHeaderKeys__c != null;
logEntry.HasHttpRequestHeaders__c = logEntry.HttpRequestHeaders__c != null;
logEntry.HasHttpResponseBody__c = logEntry.HttpResponseBody__c != null;
logEntry.HasHttpResponseHeaderKeys__c = logEntry.HttpResponseHeaderKeys__c != null;
logEntry.HasHttpResponseHeaders__c = logEntry.HttpResponseHeaders__c != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,40 @@
<identifier>RecordHttpRequestMethod_cField1</identifier>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.HttpRequestHeaderKeys__c</fieldItem>
<identifier>RecordHttpRequestHeaderKeys_cField</identifier>
<visibilityRule>
<criteria>
<leftValue>{!Record.HasHttpRequestHeaderKeys__c}</leftValue>
<operator>EQUAL</operator>
<rightValue>true</rightValue>
</criteria>
</visibilityRule>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.HttpRequestHeaders__c</fieldItem>
<identifier>RecordHttpRequestHeaders_cField</identifier>
<visibilityRule>
<criteria>
<leftValue>{!Record.HasHttpRequestHeaders__c}</leftValue>
<operator>EQUAL</operator>
<rightValue>true</rightValue>
</criteria>
</visibilityRule>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,14 @@
<behavior>Readonly</behavior>
<field>HttpRequestMethod__c</field>
</layoutItems>
<layoutItems>
<behavior>Readonly</behavior>
<field>HttpRequestHeaderKeys__c</field>
</layoutItems>
<layoutItems>
<behavior>Readonly</behavior>
<field>HttpRequestHeaders__c</field>
</layoutItems>
<layoutItems>
<behavior>Readonly</behavior>
<field>HttpRequestCompressed__c</field>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>HasHttpRequestHeaderKeys__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>None</complianceGroup>
<defaultValue>false</defaultValue>
<label>Has HTTP Request Header Keys</label>
<securityClassification>Confidential</securityClassification>
<trackTrending>false</trackTrending>
<type>Checkbox</type>
</CustomField>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>HasHttpRequestHeaders__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>None</complianceGroup>
<defaultValue>false</defaultValue>
<label>Has HTTP Request Headers</label>
<securityClassification>Confidential</securityClassification>
<trackTrending>false</trackTrending>
<type>Checkbox</type>
</CustomField>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>HttpRequestHeaderKeys__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>None</complianceGroup>
<label>HTTP Request Header Keys</label>
<length>1000</length>
<securityClassification>Confidential</securityClassification>
<trackTrending>false</trackTrending>
<type>LongTextArea</type>
<visibleLines>5</visibleLines>
</CustomField>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>HttpRequestHeaders__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>None</complianceGroup>
<label>HTTP Request Headers</label>
<length>5000</length>
<securityClassification>Confidential</securityClassification>
<trackTrending>false</trackTrending>
<type>LongTextArea</type>
<visibleLines>5</visibleLines>
</CustomField>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<columns>Origin__c</columns>
<columns>HttpRequestEndpoint__c</columns>
<columns>HttpRequestMethod__c</columns>
<columns>HttpRequestHeaderKeys__c</columns>
<columns>HttpRequestBody__c</columns>
<columns>Timestamp__c</columns>
<filterScope>Everything</filterScope>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<columns>Origin__c</columns>
<columns>RestRequestUri__c</columns>
<columns>RestRequestMethod__c</columns>
<columns>RestRequestHeaderKeys__c</columns>
<columns>RestRequestBody__c</columns>
<columns>Timestamp__c</columns>
<filterScope>Everything</filterScope>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,16 @@
<field>LogEntry__c.HasHttpRequestBody__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaderKeys__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaders__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpResponseBody__c</field>
Expand Down Expand Up @@ -561,6 +571,16 @@
<field>LogEntry__c.HttpRequestEndpoint__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestHeaderKeys__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestHeaders__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestMethod__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,16 @@
<field>LogEntry__c.HasHttpRequestBody__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaderKeys__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaders__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpResponseBody__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,16 @@
<field>LogEntry__c.HasHttpRequestBody__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaderKeys__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpRequestHeaders__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HasHttpResponseBody__c</field>
Expand Down Expand Up @@ -481,6 +491,16 @@
<field>LogEntry__c.HttpRequestEndpoint__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestHeaderKeys__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestHeaders__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>LogEntry__c.HttpRequestMethod__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,19 @@ global with sharing class LogEntryEventBuilder {
/**
* @description Sets the log entry event's HTTP Request fields
* @param request The instance of `HttpRequest` to log
* @return The same instance of `LogEntryEventBuilder`, useful for chaining methods
* @return The same instance of `LogEntryEventBuilder`, useful for chaining methods
*/
global LogEntryEventBuilder setHttpRequestDetails(System.HttpRequest request) {
return this.setHttpRequestDetails(request, new List<String>());
}

/**
* @description Sets the log entry event's HTTP Request fields
* @param request The instance of `HttpRequest` to log
* @param headersToLog An instance of `List<String>` containing the header keys to log
* @return The same instance of `LogEntryEventBuilder`, useful for chaining methods
*/
global LogEntryEventBuilder setHttpRequestDetails(System.HttpRequest request, List<String> headersToLog) {
if (this.shouldSave() == false || request == null) {
return this;
}
Expand All @@ -476,10 +486,25 @@ global with sharing class LogEntryEventBuilder {
String cleanedRequestBody = applyDataMaskRules(this.userSettings.IsDataMaskingEnabled__c, truncatedRequestBody);
Boolean requestBodyMasked = cleanedRequestBody != truncatedRequestBody;

String formattedHeaderKeysString;
String formattedHeadersString;
if (headersToLog != null & headersToLog.isEmpty() == false) {
formattedHeaderKeysString = String.join(headersToLog, NEW_LINE_DELIMITER);
if (LoggerParameter.STORE_HTTP_REQUEST_HEADER_VALUES) {
List<String> headers = new List<String>();
for (String headerKey : headersToLog) {
headers.add(String.format(HTTP_HEADER_FORMAT, new List<String>{ headerKey, request.getHeader(headerKey) }));
}
formattedHeadersString = String.join(headers, NEW_LINE_DELIMITER);
}
}

this.logEntryEvent.HttpRequestBody__c = cleanedRequestBody;
this.logEntryEvent.HttpRequestBodyMasked__c = requestBodyMasked;
this.logEntryEvent.HttpRequestCompressed__c = request.getCompressed();
this.logEntryEvent.HttpRequestEndpoint__c = request.getEndpoint();
this.logEntryEvent.HttpRequestHeaderKeys__c = formattedHeaderKeysString;
this.logEntryEvent.HttpRequestHeaders__c = LoggerDataStore.truncateFieldValue(Schema.LogEntryEvent__e.HttpRequestHeaders__c, formattedHeadersString);
this.logEntryEvent.HttpRequestMethod__c = request.getMethod();
return this;
}
Expand Down
Loading

0 comments on commit 5c4e09e

Please sign in to comment.