Skip to content

Commit

Permalink
Bugfix: session data is not populated when logging in LWC (#679)
Browse files Browse the repository at this point in the history
* Fixed #678 by updating LoggerEngineDataSelector to not filter 'ParentId = null' when querying AuthSession - sessions for LWCs have a ParentId value set, so the filter previously prevented any data from being returned from AuthSession

* Added a small enhancement to store the ParentId of the AuthSession record in new fields LogEntryEvent__e.ParentSessionId__c and Log__c.ParentSessionId__c

* Improved & expanded upon some test methods in LogEntryEventBuilder_Tests and LogEntryEventHandler_Tests
  • Loading branch information
jongpie committed Apr 24, 2024
1 parent fcb3b43 commit 18b4b52
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 45 deletions.
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 logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.

## Unlocked Package - v4.13.9
## Unlocked Package - v4.13.10

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

`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001MkHqQAK`
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000027L04QAE`

`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001MkHqQAK`
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000027L04QAE`

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler {
OrganizationType__c = logEntryEvent.OrganizationType__c,
OwnerId = this.determineLogOwnerId(logEntryEvent),
ParentLogTransactionId__c = logEntryEvent.ParentLogTransactionId__c,
ParentSessionId__c = logEntryEvent.ParentSessionId__c,
ProfileId__c = logEntryEvent.ProfileId__c,
ProfileName__c = logEntryEvent.ProfileName__c,
RequestId__c = logEntryEvent.RequestId__c,
Expand Down Expand Up @@ -613,6 +614,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler {
log.LoginPlatform__c = matchingAuthSessionProxy.LoginHistory.Platform;
log.LoginType__c = matchingAuthSessionProxy.LoginType;
log.LogoutUrl__c = matchingAuthSessionProxy.LogoutUrl;
log.ParentSessionId__c = matchingAuthSessionProxy.ParentId;
log.SessionId__c = matchingAuthSessionProxy.Id;
log.SessionSecurityLevel__c = matchingAuthSessionProxy.SessionSecurityLevel;
log.SessionType__c = matchingAuthSessionProxy.SessionType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,22 @@
<type>Facet</type>
</flexiPageRegions>
<flexiPageRegions>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>readonly</value>
</fieldInstanceProperties>
<fieldItem>Record.ParentSessionId__c</fieldItem>
<identifier>RecordParentSessionId_cField</identifier>
<visibilityRule>
<criteria>
<leftValue>{!Record.ParentSessionId__c}</leftValue>
<operator>NE</operator>
</criteria>
</visibilityRule>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>ParentSessionId__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>PII;GDPR;CCPA</complianceGroup>
<externalId>false</externalId>
<label>Parent Session ID</label>
<length>120</length>
<required>false</required>
<securityClassification>Confidential</securityClassification>
<trackFeedHistory>false</trackFeedHistory>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Text</type>
<unique>false</unique>
</CustomField>
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,11 @@
<field>Log__c.ParentLog__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Log__c.ParentSessionId__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>true</editable>
<field>Log__c.Priority__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,11 @@
<field>Log__c.ParentLog__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Log__c.ParentSessionId__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Log__c.ProfileId__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,11 @@
<field>Log__c.ParentLog__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Log__c.ParentSessionId__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Log__c.Priority__c</field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,7 @@ global with sharing class LogEntryEventBuilder {
logEntryEvent.LoginPlatform__c = CACHED_AUTH_SESSION_PROXY.LoginHistory.Platform;
logEntryEvent.LoginType__c = CACHED_AUTH_SESSION_PROXY.LoginType;
logEntryEvent.LogoutUrl__c = CACHED_AUTH_SESSION_PROXY.LogoutUrl;
logEntryEvent.ParentSessionId__c = CACHED_AUTH_SESSION_PROXY.ParentId;
logEntryEvent.SessionId__c = CACHED_AUTH_SESSION_PROXY.Id;
logEntryEvent.SessionSecurityLevel__c = CACHED_AUTH_SESSION_PROXY.SessionSecurityLevel;
logEntryEvent.SessionType__c = CACHED_AUTH_SESSION_PROXY.SessionType;
Expand Down
2 changes: 1 addition & 1 deletion nebula-logger/core/main/logger-engine/classes/Logger.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
global with sharing class Logger {
// There's no reliable way to get the version number dynamically in Apex
@TestVisible
private static final String CURRENT_VERSION_NUMBER = 'v4.13.9';
private static final String CURRENT_VERSION_NUMBER = 'v4.13.10';
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
private static final List<LogEntryEventBuilder> LOG_ENTRIES_BUFFER = new List<LogEntryEventBuilder>();
private static final String MISSING_SCENARIO_ERROR_MESSAGE = 'No logger scenario specified. A scenario is required for logging in this org.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ public without sharing virtual class LoggerEngineDataSelector {
LoginHistory.Platform,
LoginHistory.UserId,
LogoutUrl,
ParentId,
SessionSecurityLevel,
SessionType,
SourceIp,
UsersId
FROM AuthSession
WHERE UsersId IN :userIds AND IsCurrent = TRUE AND ParentId = NULL
WHERE UsersId IN :userIds AND IsCurrent = TRUE
ORDER BY ParentId NULLS FIRST
]) {
LoggerSObjectProxy.AuthSession authSessionProxy = new LoggerSObjectProxy.AuthSession(authSession);
userIdToAuthSessionProxy.put(authSessionProxy.UsersId, authSessionProxy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Each inner class maps to a corresponding `SObjectType` that is difficult to work with Apex for some reason or another,
* such as not being mockable or creatable, or not existing in all orgs.
*/
@SuppressWarnings('PMD.ExcessivePublicCount')
public without sharing class LoggerSObjectProxy {
/**
* @description All `Schema.AuthSession` SObjects are read-only in Apex, which makes them more difficult to work with, and impossible
Expand All @@ -22,6 +23,7 @@ public without sharing class LoggerSObjectProxy {
public Id LoginHistoryId;
public LoginHistory LoginHistory;
public String LogoutUrl;
public Id ParentId;
public String SessionSecurityLevel;
public String SessionType;
public String SourceIp;
Expand All @@ -35,6 +37,7 @@ public without sharing class LoggerSObjectProxy {
this.LoginHistoryId = authSessionRecord.LoginHistoryId;
this.LoginType = authSessionRecord.LoginType;
this.LogoutUrl = authSessionRecord.LogoutUrl;
this.ParentId = authSessionRecord.ParentId;
this.SessionSecurityLevel = authSessionRecord.SessionSecurityLevel;
this.SessionType = authSessionRecord.SessionType;
this.SourceIp = authSessionRecord.SourceIp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//------------------------------------------------------------------------------------------------//
import FORM_FACTOR from '@salesforce/client/formFactor';

const CURRENT_VERSION_NUMBER = 'v4.13.9';
const CURRENT_VERSION_NUMBER = 'v4.13.10';

// JavaScript equivalent to the Apex class ComponentLogger.ComponentLogEntry
const ComponentLogEntry = class {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>ParentSessionId__c</fullName>
<businessStatus>Active</businessStatus>
<complianceGroup>PII;GDPR;CCPA</complianceGroup>
<externalId>false</externalId>
<isFilteringDisabled>false</isFilteringDisabled>
<isNameField>false</isNameField>
<isSortingDisabled>false</isSortingDisabled>
<label>Parent Session ID</label>
<length>120</length>
<required>false</required>
<securityClassification>Confidential</securityClassification>
<type>Text</type>
<unique>false</unique>
</CustomField>
Original file line number Diff line number Diff line change
Expand Up @@ -581,30 +581,49 @@ private class LogEntryEventHandler_Tests {
logEntryEvent.LoginPlatform__c = null;
logEntryEvent.LoginType__c = null;
logEntryEvent.LogoutUrl__c = null;
logEntryEvent.ParentSessionId__c = null;
logEntryEvent.SessionId__c = null;
logEntryEvent.SessionSecurityLevel__c = null;
logEntryEvent.SessionType__c = null;
logEntryEvent.SourceIp__c = null;
LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'QueryAuthSessionDataSynchronously', Value__c = String.valueOf(false)));
System.Assert.isFalse(LoggerParameter.QUERY_AUTH_SESSION_DATA_SYNCHRONOUSLY);
MockLoggerEngineDataSelector mockSelector = new MockLoggerEngineDataSelector();
LoggerEngineDataSelector.setMock(mockSelector);
LoggerSObjectProxy.LoginHistory mockLoginHistoryProxy = new LoggerSObjectProxy.LoginHistory(null);
mockLoginHistoryProxy.Application = 'Application';
mockLoginHistoryProxy.Browser = 'Browser';
mockLoginHistoryProxy.Platform = 'Platform';
mockLoginHistoryProxy.UserId = System.UserInfo.getUserId();
LoggerSObjectProxy.AuthSession mockAuthSessionProxy = new LoggerSObjectProxy.AuthSession(null);
mockAuthSessionProxy.Id = LoggerMockDataCreator.createId(Schema.AuthSession.SObjectType);
mockAuthSessionProxy.LoginHistory = mockLoginHistoryProxy;
mockAuthSessionProxy.LoginHistoryId = LoggerMockDataCreator.createId(Schema.LoginHistory.SObjectType);
mockAuthSessionProxy.LoginType = 'LoginType';
mockAuthSessionProxy.LogoutUrl = 'LogoutUrl';
mockAuthSessionProxy.ParentId = LoggerMockDataCreator.createId(Schema.AuthSession.SObjectType);
mockAuthSessionProxy.SessionSecurityLevel = 'SessionSecurityLevel';
mockAuthSessionProxy.SessionType = 'SessionType';
mockAuthSessionProxy.SourceIp = 'SourceIp';
mockAuthSessionProxy.UsersId = System.UserInfo.getUserId();
mockSelector.setCachedAuthSessionProxy(mockAuthSessionProxy);
System.Assert.areEqual(0, mockSelector.getCachedAuthSessionQueryCount());

LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent);
LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler());

List<Id> userIds = new List<Id>{ logEntryEvent.LoggedById__c };
LoggerSObjectProxy.AuthSession expectedAuthSessionProxy = LoggerEngineDataSelector.getInstance()
.getAuthSessionProxies(userIds)
.get(logEntryEvent.LoggedById__c);
Log__c log = getLog();
System.Assert.areEqual(expectedAuthSessionProxy?.LoginHistory.Application, log.LoginApplication__c);
System.Assert.areEqual(expectedAuthSessionProxy?.LoginHistory.Browser, log.LoginBrowser__c);
System.Assert.areEqual(expectedAuthSessionProxy?.LoginHistoryId, log.LoginHistoryId__c);
System.Assert.areEqual(expectedAuthSessionProxy?.LoginHistory.Platform, log.LoginPlatform__c);
System.Assert.areEqual(expectedAuthSessionProxy?.LoginType, log.LoginType__c);
System.Assert.areEqual(expectedAuthSessionProxy?.LogoutUrl, log.LogoutUrl__c);
System.Assert.areEqual(expectedAuthSessionProxy?.Id, log.SessionId__c);
System.Assert.areEqual(expectedAuthSessionProxy?.SessionSecurityLevel, log.SessionSecurityLevel__c);
System.Assert.areEqual(expectedAuthSessionProxy?.SessionType, log.SessionType__c);
System.Assert.areEqual(expectedAuthSessionProxy?.SourceIp, log.SourceIp__c);
System.Assert.areEqual(mockAuthSessionProxy.Id, log.SessionId__c);
System.Assert.areEqual(mockAuthSessionProxy.LoginHistory.Application, log.LoginApplication__c);
System.Assert.areEqual(mockAuthSessionProxy.LoginHistory.Browser, log.LoginBrowser__c);
System.Assert.areEqual(mockAuthSessionProxy.LoginHistory.Platform, log.LoginPlatform__c);
System.Assert.areEqual(mockAuthSessionProxy.LoginHistoryId, log.LoginHistoryId__c);
System.Assert.areEqual(mockAuthSessionProxy.LoginType, log.LoginType__c);
System.Assert.areEqual(mockAuthSessionProxy.LogoutUrl, log.LogoutUrl__c);
System.Assert.areEqual(mockAuthSessionProxy.ParentId, log.ParentSessionId__c);
System.Assert.areEqual(mockAuthSessionProxy.SessionSecurityLevel, log.SessionSecurityLevel__c);
System.Assert.areEqual(mockAuthSessionProxy.SessionType, log.SessionType__c);
System.Assert.areEqual(mockAuthSessionProxy.SourceIp, log.SourceIp__c);
}

@IsTest
Expand Down Expand Up @@ -1253,6 +1272,7 @@ private class LogEntryEventHandler_Tests {
OrganizationType__c,
OwnerId,
ParentLogTransactionId__c,
ParentSessionId__c,
ProfileId__c,
ProfileName__c,
RequestId__c,
Expand Down Expand Up @@ -1425,11 +1445,11 @@ private class LogEntryEventHandler_Tests {
System.Assert.areEqual(logOwnerId, log.OwnerId, 'log.OwnerId was not properly set');
System.Assert.areEqual(logEntryEvent.OrganizationApiVersion__c, log.OrganizationApiVersion__c, 'log.OrganizationApiVersion__c was not properly set');
System.Assert.areEqual(logEntryEvent.ParentLogTransactionId__c, log.ParentLogTransactionId__c, 'log.ParentLogTransactionId__c was not properly set');
System.Assert.areEqual(logEntryEvent.ParentSessionId__c, log.ParentSessionId__c, 'log.ParentSessionId__c was not properly set');
System.Assert.areEqual(logEntryEvent.ProfileId__c, log.ProfileId__c, 'log.ProfileId__c was not properly set');
System.Assert.areEqual(logEntryEvent.ProfileName__c, log.ProfileName__c, 'log.ProfileName__c was not properly set');
System.Assert.areEqual(logEntryEvent.RequestId__c, log.RequestId__c, 'log.RequestId__c was not properly set');
System.Assert.areEqual(logEntryEvent.SessionId__c, log.SessionId__c, 'log.SessionId__c was not properly set');
System.Assert.areEqual(logEntryEvent.SessionId__c, log.SessionId__c, 'log.SessionId__c was not properly set');
System.Assert.areEqual(logEntryEvent.SessionSecurityLevel__c, log.SessionSecurityLevel__c, 'log.SessionSecurityLevel__c was not properly set');
System.Assert.areEqual(logEntryEvent.SessionType__c, log.SessionType__c, 'log.SessionType__c was not properly set');
System.Assert.areEqual(logEntryEvent.SourceIp__c, log.SourceIp__c, 'log.SourceIp__c was not properly set');
Expand Down Expand Up @@ -1790,4 +1810,25 @@ private class LogEntryEventHandler_Tests {
);
System.Assert.areEqual(logEntryEvent.TriggerSObjectType__c, logEntry.TriggerSObjectType__c, 'logEntry.TriggerSObjectType__c was not properly set');
}

private class MockLoggerEngineDataSelector extends LoggerEngineDataSelector {
private Integer authSessionProxiesQueryCount = 0;
private LoggerSObjectProxy.AuthSession mockAuthSessionProxy;

public Integer getCachedAuthSessionQueryCount() {
return authSessionProxiesQueryCount;
}

public override Map<Id, LoggerSObjectProxy.AuthSession> getAuthSessionProxies(List<Id> userIds) {
this.authSessionProxiesQueryCount++;
if (this.mockAuthSessionProxy != null) {
return new Map<Id, LoggerSObjectProxy.AuthSession>{ mockAuthSessionProxy.UsersId => mockAuthSessionProxy };
}
return super.getAuthSessionProxies(userIds);
}

public void setCachedAuthSessionProxy(LoggerSObjectProxy.AuthSession mockAuthSessionProxy) {
this.mockAuthSessionProxy = mockAuthSessionProxy;
}
}
}

0 comments on commit 18b4b52

Please sign in to comment.