diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..ed10ce8bf --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "babelOptions": { + "parserOpts": { + "plugins": ["classProperties", ["decorators", { "decoratorsBeforeExport": false }]] + } + } + }, + "ignorePatterns": ["**/*.html", "**/*.cmp", "**/*.cmp-meta.xml", "**/*.css", "**/*.test.js", "**/*js-meta.xml", "**/*.json"], + "plugins": ["@lwc/eslint-plugin-lwc", "@salesforce/eslint-plugin-aura"], + "extends": ["@salesforce/eslint-config-lwc/recommended"], + "rules": { + "eqeqeq": "off", + "no-console": "off", + "no-unused-expressions": "off", + "semi": "off", + "@lwc/lwc/consistent-component-name": "error", + "@lwc/lwc/no-api-reassignments": "off", + "@lwc/lwc/no-async-operation": "off", + "@lwc/lwc/no-deprecated": "error", + "@lwc/lwc/no-document-query": "error", + "@lwc/lwc/valid-api": "error" + } +} diff --git a/.forceignore b/.forceignore index 04d1f4c5e..0ebf56844 100644 --- a/.forceignore +++ b/.forceignore @@ -6,10 +6,11 @@ nebula-logger/main/default/** # Directory/package-specific README files **/README.md +**/.content/** # LWC configuration files **/jsconfig.json **/.eslintrc.json # LWC Jest -**/__tests__/** \ No newline at end of file +**/__tests__/** diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 65b926bde..06f055d36 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,4 @@ -# Unique name for this workflow +# Pipeline for Nebula Logger name: Deployment on: @@ -39,12 +39,11 @@ on: - 'sfdx-project.json' jobs: - local-tests: - name: 'Local Tests' + code-quality-tests: + name: 'Code Quality Tests' runs-on: ubuntu-latest environment: Test steps: - # Checkout the code - name: 'Checkout source code' uses: actions/checkout@v2 @@ -56,41 +55,55 @@ jobs: - name: 'Install npm' run: npm install - # Install Salesforce CLI + - name: 'Lint Lightning Components' + run: npm run lint:lwc + + - name: 'Prettier code formatting verification' + run: npm run prettier:verify + - name: Install Salesforce CLI run: npm install sfdx-cli --global - # run: | - # wget https://developer.salesforce.com/media/salesforce-cli/sfdx-linux-amd64.tar.xz - # mkdir sfdx-cli - # tar xJf sfdx-linux-amd64.tar.xz -C sfdx-cli --strip-components 1 - # ./sfdx-cli/install - - # Start local testing - # TODO uncomment - # Prettier formatting - # - name: 'Code formatting verification with Prettier' - # run: npm run prettier:verify - # TODO uncomment - # Lint LWC - # - name: 'Lint Lightning Web Components' - # run: npm run lint:lwc - # LWC unit tests + + - name: Install & run SFDX Scanner + run: | + sfdx plugins:install @salesforce/sfdx-scanner + sfdx scanner:run --pmdconfig config/pmd-ruleset.xml --target . --engine pmd --severity-threshold 3 + + lwc-tests: + name: 'LWC Tests' + needs: [code-quality-tests] + runs-on: ubuntu-latest + environment: Test + steps: + - name: 'Checkout source code' + uses: actions/checkout@v2 + + - name: 'Setup node' + uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: 'Install npm' + run: npm install + + - name: Install Salesforce CLI + run: npm install sfdx-cli --global + - name: 'Run LWC Tests' run: npm run test:lwc - # Upload code coverage data for LWC - # - name: 'Upload code coverage for LWC to Codecov.io' - # uses: codecov/codecov-action@v2.0.2 - # with: - # token: ${{ secrets.CODECOV_TOKEN }} - # flags: LWC + - name: 'Upload LWC code coverage to Codecov.io' + uses: codecov/codecov-action@v2.0.2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: LWC scratch-org-tests: name: 'Scratch Org Tests' + needs: [code-quality-tests] runs-on: ubuntu-latest environment: Test steps: - # Checkout the code - name: 'Checkout source code' uses: actions/checkout@v2 @@ -102,18 +115,9 @@ jobs: - name: 'Install npm' run: npm install - # Install Salesforce CLI - name: Install Salesforce CLI run: npm install sfdx-cli --global - # run: | - # wget https://developer.salesforce.com/media/salesforce-cli/sfdx-linux-amd64.tar.xz - # mkdir sfdx-cli - # tar xJf sfdx-linux-amd64.tar.xz -C sfdx-cli --strip-components 1 - # ./sfdx-cli/install - - # Start remote testing - # Store secrets for dev hubs - name: 'Populate DevHub Auth Files' shell: bash run: | @@ -142,31 +146,70 @@ jobs: with: args: '120' - - name: 'Deploy Metadata' - run: npm run deploy + - name: 'Push Metadata' + run: sfdx force:source:push --forceoverwrite - name: 'Run Apex Tests' run: npm run test:apex - # Delete test files that Codecov is unable to parse - # - name: 'Delete unsupported code coverage files' - # run: rm ./tests/apex/test-result-707*-codecoverage.json + - name: 'Delete unsupported code coverage files' + run: rm ./tests/apex/test-result-707*-codecoverage.json - # Upload code coverage data for Apex - # - name: 'Upload code coverage for Apex to Codecov.io' - # uses: codecov/codecov-action@v2.0.2 - # with: - # token: ${{ secrets.CODECOV_TOKEN }} - # flags: Apex + - name: 'Upload Apex test code coverage to Codecov.io' + uses: codecov/codecov-action@v2.0.2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: Apex - name: 'Delete Scratch Org' run: npm run org:delete:noprompt if: ${{ always() }} + create-and-install-test-package-version: + name: 'Create & Install Test Package Version' + needs: [lwc-tests, scratch-org-tests] + if: ${{ github.event_name == 'pull_request' }} + runs-on: ubuntu-latest + environment: Test + steps: + - name: 'Checkout source code' + uses: actions/checkout@v2 + + - name: 'Setup node' + uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: 'Install npm' + run: npm install + + - name: Install Salesforce CLI + run: npm install sfdx-cli --global + + - name: 'Populate Org Auth Files' + shell: bash + run: | + echo ${{ env.DEVHUB_SFDX_URL }} > ./DEVHUB_SFDX_URL.txt + echo ${{ env.NEBULA_PKG_DEMO_SANDBOX_SFDX_URL }} > ./NEBULA_PKG_DEMO_SANDBOX_SFDX_URL.txt + env: + DEVHUB_SFDX_URL: ${{ secrets.DEVHUB_SFDX_URL }} + NEBULA_PKG_DEMO_SANDBOX_SFDX_URL: ${{ secrets.NEBULA_PKG_DEMO_SANDBOX_SFDX_URL }} + + - name: 'Authorize Orgs' + run: | + sfdx auth:sfdxurl:store --sfdxurlfile ./DEVHUB_SFDX_URL.txt --setalias nebula-logger-packaging --setdefaultdevhubusername + sfdx auth:sfdxurl:store --sfdxurlfile ./NEBULA_PKG_DEMO_SANDBOX_SFDX_URL.txt --setalias nebula-logger-package-demo + + - name: 'Create & Install Unvalidated Package Version' + run: npx pwsh ./scripts/create-and-install-unvalidated-package-version.ps1 -targetusername nebula-logger-package-demo + + - name: 'Reinstall Latest Released Package Version' + run: npx pwsh ./scripts/install-latest-released-unlocked-package-version.ps1 -targetusername nebula-logger-package-demo + # TODO finish auto-creation & promotion of unlocked package + committing changes to docs # create-package-version: # name: 'Create Package Version' - # needs: [local-tests, scratch-org-tests] + # needs: [code-quality-tests, lwc-tests, scratch-org-tests] # runs-on: ubuntu-latest # environment: Test # steps: diff --git a/.prettierignore b/.prettierignore index e0bce02c2..464b69eab 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,12 +7,7 @@ .settings/ .sfdx/ .vscode/ -examples/ -nebula-logger/main/default/ -nebula-logger/managed-package/ -packages/ scripts/ -tests/ # NPM node_modules/ @@ -20,4 +15,4 @@ package-lock.json yarn.lock # Files to exclude -*.log \ No newline at end of file +*.log diff --git a/README.md b/README.md index de708c7ed..c0eb05ab8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Designed for Salesforce admins, developers & architects. A robust logger for Apex, Lightning Components, Flow, Process Builder & Integrations. -[![Install Unlocked Package](./content/btn-install-unlocked-package.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015khXQAQ) +[![Install Unlocked Package](./content/btn-install-unlocked-package.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015klZQAQ) [![Install Managed Package](./content/btn-install-managed-package.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015keOQAQ) [![View Documentation](./content/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/) @@ -18,10 +18,11 @@ Designed for Salesforce admins, developers & architects. A robust logger for Ape 3. Leverage `LogEntryEvent__e` platform events for real-time monitoring & integrations 4. Enable logging and set the logging level for different users & profiles using `LoggerSettings__c` custom hierarchy setting - In addition to the required fields on this Custom Setting record, `LoggerSettings__c` ships with `SystemLogMessageFormat__c`, which uses Handlebars-esque syntax to refer to fields on the `LogEntryEvent__e` Platform Event. You can use curly braces to denote merge field logic, eg: `{OriginLocation__c}\n{Message__c}` - this will output the contents of `LogEntryEvent__e.OriginLocation__c`, a line break, and then the contents of `LogEntryEvent__e.Message__c` -5. View related log entries on any Lighting SObject flexipage by adding the 'Related Log Entries' component in App Builder -6. Dynamically assign tags to `Log__c` and `LogEntry__c` records for tagging/labeling your logs -7. Plugin framework: easily build or install plugins that enhance the `Log__c` and `LogEntry__c` objects, using Apex or Flow (not currently available in the managed package) -8. Event-Driven Integrations with [Platform Events](https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_intro.htm), an event-driven messaging architecture. External integrations can subscribe to log events using the `LogEntryEvent__e` object - see more details at [the Platform Events Developer Guide site](https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_subscribe_cometd.htm) +5. Automatically mask sensitive data by configuring `LogEntryDataMaskRule__mdt` custom metadata rules +6. View related log entries on any Lighting SObject flexipage by adding the 'Related Log Entries' component in App Builder +7. Dynamically assign tags to `Log__c` and `LogEntry__c` records for tagging/labeling your logs +8. Plugin framework: easily build or install plugins that enhance the `Log__c` and `LogEntry__c` objects, using Apex or Flow (not currently available in the managed package) +9. Event-Driven Integrations with [Platform Events](https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_intro.htm), an event-driven messaging architecture. External integrations can subscribe to log events using the `LogEntryEvent__e` object - see more details at [the Platform Events Developer Guide site](https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_subscribe_cometd.htm) Learn more about the design and history of the project on [Joys Of Apex blog post](https://www.joysofapex.com/advanced-logging-using-nebula-logger/) @@ -29,7 +30,7 @@ Learn more about the design and history of the project on [Joys Of Apex blog pos ## Installing -You can choose to install the unlocked package, you can deploy the metadata from this repo to your org, or you can install the managed package. The metadata is the same in all 3 options, but there are some differences in using the 3 versions. All examples in README are for the unlocked package/unpackaged metadata (no namespace) - simply add the `Nebula` namespace from the examples if you are using the managed package. +Nebula Logger is available as both an unlocked package and a managed package. The metadata is the same in both packages, but there are some differences in the available functionality & features. All examples in `README` are for the unlocked package (no namespace) - simply add the `Nebula` namespace to the examples if you are using the managed package. @@ -57,7 +58,7 @@ You can choose to install the unlocked package, you can deploy the metadata from - + @@ -65,14 +66,9 @@ You can choose to install the unlocked package, you can deploy the metadata from - - - - - - + @@ -85,7 +81,7 @@ You can choose to install the unlocked package, you can deploy the metadata from After deploying Nebula Logger to your org, there are a few additional configuration changes needed... - Assign permission set(s) to users - - `LoggerLogCreator` provides the minimum access needed for users to generate logs via Apex, Flow or Process Builder + - `LoggerLogCreator` provides the minimum access needed for users to generate logs via Apex, Lightning Components, Flow or Process Builder - `LoggerEndUser` provides access to generate logs, as well as read-only access to any log records shared with the user. - `LoggerLogViewer` provides view-all access (read-only) to all log records. This does **not** provide access to generate logs. - `LoggerAdmin` provides view-all and modify-all access to all log records. @@ -336,7 +332,7 @@ Logger.debug('my string').setRecord(currentUser); Logger.saveLog(); ``` -### Using LogMessage to Improve CPU Usage for String Formatting +### Using LogMessage for Dynamically-Generated Strings The class `LogMessage` provides the ability to generate string messages on demand, using `String.format()`. This provides 2 benefits: diff --git a/codecov.yml b/codecov.yml index ec7ad035d..a2af70631 100644 --- a/codecov.yml +++ b/codecov.yml @@ -8,3 +8,5 @@ coverage: threshold: 1% if_ci_failed: success patch: off +ignore: + - 'nebula-logger-recipes/**/*' diff --git a/config/pmd-ruleset.xml b/config/pmd-ruleset.xml new file mode 100644 index 000000000..05b5fbd0d --- /dev/null +++ b/config/pmd-ruleset.xml @@ -0,0 +1,45 @@ + + + + Nebula Logger custom PMD ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/project-scratch-def-with-experience-cloud.json b/config/project-scratch-def-with-experience-cloud.json index 6833a3b2a..ee976d02f 100644 --- a/config/project-scratch-def-with-experience-cloud.json +++ b/config/project-scratch-def-with-experience-cloud.json @@ -8,6 +8,11 @@ "settings": { "communitiesSettings": { "enableNetworksEnabled": true + }, + "userManagementSettings": { + "enableEnhancedPermsetMgmt": true, + "enableEnhancedProfileMgmt": true, + "enableNewProfileUI": true } } } diff --git a/config/project-scratch-def.json b/config/project-scratch-def.json index 099bfebc8..0741d0930 100644 --- a/config/project-scratch-def.json +++ b/config/project-scratch-def.json @@ -3,5 +3,12 @@ "edition": "Enterprise", "hasSampleData": true, "country": "US", - "language": "en_US" + "language": "en_US", + "settings": { + "userManagementSettings": { + "enableEnhancedPermsetMgmt": true, + "enableEnhancedProfileMgmt": true, + "enableNewProfileUI": true + } + } } diff --git a/content/btn-install-managed-package.png b/content/btn-install-managed-package.png index 6fc476cb7..1bdd87336 100644 Binary files a/content/btn-install-managed-package.png and b/content/btn-install-managed-package.png differ diff --git a/content/btn-install-unlocked-package.png b/content/btn-install-unlocked-package.png index b3409be54..42c4a31ba 100644 Binary files a/content/btn-install-unlocked-package.png and b/content/btn-install-unlocked-package.png differ diff --git a/content/btn-view-documentation.png b/content/btn-view-documentation.png index 475dd95a2..4bc989503 100644 Binary files a/content/btn-view-documentation.png and b/content/btn-view-documentation.png differ diff --git a/docs/index.md b/docs/index.md index 180dee055..a9eac67c6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,7 +8,7 @@ layout: default ### [ComponentLogger](logger-engine/ComponentLogger) -Controller class used by the light web component `c/logger` +Controller class used by the lightning web component `logger` ### [FlowCollectionLogEntry](logger-engine/FlowCollectionLogEntry) @@ -82,7 +82,7 @@ Handles trigger events for the `LoggerTag__c` object ### [RelatedLogEntriesController](log-management/RelatedLogEntriesController) -Controller class for the component RelatedLogEntries +Controller class for the lightning web component `related-log-entries` ## Plugin Framework diff --git a/docs/log-management/LogEntryEventHandler.md b/docs/log-management/LogEntryEventHandler.md index 856f0f64c..057413acf 100644 --- a/docs/log-management/LogEntryEventHandler.md +++ b/docs/log-management/LogEntryEventHandler.md @@ -8,14 +8,6 @@ Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__ --- -### Constructors - -#### `LogEntryEventHandler()` - -#### `LogEntryEventHandler(TriggerOperation triggerOperationType, List logEntryEvents)` - ---- - ### Properties #### `releaseNumber` → `String` @@ -26,9 +18,9 @@ Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__ ### Methods -#### `execute()` → `void` +#### `executeAfterInsert(List triggerNew)` → `void` -Runs the trigger handler's logic for the `LogEntryEvent__e` platform event object +#### `executeBeforeInsert(List triggerNew)` → `void` #### `getSObjectType()` → `SObjectType` diff --git a/docs/log-management/LogEntryHandler.md b/docs/log-management/LogEntryHandler.md index 78ea3a67a..fd6d88bc5 100644 --- a/docs/log-management/LogEntryHandler.md +++ b/docs/log-management/LogEntryHandler.md @@ -8,18 +8,8 @@ Manages setting fields on `LogEntry__c` before insert & before update --- -### Constructors - -#### `LogEntryHandler()` - ---- - ### Methods -#### `execute()` → `void` - -Runs the trigger handler's logic for the `LogEntry__c` custom object - #### `getSObjectType()` → `SObjectType` Returns SObject Type that the handler is responsible for processing diff --git a/docs/log-management/LogEntryTagHandler.md b/docs/log-management/LogEntryTagHandler.md index 140bbdbb2..af3e00228 100644 --- a/docs/log-management/LogEntryTagHandler.md +++ b/docs/log-management/LogEntryTagHandler.md @@ -10,10 +10,6 @@ Handles trigger events for the `LogEntryTag__c` object ### Methods -#### `execute()` → `void` - -Runs the trigger handler's logic for the `LogEntryTag__c` custom object - #### `getSObjectType()` → `SObjectType` Returns SObject Type that the handler is responsible for processing diff --git a/docs/log-management/LogHandler.md b/docs/log-management/LogHandler.md index ae7b6d6a2..2839d7944 100644 --- a/docs/log-management/LogHandler.md +++ b/docs/log-management/LogHandler.md @@ -8,18 +8,8 @@ Manages setting fields on `Log__c` before insert & before update --- -### Constructors - -#### `LogHandler()` - ---- - ### Methods -#### `execute()` → `void` - -Runs the trigger handler's logic for the `Log__c` custom object - #### `getSObjectType()` → `SObjectType` Returns SObject Type that the handler is responsible for processing diff --git a/docs/log-management/LoggerTagHandler.md b/docs/log-management/LoggerTagHandler.md index 56a8562a8..aa9ae07c3 100644 --- a/docs/log-management/LoggerTagHandler.md +++ b/docs/log-management/LoggerTagHandler.md @@ -10,10 +10,6 @@ Handles trigger events for the `LoggerTag__c` object ### Methods -#### `execute()` → `void` - -Runs the trigger handler's logic for the `LoggerTag__c` custom object - #### `getSObjectType()` → `SObjectType` Returns SObject Type that the handler is responsible for processing diff --git a/docs/log-management/RelatedLogEntriesController.md b/docs/log-management/RelatedLogEntriesController.md index bd3a7ef0c..81c2fcefa 100644 --- a/docs/log-management/RelatedLogEntriesController.md +++ b/docs/log-management/RelatedLogEntriesController.md @@ -4,7 +4,7 @@ layout: default ## RelatedLogEntriesController class -Controller class for the component RelatedLogEntries +Controller class for the lightning web component `related-log-entries` --- diff --git a/docs/logger-engine/ComponentLogger.md b/docs/logger-engine/ComponentLogger.md index adf635eeb..0cedf4391 100644 --- a/docs/logger-engine/ComponentLogger.md +++ b/docs/logger-engine/ComponentLogger.md @@ -4,7 +4,7 @@ layout: default ## ComponentLogger class -Controller class used by the light web component `c/logger` +Controller class used by the lightning web component `logger` ### Related diff --git a/extra-tests/classes/ExampleInboundEmailHandler.cls b/extra-tests/classes/ExampleInboundEmailHandler.cls new file mode 100644 index 000000000..d22af4758 --- /dev/null +++ b/extra-tests/classes/ExampleInboundEmailHandler.cls @@ -0,0 +1,21 @@ +global with sharing class ExampleInboundEmailHandler implements Messaging.InboundEmailHandler { + @TestVisible + private static String logEntryMessage = 'Testing logging from InboundEmailHandler'; + + global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope env) { + Messaging.InboundEmailResult result = new Messaging.InboundEmailResult(); + try { + String nullString = null; + nullString.length(); + } catch (Exception apexException) { + Logger.error(logEntryMessage, apexException); + } finally { + result.success = true; + System.debug(LoggingLevel.DEBUG, 'Logger buffer size before save: ' + Logger.getBufferSize()); + Logger.saveLog(); + System.debug(LoggingLevel.DEBUG, 'Logger buffer size after save: ' + Logger.getBufferSize()); + } + + return result; + } +} diff --git a/extra-tests/classes/ExampleInboundEmailHandler.cls-meta.xml b/extra-tests/classes/ExampleInboundEmailHandler.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/classes/ExampleInboundEmailHandler.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/flows/LogEntryHandler_Screen_Tests_for_Flow.flow-meta.xml b/extra-tests/flows/LogEntryHandler_Screen_Tests_for_Flow.flow-meta.xml new file mode 100644 index 000000000..ea594c18b --- /dev/null +++ b/extra-tests/flows/LogEntryHandler_Screen_Tests_for_Flow.flow-meta.xml @@ -0,0 +1,168 @@ + + + + Log_after_screen + + 176 + 518 + FlowLogEntry + apex + Automatic + + loggingLevelName + + INFO + + + + saveLog + + true + + + + tagsString + + screen-flow + + + + flowName + + LogEntryHandler_Screen_Tests_for_Flow + + + + message + + finished screen, end of flow + + + true + + + Log_before_screen + + 176 + 278 + FlowRecordLogEntry + apex + + Example_Flow_Screen + + + T__record + User + + Automatic + + loggingLevelName + + INFO + + + + tagsString + + screen-flow + + + + flowName + + LogEntryHandler_Screen_Tests_for_Flow + + + + message + + loaded current user's record, screen is next + + + + record + + Get_Current_User + + + true + + 52.0 + A screen Flow used to help test the Apex class LogEntryHandler + LogEntryHandler Screen Tests for Flow {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + Flow + + Get_Current_User + + 176 + 158 + false + + Log_before_screen + + and + + Id + EqualTo + + $User.Id + + + true + User + true + + SystemModeWithSharing + + Example_Flow_Screen + + 176 + 398 + true + true + true + + Log_after_screen + + + ObjectProvided + false + Get_Current_User.Department + + + ObjectProvided + false + Get_Current_User.AboutMe + + <p>Are you sure you want to pause this Flow?!</p> + true + true + + + 50 + 0 + + Get_Current_User + + + Active + diff --git a/extra-tests/flows/LogEntryHandler_Tests_Flow.flow-meta.xml b/extra-tests/flows/LogEntryHandler_Tests_Flow.flow-meta.xml new file mode 100644 index 000000000..3b5abbaee --- /dev/null +++ b/extra-tests/flows/LogEntryHandler_Tests_Flow.flow-meta.xml @@ -0,0 +1,110 @@ + + + + Log_Current_User + + 176 + 278 + FlowRecordLogEntry + apex + + T__record + User + + CurrentTransaction + + loggingLevelName + + INFO + + + + saveLog + + true + + + + tagsString + + example flow, some other tag + + + + flowName + + LogEntryHandler_Tests_Flow + + + + message + + Example of logging a User record + + + + record + + Get_Current_User + + + true + + 50.0 + An auto-launched Flow used to help test the Apex class LogEntryHandler + LogEntryHandler_Tests_Flow {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + Get_Current_User + + 176 + 158 + false + + Log_Current_User + + and + + Id + EqualTo + + $User.Id + + + true + User + Id + Username + Email + LanguageLocaleKey + true + + DefaultMode + + 50 + 0 + + Get_Current_User + + + Active + diff --git a/extra-tests/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml b/extra-tests/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml new file mode 100644 index 000000000..026b4beda --- /dev/null +++ b/extra-tests/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml @@ -0,0 +1,91 @@ + + + + Log_Organization_Record + + 176 + 276 + FlowRecordLogEntry + apex + + T__record + Organization + + CurrentTransaction + + loggingLevelName + + INFO + + + + saveLog + + true + + + + tagsString + + scheduled flow + + + + flowName + + LogEntryHandler_Tests_Scheduled_Flow + + + + message + + logging something from within a scheduled flow + + + + record + + $Record + + + true + + 52.0 + A scheduled Flow used in tests to verify that LogEntryHandler automatically logs details about the Flow (metadata data) + LogEntryHandler_Tests_Scheduled_Flow {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + 50 + 0 + + Log_Organization_Record + + Organization + + Daily + 2021-08-01 + 00:00:00.000Z + + Scheduled + + Draft + diff --git a/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml b/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml new file mode 100644 index 000000000..dafdf52ac --- /dev/null +++ b/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml @@ -0,0 +1,213 @@ + + + + Log_user_after_updating + + 176 + 638 + FlowRecordLogEntry + apex + + T__record + User + + CurrentTransaction + + loggingLevelName + + INFO + + + + saveLog + + true + + + + tagsString + + flow tag + + + + flowName + + LogHandler_Tests_Flow + + + + message + + Logging user after updating + + + + record + + Get_current_user + + + true + + + Log_user_before_updating + + 176 + 278 + FlowRecordLogEntry + apex + + Update_user_s_first_name + + + T__record + User + + CurrentTransaction + + loggingLevelName + + INFO + + + + tagsString + + flow tag + + + + flowName + + LogHandler_Tests_Flow + + + + message + + Logging user before updating + + + + record + + Get_current_user + + + true + + 49.0 + + Update_user_s_first_name + + 176 + 398 + + Get_current_user.FirstName + Assign + + Logger-Flow-Test + + + + Save_current_user + + + An additional Flow used test dynamically running Flow plugins from LoggerSObjectHandler + LogHandler_Tests_Flow {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + Get_current_user + + 176 + 158 + false + + Log_user_before_updating + + and + + Id + EqualTo + + $User.Id + + + true + User + true + + + Save_current_user + + 176 + 518 + + Log_user_after_updating + + Get_current_user + + DefaultMode + + 50 + 0 + + Get_current_user + + + Active + + Used by test class to verify that the Flow ran successfully + ranSuccessfully + Boolean + false + false + true + + false + + + + records + SObject + true + true + false + Log__c + + + triggerOld + SObject + true + true + false + Log__c + + + triggerOperationType + String + false + true + false + + diff --git a/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls b/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls new file mode 100644 index 000000000..723b973f4 --- /dev/null +++ b/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@IsTest +private class LogEntryEventBuilder_IntegrationTests { + @IsTest + static void it_should_strip_inaccessible_fields_for_record_when_enabled() { + User standardUser = LoggerTestUtils.createStandardUser(); + AccountBrand mockAccountBrand = new AccountBrand( + Id = LoggerTestUtils.createMockId(Schema.AccountBrand.SObjectType), + CompanyName = 'Some Company, Inc.', + Email = 'some.one@some.company.com', + Name = 'Something', + Phone = '510-555-1234' + ); + // The 'standard user' profile doesn't have access to AccountBrand, + // so stripAccessible will remove everything except the ID field + AccountBrand strippedAccountBrand = new AccountBrand(Id = mockAccountBrand.Id); + + LogEntryEventBuilder builder; + System.runAs(standardUser) { + System.assertEquals(false, Schema.AccountBrand.SObjectType.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.CompanyName.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Email.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Name.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Phone.getDescribe().isAccessible()); + + Logger.getUserSettings().StripInaccessibleRecordFields__c = true; + builder = new LogEntryEventBuilder(LoggingLevel.INFO, true).setRecord(mockAccountBrand); + } + + System.assertNotEquals(JSON.serializePretty(mockAccountBrand), builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(strippedAccountBrand), builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_strip_inaccessible_fields_for_records_when_enabled() { + User standardUser = LoggerTestUtils.createStandardUser(); + List mockAccountBrands = new List(); + List strippedAccountBrands = new List(); + for (Integer i = 0; i < 5; i++) { + AccountBrand mockAccountBrand = new AccountBrand( + Id = LoggerTestUtils.createMockId(Schema.AccountBrand.SObjectType), + CompanyName = 'Some Company, Inc.', + Email = 'some.one.number_' + i + '@some.company.com', + Name = 'Something', + Phone = '510-555-1234' + ); + mockAccountBrands.add(mockAccountBrand); + + // The 'standard user' profile doesn't have access to AccountBrand, + // so stripAccessible will remove everything except the ID field + AccountBrand strippedAccountBrand = new AccountBrand(Id = mockAccountBrand.Id); + strippedAccountBrands.add(strippedAccountBrand); + } + + LogEntryEventBuilder builder; + System.runAs(standardUser) { + System.assertEquals(false, Schema.AccountBrand.SObjectType.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.CompanyName.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Email.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Name.getDescribe().isAccessible()); + System.assertEquals(false, Schema.AccountBrand.Phone.getDescribe().isAccessible()); + + Logger.getUserSettings().StripInaccessibleRecordFields__c = true; + builder = new LogEntryEventBuilder(LoggingLevel.INFO, true).setRecord(mockAccountBrands); + } + + System.assertNotEquals(JSON.serializePretty(mockAccountBrands), builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(strippedAccountBrands), builder.getLogEntryEvent().RecordJson__c); + } +} diff --git a/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls-meta.xml b/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/LogEntryEventBuilder_IntegrationTests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/tests/LogEntryHandler_Tests_Flow.cls b/extra-tests/tests/LogEntryHandler_Tests_Flow.cls new file mode 100644 index 000000000..04130c890 --- /dev/null +++ b/extra-tests/tests/LogEntryHandler_Tests_Flow.cls @@ -0,0 +1,92 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@IsTest +private class LogEntryHandler_Tests_Flow { + private static final String EXAMPLE_FLOW_API_NAME = 'LogEntryHandler_Tests_Flow'; + + @IsTest + static void it_should_set_skip_setting_flow_details_when_origin_location_is_null() { + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = null, OriginType__c = 'Flow'); + insert logEntry; + logEntry = getLogEntry(); + + System.assertEquals(null, logEntry.OriginLocation__c); + System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(null, logEntry.FlowActiveVersionId__c); + System.assertEquals(null, logEntry.FlowDescription__c); + System.assertEquals(null, logEntry.FlowDurableId__c); + System.assertEquals(null, logEntry.FlowLabel__c); + System.assertEquals(null, logEntry.FlowLastModifiedByName__c); + System.assertEquals(null, logEntry.FlowLastModifiedDate__c); + System.assertEquals(null, logEntry.FlowProcessType__c); + System.assertEquals(null, logEntry.FlowTriggerType__c); + System.assertEquals(null, logEntry.FlowVersionApiVersionRuntime__c); + System.assertEquals(null, logEntry.FlowVersionNumber__c); + System.assertEquals(null, logEntry.FlowVersionRunInMode__c); + } + + @IsTest + static void it_should_set_flow_details() { + FlowDefinitionView flowDefinition = getFlowDefinition(); + FlowVersionView flowVersion = getFlowVersion(flowDefinition.ActiveVersionId); + + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = flowDefinition.ApiName, OriginType__c = 'Flow'); + insert logEntry; + logEntry = getLogEntry(); + + System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(flowDefinition.ActiveVersionId, logEntry.FlowActiveVersionId__c); + System.assertEquals(flowDefinition.Description, logEntry.FlowDescription__c); + System.assertEquals(flowDefinition.DurableId, logEntry.FlowDurableId__c); + System.assertEquals(flowDefinition.Label, logEntry.FlowLabel__c); + System.assertEquals(flowDefinition.LastModifiedBy, logEntry.FlowLastModifiedByName__c); + System.assertEquals(flowDefinition.LastModifiedDate, logEntry.FlowLastModifiedDate__c); + System.assertEquals(flowDefinition.ProcessType, logEntry.FlowProcessType__c); + System.assertEquals(flowDefinition.TriggerType, logEntry.FlowTriggerType__c); + System.assertEquals('v' + flowVersion.ApiVersionRuntime + '.0', logEntry.FlowVersionApiVersionRuntime__c); + System.assertEquals(flowVersion.RunInMode, logEntry.FlowVersionRunInMode__c); + System.assertEquals(flowVersion.VersionNumber, logEntry.FlowVersionNumber__c); + } + + private static LogEntry__c getLogEntry() { + return [ + SELECT + FlowActiveVersionId__c, + FlowDescription__c, + FlowDurableId__c, + FlowLabel__c, + FlowLastModifiedByName__c, + FlowLastModifiedDate__c, + FlowProcessType__c, + FlowTriggerType__c, + FlowVersionApiVersionRuntime__c, + FlowVersionNumber__c, + FlowVersionRunInMode__c, + OriginLocation__c, + OriginType__c + FROM LogEntry__c + // WHERE OriginType__c = 'Flow' + ORDER BY CreatedDate + LIMIT 1 + ]; + } + + private static FlowDefinitionView getFlowDefinition() { + return [ + SELECT ActiveVersionId, ApiName, Description, DurableId, Label, LastModifiedBy, LastModifiedDate, ManageableState, ProcessType, TriggerType + FROM FlowDefinitionView + WHERE ApiName = :EXAMPLE_FLOW_API_NAME AND IsActive = TRUE + ]; + } + + private static FlowVersionView getFlowVersion(Id flowActiveVersionId) { + return [SELECT ApiVersionRuntime, FlowDefinitionViewId, RunInMode, Status, VersionNumber FROM FlowVersionView WHERE DurableId = :flowActiveVersionId]; + } +} diff --git a/extra-tests/tests/LogEntryHandler_Tests_Flow.cls-meta.xml b/extra-tests/tests/LogEntryHandler_Tests_Flow.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/LogEntryHandler_Tests_Flow.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/tests/LogHandler_Tests_Flow.cls b/extra-tests/tests/LogHandler_Tests_Flow.cls new file mode 100644 index 000000000..2883b114c --- /dev/null +++ b/extra-tests/tests/LogHandler_Tests_Flow.cls @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@IsTest +private class LogHandler_Tests_Flow { + @IsTest + static void it_should_run_flow_plugin_when_configured() { + // Assumption: the Flow LogHandler_Tests_Flow makes an update to the current user's FirstName + // The specific action within the Flow isn't that important - we just want to make sure... + // ...that that Flow is dynamically executed + String pluginFlowApiName = 'LogHandler_Tests_Flow'; + String expectedUserFirstName = 'Logger-Flow-Test'; + System.assertNotEquals(expectedUserFirstName, UserInfo.getFirstName()); + + Test.startTest(); + + // Use the mock configurations + LoggerSObjectHandlerPlugin__mdt plugin = new LoggerSObjectHandlerPlugin__mdt(PluginType__c = 'Flow', PluginApiName__c = pluginFlowApiName); + LoggerSObjectHandler.setMockPlugin(Schema.Log__c.SObjectType, plugin); + + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + + Test.stopTest(); + + // Verify that the Flow ran by checking if the user's FirstName was updated + User currentUser = [SELECT Id, FirstName FROM User WHERE Id = :UserInfo.getUserId()]; + System.assertEquals(expectedUserFirstName, currentUser.FirstName); + } +} diff --git a/extra-tests/tests/LogHandler_Tests_Flow.cls-meta.xml b/extra-tests/tests/LogHandler_Tests_Flow.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/LogHandler_Tests_Flow.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/tests/Logger_Tests_ExperienceSite.cls b/extra-tests/tests/Logger_Tests_ExperienceSite.cls new file mode 100644 index 000000000..208c77653 --- /dev/null +++ b/extra-tests/tests/Logger_Tests_ExperienceSite.cls @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Extra Tests + * @description Additional integration tests for orgs with Experience Sites (Communities) enabled + */ +@IsTest +private class Logger_Tests_ExperienceSite { + private static final String GUEST_USER_PROFILE_NAME = 'Logger Test Site Profile'; + private static final String LOG_CREATOR_PERMISSION_SET_NAME = 'LoggerLogCreator'; + + @TestSetup + static void setupData() { + Profile loggerSiteProfile = [SELECT Id, UserLicense.Name FROM Profile WHERE Name = :GUEST_USER_PROFILE_NAME]; + System.assertEquals('Guest User License', loggerSiteProfile.UserLicense.Name); + + User guestUser = [SELECT Id FROM USER WHERE Profile.NAME = :GUEST_USER_PROFILE_NAME]; + + PermissionSet logCreatorPermissionSet = [SELECT Id, Name FROM PermissionSet WHERE Name = :LOG_CREATOR_PERMISSION_SET_NAME]; + PermissionSetAssignment permissionSetAssignment = new PermissionSetAssignment(AssigneeId = guestUser.Id, PermissionSetId = logCreatorPermissionSet.Id); + insert permissionSetAssignment; + } + + @IsTest + private static void it_should_fail_to_save_log_when_assigned_to_guest_user() { + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + + Test.startTest(); + + User guestUser = [SELECT Id FROM USER WHERE Profile.NAME = :GUEST_USER_PROFILE_NAME]; + try { + log.OwnerId = guestUser.Id; + update log; + System.assert(false, 'Expected exception, this exception should not occur'); + } catch (Exception ex) { + String expectedExceptionMessage = 'FIELD_INTEGRITY_EXCEPTION, field integrity exception (Guest users cannot be record owners.)'; + System.assert(ex.getMessage().contains(expectedExceptionMessage)); + } + Test.stopTest(); + } + + @IsTest + private static void it_should_save_log_for_guest_user() { + Profile loggerSiteProfile = [SELECT Id, UserLicense.Name FROM Profile WHERE Name = :GUEST_USER_PROFILE_NAME]; + System.assertEquals('Guest User License', loggerSiteProfile.UserLicense.Name); + + User guestUser = [SELECT Id FROM USER WHERE Profile.NAME = :GUEST_USER_PROFILE_NAME]; + String message = 'testing logging as a guest user'; + + System.runAs(guestUser) { + Logger.debug(message); + Logger.saveLog(); + + Test.getEventBus().deliver(); + } + + LogEntry__c logEntry = [SELECT Id, Log__r.LoggedBy__c, Log__r.OwnerId, Log__r.UserLicenseDefinitionKey__c, Message__c FROM LogEntry__c]; + System.assertEquals(guestUser.Id, logEntry.Log__r.LoggedBy__c); + System.assertNotEquals(guestUser.Id, logEntry.Log__r.OwnerId); + System.assertEquals('PID_Guest_User', logEntry.Log__r.UserLicenseDefinitionKey__c); + System.assertEquals(message, logEntry.Message__c); + } +} diff --git a/extra-tests/tests/Logger_Tests_ExperienceSite.cls-meta.xml b/extra-tests/tests/Logger_Tests_ExperienceSite.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/Logger_Tests_ExperienceSite.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls b/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls new file mode 100644 index 000000000..a7c549bfe --- /dev/null +++ b/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Extra Tests + * @description Additional integration tests for logging from an instance of `Messaging.InboundEmailHandler` + */ +@IsTest +private class Logger_Tests_InboundEmailHandler { + @IsTest + private static void it_should_save_logs_when_running_email_service() { + // Create a new email and envelope object + Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope(); + + // Create the email body + Messaging.InboundEmail email = new Messaging.InboundEmail(); + email.plainTextBody = 'Example email content'; + email.fromAddress = 'test@test.com'; + email.subject = 'My example email'; + + // Create an instance of the example handler class + ExampleInboundEmailHandler handler = new ExampleInboundEmailHandler(); + + Test.startTest(); + + String transactionId = Logger.getTransactionId(); + Messaging.InboundEmailResult result = handler.handleInboundEmail(email, envelope); + + Test.stopTest(); + + System.assert(result.success, 'InboundEmailResult returned a failure message'); + + List logs = [SELECT Id, TransactionId__c FROM Log__c]; + System.assertEquals(1, logs.size()); + System.assertEquals(transactionId, logs.get(0).TransactionId__c); + + List logEntries = [SELECT Id, Message__c FROM LogEntry__c]; + System.assertEquals(1, logEntries.size()); + System.assertEquals(ExampleInboundEmailHandler.logEntryMessage, logEntries.get(0).Message__c); + } +} diff --git a/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls-meta.xml b/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/extra-tests/tests/Logger_Tests_MergeResult.cls b/extra-tests/tests/Logger_Tests_MergeResult.cls new file mode 100644 index 000000000..47bb9ae5e --- /dev/null +++ b/extra-tests/tests/Logger_Tests_MergeResult.cls @@ -0,0 +1,728 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Extra Tests + * @description Additional integration tests for merging records. + * Since merging is only supported on some standard objects, there's not a good way to test merging... + * ...from within the normal tests, and each org might have additional required fields, VR, etc on the std objects + */ +@IsTest +private class Logger_Tests_MergeResult { + static String getMessage() { + return 'Hello, world'; + } + + static LogMessage getLogMessage() { + return new LogMessage('The current date is {0}', System.today()); + } + + static Database.MergeResult getMergeResult() { + Account mainAccount = new Account(Name = 'Main'); + Account duplicateAccount = new Account(Name = 'Duplicate'); + List accounts = new List{ mainAccount, duplicateAccount }; + insert accounts; + + Database.MergeResult mergeResult = Database.merge(mainAccount, duplicateAccount); + return mergeResult; + } + + static List getMergeResultList() { + return new List{ getMergeResult() }; + } + + @IsTest + static void it_should_add_an_error_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.ERROR; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.error(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_error_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.ERROR; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.error(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_error_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.ERROR; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.error(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_error_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.ERROR; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.error(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_warn_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.WARN; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.warn(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_warn_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.WARN; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.warn(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_warn_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.WARN; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.warn(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_warn_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.WARN; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.warn(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_info_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.INFO; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.info(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_info_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.INFO; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.info(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_info_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.INFO; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.info(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_info_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.INFO; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.info(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_debug_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.DEBUG; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.debug(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_debug_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.DEBUG; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.debug(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_debug_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.DEBUG; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.debug(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_debug_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.DEBUG; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.debug(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_fine_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINE; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.fine(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_fine_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINE; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.fine(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_fine_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINE; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.fine(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_fine_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINE; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.fine(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finer_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINER; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finer(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finer_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINER; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finer(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finer_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINER; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finer(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finer_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINER; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finer(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finest_entry_for_logMessage_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINEST; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finest(getLogMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finest_entry_for_logMessage_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINEST; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finest(getLogMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getLogMessage().getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finest_entry_for_string_message_with_mergeResult() { + LoggingLevel loggingLevel = LoggingLevel.FINEST; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + Database.MergeResult mergeResult = getMergeResult(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finest(getMessage(), mergeResult); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(mergeResult.getId(), entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('Single', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResult), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } + + @IsTest + static void it_should_add_an_finest_entry_for_string_message_with_mergeResultList() { + LoggingLevel loggingLevel = LoggingLevel.FINEST; + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + System.assertEquals(0, Logger.getBufferSize()); + + List mergeResults = getMergeResultList(); + + Test.startTest(); + + LogEntryEventBuilder entryBuilder = Logger.finest(getMessage(), mergeResults); + + Test.stopTest(); + + System.assertEquals(1, Logger.getBufferSize()); + System.assertEquals(loggingLevel.name(), entryBuilder.getLogEntryEvent().LoggingLevel__c); + System.assertEquals(getMessage(), entryBuilder.getLogEntryEvent().Message__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordId__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().RecordJson__c); + System.assertEquals('List', entryBuilder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(mergeResults), entryBuilder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), entryBuilder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(null, entryBuilder.getLogEntryEvent().Tags__c); + } +} diff --git a/extra-tests/tests/Logger_Tests_MergeResult.cls-meta.xml b/extra-tests/tests/Logger_Tests_MergeResult.cls-meta.xml new file mode 100644 index 000000000..f8e5ab635 --- /dev/null +++ b/extra-tests/tests/Logger_Tests_MergeResult.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/nebula-logger-plugins/Slack/.content/btn-install-unlocked-package-plugin.png b/nebula-logger-plugins/Slack/.content/btn-install-unlocked-package-plugin.png new file mode 100644 index 000000000..9c3bbf6a8 Binary files /dev/null and b/nebula-logger-plugins/Slack/.content/btn-install-unlocked-package-plugin.png differ diff --git a/content/slack-plugin-configuration.png b/nebula-logger-plugins/Slack/.content/slack-plugin-configuration.png similarity index 100% rename from content/slack-plugin-configuration.png rename to nebula-logger-plugins/Slack/.content/slack-plugin-configuration.png diff --git a/content/slack-plugin-notification.png b/nebula-logger-plugins/Slack/.content/slack-plugin-notification.png similarity index 100% rename from content/slack-plugin-notification.png rename to nebula-logger-plugins/Slack/.content/slack-plugin-notification.png diff --git a/nebula-logger-plugins/Slack/README.md b/nebula-logger-plugins/Slack/README.md index e83905678..c15907dea 100644 --- a/nebula-logger-plugins/Slack/README.md +++ b/nebula-logger-plugins/Slack/README.md @@ -1,10 +1,10 @@ # Slack plugin for Nebula Logger -Adds a Slack integration for Nebula Logger. Any logs with log entries that meet a certain (configurable) logging level will automatically be posted to your Slack channel via an asynchronous `Queueable` job. +Adds a Slack integration for the unlocked package edition of Nebula Logger. Any logs with log entries that meet a certain (configurable) logging level will automatically be posted to your Slack channel via an asynchronous `Queueable` job. -[![Install Unlocked Package](./../../content/btn-install-unlocked-package.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5e00000065xiAAA) +[![Install Unlocked Package](./.content/btn-install-unlocked-package-plugin.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5e00000065xiAAA) -![Slack plugin: notification](./../../content/slack-plugin-notification.png) +![Slack plugin: notification](./.content/slack-plugin-notification.png) --- @@ -46,4 +46,4 @@ Check out [Slack's webhooks documentation](https://api.slack.com/messaging/webho The Slack integration should now be setup & working - any new logs that meet the specified notification logging level (step 6 above) will send a Slack notification. -![Slack plugin: configuration](./../../content/slack-plugin-configuration.png) +![Slack plugin: configuration](./.content/slack-plugin-configuration.png) diff --git a/nebula-logger-plugins/Slack/classes/SlackLoggerPlugin.cls b/nebula-logger-plugins/Slack/classes/SlackLoggerPlugin.cls index 9d5855d20..acdd07de2 100644 --- a/nebula-logger-plugins/Slack/classes/SlackLoggerPlugin.cls +++ b/nebula-logger-plugins/Slack/classes/SlackLoggerPlugin.cls @@ -13,6 +13,8 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi @TestVisible private static LoggingLevel notificationLoggingLevel; + private List logs; + static { endpoint = LoggerParameter.Plugin.getString('SlackEndpoint'); @@ -20,8 +22,6 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi notificationLoggingLevel = Logger.getLoggingLevel(notificationLoggingLevelName); } - private List logs; - // Constructors public SlackLoggerPlugin() { } @@ -78,8 +78,8 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi request.setBody(notificationJson); HttpResponse response = new Http().send(request); - System.debug('response.getStatusCode()==' + response.getStatusCode()); - System.debug('response.getStatus()==' + response.getStatus()); + System.debug(notificationLoggingLevel, 'response.getStatusCode()==' + response.getStatusCode()); + System.debug(notificationLoggingLevel, 'response.getStatus()==' + response.getStatus()); log.SlackNotificationDate__c = System.now(); sentLogs.add(log); @@ -163,7 +163,7 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi } private HttpRequest createSlackHttpRequest() { - System.debug('endpoint==' + endpoint); + System.debug(notificationLoggingLevel, 'endpoint==' + endpoint); HttpRequest request = new HttpRequest(); request.setEndpoint(endpoint); diff --git a/nebula-logger-recipes/main/default/applications/LoggerRecipes.app-meta.xml b/nebula-logger-recipes/main/default/applications/LoggerRecipes.app-meta.xml index a74e329cb..bfca8c11b 100644 --- a/nebula-logger-recipes/main/default/applications/LoggerRecipes.app-meta.xml +++ b/nebula-logger-recipes/main/default/applications/LoggerRecipes.app-meta.xml @@ -1,4 +1,4 @@ - + #F47536 diff --git a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.cmp-meta.xml b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.cmp-meta.xml index e06e82b11..1962ba343 100644 --- a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.cmp-meta.xml +++ b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.cmp-meta.xml @@ -2,4 +2,4 @@ 52.0 A Lightning Component Bundle - \ No newline at end of file + diff --git a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.css b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.css index 3e4fb7d94..6567260ea 100644 --- a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.css +++ b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemo.css @@ -1,4 +1,4 @@ .THIS { background-color: white; padding: 10px; -} \ No newline at end of file +} diff --git a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemoController.js b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemoController.js index d077d15ce..daa1b91fc 100644 --- a/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemoController.js +++ b/nebula-logger-recipes/main/default/aura/loggerAuraDemo/loggerAuraDemoController.js @@ -1,6 +1,6 @@ ({ - saveLogExample : function(component, event, helper) { - console.log('start of aura cmp\'s saveLog function'); + saveLogExample: function (component) { + console.log("start of aura cmp's saveLog function"); const logger = component.find('logger'); console.log(logger); @@ -9,4 +9,4 @@ console.log('stack==' + entry.stack); logger.saveLog(); } -}) +}); diff --git a/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls b/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls index 17bffc808..7c34b9876 100644 --- a/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls +++ b/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls @@ -41,4 +41,4 @@ public with sharing class Account_Batch_Logger_Example implements Database.Batch Logger.info('Finishing running Account_Batch_Logger_Example'); Logger.saveLog(); } -} \ No newline at end of file +} diff --git a/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls-meta.xml b/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls-meta.xml +++ b/nebula-logger-recipes/main/default/classes/Account_Batch_Logger_Example.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls b/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls index d91e28eac..5e5a734bb 100644 --- a/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls +++ b/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls @@ -35,4 +35,4 @@ public with sharing class Account_Queueable_Logger_Example implements Queueable System.enqueueJob(new Account_Queueable_Logger_Example(this.numberOfJobsToChain, parentLogTransactionId)); } } -} \ No newline at end of file +} diff --git a/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls-meta.xml b/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls-meta.xml +++ b/nebula-logger-recipes/main/default/classes/Account_Queueable_Logger_Example.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger-recipes/main/default/classes/ExampleInboundEmailHandler.cls b/nebula-logger-recipes/main/default/classes/ExampleInboundEmailHandler.cls index 5de406112..d22af4758 100644 --- a/nebula-logger-recipes/main/default/classes/ExampleInboundEmailHandler.cls +++ b/nebula-logger-recipes/main/default/classes/ExampleInboundEmailHandler.cls @@ -11,9 +11,9 @@ global with sharing class ExampleInboundEmailHandler implements Messaging.Inboun Logger.error(logEntryMessage, apexException); } finally { result.success = true; - System.debug('Logger buffer size before save: ' + Logger.getBufferSize()); + System.debug(LoggingLevel.DEBUG, 'Logger buffer size before save: ' + Logger.getBufferSize()); Logger.saveLog(); - System.debug('Logger buffer size after save: ' + Logger.getBufferSize()); + System.debug(LoggingLevel.DEBUG, 'Logger buffer size after save: ' + Logger.getBufferSize()); } return result; diff --git a/nebula-logger-recipes/main/default/flexipages/Logger_Recipes_UtilityBar.flexipage-meta.xml b/nebula-logger-recipes/main/default/flexipages/Logger_Recipes_UtilityBar.flexipage-meta.xml index 0b7f20af2..753437a41 100644 --- a/nebula-logger-recipes/main/default/flexipages/Logger_Recipes_UtilityBar.flexipage-meta.xml +++ b/nebula-logger-recipes/main/default/flexipages/Logger_Recipes_UtilityBar.flexipage-meta.xml @@ -1,4 +1,4 @@ - + utilityItems diff --git a/nebula-logger-recipes/main/default/flows/Account_Flow_Logger_Example.flow-meta.xml b/nebula-logger-recipes/main/default/flows/Account_Flow_Logger_Example.flow-meta.xml index fac3b0636..c03addb27 100644 --- a/nebula-logger-recipes/main/default/flows/Account_Flow_Logger_Example.flow-meta.xml +++ b/nebula-logger-recipes/main/default/flows/Account_Flow_Logger_Example.flow-meta.xml @@ -1,4 +1,4 @@ - + Logs the account again after the field assignment has made changes to the account @@ -106,7 +106,9 @@ Account_Process_Logger_Example - An example process to demo logging Account records in Flow + An example process to demo logging Account records in Flow. + +As an additional test, this Flow also has a really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really, really long description. Account_Flow_Logger_Example {!$Flow.CurrentDateTime} diff --git a/nebula-logger-recipes/main/default/flows/Account_Process_Logger_Example.flow-meta.xml b/nebula-logger-recipes/main/default/flows/Account_Process_Logger_Example.flow-meta.xml index e7511af66..2149326a4 100644 --- a/nebula-logger-recipes/main/default/flows/Account_Process_Logger_Example.flow-meta.xml +++ b/nebula-logger-recipes/main/default/flows/Account_Process_Logger_Example.flow-meta.xml @@ -1,4 +1,4 @@ - + @@ -45,7 +45,7 @@ objectType - + @@ -87,7 +87,7 @@ objectType - + @@ -129,7 +129,7 @@ objectType - + @@ -171,7 +171,7 @@ objectType - + @@ -297,7 +297,7 @@ objectType - + @@ -339,7 +339,7 @@ objectType - + @@ -552,7 +552,7 @@ leftHandSideReferenceTo - + @@ -633,7 +633,7 @@ leftHandSideReferenceTo - + diff --git a/nebula-logger-recipes/main/default/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml b/nebula-logger-recipes/main/default/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml index b30e17e93..026b4beda 100644 --- a/nebula-logger-recipes/main/default/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml +++ b/nebula-logger-recipes/main/default/flows/LogEntryHandler_Tests_Scheduled_Flow.flow-meta.xml @@ -1,4 +1,4 @@ - + Log_Organization_Record diff --git a/nebula-logger-recipes/main/default/lwc/jsconfig.json b/nebula-logger-recipes/main/default/lwc/jsconfig.json index c613acd4b..a72666d71 100644 --- a/nebula-logger-recipes/main/default/lwc/jsconfig.json +++ b/nebula-logger-recipes/main/default/lwc/jsconfig.json @@ -2,18 +2,11 @@ "compilerOptions": { "experimentalDecorators": true }, - "include": [ - "**/*", - "../../../../.sfdx/typings/lwc/**/*.d.ts" - ], + "include": ["**/*", "../../../../.sfdx/typings/lwc/**/*.d.ts"], "paths": { - "c/*": [ - "*" - ] + "c/*": ["*"] }, "typeAcquisition": { - "include": [ - "jest" - ] + "include": ["jest"] } } diff --git a/nebula-logger-recipes/main/default/lwc/loggerLWCDemo/loggerLWCDemo.js b/nebula-logger-recipes/main/default/lwc/loggerLWCDemo/loggerLWCDemo.js index c58e61167..d74037571 100644 --- a/nebula-logger-recipes/main/default/lwc/loggerLWCDemo/loggerLWCDemo.js +++ b/nebula-logger-recipes/main/default/lwc/loggerLWCDemo/loggerLWCDemo.js @@ -7,7 +7,7 @@ import { LightningElement } from 'lwc'; const LOGGER_NAME = 'c-logger'; -export default class loggerLWCDemo extends LightningElement { +export default class LoggerLWCDemo extends LightningElement { message = 'Hello, world!'; tagsString = 'Tag-one, Another tag here'; @@ -23,12 +23,7 @@ export default class loggerLWCDemo extends LightningElement { console.log('running logError for btn'); const logger = this.template.querySelector(LOGGER_NAME); console.log(logger); - let someError; - try { - missingVariable / 0; - } catch(e) { - someError = e; - } + const someError = new TypeError('oops'); const entry = logger.error(this.message).setError(someError).addTag('lwc logging demo'); console.log('stack==' + entry.stack); } diff --git a/nebula-logger-recipes/main/default/profiles/Admin.profile-meta.xml b/nebula-logger-recipes/main/default/profiles/Admin.profile-meta.xml index 7df0654af..a35475bc2 100644 --- a/nebula-logger-recipes/main/default/profiles/Admin.profile-meta.xml +++ b/nebula-logger-recipes/main/default/profiles/Admin.profile-meta.xml @@ -215,605 +215,625 @@ true false + + false + LogEntryDataMaskRule__mdt.ApplyToMessage__c + true + + + false + LogEntryDataMaskRule__mdt.ApplyToRecordJson__c + true + + + false + LogEntryDataMaskRule__mdt.IsEnabled__c + true + false LogEntryEvent__e.ApiVersion__c - false + true false LogEntryEvent__e.ComponentType__c - false + true false LogEntryEvent__e.DatabaseResultCollectionType__c - false + true false LogEntryEvent__e.DatabaseResultJson__c - false + true false LogEntryEvent__e.DatabaseResultType__c - false + true false LogEntryEvent__e.EpochTimestamp__c - false + true false LogEntryEvent__e.ExceptionMessage__c - false + true false LogEntryEvent__e.ExceptionStackTrace__c - false + true false LogEntryEvent__e.ExceptionType__c - false + true false LogEntryEvent__e.LimitsAggregateQueriesMax__c - false + true false LogEntryEvent__e.LimitsAggregateQueriesUsed__c - false + true false LogEntryEvent__e.LimitsAggregateQueryMax__c - false + true false LogEntryEvent__e.LimitsAsyncCallsMax__c - false + true false LogEntryEvent__e.LimitsAsyncCallsUsed__c - false + true false LogEntryEvent__e.LimitsCalloutsMax__c - false + true false LogEntryEvent__e.LimitsCalloutsUsed__c - false + true false LogEntryEvent__e.LimitsCpuTimeMax__c - false + true false LogEntryEvent__e.LimitsCpuTimeUsed__c - false + true false LogEntryEvent__e.LimitsDmlRowsMax__c - false + true false LogEntryEvent__e.LimitsDmlRowsUsed__c - false + true false LogEntryEvent__e.LimitsDmlStatementsMax__c - false + true false LogEntryEvent__e.LimitsDmlStatementsUsed__c - false + true false LogEntryEvent__e.LimitsEmailInvocationsMax__c - false + true false LogEntryEvent__e.LimitsEmailInvocationsUsed__c - false + true false LogEntryEvent__e.LimitsFutureCallsMax__c - false + true false LogEntryEvent__e.LimitsFutureCallsUsed__c - false + true false LogEntryEvent__e.LimitsHeapSizeMax__c - false + true false LogEntryEvent__e.LimitsHeapSizeUsed__c - false + true false LogEntryEvent__e.LimitsMobilePushApexCallsMax__c - false + true false LogEntryEvent__e.LimitsMobilePushApexCallsUsed__c - false + true false LogEntryEvent__e.LimitsPublishImmediateDmlStatementsMax__c - false + true false LogEntryEvent__e.LimitsPublishImmediateDmlStatementsUsed__c - false + true false LogEntryEvent__e.LimitsQueueableJobsMax__c - false + true false LogEntryEvent__e.LimitsQueueableJobsUsed__c - false + true false LogEntryEvent__e.LimitsSoqlQueriesMax__c - false + true false LogEntryEvent__e.LimitsSoqlQueriesUsed__c - false + true false LogEntryEvent__e.LimitsSoqlQueryLocatorRowsMax__c - false + true false LogEntryEvent__e.LimitsSoqlQueryLocatorRowsUsed__c - false + true false LogEntryEvent__e.LimitsSoqlQueryRowsMax__c - false + true false LogEntryEvent__e.LimitsSoqlQueryRowsUsed__c - false + true false LogEntryEvent__e.LimitsSoslSearchesMax__c - false + true false LogEntryEvent__e.LimitsSoslSearchesUsed__c - false + true false LogEntryEvent__e.Locale__c - false + true false LogEntryEvent__e.LoggedById__c - false + true false LogEntryEvent__e.LoggedByUsername__c - false + true false LogEntryEvent__e.LoggingLevelOrdinal__c - false + true false LogEntryEvent__e.LoggingLevel__c - false + true false LogEntryEvent__e.LoginApplication__c - false + true false LogEntryEvent__e.LoginBrowser__c - false + true false LogEntryEvent__e.LoginDomain__c - false + true false LogEntryEvent__e.LoginHistoryId__c - false + true false LogEntryEvent__e.LoginPlatform__c - false + true false LogEntryEvent__e.LoginType__c - false + true false LogEntryEvent__e.LogoutUrl__c - false + true + + + false + LogEntryEvent__e.MessageMasked__c + true false LogEntryEvent__e.MessageTruncated__c - false + true false LogEntryEvent__e.Message__c - false + true false LogEntryEvent__e.NetworkId__c - false + true false LogEntryEvent__e.NetworkLoginUrl__c - false + true false LogEntryEvent__e.NetworkLogoutUrl__c - false + true false LogEntryEvent__e.NetworkName__c - false + true false LogEntryEvent__e.NetworkSelfRegistrationUrl__c - false + true false LogEntryEvent__e.NetworkUrlPathPrefix__c - false + true false LogEntryEvent__e.OrganizationDomainUrl__c - false + true false LogEntryEvent__e.OrganizationEnvironmentType__c - false + true false LogEntryEvent__e.OrganizationId__c - false + true false LogEntryEvent__e.OrganizationInstanceName__c - false + true false LogEntryEvent__e.OrganizationName__c - false + true false LogEntryEvent__e.OrganizationNamespacePrefix__c - false + true false LogEntryEvent__e.OrganizationType__c - false + true false LogEntryEvent__e.OriginLocation__c - false + true false LogEntryEvent__e.OriginType__c - false + true false LogEntryEvent__e.ParentLogTransactionId__c - false + true false LogEntryEvent__e.ProfileId__c - false + true false LogEntryEvent__e.ProfileName__c - false + true false LogEntryEvent__e.RecordCollectionType__c - false + true false LogEntryEvent__e.RecordId__c - false + true false LogEntryEvent__e.RecordJson__c - false + true false LogEntryEvent__e.RecordSObjectClassification__c - false + true false LogEntryEvent__e.RecordSObjectTypeNamespace__c - false + true false LogEntryEvent__e.RecordSObjectType__c - false + true false LogEntryEvent__e.SessionId__c - false + true false LogEntryEvent__e.SessionSecurityLevel__c - false + true false LogEntryEvent__e.SessionType__c - false + true false LogEntryEvent__e.SourceIp__c - false + true false LogEntryEvent__e.StackTrace__c - false + true false LogEntryEvent__e.SystemMode__c - false + true false LogEntryEvent__e.Tags__c - false + true false LogEntryEvent__e.ThemeDisplayed__c - false + true false LogEntryEvent__e.TimeZoneId__c - false + true false LogEntryEvent__e.TimeZoneName__c - false + true false LogEntryEvent__e.TimestampString__c - false + true false LogEntryEvent__e.Topics__c - false + true false LogEntryEvent__e.TriggerIsExecuting__c - false + true false LogEntryEvent__e.TriggerOperationType__c - false + true false LogEntryEvent__e.TriggerSObjectType__c - false + true false LogEntryEvent__e.UserLicenseDefinitionKey__c - false + true false LogEntryEvent__e.UserLicenseId__c - false + true false LogEntryEvent__e.UserLicenseName__c - false + true false LogEntryEvent__e.UserLoggingLevelOrdinal__c - false + true false LogEntryEvent__e.UserLoggingLevel__c - false + true false LogEntryEvent__e.UserRoleId__c - false + true false LogEntryEvent__e.UserRoleName__c - false + true false LogEntryEvent__e.UserType__c - false + true false LogEntryTagRule__mdt.ComparisonValue__c - false + true false LogEntryTagRule__mdt.IsEnabled__c - false + true false LogEntryTagRule__mdt.Tags__c - false + true false LogEntryTag__c.LogEntryOrigin__c - false + true false LogEntryTag__c.LogEntryTimestamp__c - false + true false LogEntryTag__c.LogLink__c - false + true false LogEntryTag__c.LoggedByUsernameLink__c - false + true false LogEntryTag__c.UniqueId__c - false + true false LogEntry__c.ApexClassApiVersion__c - false + true false LogEntry__c.ApexClassCreatedDate__c - false + true false LogEntry__c.ApexClassId__c - false + true false LogEntry__c.ApexClassLastModifiedDate__c - false + true false LogEntry__c.ApexClassName__c - false + true false LogEntry__c.ApexInnerClassName__c - false + true false LogEntry__c.ApexMethodName__c - false + true false LogEntry__c.ComponentApiName__c - false + true false LogEntry__c.ComponentFunctionName__c - false + true true @@ -823,943 +843,956 @@ false LogEntry__c.DatabaseResultCollectionType__c - false + true false LogEntry__c.DatabaseResultJson__c - false + true false LogEntry__c.DatabaseResultType__c - false + true false LogEntry__c.EpochTimestamp__c - false + true false LogEntry__c.EventUuid__c - false + true false LogEntry__c.ExceptionMessage__c - false + true false LogEntry__c.ExceptionStackTrace__c - false + true false LogEntry__c.ExceptionType__c - false + true false LogEntry__c.FlowActiveVersionId__c - false + true false LogEntry__c.FlowDescription__c - false + true false LogEntry__c.FlowDurableId__c - false + true false LogEntry__c.FlowLabel__c - false + true false LogEntry__c.FlowLastModifiedByName__c - false + true false LogEntry__c.FlowLastModifiedDate__c - false + true false LogEntry__c.FlowProcessType__c - false + true false LogEntry__c.FlowTriggerType__c - false + true false LogEntry__c.FlowVersionApiVersionRuntime__c - false + true false LogEntry__c.FlowVersionNumber__c - false + true false LogEntry__c.FlowVersionRunInMode__c - false + true false LogEntry__c.HasDatabaseResult__c - false + true false LogEntry__c.HasExceptionStackTrace__c - false + true false LogEntry__c.HasException__c - false + true false LogEntry__c.HasRecordId__c - false + true false LogEntry__c.HasRecordJson__c - false + true false LogEntry__c.HasStackTrace__c - false + true false LogEntry__c.LimitsAggregateQueriesMax__c - false + true false LogEntry__c.LimitsAggregateQueriesUsed__c - false + true false LogEntry__c.LimitsAggregateQueries__c - false + true false LogEntry__c.LimitsAsyncCallsMax__c - false + true false LogEntry__c.LimitsAsyncCallsUsed__c - false + true false LogEntry__c.LimitsAsyncCalls__c - false + true false LogEntry__c.LimitsCalloutsMax__c - false + true false LogEntry__c.LimitsCalloutsUsed__c - false + true false LogEntry__c.LimitsCallouts__c - false + true false LogEntry__c.LimitsCpuTimeMax__c - false + true false LogEntry__c.LimitsCpuTimeUsed__c - false + true false LogEntry__c.LimitsCpuTime__c - false + true false LogEntry__c.LimitsDmlRowsMax__c - false + true false LogEntry__c.LimitsDmlRowsUsed__c - false + true false LogEntry__c.LimitsDmlRows__c - false + true false LogEntry__c.LimitsDmlStatementsMax__c - false + true false LogEntry__c.LimitsDmlStatementsUsed__c - false + true false LogEntry__c.LimitsDmlStatements__c - false + true false LogEntry__c.LimitsEmailInvocationsMax__c - false + true false LogEntry__c.LimitsEmailInvocationsUsed__c - false + true false LogEntry__c.LimitsEmailInvocations__c - false + true false LogEntry__c.LimitsFutureCallsMax__c - false + true false LogEntry__c.LimitsFutureCallsUsed__c - false + true false LogEntry__c.LimitsFutureCalls__c - false + true false LogEntry__c.LimitsHeapSizeMax__c - false + true false LogEntry__c.LimitsHeapSizeUsed__c - false + true false LogEntry__c.LimitsHeapSize__c - false + true false LogEntry__c.LimitsMobilePushApexCallsMax__c - false + true false LogEntry__c.LimitsMobilePushApexCallsUsed__c - false + true false LogEntry__c.LimitsMobilePushApexCalls__c - false + true false LogEntry__c.LimitsPublishImmediateDmlStatementsMax__c - false + true false LogEntry__c.LimitsPublishImmediateDmlStatementsUsed__c - false + true false LogEntry__c.LimitsPublishImmediateDmlStatements__c - false + true false LogEntry__c.LimitsQueueableJobsMax__c - false + true false LogEntry__c.LimitsQueueableJobsUsed__c - false + true false LogEntry__c.LimitsQueueableJobs__c - false + true false LogEntry__c.LimitsSoqlQueriesMax__c - false + true false LogEntry__c.LimitsSoqlQueriesUsed__c - false + true false LogEntry__c.LimitsSoqlQueries__c - false + true false LogEntry__c.LimitsSoqlQueryLocatorRowsMax__c - false + true false LogEntry__c.LimitsSoqlQueryLocatorRowsUsed__c - false + true false LogEntry__c.LimitsSoqlQueryLocatorRows__c - false + true false LogEntry__c.LimitsSoqlQueryRowsMax__c - false + true false LogEntry__c.LimitsSoqlQueryRowsUsed__c - false + true false LogEntry__c.LimitsSoqlQueryRows__c - false + true false LogEntry__c.LimitsSoslSearchesMax__c - false + true false LogEntry__c.LimitsSoslSearchesUsed__c - false + true false LogEntry__c.LimitsSoslSearches__c - false + true false LogEntry__c.LogTransactionId__c - false + true false LogEntry__c.LoggedByUsernameLink__c - false + true false LogEntry__c.LoggingLevelOrdinal__c - false + true false LogEntry__c.LoggingLevelWithImage__c - false + true false LogEntry__c.LoggingLevel__c - false + true + + + false + LogEntry__c.MessageMasked__c + true false LogEntry__c.MessageTruncated__c - false + true false LogEntry__c.Message__c - false + true false LogEntry__c.OriginLocation__c - false + true false LogEntry__c.OriginType__c - false + true false LogEntry__c.Origin__c - false + true false LogEntry__c.RecordCollectionType__c - false + true false LogEntry__c.RecordDetailedLink__c - false + true false LogEntry__c.RecordId__c - false + true + + + true + LogEntry__c.RecordJsonMasked__c + true false LogEntry__c.RecordJson__c - false + true false LogEntry__c.RecordLink__c - false + true false LogEntry__c.RecordName__c - false + true false LogEntry__c.RecordSObjectClassification__c - false + true false LogEntry__c.RecordSObjectTypeNamespace__c - false + true false LogEntry__c.RecordSObjectType__c - false + true false LogEntry__c.StackTrace__c - false + true false LogEntry__c.Timestamp__c - false + true false LogEntry__c.TransactionEntryNumber__c - false + true false LogEntry__c.TriggerIsExecuting__c - false + true false LogEntry__c.TriggerOperationType__c - false + true false LogEntry__c.TriggerSObjectType__c - false + true false LogEntry__c.Trigger__c - false + true false LogStatus__mdt.IsActive__c - false + true false LogStatus__mdt.IsClosed__c - false + true false LogStatus__mdt.IsResolved__c - false + true false Log__c.ApiReleaseNumber__c - false + true false Log__c.ApiReleaseVersion__c - false + true false Log__c.ApiVersion__c - false + true false Log__c.ClosedBy__c - false + true false Log__c.ClosedDate__c - false + true false Log__c.Comments__c - false + true false Log__c.EndTime__c - false + true false Log__c.IsClosed__c - false + true false Log__c.IsResolved__c - false + true false Log__c.Issue__c - false + true false Log__c.Locale__c - false + true false Log__c.LogEntriesSummary__c - false + true false Log__c.LogRetentionDate__c - false + true false Log__c.LoggedByUsernameLink__c - false + true false Log__c.LoggedByUsername__c - false + true false Log__c.LoggedBy__c - false + true false Log__c.LoginApplication__c - false + true false Log__c.LoginBrowser__c - false + true false Log__c.LoginDomain__c - false + true false Log__c.LoginHistoryId__c - false + true false Log__c.LoginPlatform__c - false + true false Log__c.LoginType__c - false + true false Log__c.LogoutUrl__c - false + true false Log__c.MaxLogEntryLoggingLevelOrdinal__c - false + true false Log__c.NetworkId__c - false + true false Log__c.NetworkLoginUrl__c - false + true false Log__c.NetworkLogoutUrl__c - false + true false Log__c.NetworkName__c - false + true false Log__c.NetworkSelfRegistrationUrl__c - false + true false Log__c.NetworkUrlPathPrefix__c - false + true false Log__c.OrganizationDomainUrl__c - false + true false Log__c.OrganizationEnvironmentType__c - false + true false Log__c.OrganizationId__c - false + true false Log__c.OrganizationInstanceName__c - false + true false Log__c.OrganizationInstanceReleaseCycle__c - false + true false Log__c.OrganizationName__c - false + true false Log__c.OrganizationNamespacePrefix__c - false + true false Log__c.OrganizationType__c - false + true false Log__c.ParentLog__c - false + true false Log__c.Priority__c - false + true false Log__c.ProfileId__c - false + true false Log__c.ProfileLink__c - false + true false Log__c.ProfileName__c - false + true false Log__c.SessionId__c - false + true false Log__c.SessionSecurityLevel__c - false + true false Log__c.SessionType__c - false + true false Log__c.SourceIp__c - false + true false Log__c.StartTime__c - false + true false Log__c.Status__c - false + true false Log__c.SystemModeSummary__c - false + true false Log__c.SystemMode__c - false + true false Log__c.ThemeDisplayed__c - false + true false Log__c.TimeZoneId__c - false + true false Log__c.TimeZoneName__c - false + true false Log__c.TotalDEBUGLogEntries__c - false + true false Log__c.TotalERRORLogEntries__c - false + true false Log__c.TotalFINELogEntries__c - false + true false Log__c.TotalFINERLogEntries__c - false + true false Log__c.TotalFINESTLogEntries__c - false + true false Log__c.TotalINFOLogEntries__c - false + true false Log__c.TotalLimitsCpuTimeUsed__c - false + true false Log__c.TotalLogEntries__c - false + true false Log__c.TotalWARNLogEntries__c - false + true false Log__c.TransactionId__c - false + true false Log__c.UserLicenseDefinitionKey__c - false + true false Log__c.UserLicenseId__c - false + true false Log__c.UserLicenseName__c - false + true false Log__c.UserLoggingLevelOrdinal__c - false + true false Log__c.UserLoggingLevel__c - false + true false Log__c.UserRoleId__c - false + true false Log__c.UserRoleLink__c - false + true false Log__c.UserRoleName__c - false + true false Log__c.UserType__c - false + true false Log__c.WasLoggedByCurrentUser__c - false + true false LoggerSObjectHandlerParameter__mdt.Description__c - false + true false LoggerSObjectHandlerParameter__mdt.IsEnabled__c - false + true false LoggerSObjectHandlerParameter__mdt.Value__c - false + true false LoggerSObjectHandlerPluginParameter__mdt.Description__c - false + true false LoggerSObjectHandlerPluginParameter__mdt.IsEnabled__c - false + true false LoggerSObjectHandlerPluginParameter__mdt.Value__c - false + true false LoggerSObjectHandlerPlugin__mdt.Description__c - false + true false LoggerSObjectHandlerPlugin__mdt.ExecutionOrder__c - false + true false LoggerSObjectHandlerPlugin__mdt.IsEnabled__c - false + true false LoggerSObjectHandler__mdt.IsEnabled__c - false + true false LoggerTag__c.TotalLogEntries__c - false + true false LoggerTag__c.UniqueId__c - false + true + + LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout + LogEntryTagRule__mdt-Logger Tag Rule Layout diff --git a/nebula-logger-recipes/main/default/tabs/LoggerAuraDemo.tab-meta.xml b/nebula-logger-recipes/main/default/tabs/LoggerAuraDemo.tab-meta.xml index 50430a497..c0f5b4865 100644 --- a/nebula-logger-recipes/main/default/tabs/LoggerAuraDemo.tab-meta.xml +++ b/nebula-logger-recipes/main/default/tabs/LoggerAuraDemo.tab-meta.xml @@ -1,4 +1,4 @@ - + loggerAuraDemo diff --git a/nebula-logger-recipes/main/default/tabs/Logger_lwc_demo.tab-meta.xml b/nebula-logger-recipes/main/default/tabs/Logger_lwc_demo.tab-meta.xml index 3fb40aefe..fb8ad71c8 100644 --- a/nebula-logger-recipes/main/default/tabs/Logger_lwc_demo.tab-meta.xml +++ b/nebula-logger-recipes/main/default/tabs/Logger_lwc_demo.tab-meta.xml @@ -1,4 +1,4 @@ - + loggerLWCDemo diff --git a/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger b/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger index 95766f285..8942bbc66 100644 --- a/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger +++ b/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger @@ -1,14 +1,6 @@ // An example trigger to demo logging Account records, using all trigger operations // Normally, you should use a trigger handler framework, but this trigger is just for demo purposes -trigger Account_Trigger_Logger_Example on Account ( - before insert, - before update, - before delete, - after insert, - after update, - after delete, - after undelete -) { +trigger Account_Trigger_Logger_Example on Account(before insert, before update, before delete, after insert, after update, after delete, after undelete) { // Get the trigger's list of records List triggerRecords = Trigger.new != null ? Trigger.new : Trigger.old; @@ -24,4 +16,4 @@ trigger Account_Trigger_Logger_Example on Account ( // Save any pending log entries Logger.saveLog(); -} \ No newline at end of file +} diff --git a/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger-meta.xml b/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger-meta.xml index 23257e155..63037f969 100644 --- a/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger-meta.xml +++ b/nebula-logger-recipes/main/default/triggers/Account_Trigger_Logger_Example.trigger-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger-recipes/tests/LogEntryHandler_Tests_Flow.cls b/nebula-logger-recipes/tests/LogEntryHandler_Tests_Flow.cls index 51913d6bb..04130c890 100644 --- a/nebula-logger-recipes/tests/LogEntryHandler_Tests_Flow.cls +++ b/nebula-logger-recipes/tests/LogEntryHandler_Tests_Flow.cls @@ -89,5 +89,4 @@ private class LogEntryHandler_Tests_Flow { private static FlowVersionView getFlowVersion(Id flowActiveVersionId) { return [SELECT ApiVersionRuntime, FlowDefinitionViewId, RunInMode, Status, VersionNumber FROM FlowVersionView WHERE DurableId = :flowActiveVersionId]; } - } diff --git a/nebula-logger-recipes/tests/Logger_Tests_InboundEmailHandler.cls b/nebula-logger-recipes/tests/Logger_Tests_InboundEmailHandler.cls index 77170acd5..a7c549bfe 100644 --- a/nebula-logger-recipes/tests/Logger_Tests_InboundEmailHandler.cls +++ b/nebula-logger-recipes/tests/Logger_Tests_InboundEmailHandler.cls @@ -18,7 +18,6 @@ private class Logger_Tests_InboundEmailHandler { Messaging.InboundEmail email = new Messaging.InboundEmail(); email.plainTextBody = 'Example email content'; email.fromAddress = 'test@test.com'; - String contactEmail = 'someone@salesforce.com'; email.subject = 'My example email'; // Create an instance of the example handler class diff --git a/nebula-logger/main/log-management/classes/LogEntryEventHandler.cls b/nebula-logger/main/log-management/classes/LogEntryEventHandler.cls index 84d02e7dc..0c90e2cb9 100644 --- a/nebula-logger/main/log-management/classes/LogEntryEventHandler.cls +++ b/nebula-logger/main/log-management/classes/LogEntryEventHandler.cls @@ -7,6 +7,7 @@ * @group Log Management * @description Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__c` and `LogEntry__c` records */ +@SuppressWarnings('PMD.ApexCRUDViolation') public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { private static final Map TRANSACTION_ID_TO_LOG = new Map(); @TestVisible @@ -186,6 +187,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { LoggingLevel__c = logEntryEvent.LoggingLevel__c, LoggingLevelOrdinal__c = logEntryEvent.LoggingLevelOrdinal__c, Message__c = logEntryEvent.Message__c, + MessageMasked__c = logEntryEvent.MessageMasked__c, MessageTruncated__c = logEntryEvent.MessageTruncated__c, Name = null, // Salesforce will auto-set the record ID as the name when null OriginLocation__c = logEntryEvent.OriginLocation__c, @@ -193,6 +195,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { RecordCollectionType__c = logEntryEvent.RecordCollectionType__c, RecordId__c = logEntryEvent.RecordId__c, RecordJson__c = logEntryEvent.RecordJson__c, + RecordJsonMasked__c = logEntryEvent.RecordJsonMasked__c, RecordSObjectClassification__c = logEntryEvent.RecordSObjectClassification__c, RecordSObjectType__c = logEntryEvent.RecordSObjectType__c, RecordSObjectTypeNamespace__c = logEntryEvent.RecordSObjectTypeNamespace__c, @@ -212,7 +215,9 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { this.logEntryEventUuidToTagNames.put(logEntry.EventUuid__c, logEntryTagNames); } } - insert this.logEntries; + Database.DmlOptions dmlOptions = new Database.DmlOptions(); + dmlOptions.AllowFieldTruncation = true; + Database.insert(this.logEntries, dmlOptions); } private void appendRuleBasedTags() { @@ -272,6 +277,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { insert new List(tagAssignments); } + @SuppressWarnings('PMD.ApexSOQLInjection') private Map getTagNameToId(Schema.SObjectType tagSObjectType) { Map tagNameToId = new Map(); @@ -392,7 +398,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { @future(callout=true) private static void setStatusApiDetails() { - System.debug('Running setStatusApiDetails()'); + System.debug(LoggingLevel.DEBUG, 'Running setStatusApiDetails()'); Organization organization = [SELECT InstanceName FROM Organization]; String statusApiEndpoint = 'https://api.status.salesforce.com/v1/instances/' + organization.InstanceName + '/status'; @@ -415,7 +421,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } StatusApiResponse statusApiResponse = (StatusApiResponse) JSON.deserialize(response.getBody(), StatusApiResponse.class); - System.debug('statusApiResponse==' + statusApiResponse); + System.debug(LoggingLevel.DEBUG, 'statusApiResponse==' + statusApiResponse); List logsToUpdate = new List(); for (Log__c log : [ @@ -430,7 +436,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { logsToUpdate.add(log); } - System.debug('logsToUpdate==' + logsToUpdate); + System.debug(LoggingLevel.DEBUG, 'logsToUpdate==' + logsToUpdate); update logsToUpdate; } diff --git a/nebula-logger/main/log-management/classes/LogEntryFieldSetPicklist.cls b/nebula-logger/main/log-management/classes/LogEntryFieldSetPicklist.cls index 1736436b6..7f2f23ef3 100644 --- a/nebula-logger/main/log-management/classes/LogEntryFieldSetPicklist.cls +++ b/nebula-logger/main/log-management/classes/LogEntryFieldSetPicklist.cls @@ -26,7 +26,7 @@ public without sharing class LogEntryFieldSetPicklist extends VisualEditor.Dynam List
fieldSets = Schema.SObjectType.LogEntry__c.fieldSets.getMap().values(); for (FieldSet fieldSet : fieldSets) { - String namespacePrefix = String.isEmpty(fieldSet.getNameSpace()) ? '' : fieldSet.getNameSpace() + '__'; + String namespacePrefix = String.isBlank(fieldSet.getNameSpace()) ? '' : fieldSet.getNameSpace() + '__'; VisualEditor.DataRow picklistRow = new VisualEditor.DataRow(fieldSet.getLabel(), namespacePrefix + fieldSet.getName()); picklistRows.addRow(picklistRow); diff --git a/nebula-logger/main/log-management/classes/LogEntryHandler.cls b/nebula-logger/main/log-management/classes/LogEntryHandler.cls index 9054e03f7..f002936c8 100644 --- a/nebula-logger/main/log-management/classes/LogEntryHandler.cls +++ b/nebula-logger/main/log-management/classes/LogEntryHandler.cls @@ -88,7 +88,7 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { String innerApexClassName = logEntry.OriginLocation__c.substringAfter(topLevelApexClassName + '.').substringBeforeLast('.'); if (innerApexClassName == topLevelApexClassName || innerApexClassName == methodName) { innerApexClassName = null; - } else if(innerApexClassName.startsWith(topLevelApexClassName + '.')) { + } else if (innerApexClassName.startsWith(topLevelApexClassName + '.')) { innerApexClassName = innerApexClassName.substringAfter(topLevelApexClassName + '.'); } @@ -205,6 +205,7 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { } } + @SuppressWarnings('PMD.OperationWithLimitsInLoop') private void setRecordNames() { // Assumption - only valid record IDs will be populated in LogEntry__c.RecordId__c // If that changes, then extra checks may be needed before casting to Id, using getSObjectType(), etc. diff --git a/nebula-logger/main/log-management/classes/LogHandler.cls b/nebula-logger/main/log-management/classes/LogHandler.cls index dc587a261..fdb23343b 100644 --- a/nebula-logger/main/log-management/classes/LogHandler.cls +++ b/nebula-logger/main/log-management/classes/LogHandler.cls @@ -11,6 +11,11 @@ public without sharing class LogHandler extends LoggerSObjectHandler { @TestVisible private static Map logStatusByName = loadActiveLogStatuses(); + @TestVisible + private List logs; + @TestVisible + private Map oldLogsById; + private static Map loadActiveLogStatuses() { Map logStatusByName = new Map(); for (LogStatus__mdt logStatus : LogStatus__mdt.getAll().values()) { @@ -22,12 +27,6 @@ public without sharing class LogHandler extends LoggerSObjectHandler { return logStatusByName; } - @TestVisible - private List logs; - - @TestVisible - private Map oldLogsById; - /** * @description Returns SObject Type that the handler is responsible for processing * @return The instance of `SObjectType` @@ -133,16 +132,16 @@ public without sharing class LogHandler extends LoggerSObjectHandler { // 1. Assume that that there will always be 3+ picklist values for the Priority__c field (out of the box, the values are: High, Medium, Low) // 2. Assume that not everyone will want those exact values, so dynamiclly get picklist entries (e.g., some orgs may instead use Critical, High, Medium, Low) // 3. Assume that the picklist entries are sorted in order of priority (not alphabetically, etc.) - final String FIRST_PRIORITY = picklistEntries.get(0).getValue(); - final String SECOND_PRIORITY = picklistEntries.get(1).getValue(); + final String firstPriority = picklistEntries.get(0).getValue(); + final String secondPriority = picklistEntries.get(1).getValue(); for (Log__c log : this.logs) { Log__c oldLog = this.oldLogsById.get(log.Id); if (log.TotalERRORLogEntries__c != oldLog.TotalERRORLogEntries__c && log.TotalERRORLogEntries__c > 0) { - log.Priority__c = FIRST_PRIORITY; + log.Priority__c = firstPriority; } else if (log.TotalWARNLogEntries__c != oldLog.TotalWARNLogEntries__c && log.TotalWARNLogEntries__c > 0) { - log.Priority__c = SECOND_PRIORITY; + log.Priority__c = secondPriority; } } } @@ -151,6 +150,11 @@ public without sharing class LogHandler extends LoggerSObjectHandler { // For each log record, share the record with the user that created the log (Log__c.LoggedBy__c) List logShares = new List(); for (Log__c log : this.logs) { + // Anonymous logs don't have a user set for LoggedBy__c, so there's no one to share the record with + if (log.LoggedBy__c == null) { + continue; + } + // Load the logging user's settings User loggingUser = new User(Id = log.LoggedBy__c, ProfileId = log.ProfileId__c); LoggerSettings__c loggingUserSettings = Logger.getUserSettings(loggingUser); @@ -168,7 +172,6 @@ public without sharing class LogHandler extends LoggerSObjectHandler { ); logShares.add(logShare); } - List saveResults = Database.insert(logShares, false); - System.debug('saveResults==' + saveResults); + Database.insert(logShares, false); } } diff --git a/nebula-logger/main/log-management/classes/LogMassDeleteExtension.cls b/nebula-logger/main/log-management/classes/LogMassDeleteExtension.cls index 2c7a350f3..8ab0c3d3e 100644 --- a/nebula-logger/main/log-management/classes/LogMassDeleteExtension.cls +++ b/nebula-logger/main/log-management/classes/LogMassDeleteExtension.cls @@ -28,6 +28,7 @@ public with sharing class LogMassDeleteExtension { * @description Filters the list of selected `Log__c` records to only include records that the current user can delete (based on object-level access) * @return The matching `Log__c` records that the current user has access to delete */ + @SuppressWarnings('PMD.ApexCRUDViolation') public List getDeletableLogs() { // The UserRecordAccess object is weird - RecordId is not an actual ID field, so you can't filter using `List` or `List`, you have to use strings // So, here's some code that would be unnecessary if RecordId were a polymorphic ID field instead diff --git a/nebula-logger/main/log-management/classes/LoggerSObjectHandler.cls b/nebula-logger/main/log-management/classes/LoggerSObjectHandler.cls index a847b9b27..e252cdcc6 100644 --- a/nebula-logger/main/log-management/classes/LoggerSObjectHandler.cls +++ b/nebula-logger/main/log-management/classes/LoggerSObjectHandler.cls @@ -7,10 +7,25 @@ * @group Log Management * @description Abstract class used by trigger handlers for shared logic */ -public abstract class LoggerSObjectHandler { +@SuppressWarnings('PMD.ApexCRUDViolation') +public without sharing abstract class LoggerSObjectHandler { private static Map configurationBySObjectType; private static Map> pluginsBySObjectType; + @TestVisible + private TriggerOperation triggerOperationType; + @TestVisible + private List triggerNew; + @TestVisible + private Map triggerNewMap; + @TestVisible + private List triggerOld; + @TestVisible + private Map triggerOldMap; + + private LoggerSObjectHandler__mdt handlerConfiguration; + private List plugins; + static { // When using CMDT's getAll(), it does not return relationship fields for EntityDefinition fields or child CMDT objects... // ... so instead query the LoggerSObjectHandler__mdt CMDT object @@ -42,7 +57,8 @@ public abstract class LoggerSObjectHandler { } if (Test.isRunningTest() == true) { - // Test shouldn't rely on the actual CMDT rules in the org - clear the loaded values, and defaults will be used + // Tests shouldn't rely on the actual CMDT rules in the org + // Clear the org's loaded records during tests, and mock via setMockConfiguration() configurationBySObjectType.clear(); pluginsBySObjectType.clear(); } @@ -64,20 +80,6 @@ public abstract class LoggerSObjectHandler { pluginsBySObjectType.put(sobjectType, plugins); } - @TestVisible - private TriggerOperation triggerOperationType; - @TestVisible - private List triggerNew; - @TestVisible - private Map triggerNewMap; - @TestVisible - private List triggerOld; - @TestVisible - private Map triggerOldMap; - - private LoggerSObjectHandler__mdt handlerConfiguration; - private List plugins; - public LoggerSObjectHandler() { this.setConfigurations(); diff --git a/nebula-logger/main/log-management/classes/RelatedLogEntriesController.cls b/nebula-logger/main/log-management/classes/RelatedLogEntriesController.cls index fc60a4a1f..04942d620 100644 --- a/nebula-logger/main/log-management/classes/RelatedLogEntriesController.cls +++ b/nebula-logger/main/log-management/classes/RelatedLogEntriesController.cls @@ -5,7 +5,7 @@ /** * @group Log Management - * @description Controller class for the component RelatedLogEntries + * @description Controller class for the lightning web component `related-log-entries` */ public with sharing class RelatedLogEntriesController { private static final SObjectType LOG_SOBJECT_TYPE = Schema.Log__c.SObjectType; @@ -24,6 +24,7 @@ public with sharing class RelatedLogEntriesController { * @param search An optional search term to filter by * @return The instance of LogEntryQueryResult, containing matching records and metadata */ + @SuppressWarnings('PMD.ApexCRUDViolation') @AuraEnabled(cacheable=true) public static LogEntryQueryResult getQueryResult( Id recordId, @@ -84,7 +85,7 @@ public with sharing class RelatedLogEntriesController { }; String logEntryQuery = 'SELECT {0} FROM {1} WHERE {2} = :recordId ORDER BY {3} LIMIT {4}'; logEntryQuery = String.format(logEntryQuery, queryTextReplacements); - System.debug('logEntryQuery==' + logEntryQuery); + System.debug(LoggingLevel.DEBUG, 'logEntryQuery==' + logEntryQuery); return (List) Database.query(logEntryQuery); } diff --git a/nebula-logger/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml b/nebula-logger/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml index a5d5cf90f..d2189acb7 100644 --- a/nebula-logger/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml +++ b/nebula-logger/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml @@ -162,6 +162,15 @@ Record.MessageTruncated__c + + + + uiBehavior + readonly + + Record.MessageMasked__c + + @@ -652,6 +661,22 @@ + + + + uiBehavior + readonly + + Record.RecordJsonMasked__c + + + {!Record.HasRecordJson__c} + EQUAL + true + + + + Facet-1da92bf7-f9ed-4842-b880-7625370f3c70 Facet @@ -881,11 +906,16 @@ flexipage:fieldSection + 1 AND 2 {!Record.OriginType__c} EQUAL Apex + + {!Record.ApexClassName__c} + NE + diff --git a/nebula-logger/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml b/nebula-logger/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml index 16d469751..80497e3e1 100644 --- a/nebula-logger/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml +++ b/nebula-logger/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml @@ -1,4 +1,4 @@ - + ChangeOwnerOne ChangeRecordType @@ -72,6 +72,10 @@ Readonly MessageTruncated__c + + Readonly + MessageMasked__c + Readonly StackTrace__c @@ -272,6 +276,10 @@ Readonly RecordJson__c + + Readonly + RecordJsonMasked__c + @@ -355,8 +363,8 @@ true true - - + + @@ -364,9 +372,9 @@ false true - - - + + + @@ -389,7 +397,7 @@ false false - 00hJ0000004XDt4 + 00h1h000002oBf9 4 0 Default diff --git a/nebula-logger/main/log-management/lwc/logViewer/__tests__/logViewer.test.js b/nebula-logger/main/log-management/lwc/logViewer/__tests__/logViewer.test.js index 099e2c939..d874bedad 100644 --- a/nebula-logger/main/log-management/lwc/logViewer/__tests__/logViewer.test.js +++ b/nebula-logger/main/log-management/lwc/logViewer/__tests__/logViewer.test.js @@ -65,8 +65,6 @@ describe('Logger JSON Viewer lwc tests', () => { logViewer.shadowRoot.querySelector('lightning-button-stateful').click(); }) .then(() => { - const inputButton = logViewer.shadowRoot.querySelector('lightning-button-stateful'); - const clipboardContent = JSON.parse(logViewer.shadowRoot.querySelector('pre').textContent); expect(clipboardContent).toEqual(mockGetLog); }); diff --git a/nebula-logger/main/log-management/lwc/logViewer/logViewer.js b/nebula-logger/main/log-management/lwc/logViewer/logViewer.js index 9af3c8604..a655111ca 100644 --- a/nebula-logger/main/log-management/lwc/logViewer/logViewer.js +++ b/nebula-logger/main/log-management/lwc/logViewer/logViewer.js @@ -5,7 +5,7 @@ import { api, LightningElement, track, wire } from 'lwc'; import getLog from '@salesforce/apex/Logger.getLog'; -export default class LogJSONViewer extends LightningElement { +export default class LogViewer extends LightningElement { // TODO: recordId is a reserved keyword in LWC that only works if the component has been inserted by means of Flexipage // onto a record page. We can rename this variable (probably) once LWC quick actions are GA'd @api diff --git a/nebula-logger/main/log-management/lwc/relatedLogEntries/relatedLogEntries.js b/nebula-logger/main/log-management/lwc/relatedLogEntries/relatedLogEntries.js index 268ae9815..6239d9f5c 100644 --- a/nebula-logger/main/log-management/lwc/relatedLogEntries/relatedLogEntries.js +++ b/nebula-logger/main/log-management/lwc/relatedLogEntries/relatedLogEntries.js @@ -53,7 +53,7 @@ export default class RelatedLogEntries extends LightningElement { // Parse the Apex results & add any UI-specific attributes based on field metadata processResult(queryResult) { if (queryResult.fieldSet == undefined) { - return; + return null; } queryResult = Object.assign({}, queryResult); // clone queryResult @@ -89,7 +89,7 @@ export default class RelatedLogEntries extends LightningElement { }; // Add the link to each log entry record - for (var j = 0; j < records.length; j++) { + for (let j = 0; j < records.length; j++) { let record = Object.assign({}, records[j]); //cloning object let parentObject = record[field.relationshipName]; @@ -111,7 +111,7 @@ export default class RelatedLogEntries extends LightningElement { }; // Add the link to each log entry record - for (var j = 0; j < records.length; j++) { + for (let j = 0; j < records.length; j++) { let record = Object.assign({}, records[j]); //cloning object record[displayFieldName] = record[field.fieldName]; record[field.fieldName] = '/' + record.Id; diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/compactLayouts/LogEntryCompactLayout.compactLayout-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/compactLayouts/LogEntryCompactLayout.compactLayout-meta.xml index 254265ce4..bc6a84c61 100644 --- a/nebula-logger/main/log-management/objects/LogEntry__c/compactLayouts/LogEntryCompactLayout.compactLayout-meta.xml +++ b/nebula-logger/main/log-management/objects/LogEntry__c/compactLayouts/LogEntryCompactLayout.compactLayout-meta.xml @@ -6,5 +6,8 @@ LoggedByUsernameLink__c Timestamp__c LoggingLevelWithImage__c + LogTransactionId__c + TransactionEntryNumber__c + EventUuid__c diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentFunctionName__c.field-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentFunctionName__c.field-meta.xml index e33060d51..6a23df3e2 100644 --- a/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentFunctionName__c.field-meta.xml +++ b/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentFunctionName__c.field-meta.xml @@ -1,4 +1,4 @@ - + ComponentFunctionName__c false diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentType__c.field-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentType__c.field-meta.xml index ec7262d51..c898271ea 100644 --- a/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentType__c.field-meta.xml +++ b/nebula-logger/main/log-management/objects/LogEntry__c/fields/ComponentType__c.field-meta.xml @@ -1,4 +1,4 @@ - + ComponentType__c false diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/fields/FlowDescription__c.field-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/fields/FlowDescription__c.field-meta.xml index 1bd14cb96..e37d8f0e2 100644 --- a/nebula-logger/main/log-management/objects/LogEntry__c/fields/FlowDescription__c.field-meta.xml +++ b/nebula-logger/main/log-management/objects/LogEntry__c/fields/FlowDescription__c.field-meta.xml @@ -5,8 +5,10 @@ false Flow definition information, specified by the org’s admin. - false + 131072 false + false false - TextArea + LongTextArea + 8 diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/fields/MessageMasked__c.field-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/fields/MessageMasked__c.field-meta.xml new file mode 100644 index 000000000..4963a9f73 --- /dev/null +++ b/nebula-logger/main/log-management/objects/LogEntry__c/fields/MessageMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + MessageMasked__c + false + false + Indicates if sensitive data was removed from the message, using log entry data mask rules + + true + false + Checkbox + diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/fields/RecordJsonMasked__c.field-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/fields/RecordJsonMasked__c.field-meta.xml new file mode 100644 index 000000000..643317f3d --- /dev/null +++ b/nebula-logger/main/log-management/objects/LogEntry__c/fields/RecordJsonMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + RecordJsonMasked__c + false + false + Indicates if sensitive data was removed from the record JSON, using log entry data mask rules + + false + false + Checkbox + diff --git a/nebula-logger/main/log-management/objects/LogEntry__c/listViews/AllComponentLogEntries.listView-meta.xml b/nebula-logger/main/log-management/objects/LogEntry__c/listViews/AllComponentLogEntries.listView-meta.xml index e2431fab1..7c2d39f29 100644 --- a/nebula-logger/main/log-management/objects/LogEntry__c/listViews/AllComponentLogEntries.listView-meta.xml +++ b/nebula-logger/main/log-management/objects/LogEntry__c/listViews/AllComponentLogEntries.listView-meta.xml @@ -1,4 +1,4 @@ - + AllComponentLogEntries NAME diff --git a/nebula-logger/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml b/nebula-logger/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml index ea51fd84f..24d8e746b 100644 --- a/nebula-logger/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml +++ b/nebula-logger/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml @@ -48,14 +48,42 @@ Logger true + + LoggerParameter + true + RelatedLogEntriesController true + + true + LogEntryDataMaskRule__mdt + + + true + LogEntryTagRule__mdt + true LogStatus__mdt + + true + LoggerSObjectHandlerParameter__mdt + + + true + LoggerSObjectHandlerPluginParameter__mdt + + + true + LoggerSObjectHandlerPlugin__mdt + + + true + LoggerSObjectHandler__mdt + true LoggerSettings__c @@ -526,6 +554,11 @@ LogEntry__c.LoggingLevel__c true + + false + LogEntry__c.MessageMasked__c + true + false LogEntry__c.MessageTruncated__c @@ -571,6 +604,11 @@ LogEntry__c.RecordJson__c true + + false + LogEntry__c.RecordJsonMasked__c + true + false LogEntry__c.RecordLink__c diff --git a/nebula-logger/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml b/nebula-logger/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml index 1486d5043..b1d4279a5 100644 --- a/nebula-logger/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml +++ b/nebula-logger/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml @@ -434,6 +434,11 @@ LogEntry__c.LoggingLevel__c true + + false + LogEntry__c.MessageMasked__c + true + false LogEntry__c.MessageTruncated__c @@ -474,6 +479,16 @@ LogEntry__c.RecordId__c true + + false + LogEntry__c.RecordJson__c + true + + + false + LogEntry__c.RecordJsonMasked__c + true + false LogEntry__c.RecordLink__c diff --git a/nebula-logger/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml b/nebula-logger/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml index 51ae0d112..2734b6585 100644 --- a/nebula-logger/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml +++ b/nebula-logger/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml @@ -478,6 +478,11 @@ LogEntry__c.LoggingLevel__c true + + false + LogEntry__c.MessageMasked__c + true + false LogEntry__c.MessageTruncated__c @@ -523,6 +528,11 @@ LogEntry__c.RecordJson__c true + + false + LogEntry__c.RecordJsonMasked__c + true + false LogEntry__c.RecordLink__c diff --git a/nebula-logger/main/log-management/reports/LogReports/LogEntryDetails.report-meta.xml b/nebula-logger/main/log-management/reports/LogReports/LogEntryDetails.report-meta.xml index 32d7387b5..61bade231 100644 --- a/nebula-logger/main/log-management/reports/LogReports/LogEntryDetails.report-meta.xml +++ b/nebula-logger/main/log-management/reports/LogReports/LogEntryDetails.report-meta.xml @@ -46,6 +46,10 @@ Sum LogEntry__c.MessageTruncated__c + + Sum + LogEntry__c.MessageMasked__c + LogEntry__c.OriginType__c diff --git a/nebula-logger/main/logger-engine/classes/ComponentLogger.cls b/nebula-logger/main/logger-engine/classes/ComponentLogger.cls index 821712d86..4eb2b8d88 100644 --- a/nebula-logger/main/logger-engine/classes/ComponentLogger.cls +++ b/nebula-logger/main/logger-engine/classes/ComponentLogger.cls @@ -5,7 +5,7 @@ /** * @group Logger Engine - * @description Controller class used by the light web component `c/logger` + * @description Controller class used by the lightning web component `logger` * @see Logger * @see LogEntryEventBuilder */ @@ -60,7 +60,6 @@ public inherited sharing class ComponentLogger { private static void setStackTraceDetails(LogEntryEventBuilder logEntryEventBuilder, String stackTraceString) { String originLocation; - String originType; Boolean isAuraComponent = false; if (String.isNotBlank(stackTraceString) == true) { @@ -109,7 +108,7 @@ public inherited sharing class ComponentLogger { private static String truncateFieldValue(Schema.SObjectField field, String value) { Integer fieldMaxLength = field.getDescribe().getLength(); - if (String.isEmpty(value)) { + if (String.isBlank(value)) { return value; } else if (value.length() <= fieldMaxLength) { return value; diff --git a/nebula-logger/main/logger-engine/classes/FlowCollectionLogEntry.cls b/nebula-logger/main/logger-engine/classes/FlowCollectionLogEntry.cls index d9c542bba..d4c8bf9a0 100644 --- a/nebula-logger/main/logger-engine/classes/FlowCollectionLogEntry.cls +++ b/nebula-logger/main/logger-engine/classes/FlowCollectionLogEntry.cls @@ -29,7 +29,7 @@ global inherited sharing class FlowCollectionLogEntry { /** * @description The records to relate to this log entry - the records' JSON is automatically added to the log entry */ - @InvocableVariable(required=true label='Records') + @InvocableVariable(required=false label='Records') global List records; /** diff --git a/nebula-logger/main/logger-engine/classes/FlowRecordLogEntry.cls b/nebula-logger/main/logger-engine/classes/FlowRecordLogEntry.cls index 36e3d30d7..6753a12c6 100644 --- a/nebula-logger/main/logger-engine/classes/FlowRecordLogEntry.cls +++ b/nebula-logger/main/logger-engine/classes/FlowRecordLogEntry.cls @@ -29,7 +29,7 @@ global inherited sharing class FlowRecordLogEntry { /** * @description The record to relate to this log entry - the record's JSON is automatically added to the log entry */ - @InvocableVariable(required=true label='Record') + @InvocableVariable(required=false label='Record') global SObject record; /** diff --git a/nebula-logger/main/logger-engine/classes/LogEntryEventBuilder.cls b/nebula-logger/main/logger-engine/classes/LogEntryEventBuilder.cls index bf4480bc6..c5532fa7d 100644 --- a/nebula-logger/main/logger-engine/classes/LogEntryEventBuilder.cls +++ b/nebula-logger/main/logger-engine/classes/LogEntryEventBuilder.cls @@ -8,18 +8,8 @@ * @description Builder class that generates each `LogEntryEvent__e` record * @see Logger */ +@SuppressWarnings('PMD.NcssTypeCount, PMD.ApexCRUDViolation') global with sharing class LogEntryEventBuilder { - private static final String API_VERSION = getApiVersion(); - private static final AuthSession AUTH_SESSION = getAuthSession(); - private static final List IGNORED_CLASSES = getIgnoredClasses(); - private static final String NAMESPACE_PREFIX = getNamespacePrefix(); - private static final SObject NETWORK_SITE = getNetwork(); - private static final Organization ORGANIZATION = getOrganization(); - private static final String ORIGIN_TYPE_APEX = 'Apex'; - private static final User USER = getUser(); - private static final Map SOBJECT_NAME_TO_CLASSIFICATION = new Map(); - private static final Map SOBJECT_SUFFIX_TO_CLASSIFICATION = getSObjectSuffixToClassification(); - private final LogEntryEvent__e logEntryEvent; private final LoggingLevel entryLoggingLevel; @@ -28,7 +18,76 @@ global with sharing class LogEntryEventBuilder { private Boolean detailsAreSet = false; private Boolean shouldSave; - private List tags = new List(); + private Set tags = new Set(); + private Boolean tagDetailsAreSet = true; + + private static final String API_VERSION = getApiVersion(); + private static final List IGNORED_CLASSES = getIgnoredClasses(); + private static final String NAMESPACE_PREFIX = getNamespacePrefix(); + private static final Map SOBJECT_NAME_TO_CLASSIFICATION = new Map(); + private static final Map SOBJECT_SUFFIX_TO_CLASSIFICATION = getSObjectSuffixToClassification(); + + // These constants all involve queries and/or increasing heap size, so custom getters are used for lazy-loading + // This avoids unnecessarily consuming resources when logging is disabled, etc. + private static final AuthSession CACHED_AUTH_SESSION { + get { + if (CACHED_AUTH_SESSION == null) { + CACHED_AUTH_SESSION = queryAuthSession(); + } + return CACHED_AUTH_SESSION; + } + set; + } + + private static final List CACHED_DATA_MASK_RULES { + get { + if (CACHED_DATA_MASK_RULES == null) { + CACHED_DATA_MASK_RULES = loadDataMaskRules(); + } + return CACHED_DATA_MASK_RULES; + } + set; + } + + private static final SObject CACHED_NETWORK_SITE { + get { + if (CACHED_NETWORK_SITE == null) { + CACHED_NETWORK_SITE = queryNetwork(); + } + return CACHED_NETWORK_SITE; + } + set; + } + + private static final Organization CACHED_ORGANIZATION { + get { + if (CACHED_ORGANIZATION == null) { + CACHED_ORGANIZATION = queryOrganization(); + } + return CACHED_ORGANIZATION; + } + set; + } + + private static final String CACHED_ORGANIZATION_ENVIRONMENT_TYPE { + get { + if (CACHED_ORGANIZATION_ENVIRONMENT_TYPE == null) { + CACHED_ORGANIZATION_ENVIRONMENT_TYPE = getOrganizationEnvironmentType(); + } + return CACHED_ORGANIZATION_ENVIRONMENT_TYPE; + } + set; + } + + private static final User CACHED_USER { + get { + if (CACHED_USER == null) { + CACHED_USER = queryUser(); + } + return CACHED_USER; + } + set; + } /** * @description Used by `Logger` to instantiate a new instance of `LogEntryEventBuilder` @@ -44,59 +103,26 @@ global with sharing class LogEntryEventBuilder { return; } - String orgEnvironmentType; - if (ORGANIZATION.IsSandbox == true && ORGANIZATION.TrialExpirationDate != null) { - orgEnvironmentType = 'Scratch Org'; - } else if (ORGANIZATION.IsSandbox == true) { - orgEnvironmentType = 'Sandbox'; - } else { - orgEnvironmentType = 'Production'; - } - this.logEntryEvent = new LogEntryEvent__e( - ApiVersion__c = API_VERSION, - LimitsAggregateQueriesMax__c = Limits.getLimitAggregateQueries(), LimitsAggregateQueriesUsed__c = Limits.getAggregateQueries(), - LimitsAsyncCallsMax__c = Limits.getLimitAsyncCalls(), LimitsAsyncCallsUsed__c = Limits.getAsyncCalls(), - LimitsCalloutsMax__c = Limits.getLimitCallouts(), LimitsCalloutsUsed__c = Limits.getCallouts(), - LimitsCpuTimeMax__c = Limits.getLimitCpuTime(), LimitsCpuTimeUsed__c = Limits.getCpuTime(), - LimitsDmlRowsMax__c = Limits.getLimitDmlRows(), LimitsDmlRowsUsed__c = Limits.getDmlRows(), - LimitsDmlStatementsMax__c = Limits.getLimitDmlStatements(), LimitsDmlStatementsUsed__c = Limits.getDmlStatements(), - LimitsEmailInvocationsMax__c = Limits.getLimitEmailInvocations(), LimitsEmailInvocationsUsed__c = Limits.getEmailInvocations(), - LimitsFutureCallsMax__c = Limits.getLimitFutureCalls(), LimitsFutureCallsUsed__c = Limits.getFutureCalls(), - LimitsHeapSizeMax__c = Limits.getLimitHeapSize(), LimitsHeapSizeUsed__c = Limits.getHeapSize(), - LimitsMobilePushApexCallsMax__c = Limits.getLimitMobilePushApexCalls(), LimitsMobilePushApexCallsUsed__c = Limits.getMobilePushApexCalls(), - LimitsQueueableJobsMax__c = Limits.getLimitQueueableJobs(), LimitsQueueableJobsUsed__c = Limits.getQueueableJobs(), - LimitsPublishImmediateDmlStatementsMax__c = Limits.getLimitPublishImmediateDML(), LimitsPublishImmediateDmlStatementsUsed__c = Limits.getPublishImmediateDML(), - LimitsSoqlQueriesMax__c = Limits.getLimitQueries(), LimitsSoqlQueriesUsed__c = Limits.getQueries(), - LimitsSoqlQueryLocatorRowsMax__c = Limits.getLimitQueryLocatorRows(), LimitsSoqlQueryLocatorRowsUsed__c = Limits.getQueryLocatorRows(), - LimitsSoqlQueryRowsMax__c = Limits.getLimitQueryRows(), LimitsSoqlQueryRowsUsed__c = Limits.getQueryRows(), - LimitsSoslSearchesMax__c = Limits.getLimitSoslQueries(), LimitsSoslSearchesUsed__c = Limits.getSoslQueries(), LoggingLevel__c = entryLoggingLevel.NAME(), LoggingLevelOrdinal__c = entryLoggingLevel.ORDINAL(), - OrganizationDomainUrl__c = Url.getOrgDomainUrl()?.toExternalForm(), - OrganizationEnvironmentType__c = orgEnvironmentType, - OrganizationId__c = ORGANIZATION.Id, - OrganizationInstanceName__c = ORGANIZATION.InstanceName, - OrganizationName__c = ORGANIZATION.Name, - OrganizationNamespacePrefix__c = ORGANIZATION.NamespacePrefix, - OrganizationType__c = ORGANIZATION.OrganizationType, - OriginType__c = ORIGIN_TYPE_APEX, + OriginType__c = 'Apex', Timestamp__c = System.now(), EpochTimestamp__c = System.now().getTime(), TriggerIsExecuting__c = Trigger.isExecuting, @@ -114,7 +140,7 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setMessage(LogMessage logMessage) { - if (this.shouldSave == false) { + if (this.shouldSave == false && Test.isRunningTest() == false) { return this; } @@ -129,9 +155,15 @@ global with sharing class LogEntryEventBuilder { global LogEntryEventBuilder setMessage(String message) { // To help with debugging unit tests, always run System.debug statement in a test context if ((this.shouldSave == true || Test.isRunningTest() == true) && this.logEntryEvent != null) { - String truncatedMessage = truncateFieldValue(Schema.LogEntryEvent__e.Message__c, message); + String cleanedMessage = applyDataMaskRules(message, true, false); + Boolean messageMasked = cleanedMessage != message; + String truncatedMessage = truncateFieldValue(Schema.LogEntryEvent__e.Message__c, cleanedMessage); + Boolean messageTruncated = + String.isNotBlank(cleanedMessage) && cleanedMessage.length() > Schema.LogEntryEvent__e.Message__c.getDescribe().getLength(); + this.logEntryEvent.Message__c = truncatedMessage; - this.logEntryEvent.MessageTruncated__c = message != truncatedMessage; + this.logEntryEvent.MessageMasked__c = messageMasked; + this.logEntryEvent.MessageTruncated__c = messageTruncated; this.logToApexDebug(message); } return this; @@ -374,9 +406,14 @@ global with sharing class LogEntryEventBuilder { return this; } + String recordJson = getJson(record); + String cleanedRecordJson = applyDataMaskRules(recordJson, false, true); + Boolean recordJsonMasked = cleanedRecordJson != recordJson; + this.logEntryEvent.RecordCollectionType__c = 'Single'; this.logEntryEvent.RecordId__c = record.Id; - this.logEntryEvent.RecordJson__c = truncateFieldValue(Schema.LogEntryEvent__e.RecordJson__c, JSON.serializePretty(record)); + this.logEntryEvent.RecordJson__c = cleanedRecordJson; + this.logEntryEvent.RecordJsonMasked__c = recordJsonMasked; this.logEntryEvent.RecordSObjectClassification__c = getSObjectClassification(record.getSObjectType()); this.logEntryEvent.RecordSObjectType__c = record.getSObjectType().getDescribe().getName(); this.logEntryEvent.RecordSObjectTypeNamespace__c = getSObjectTypeNamespace(record.getSObjectType()); @@ -398,7 +435,7 @@ global with sharing class LogEntryEventBuilder { String sobjectTypeName = sobjectType?.getDescribe().getName(); this.logEntryEvent.RecordCollectionType__c = 'List'; - this.logEntryEvent.RecordJson__c = truncateFieldValue(Schema.LogEntryEvent__e.RecordJson__c, JSON.serializePretty(records)); + this.logEntryEvent.RecordJson__c = getJson(records); this.logEntryEvent.RecordSObjectClassification__c = getSObjectClassification(sobjectType); this.logEntryEvent.RecordSObjectType__c = sobjectTypeName; this.logEntryEvent.RecordSObjectTypeNamespace__c = getSObjectTypeNamespace(sobjectType); @@ -417,6 +454,7 @@ global with sharing class LogEntryEventBuilder { } this.tags.add(tag); + this.tagDetailsAreSet = false; return this; } @@ -426,11 +464,13 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder addTags(List tags) { - if (this.shouldSave == false || tags == null || tags.isEmpty()) { + if (tags == null || tags.isEmpty()) { return this; } - this.tags.addAll(tags); + for (String tag : tags) { + this.addTag(tag); + } return this; } @@ -512,15 +552,24 @@ global with sharing class LogEntryEventBuilder { } // Lazy-loading of some details to help minimize Apex heap size usage until needed - if (this.detailsAreSet == false && Logger.getUserSettings().AnonymousMode__c == false) { + if (this.detailsAreSet == false) { + if (Logger.getUserSettings().AnonymousMode__c == false) { + this.setUserDetails(); + this.setUserSessionDetails(); + } this.setNetworkDetails(); - this.setUserDetails(); - this.setUserSessionDetails(); - + this.setTransactionDetails(); this.detailsAreSet = true; } - this.logEntryEvent.Tags__c = getTagsString(this.tags); + // getLogEntryEvent() and addTag() could both be called multiple times + // for the same instance of LogEntryBuilder, so tags are set (if needed) + // each time getLogEntryEvent() is called, whereas methods executed above (using Boolean + // this.detailsAreSet) only need to be run once + if (this.tagDetailsAreSet == false) { + this.setTagsDetails(); + this.tagDetailsAreSet = true; + } // Salesforce does not provide precise datetimes in Apex triggers for platform events // Set the string value of timestamp to a second field as a workaround @@ -532,26 +581,83 @@ global with sharing class LogEntryEventBuilder { return this.logEntryEvent; } + private void logToApexDebug(String message) { + String template = Logger.getUserSettings()?.SystemLogMessageFormat__c?.unescapeJava(); + if (String.isNotBlank(template)) { + List possibleReplacements = template.split('\\{'); + for (String possibleReplacement : possibleReplacements) { + if (String.isBlank(possibleReplacement)) { + continue; + } + String logEntryFieldName = possibleReplacement.substringBefore('}'); + Object logEntryFieldValue = this.logEntryEvent.get(logEntryFieldName); + if (logEntryFieldValue == null) { + logEntryFieldValue = '(null)'; + } + template = template.replace('{' + logEntryFieldName + '}', String.valueOf(logEntryFieldValue)); + } + this.debugMessage = template; + } else { + this.debugMessage = message; + } + System.debug(this.entryLoggingLevel, this.debugMessage); + } + private void setNetworkDetails() { - if (NETWORK_SITE == null) { + if (CACHED_NETWORK_SITE == null) { + return; + } + + this.logEntryEvent.NetworkName__c = (String) CACHED_NETWORK_SITE.get('Name'); + this.logEntryEvent.NetworkLoginUrl__c = Network.getLoginUrl(CACHED_NETWORK_SITE.ID); + this.logEntryEvent.NetworkLogoutUrl__c = Network.getLogoutUrl(CACHED_NETWORK_SITE.ID); + this.logEntryEvent.NetworkSelfRegistrationUrl__c = Network.getSelfRegUrl(CACHED_NETWORK_SITE.ID); + this.logEntryEvent.NetworkUrlPathPrefix__c = (String) CACHED_NETWORK_SITE.get('UrlPathPrefix'); + } + + private void setTagsDetails() { + if (this.tags.isEmpty() == true || this.tagDetailsAreSet == true) { return; } - this.logEntryEvent.NetworkName__c = (String) NETWORK_SITE.get('Name'); - this.logEntryEvent.NetworkLoginUrl__c = Network.getLoginUrl(NETWORK_SITE.ID); - this.logEntryEvent.NetworkLogoutUrl__c = Network.getLogoutUrl(NETWORK_SITE.ID); - this.logEntryEvent.NetworkSelfRegistrationUrl__c = Network.getSelfRegUrl(NETWORK_SITE.ID); - this.logEntryEvent.NetworkUrlPathPrefix__c = (String) NETWORK_SITE.get('UrlPathPrefix'); + this.logEntryEvent.Tags__c = String.escapeSingleQuotes(String.join(new List(this.tags), '\n')); + } + + private void setTransactionDetails() { + this.logEntryEvent.ApiVersion__c = API_VERSION; + this.logEntryEvent.LimitsAggregateQueriesMax__c = Limits.getLimitAggregateQueries(); + this.logEntryEvent.LimitsAsyncCallsMax__c = Limits.getLimitAsyncCalls(); + this.logEntryEvent.LimitsCalloutsMax__c = Limits.getLimitCallouts(); + this.logEntryEvent.LimitsCpuTimeMax__c = Limits.getLimitCpuTime(); + this.logEntryEvent.LimitsDmlRowsMax__c = Limits.getLimitDmlRows(); + this.logEntryEvent.LimitsDmlStatementsMax__c = Limits.getLimitDmlStatements(); + this.logEntryEvent.LimitsEmailInvocationsMax__c = Limits.getLimitEmailInvocations(); + this.logEntryEvent.LimitsFutureCallsMax__c = Limits.getLimitFutureCalls(); + this.logEntryEvent.LimitsHeapSizeMax__c = Limits.getLimitHeapSize(); + this.logEntryEvent.LimitsMobilePushApexCallsMax__c = Limits.getLimitMobilePushApexCalls(); + this.logEntryEvent.LimitsQueueableJobsMax__c = Limits.getLimitQueueableJobs(); + this.logEntryEvent.LimitsPublishImmediateDmlStatementsMax__c = Limits.getLimitPublishImmediateDML(); + this.logEntryEvent.LimitsSoqlQueriesMax__c = Limits.getLimitQueries(); + this.logEntryEvent.LimitsSoqlQueryLocatorRowsMax__c = Limits.getLimitQueryLocatorRows(); + this.logEntryEvent.LimitsSoqlQueryRowsMax__c = Limits.getLimitQueryRows(); + this.logEntryEvent.LimitsSoslSearchesMax__c = Limits.getLimitSoslQueries(); + this.logEntryEvent.OrganizationDomainUrl__c = Url.getOrgDomainUrl()?.toExternalForm(); + this.logEntryEvent.OrganizationEnvironmentType__c = CACHED_ORGANIZATION_ENVIRONMENT_TYPE; + this.logEntryEvent.OrganizationId__c = CACHED_ORGANIZATION.Id; + this.logEntryEvent.OrganizationInstanceName__c = CACHED_ORGANIZATION.InstanceName; + this.logEntryEvent.OrganizationName__c = CACHED_ORGANIZATION.Name; + this.logEntryEvent.OrganizationNamespacePrefix__c = CACHED_ORGANIZATION.NamespacePrefix; + this.logEntryEvent.OrganizationType__c = CACHED_ORGANIZATION.OrganizationType; } private void setUserDetails() { - this.logEntryEvent.LoggedById__c = USER.Id; - this.logEntryEvent.LoggedByUsername__c = USER.Username; - this.logEntryEvent.ProfileName__c = USER.Profile.Name; - this.logEntryEvent.UserLicenseDefinitionKey__c = USER.Profile.UserLicense.LicenseDefinitionKey; - this.logEntryEvent.UserLicenseId__c = USER.Profile.UserLicenseId; - this.logEntryEvent.UserLicenseName__c = USER.Profile.UserLicense.Name; - this.logEntryEvent.UserRoleName__c = USER.UserRole?.Name; + this.logEntryEvent.LoggedById__c = CACHED_USER.Id; + this.logEntryEvent.LoggedByUsername__c = CACHED_USER.Username; + this.logEntryEvent.ProfileName__c = CACHED_USER.Profile.Name; + this.logEntryEvent.UserLicenseDefinitionKey__c = CACHED_USER.Profile.UserLicense.LicenseDefinitionKey; + this.logEntryEvent.UserLicenseId__c = CACHED_USER.Profile.UserLicenseId; + this.logEntryEvent.UserLicenseName__c = CACHED_USER.Profile.UserLicense.Name; + this.logEntryEvent.UserRoleName__c = CACHED_USER.UserRole?.Name; } private void setUserSessionDetails() { @@ -559,17 +665,17 @@ global with sharing class LogEntryEventBuilder { this.logEntryEvent.Locale__c = UserInfo.getLocale(); this.logEntryEvent.NetworkId__c = Network.getNetworkId(); - this.logEntryEvent.LoginHistoryId__c = AUTH_SESSION?.LoginHistoryId; - this.logEntryEvent.LoginApplication__c = AUTH_SESSION?.LoginHistory.Application; - this.logEntryEvent.LoginBrowser__c = AUTH_SESSION?.LoginHistory.Browser; - this.logEntryEvent.LoginPlatform__c = AUTH_SESSION?.LoginHistory.Platform; - this.logEntryEvent.LoginType__c = AUTH_SESSION?.LoginType; - this.logEntryEvent.LogoutUrl__c = AUTH_SESSION?.LogoutUrl; + this.logEntryEvent.LoginHistoryId__c = CACHED_AUTH_SESSION?.LoginHistoryId; + this.logEntryEvent.LoginApplication__c = CACHED_AUTH_SESSION?.LoginHistory.Application; + this.logEntryEvent.LoginBrowser__c = CACHED_AUTH_SESSION?.LoginHistory.Browser; + this.logEntryEvent.LoginPlatform__c = CACHED_AUTH_SESSION?.LoginHistory.Platform; + this.logEntryEvent.LoginType__c = CACHED_AUTH_SESSION?.LoginType; + this.logEntryEvent.LogoutUrl__c = CACHED_AUTH_SESSION?.LogoutUrl; this.logEntryEvent.ProfileId__c = UserInfo.getProfileId(); - this.logEntryEvent.SessionId__c = AUTH_SESSION?.Id; - this.logEntryEvent.SessionSecurityLevel__c = AUTH_SESSION?.SessionSecurityLevel; - this.logEntryEvent.SessionType__c = AUTH_SESSION?.SessionType; - this.logEntryEvent.SourceIp__c = AUTH_SESSION?.SourceIp; + this.logEntryEvent.SessionId__c = CACHED_AUTH_SESSION?.Id; + this.logEntryEvent.SessionSecurityLevel__c = CACHED_AUTH_SESSION?.SessionSecurityLevel; + this.logEntryEvent.SessionType__c = CACHED_AUTH_SESSION?.SessionType; + this.logEntryEvent.SourceIp__c = CACHED_AUTH_SESSION?.SourceIp; this.logEntryEvent.TimeZoneId__c = UserInfo.getTimeZone().getId(); this.logEntryEvent.TimeZoneName__c = UserInfo.getTimeZone().getDisplayName(); this.logEntryEvent.UserLoggingLevel__c = userLoggingLevel.name(); @@ -582,7 +688,90 @@ global with sharing class LogEntryEventBuilder { } } - private String getSObjectClassification(Schema.SObjectType sobjectType) { + // Private static helper methods + @TestVisible + private static void addMockDataMaskRule(LogEntryDataMaskRule__mdt dataMaskRule) { + CACHED_DATA_MASK_RULES.add(dataMaskRule); + } + + private static String applyDataMaskRules(String dataInput, Boolean applyToMessage, Boolean applyToRecordJson) { + if (Logger.getUserSettings().ApplyDataMaskRules__c == false) { + return dataInput; + } + + for (LogEntryDataMaskRule__mdt dataMaskRule : CACHED_DATA_MASK_RULES) { + if ((applyToMessage && dataMaskRule.ApplyToMessage__c) == true || (applyToRecordJson && dataMaskRule.ApplyToRecordJson__c) == true) { + dataInput = dataInput.replaceAll(dataMaskRule.SensitiveDataRegEx__c, dataMaskRule.ReplacementRegEx__c); + } + } + return dataInput; + } + + private static String getApiVersion() { + // Small hack to determine the org's current API version (since Apex doesn't natively provide it) + // Serializing any SObject w/ an ID will include the API version + // So, use UserInfo.getUserId() to create the current user's record without querying + // Then parse the JSON to get the API version + // Expected JSON: {"attributes":{"type":"User","url":"/services/data/v52.0/sobjects/User/005J000000AugnYIAR"} + String userJson = JSON.serialize(new User(Id = UserInfo.getUserId())); + return userJson.substringAfter('/data/').substringBefore('/sobjects/User'); + } + + private static List loadDataMaskRules() { + List activeDataMaskRules = new List(); + for (LogEntryDataMaskRule__mdt dataMaskRule : LogEntryDataMaskRule__mdt.getAll().values()) { + if (dataMaskRule.IsEnabled__c == true) { + activeDataMaskRules.add(dataMaskRule); + } + } + if (Test.isRunningTest() == true) { + // Tests shouldn't rely on the actual CMDT rules in the org + // Clear the org's loaded records during tests, and mock via addMockDataMaskRule() + activeDataMaskRules.clear(); + } + return activeDataMaskRules; + } + + private static List getIgnoredClasses() { + return new List{ + ComponentLogger.class.getName(), + FlowLogger.class.getName(), + Logger.class.getName(), + LogMessage.class.getName(), + LogEntryEventBuilder.class.getName() + }; + } + + private static String getJson(SObject record) { + SObject strippedRecord = stripInaccessible(new List{ record }).get(0); + return truncateFieldValue(Schema.LogEntryEvent__e.RecordJson__c, JSON.serializePretty(strippedRecord)); + } + + private static String getJson(List records) { + List strippedRecords = stripInaccessible(records); + return truncateFieldValue(Schema.LogEntryEvent__e.RecordJson__c, JSON.serializePretty(strippedRecords)); + } + + private static String getOrganizationEnvironmentType() { + String orgEnvironmentType; + if (CACHED_ORGANIZATION.IsSandbox == true && CACHED_ORGANIZATION.TrialExpirationDate != null) { + orgEnvironmentType = 'Scratch Org'; + } else if (CACHED_ORGANIZATION.IsSandbox == true) { + orgEnvironmentType = 'Sandbox'; + } else { + orgEnvironmentType = 'Production'; + } + return orgEnvironmentType; + } + + private static String getNamespacePrefix() { + String className = LogEntryEventBuilder.class.getName(); + String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; + + return namespacePrefix; + } + + private static String getSObjectClassification(Schema.SObjectType sobjectType) { String sobjectName = sobjectType.getDescribe().getName(); // Check the map to see if we've already determined the classification for this SObject type @@ -615,7 +804,7 @@ global with sharing class LogEntryEventBuilder { return sobjectClassification; } - private String getSObjectTypeNamespace(Schema.SObjectType sobjectType) { + private static String getSObjectTypeNamespace(Schema.SObjectType sobjectType) { String sobjectFullName = sobjectType.getDescribe().getName(); String sobjectLocalName = sobjectType.getDescribe().getLocalName(); @@ -627,79 +816,11 @@ global with sharing class LogEntryEventBuilder { return namespace; } - private void logToApexDebug(String message) { - String template = Logger.getUserSettings()?.SystemLogMessageFormat__c; - if (String.isNotBlank(template)) { - List possibleReplacements = template.split('\\{'); - for (String possibleReplacement : possibleReplacements) { - if (String.isBlank(possibleReplacement)) { - continue; - } - String logEntryFieldName = possibleReplacement.substringBefore('}'); - template = template.replace('{' + logEntryFieldName + '}', String.valueOf(this.logEntryEvent.get(logEntryFieldName))); - } - this.debugMessage = template; - } else { - this.debugMessage = message; - } - System.debug(this.entryLoggingLevel, this.debugMessage); - } - - // Private static methods - private static AuthSession getAuthSession() { - if (String.isBlank(UserInfo.getSessionId())) { - return null; - } - - // Scheduled jobs, batch jobs, invocables, future methods and queueables are ALL - // run by the Automated Process user - attempting to access Auth.SessionManagement - // methods as that user throws an UNCATCHABLE error. Let's sidestep that by querying AuthSession instead. - - List sessions = [ - SELECT - Id, - LoginType, - LoginHistoryId, - LoginHistory.Application, - LoginHistory.Browser, - LoginHistory.Platform, - LogoutUrl, - SessionSecurityLevel, - SessionType, - SourceIp - FROM AuthSession - WHERE UsersId = :UserInfo.getUserId() AND IsCurrent = TRUE AND ParentId = NULL - ]; - - if (sessions.isEmpty()) { - return null; - } else { - return sessions.get(0); - } - } - - private static String getApiVersion() { - // Small hack to determine the org's current API version (since Apex doesn't natively provide it) - // Serializing any SObject w/ an ID will include the API version - // So, use UserInfo.getUserId() to create the current user's record without querying - // Then parse the JSON to get the API version - // Expected JSON: {"attributes":{"type":"User","url":"/services/data/v52.0/sobjects/User/005J000000AugnYIAR"} - String userJson = JSON.serialize(new User(Id = UserInfo.getUserId())); - return userJson.substringAfter('/data/').substringBefore('/sobjects/User'); - } - - private static List getIgnoredClasses() { - return new List{ FlowLogger.class.getName(), Logger.class.getName(), LogMessage.class.getName(), LogEntryEventBuilder.class.getName() }; - } - - private static String getNamespacePrefix() { - String className = LogEntryEventBuilder.class.getName(); - String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; - - return namespacePrefix; - } - private static Map getSObjectSuffixToClassification() { + // TODO add sample metadata for external object + picklist value + test + // Example: MyExternalObject__x + // '__x' => 'External Object' + return new Map{ // Example: MyBigObject__b '__b' => 'Big Object', @@ -720,39 +841,6 @@ global with sharing class LogEntryEventBuilder { }; } - private static Organization getOrganization() { - return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; - } - - private static SObject getNetwork() { - Id networkId; - if (Network.getNetworkId() == null) { - return null; - } else { - networkId = Network.getNetworkId(); - } - - String networkApiName = 'Network'; - // Networks (communities) may not be enabled in the org (no Network object), so run everything dynamically - Boolean networksEnabled = Schema.getGlobalDescribe().containsKey(networkApiName); - - if (!networksEnabled) { - return null; - } - - String queryString = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :networkId'; - - return Database.query(queryString); - } - - private static User getUser() { - return [ - SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name - FROM User - WHERE Id = :UserInfo.getUserId() - ]; - } - // TODO need to revisit Visualforce logic, re-add fields to either Log__c or LogEntry__c, etc. /* private static String getVisualforcePageName() { String visualforcePageName = ApexPages.currentPage() == null ? null : ApexPages.currentPage().getUrl(); @@ -766,36 +854,78 @@ global with sharing class LogEntryEventBuilder { } */ private static Boolean isValidStackTrace(String stackTraceString) { - if (String.isEmpty(stackTraceString)) { + if (String.isBlank(stackTraceString) || stackTraceString == '()' || stackTraceString == '(' + NAMESPACE_PREFIX + ')') { return false; } - if (stackTraceString == '()' || stackTraceString == '(' + NAMESPACE_PREFIX + ')') { - return false; + return true; + } + + private static AuthSession queryAuthSession() { + if (String.isBlank(UserInfo.getSessionId())) { + return new AuthSession(); } - return true; + // Scheduled jobs, batch jobs, invocables, future methods and queueables are ALL + // run by the Automated Process user - attempting to access Auth.SessionManagement + // methods as that user throws an UNCATCHABLE error. Let's sidestep that by querying AuthSession instead. + List sessions = [ + SELECT + Id, + LoginType, + LoginHistoryId, + LoginHistory.Application, + LoginHistory.Browser, + LoginHistory.Platform, + LogoutUrl, + SessionSecurityLevel, + SessionType, + SourceIp + FROM AuthSession + WHERE UsersId = :UserInfo.getUserId() AND IsCurrent = TRUE AND ParentId = NULL + ]; + return sessions.isEmpty() ? new AuthSession() : sessions.get(0); } - private static String getTagsString(List tags) { - if (tags == null || tags.isEmpty()) { + private static SObject queryNetwork() { + Id networkId = Network.getNetworkId(); + if (networkId == null || Schema.getGlobalDescribe().containsKey('Network') == false) { return null; } - // De-duplicate the list of tags - tags = new List(new Set(tags)); + // Networks (aka experience sites aka community sites aka portal sites ò_ô) + // may not be enabled in the org (no Network object), so run everything dynamically + String queryString = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :networkId'; + return Database.query(queryString); + } - return String.escapeSingleQuotes(String.join(tags, '\n')); + private static Organization queryOrganization() { + return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; } - private static String truncateFieldValue(Schema.SObjectField field, String value) { - Integer fieldMaxLength = field.getDescribe().getLength(); - if (String.isEmpty(value)) { - return value; - } else if (value.length() <= fieldMaxLength) { - return value; + private static User queryUser() { + return [ + SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name + FROM User + WHERE Id = :UserInfo.getUserId() + ]; + } + + private static List stripInaccessible(List records) { + if ( + Logger.getUserSettings().StripInaccessibleRecordFields__c == false || + records == null || + records.get(0).getSObjectType() == Schema.AggregateResult.SObjectType + ) { + return records; } - return value.left(fieldMaxLength); + SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE, records, false); + return securityDecision.getRecords(); + } + + private static String truncateFieldValue(Schema.SObjectField field, String value) { + Integer fieldMaxLength = field.getDescribe().getLength(); + return value?.left(fieldMaxLength); } } diff --git a/nebula-logger/main/logger-engine/classes/Logger.cls b/nebula-logger/main/logger-engine/classes/Logger.cls index 4a6c264c0..73fdeb856 100644 --- a/nebula-logger/main/logger-engine/classes/Logger.cls +++ b/nebula-logger/main/logger-engine/classes/Logger.cls @@ -44,11 +44,7 @@ global with sharing class Logger { static { System.debug(LoggingLevel.INFO, 'Logger.getTransactionId() == ' + getTransactionId()); - // If settings have not been configured, then insert the org defaults - LoggerSettings__c orgDefaults = LoggerSettings__c.getOrgDefaults(); - if (orgDefaults.Id == null) { - insert orgDefaults; - } + setupOrgDefaults(); } /** @@ -2510,7 +2506,7 @@ global with sharing class Logger { when EVENT_BUS { // TODO add error handling for when event bus fails to publish List results = EventBus.publish(logEntryEvents); - System.debug('saveResults =' + results); + System.debug(DEFAULT_LOGGING_LEVEL, 'saveResults =' + results); } when QUEUEABLE { System.enqueueJob(new QueueableSaver(logEntryEvents)); @@ -2641,6 +2637,15 @@ global with sharing class Logger { return newEntry(loggingLevel, isEnabled(loggingLevel)); } + @SuppressWarnings('PMD.ApexCRUDViolation') + private static void setupOrgDefaults() { + // If settings have not been configured, then insert the org defaults + LoggerSettings__c orgDefaults = LoggerSettings__c.getOrgDefaults(); + if (orgDefaults.Id == null) { + insert orgDefaults; + } + } + private static LogEntryEventBuilder newEntry(LoggingLevel loggingLevel, Boolean shouldSave) { LogEntryEventBuilder logEntryEventBuilder = new LogEntryEventBuilder(LoggingLevel, shouldSave); if (logEntryEventBuilder.shouldSave() == true) { @@ -2720,8 +2725,6 @@ global with sharing class Logger { // Inner class for saving log entries via a queuable job global class QueueableSaver implements Queueable { - private Id jobId; - private List logEntryEvents = new List(); private QueueableSaver(List logEntryEvents) { @@ -2738,6 +2741,7 @@ global with sharing class Logger { private final String BASE_URL = System.Url.getSalesforceBaseUrl().toExternalForm() + '/services/data/v52.0'; private final String COMPOSITE_ENDPOINT = '/composite/sobjects'; + @SuppressWarnings('PMD.ApexSuggestUsingNamedCred') public void insertRecords(List records) { HttpRequest request = new HttpRequest(); request.setEndpoint(BASE_URL + COMPOSITE_ENDPOINT); @@ -2827,8 +2831,6 @@ global with sharing class Logger { } private String formatValue(String unformattedValue) { - final String invalidValueError = unformattedValue + ' is not a valid UUID value'; - // Remove any non-alphanumeric characters unformattedValue = unformattedValue.replaceAll('[^a-zA-Z0-9]', ''); @@ -2855,8 +2857,9 @@ global with sharing class Logger { private Integer convertHexToInteger(String hexValue) { hexValue = hexValue.toLowerCase(); - if (hexValue.startsWith(HEX_PREFIX)) + if (hexValue.startsWith(HEX_PREFIX)) { hexValue = hexValue.substringAfter(HEX_PREFIX); + } Integer integerValue = 0; for (String hexCharacter : hexValue.split('')) { diff --git a/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.MastercardCreditCardNumber.md-meta.xml b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.MastercardCreditCardNumber.md-meta.xml new file mode 100644 index 000000000..4d4a6b067 --- /dev/null +++ b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.MastercardCreditCardNumber.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ApplyToMessage__c + true + + + ApplyToRecordJson__c + true + + + IsEnabled__c + true + + + ReplacementRegEx__c + $1****-****-****-$5 + + + SensitiveDataRegEx__c + (^|[ ])(5\d{3})[- ]*(\d{4})[- ]*(\d{4})[- ]*(\d{4}) + + diff --git a/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.SocialSecurityNumber.md-meta.xml b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.SocialSecurityNumber.md-meta.xml new file mode 100644 index 000000000..bd25920ff --- /dev/null +++ b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.SocialSecurityNumber.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ApplyToMessage__c + true + + + ApplyToRecordJson__c + true + + + IsEnabled__c + true + + + ReplacementRegEx__c + $1XXX-XX-$4 + + + SensitiveDataRegEx__c + (^|[ ])(\d{3})[- ]*(\d{2})[- ]*(\d{4}) + + diff --git a/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.VisaCreditCardNumber.md-meta.xml b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.VisaCreditCardNumber.md-meta.xml new file mode 100644 index 000000000..5a565da9e --- /dev/null +++ b/nebula-logger/main/logger-engine/customMetadata/LogEntryDataMaskRule.VisaCreditCardNumber.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ApplyToMessage__c + true + + + ApplyToRecordJson__c + true + + + IsEnabled__c + true + + + ReplacementRegEx__c + $1****-****-****-$5 + + + SensitiveDataRegEx__c + (^|[ ])(4\d{3})[- ]*(\d{4})[- ]*(\d{4})[- ]*(\d{4}) + + diff --git a/nebula-logger/main/logger-engine/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml b/nebula-logger/main/logger-engine/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml new file mode 100644 index 000000000..73e37b0ba --- /dev/null +++ b/nebula-logger/main/logger-engine/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml @@ -0,0 +1,101 @@ + + + + false + true + true + + + + Required + MasterLabel + + + Required + DeveloperName + + + + + Edit + IsEnabled__c + + + Edit + ApplyToMessage__c + + + Edit + ApplyToRecordJson__c + + + + + + true + true + true + + + + Required + SensitiveDataRegEx__c + + + + + Required + ReplacementRegEx__c + + + + + + false + true + true + + + + Edit + IsProtected + + + Readonly + CreatedById + + + + + Required + NamespacePrefix + + + Readonly + LastModifiedById + + + + + + true + true + false + + + + + + + false + false + false + false + false + + 00h1h000002oSky + 4 + 0 + Default + + diff --git a/nebula-logger/main/logger-engine/lwc/logger/__tests__/logger.test.js b/nebula-logger/main/logger-engine/lwc/logger/__tests__/logger.test.js index 617cacf0a..c2f7a337f 100644 --- a/nebula-logger/main/logger-engine/lwc/logger/__tests__/logger.test.js +++ b/nebula-logger/main/logger-engine/lwc/logger/__tests__/logger.test.js @@ -1,7 +1,6 @@ import { createElement } from 'lwc'; import Logger from 'c/logger'; import getSettings from '@salesforce/apex/ComponentLogger.getSettings'; -import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries'; import { registerApexTestWireAdapter } from '@salesforce/sfdx-lwc-jest'; const mockGetSettings = require('./data/getLoggerSettings.json'); @@ -139,7 +138,7 @@ describe('Logger lwc tests', () => { return Promise.resolve().then(() => { const numberOfLogEntries = 3; for (let i = 0; i < numberOfLogEntries; i++) { - const logEntry = logger.info('entry number: ' + i); + logger.info('entry number: ' + i); } expect(logger.getBufferSize()).toEqual(numberOfLogEntries); @@ -188,12 +187,7 @@ describe('Logger lwc tests', () => { const logEntry = logger.info('example log entry'); expect(logEntry.error).toBeFalsy(); - let error; - try { - missingVariable / 0; - } catch(e) { - error = e; - } + let error = new TypeError('oops'); expect(error).toBeTruthy(); expect(error.message).toBeTruthy(); expect(error.stack).toBeTruthy(); @@ -201,7 +195,7 @@ describe('Logger lwc tests', () => { logEntry.setError(error); expect(logEntry.error.message).toEqual(error.message); expect(logEntry.error.stack).toEqual(error.stack); - expect(logEntry.error.type).toEqual('ReferenceError'); + expect(logEntry.error.type).toEqual('TypeError'); }); }); it('adds tags', async () => { @@ -244,15 +238,17 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); - return Promise.resolve().then(() => { - logger.info('example INFO log entry'); - logger.debug('example DEBUG log entry'); - expect(logger.getBufferSize()).toBe(2); - - logger.saveLog(); - }).then(() => { - expect(logger.getBufferSize()).toBe(0); - }); + return Promise.resolve() + .then(() => { + logger.info('example INFO log entry'); + logger.debug('example DEBUG log entry'); + expect(logger.getBufferSize()).toBe(2); + + logger.saveLog(); + }) + .then(() => { + expect(logger.getBufferSize()).toBe(0); + }); }); it('still works for ERROR when disabled', async () => { const logger = createElement('c-logger', { is: Logger }); @@ -262,10 +258,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.error('example ERROR log entry') + const logEntry = logger + .error('example ERROR log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -288,10 +285,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.warn('example WARN log entry') + const logEntry = logger + .warn('example WARN log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -315,10 +313,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.info('example INFO log entry') + const logEntry = logger + .info('example INFO log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -342,10 +341,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.debug('example DEBUG log entry') + const logEntry = logger + .debug('example DEBUG log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -369,10 +369,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.fine('example FINE log entry') + const logEntry = logger + .fine('example FINE log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -396,10 +397,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.finer('example FINER log entry') + const logEntry = logger + .finer('example FINER log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); @@ -423,10 +425,11 @@ describe('Logger lwc tests', () => { getSettingsAdapter.emit(mockGetSettings); return Promise.resolve().then(() => { - const logEntry = logger.finest('example FINEST log entry') + const logEntry = logger + .finest('example FINEST log entry') .setMessage('some message') .setRecordId('some_record_Id') - .setRecord({Id: 'some_record_Id'}) + .setRecord({ Id: 'some_record_Id' }) .setError(new TypeError('oops')) .addTag('a tag') .addTags(['a second tag', 'a third tag']); diff --git a/nebula-logger/main/logger-engine/lwc/logger/logEntryBuilder.js b/nebula-logger/main/logger-engine/lwc/logger/logEntryBuilder.js index 1900944be..f252d72fe 100644 --- a/nebula-logger/main/logger-engine/lwc/logger/logEntryBuilder.js +++ b/nebula-logger/main/logger-engine/lwc/logger/logEntryBuilder.js @@ -64,7 +64,7 @@ const LogEntryBuilder = class { } _logToConsole() { - switch(this.loggingLevel) { + switch (this.loggingLevel) { case 'ERROR': console.error(this.message); console.error(this); diff --git a/nebula-logger/main/logger-engine/lwc/logger/logger.js b/nebula-logger/main/logger-engine/lwc/logger/logger.js index 2cd28024e..7100412d7 100644 --- a/nebula-logger/main/logger-engine/lwc/logger/logger.js +++ b/nebula-logger/main/logger-engine/lwc/logger/logger.js @@ -16,6 +16,8 @@ export default class Logger extends LightningElement { wiredSettings({ error, data }) { if (data) { this.settings = data; + } else if (error) { + console.error(error); } } @@ -68,9 +70,7 @@ export default class Logger extends LightningElement { saveLog() { if (this.getBufferSize() > 0) { saveComponentLogEntries({ componentLogEntries: this.componentLogEntries }) - .then(result => { - this.flushBuffer(); - }) + .then(this.flushBuffer()) .catch(error => { console.error(error); console.error(this.componentLogEntries); diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/LogEntryDataMaskRule__mdt.object-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/LogEntryDataMaskRule__mdt.object-meta.xml new file mode 100644 index 000000000..08b5e9333 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/LogEntryDataMaskRule__mdt.object-meta.xml @@ -0,0 +1,8 @@ + + + Used to configure RegEx-based rules to mask sensitive data in log entry messages (stored in LogEntryEvent__e.Message__c and LogEntry__c.Message__c) + + Log Entry Data Mask Rules + Public + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml new file mode 100644 index 000000000..eac8ff40c --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml @@ -0,0 +1,11 @@ + + + ApplyToMessage__c + true + false + DeveloperControlled + When checked, the data mask rule is applied to log entry messages (stored in LogEntryEvent__e.Message__c and LogEntry__c.Message__c) + + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml new file mode 100644 index 000000000..c2a7a021e --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml @@ -0,0 +1,11 @@ + + + ApplyToRecordJson__c + true + false + DeveloperControlled + When checked, the data mask rule is applied to log entry messages (stored in LogEntryEvent__e.RecordJson__c and LogEntry__c.RecordJson__c) + + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/IsEnabled__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/IsEnabled__c.field-meta.xml new file mode 100644 index 000000000..7c3dca299 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/IsEnabled__c.field-meta.xml @@ -0,0 +1,9 @@ + + + IsEnabled__c + true + false + SubscriberControlled + + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ReplacementRegEx__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ReplacementRegEx__c.field-meta.xml new file mode 100644 index 000000000..dcc111006 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/ReplacementRegEx__c.field-meta.xml @@ -0,0 +1,11 @@ + + + ReplacementRegEx__c + false + DeveloperControlled + + 255 + true + Text + false + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/SensitiveDataRegEx__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/SensitiveDataRegEx__c.field-meta.xml new file mode 100644 index 000000000..425d8bac5 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/fields/SensitiveDataRegEx__c.field-meta.xml @@ -0,0 +1,11 @@ + + + SensitiveDataRegEx__c + false + DeveloperControlled + + 255 + true + Text + false + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml new file mode 100644 index 000000000..857957973 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml @@ -0,0 +1,13 @@ + + + All + MasterLabel + DeveloperName + IsEnabled__c + ApplyToMessage__c + ApplyToRecordJson__c + SensitiveDataRegEx__c + ReplacementRegEx__c + Everything + + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/ComponentType__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/ComponentType__c.field-meta.xml index 61919a8d7..630e3e4d3 100644 --- a/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/ComponentType__c.field-meta.xml +++ b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/ComponentType__c.field-meta.xml @@ -1,4 +1,4 @@ - + ComponentType__c false diff --git a/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/MessageMasked__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/MessageMasked__c.field-meta.xml new file mode 100644 index 000000000..50c330553 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/MessageMasked__c.field-meta.xml @@ -0,0 +1,9 @@ + + + MessageMasked__c + false + false + + false + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/RecordJsonMasked__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/RecordJsonMasked__c.field-meta.xml new file mode 100644 index 000000000..72fb8ea22 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LogEntryEvent__e/fields/RecordJsonMasked__c.field-meta.xml @@ -0,0 +1,9 @@ + + + RecordJsonMasked__c + false + false + + false + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/ApplyDataMaskRules__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/ApplyDataMaskRules__c.field-meta.xml new file mode 100644 index 000000000..2436f49d0 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/ApplyDataMaskRules__c.field-meta.xml @@ -0,0 +1,11 @@ + + + ApplyDataMaskRules__c + true + false + When enabled, any data-mask rules (configured in LogEntryDataMaskRule__mdt) will be automatically applied to log entry messages. + + false + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/StripInaccessibleRecordFields__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/StripInaccessibleRecordFields__c.field-meta.xml new file mode 100644 index 000000000..6edea3991 --- /dev/null +++ b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/StripInaccessibleRecordFields__c.field-meta.xml @@ -0,0 +1,11 @@ + + + StripInaccessibleRecordFields__c + false + false + When enabled, any time an SObject record is logged, only fields that the current user can access will be included in the record's JSON. + + false + Checkbox + diff --git a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/SystemLogMessageFormat__c.field-meta.xml b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/SystemLogMessageFormat__c.field-meta.xml index a812ed6ed..bbbccd6b5 100644 --- a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/SystemLogMessageFormat__c.field-meta.xml +++ b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/fields/SystemLogMessageFormat__c.field-meta.xml @@ -1,4 +1,4 @@ - + SystemLogMessageFormat__c '{OriginLocation__c}\n{Message__c}' diff --git a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/listViews/All.listView-meta.xml b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/listViews/All.listView-meta.xml index 21d5585ac..47367afde 100644 --- a/nebula-logger/main/logger-engine/objects/LoggerSettings__c/listViews/All.listView-meta.xml +++ b/nebula-logger/main/logger-engine/objects/LoggerSettings__c/listViews/All.listView-meta.xml @@ -5,10 +5,13 @@ SETUP_TYPE IsEnabled__c LoggingLevel__c + ApplyDataMaskRules__c + StripInaccessibleRecordFields__c AnonymousMode__c - EnableSystemMessages__c + SystemLogMessageFormat__c DefaultLogShareAccessLevel__c DefaultNumberOfDaysToRetainLogs__c + EnableSystemMessages__c Everything diff --git a/nebula-logger/main/plugin-framework/classes/LoggerParameter.cls b/nebula-logger/main/plugin-framework/classes/LoggerParameter.cls index 1f44eeb33..c2274b54d 100644 --- a/nebula-logger/main/plugin-framework/classes/LoggerParameter.cls +++ b/nebula-logger/main/plugin-framework/classes/LoggerParameter.cls @@ -9,6 +9,9 @@ * and casts the parameters to common data types */ public class LoggerParameter { + private SObjectType configurationSObjectType; + private Map mockParameterByDeveloperName = new Map(); + /** * @description An instance of `LoggerParameter` that loads SObject Handler parameters from the object `LoggerSObjectHandlerParameter__mdt` */ @@ -35,9 +38,6 @@ public class LoggerParameter { set; } - private SObjectType configurationSObjectType; - private Map mockParameterByDeveloperName = new Map(); - private LoggerParameter(Schema.SObjectType configurationSObjectType) { this.configurationSObjectType = configurationSObjectType; } diff --git a/nebula-logger/tests/common/LoggerTestUtils.cls b/nebula-logger/tests/common/LoggerTestUtils.cls index fafe0f49d..535a79e02 100644 --- a/nebula-logger/tests/common/LoggerTestUtils.cls +++ b/nebula-logger/tests/common/LoggerTestUtils.cls @@ -5,7 +5,36 @@ @IsTest public class LoggerTestUtils { - private static Profile STANDARD_USER_PROFILE = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1]; + private static final Map SOBJECT_TYPE_TO_MOCK_ID_COUNT = new Map(); + private static final Profile STANDARD_USER_PROFILE = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1]; + + public static AggregateResult createMockAggregateResult() { + Map defaultMockAggregateKeyValues = new Map{ + 'fieldAvg' => 62.5, + 'fieldMax' => 100, + 'fieldMin' => 25, + 'fieldCount' => 4 + }; + return createMockAggregateResult(defaultMockAggregateKeyValues); + } + + public static AggregateResult createMockAggregateResult(Map mockAggregateKeyValues) { + return (AggregateResult) JSON.deserialize(JSON.serialize(mockAggregateKeyValues), AggregateResult.class); + } + + public static String createMockId(Schema.SObjectType sobjectType) { + Integer recordIdNumber = 1; + if (SOBJECT_TYPE_TO_MOCK_ID_COUNT.containsKey(sobjectType)) { + recordIdNumber = SOBJECT_TYPE_TO_MOCK_ID_COUNT.get(sobjectType); + } + String recordIdSuffix = String.valueOf(recordIdNumber++); + SOBJECT_TYPE_TO_MOCK_ID_COUNT.put(sobjectType, recordIdNumber); + + String recordIdKeyPrefix = sobjectType.getDescribe().getKeyPrefix(); + Integer idFieldLength = sobjectType.getDescribe().fields.getMap().get('Id').getDescribe().getLength(); + Integer recordIdCenterLength = idFieldLength - recordIdKeyPrefix.length() - recordIdSuffix.length(); + return recordIdKeyPrefix + '0'.repeat(recordIdCenterLength) + recordIdSuffix; + } public static User createStandardUser() { return new User( @@ -20,4 +49,48 @@ public class LoggerTestUtils { Username = 'logger_xyz@test.com.net.org' ); } + + public static Organization getOrganization() { + return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; + } + + public static String getOrganizationEnvironmentType() { + Organization organization = getOrganization(); + + String orgEnvironmentType; + if (organization.IsSandbox == true && organization.TrialExpirationDate != null) { + orgEnvironmentType = 'Scratch Org'; + } else if (organization.IsSandbox == true) { + orgEnvironmentType = 'Sandbox'; + } else { + orgEnvironmentType = 'Production'; + } + return orgEnvironmentType; + } + + public static SObject getNetwork() { + if (Network.getNetworkId() == null) { + return null; + } + + String networkApiName = 'Network'; + // Networks (communities) may not be enabled in the org (no Network object), so run everything dynamically + Boolean networksEnabled = Schema.getGlobalDescribe().containsKey(networkApiName); + + if (!networksEnabled) { + return null; + } + + String queryString = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :Network.getNetworkId()'; + + return Database.query(queryString); + } + + public static User getUser() { + return [ + SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name + FROM User + WHERE Id = :UserInfo.getUserId() + ]; + } } diff --git a/nebula-logger/tests/common/LoggerTestUtils.cls-meta.xml b/nebula-logger/tests/common/LoggerTestUtils.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/common/LoggerTestUtils.cls-meta.xml +++ b/nebula-logger/tests/common/LoggerTestUtils.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls b/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls index 87cc4de37..c99eeedc3 100644 --- a/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls @@ -28,7 +28,6 @@ private class LogBatchPurger_Tests { } insert logEntries; - LoggerTag__c tag = new LoggerTag__c(Name = 'My important tag'); insert tag; @@ -40,7 +39,6 @@ private class LogBatchPurger_Tests { insert logEntryTags; } - @IsTest static void it_should_throw_exception_when_user_does_not_have_delete_access() { Integer originalCountOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; @@ -53,9 +51,8 @@ private class LogBatchPurger_Tests { Test.startTest(); Database.executeBatch(new LogBatchPurger()); Test.stopTest(); - } catch(NoAccessException ex) { + } catch (NoAccessException ex) { System.assertEquals(LogBatchPurger.NO_DELETE_ACCESS_EXCEPTION_MESSAGE, ex.getMessage()); - } } Integer updatedCountOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; diff --git a/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogBatchPurger_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls b/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls index af6a04a0a..a53a46d30 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls @@ -347,12 +347,14 @@ private class LogEntryEventHandler_Tests { Test.startTest(); String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add(new LogEntryTagRule__mdt( - SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), - ComparisonType__c = 'CONTAINS', - ComparisonValue__c = logEntryEvent.Message__c.substring(1, 4), - Tags__c = configuredTagName - )); + LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + new LogEntryTagRule__mdt( + SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), + ComparisonType__c = 'CONTAINS', + ComparisonValue__c = logEntryEvent.Message__c.substring(1, 4), + Tags__c = configuredTagName + ) + ); Database.SaveResult saveResult = EventBus.publish(logEntryEvent); Test.stopTest(); @@ -387,12 +389,14 @@ private class LogEntryEventHandler_Tests { Test.startTest(); String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add(new LogEntryTagRule__mdt( - SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), - ComparisonType__c = 'EQUALS', - ComparisonValue__c = logEntryEvent.Message__c, - Tags__c = configuredTagName - )); + LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + new LogEntryTagRule__mdt( + SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), + ComparisonType__c = 'EQUALS', + ComparisonValue__c = logEntryEvent.Message__c, + Tags__c = configuredTagName + ) + ); Database.SaveResult saveResult = EventBus.publish(logEntryEvent); Test.stopTest(); @@ -429,12 +433,14 @@ private class LogEntryEventHandler_Tests { Test.startTest(); String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add(new LogEntryTagRule__mdt( - SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), - ComparisonType__c = 'MATCHES_REGEX', - ComparisonValue__c = zipCodeRegEx, - Tags__c = configuredTagName - )); + LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + new LogEntryTagRule__mdt( + SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), + ComparisonType__c = 'MATCHES_REGEX', + ComparisonValue__c = zipCodeRegEx, + Tags__c = configuredTagName + ) + ); Database.SaveResult saveResult = EventBus.publish(logEntryEvent); Test.stopTest(); @@ -469,12 +475,14 @@ private class LogEntryEventHandler_Tests { Test.startTest(); String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add(new LogEntryTagRule__mdt( - SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), - ComparisonType__c = 'STARTS_WITH', - ComparisonValue__c = logEntryEvent.Message__c.left(3), - Tags__c = configuredTagName - )); + LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + new LogEntryTagRule__mdt( + SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), + ComparisonType__c = 'STARTS_WITH', + ComparisonValue__c = logEntryEvent.Message__c.left(3), + Tags__c = configuredTagName + ) + ); Database.SaveResult saveResult = EventBus.publish(logEntryEvent); Test.stopTest(); @@ -537,17 +545,10 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_set_api_release_number_and_api_release_version_from_recent_record() { - Log__c recentLog = new Log__c( - ApiReleaseNumber__c = 'QWERTY', - ApiReleaseVersion__c = 'ASDF', - TransactionId__c = 'ABC-XYZ' - ); + Log__c recentLog = new Log__c(ApiReleaseNumber__c = 'QWERTY', ApiReleaseVersion__c = 'ASDF', TransactionId__c = 'ABC-XYZ'); insert recentLog; - insert new LogEntry__c( - Log__c = recentLog.Id, - Timestamp__c = System.now().addHours(-1) - ); + insert new LogEntry__c(Log__c = recentLog.Id, Timestamp__c = System.now().addHours(-1)); LoggerSObjectHandlerParameter__mdt mockCallStatusApiParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'LogEntryEventHandler_CallStatusApi', @@ -600,7 +601,6 @@ private class LogEntryEventHandler_Tests { ); LoggerParameter.Handler.setMockParameter(mockCallStatusApiParameter); - String transactionId = '123-456-789-0'; LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( EpochTimestamp__c = System.now().getTime(), @@ -832,7 +832,6 @@ private class LogEntryEventHandler_Tests { private static void validateLogFields(LogEntryEvent__e logEntryEvent, Log__c log) { Organization org = [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; - User currentUser = getCurrentUser(); String orgEnvironmentType; if (org.IsSandbox == true && org.TrialExpirationDate != null) { orgEnvironmentType = 'Scratch Org'; diff --git a/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogEntryEventHandler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls b/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls index 535093993..95e2d8d9b 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls @@ -5,7 +5,6 @@ @IsTest private class LogEntryHandler_Tests { - public class LogEntryPluginTest extends LoggerSObjectHandlerPlugin { public override void execute( TriggerOperation triggerOperationType, @@ -56,7 +55,7 @@ private class LogEntryHandler_Tests { Test.startTest(); // Use the mock configurations - LoggerSObjectHandler.setMockConfiguration(Schema.LogEntry__c.SObjectType, logEntryHandlerConfiguration); + LoggerSObjectHandler.setMockConfiguration(Schema.LogEntry__c.SObjectType, logEntryHandlerConfiguration); insert logEntry; diff --git a/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogEntryHandler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls b/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls index 6477247e0..04295f4bc 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls @@ -33,7 +33,10 @@ private class LogEntryTagHandler_Tests { @IsTest static void it_should_not_set_unique_id_when_disabled() { - LoggerSObjectHandler__mdt loggerTagHandlerConfiguration = new LoggerSObjectHandler__mdt(IsEnabled__c = false, SObjectType__c = LogEntryTag__c.SObjectType.getDescribe().getName()); + LoggerSObjectHandler__mdt loggerTagHandlerConfiguration = new LoggerSObjectHandler__mdt( + IsEnabled__c = false, + SObjectType__c = LogEntryTag__c.SObjectType.getDescribe().getName() + ); LoggerSObjectHandler.setMockConfiguration(Schema.LogEntryTag__c.SObjectType, loggerTagHandlerConfiguration); LogEntry__c logEntry = [SELECT Id FROM LogEntry__c LIMIT 1]; @@ -58,7 +61,7 @@ private class LogEntryTagHandler_Tests { try { insert duplicateLogEntryTag; System.assert(false, 'Exception expected on previous line'); - } catch(Exception ex) { + } catch (Exception ex) { String expectedDuplicateError = 'DUPLICATE_VALUE, duplicate value found'; System.assert(ex.getMessage().contains(expectedDuplicateError), ex.getMessage()); } diff --git a/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogEntryTagHandler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls b/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls index f856b99a8..5362fc2f3 100644 --- a/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls @@ -64,12 +64,12 @@ private class LogHandler_Tests { LoggerSObjectHandler__mdt logHandlerConfiguration = getMockConfiguration(); logHandlerConfiguration.IsEnabled__c = false; - LogStatus__mdt closedLogStatus = [SELECT Id, MasterLabel FROM LogStatus__mdt WHERE IsActive__c = true AND IsClosed__c = true LIMIT 1]; + LogStatus__mdt closedLogStatus = [SELECT Id, MasterLabel FROM LogStatus__mdt WHERE IsActive__c = TRUE AND IsClosed__c = TRUE LIMIT 1]; Test.startTest(); // Use the mock configurations - LoggerSObjectHandler.setMockConfiguration(Schema.Log__c.SObjectType, logHandlerConfiguration); + LoggerSObjectHandler.setMockConfiguration(Schema.Log__c.SObjectType, logHandlerConfiguration); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), Status__c = closedLogStatus.MasterLabel, TransactionId__c = '1234'); insert log; @@ -313,10 +313,7 @@ private class LogHandler_Tests { Test.startTest(); // Use the mock configurations - LoggerSObjectHandlerPlugin__mdt plugin = new LoggerSObjectHandlerPlugin__mdt( - PluginType__c = 'Apex', - PluginApiName__c = LogPluginTest.class.getName() - ); + LoggerSObjectHandlerPlugin__mdt plugin = new LoggerSObjectHandlerPlugin__mdt(PluginType__c = 'Apex', PluginApiName__c = LogPluginTest.class.getName()); LoggerSObjectHandler.setMockPlugin(Schema.Log__c.SObjectType, plugin); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); diff --git a/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogHandler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls b/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls index aacc19d2f..43b2b4048 100644 --- a/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls @@ -113,7 +113,7 @@ private class LogMassDeleteExtension_Tests { String deleteAccessError = 'You do not have access to delete logs records'; - LogMassDeleteExtension extension = new LogMassDeleteExtension(controller); + new LogMassDeleteExtension(controller); System.assertEquals(true, ApexPages.hasMessages(ApexPages.SEVERITY.ERROR)); System.assertEquals(deleteAccessError, ApexPages.getMessages().get(0).getSummary()); diff --git a/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LogMassDeleteExtension_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls b/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls index 5694b370c..4a5be3f7e 100644 --- a/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls +++ b/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls @@ -5,7 +5,6 @@ @IsTest private class LoggerTagHandler_Tests { - @IsTest static void it_should_set_unique_id_when_enabled() { LoggerTag__c tag = new LoggerTag__c(Name = 'some tag'); @@ -17,7 +16,10 @@ private class LoggerTagHandler_Tests { @IsTest static void it_should_not_set_unique_id_when_disabled() { - LoggerSObjectHandler__mdt loggerTagHandlerConfiguration = new LoggerSObjectHandler__mdt(IsEnabled__c = false, SObjectType__c = LoggerTag__c.SObjectType.getDescribe().getName()); + LoggerSObjectHandler__mdt loggerTagHandlerConfiguration = new LoggerSObjectHandler__mdt( + IsEnabled__c = false, + SObjectType__c = LoggerTag__c.SObjectType.getDescribe().getName() + ); LoggerSObjectHandler.setMockConfiguration(Schema.LoggerTag__c.SObjectType, loggerTagHandlerConfiguration); LoggerTag__c tag = new LoggerTag__c(Name = 'some tag'); @@ -36,7 +38,7 @@ private class LoggerTagHandler_Tests { try { insert duplicateTag; System.assert(false, 'Exception expected on previous line'); - } catch(Exception ex) { + } catch (Exception ex) { String expectedDuplicateError = 'DUPLICATE_VALUE, duplicate value found'; System.assert(ex.getMessage().contains(expectedDuplicateError), ex.getMessage()); } diff --git a/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/LoggerTagHandler_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls b/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls index 4380e39ef..cf25bfb43 100644 --- a/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls +++ b/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls @@ -86,7 +86,6 @@ private class RelatedLogEntriesController_Tests { System.assertEquals(TOTAL_LOG_ENTRIES + 1, logEntries.size()); Integer countOfMatches = 0; for (LogEntry__c logEntry : logEntries) { - System.debug('checking logEntry: ' + logEntry); if (logEntry.Message__c.contains(search)) { countOfMatches = countOfMatches + 1; } diff --git a/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls-meta.xml b/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls-meta.xml +++ b/nebula-logger/tests/log-management/classes/RelatedLogEntriesController_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml b/nebula-logger/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml new file mode 100644 index 000000000..d78747061 --- /dev/null +++ b/nebula-logger/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml @@ -0,0 +1,13 @@ + + + LogBatchPurger_Tests + LogBatchPurgeScheduler_Tests + LogEntryEventHandler_Tests + LogEntryFieldSetPicklist_Tests + LogEntryHandler_Tests + LogEntryTagHandler_Tests + LoggerTagHandler_Tests + LogHandler_Tests + LogMassDeleteExtension_Tests + RelatedLogEntriesController_Tests + diff --git a/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls b/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls index 925335772..c5f6160f6 100644 --- a/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls +++ b/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls @@ -23,13 +23,16 @@ private class ComponentLogger_Tests { System.assertEquals(userLoggingLevel.name(), componentLoggerSettings.userLoggingLevel.name); System.assertEquals(userLoggingLevel.ordinal(), componentLoggerSettings.userLoggingLevel.ordinal); - for(LoggingLevel currentLoggingLevel : LoggingLevel.values()) { + for (LoggingLevel currentLoggingLevel : LoggingLevel.values()) { // We don't care about logging level NONE, or the secret/undocumented INTERNAL logging level - if(currentLoggingLevel == LoggingLevel.NONE || currentLoggingLevel == LoggingLevel.INTERNAL) { + if (currentLoggingLevel == LoggingLevel.NONE || currentLoggingLevel == LoggingLevel.INTERNAL) { continue; } - System.assert(componentLoggerSettings.supportedLoggingLevels.containsKey(currentLoggingLevel.name()), 'Cmp settings did not contain level: ' + currentLoggingLevel); + System.assert( + componentLoggerSettings.supportedLoggingLevels.containsKey(currentLoggingLevel.name()), + 'Cmp settings did not contain level: ' + currentLoggingLevel + ); Integer returnedOrdinal = componentLoggerSettings.supportedLoggingLevels.get(currentLoggingLevel.name()); System.assertEquals(currentLoggingLevel.ordinal(), returnedOrdinal); @@ -42,7 +45,7 @@ private class ComponentLogger_Tests { try { ComponentLogger.saveComponentLogEntries(null); System.assert(false, 'This assert shouldn\'t run since this is a negative test'); - } catch(Exception apexException) { + } catch (Exception apexException) { System.assertEquals(AuraHandledException.class.getName(), apexException.getTypeName()); } Test.stopTest(); @@ -61,15 +64,18 @@ private class ComponentLogger_Tests { componentLogEntry.message = 'hello, world'; componentLogEntry.recordId = currentUser.Id; componentLogEntry.record = currentUser; - componentLogEntry.timestamp = System.now().addDays(- 1 / 24); - componentLogEntry.tags = new List{'some tag', 'one more tag'}; + componentLogEntry.timestamp = System.now().addDays(-1 / 24); + componentLogEntry.tags = new List{ 'some tag', 'one more tag' }; componentLogEntries.add(componentLogEntry); Test.startTest(); ComponentLogger.saveComponentLogEntries(componentLogEntries); Test.stopTest(); - List logEntries = [SELECT Id, LoggingLevel__c, Message__c, RecordId__c, RecordJson__c, RecordSObjectType__c, Timestamp__c FROM LogEntry__c]; + List logEntries = [ + SELECT Id, LoggingLevel__c, Message__c, RecordId__c, RecordJson__c, RecordSObjectType__c, Timestamp__c + FROM LogEntry__c + ]; System.assertEquals(1, logEntries.size()); LogEntry__c logEntry = logEntries.get(0); @@ -101,17 +107,18 @@ private class ComponentLogger_Tests { componentLogEntry.message = 'hello, world'; componentLogEntry.recordId = currentUser.Id; componentLogEntry.record = currentUser; - componentLogEntry.timestamp = System.now().addDays(- 1 / 24); - componentLogEntry.tags = new List{'some tag', 'one more tag'}; + componentLogEntry.timestamp = System.now().addDays(-1 / 24); + componentLogEntry.tags = new List{ 'some tag', 'one more tag' }; componentLogEntries.add(componentLogEntry); Test.startTest(); ComponentLogger.saveComponentLogEntries(componentLogEntries); Test.stopTest(); - List logEntries = [SELECT Id, LoggingLevel__c, Message__c, ExceptionMessage__c, - ExceptionStackTrace__c, - ExceptionType__c, Timestamp__c FROM LogEntry__c]; + List logEntries = [ + SELECT Id, LoggingLevel__c, Message__c, ExceptionMessage__c, ExceptionStackTrace__c, ExceptionType__c, Timestamp__c + FROM LogEntry__c + ]; System.assertEquals(1, logEntries.size()); LogEntry__c logEntry = logEntries.get(0); @@ -135,7 +142,7 @@ private class ComponentLogger_Tests { componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; componentLogEntry.stack = getMockAuraComponentStackTrace(); - componentLogEntry.timestamp = System.now().addDays(- 1 / 24); + componentLogEntry.timestamp = System.now().addDays(-1 / 24); componentLogEntries.add(componentLogEntry); Test.startTest(); @@ -143,7 +150,19 @@ private class ComponentLogger_Tests { ComponentLogger.saveComponentLogEntries(componentLogEntries); Test.stopTest(); - List logEntries = [SELECT Id, LoggingLevel__c, Message__c, ComponentApiName__c, ComponentFunctionName__c, ComponentType__c, OriginLocation__c, OriginType__c, Timestamp__c FROM LogEntry__c]; + List logEntries = [ + SELECT + Id, + LoggingLevel__c, + Message__c, + ComponentApiName__c, + ComponentFunctionName__c, + ComponentType__c, + OriginLocation__c, + OriginType__c, + Timestamp__c + FROM LogEntry__c + ]; System.assertEquals(1, logEntries.size()); LogEntry__c logEntry = logEntries.get(0); @@ -169,7 +188,7 @@ private class ComponentLogger_Tests { componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; componentLogEntry.stack = getMockWebComponentStackTrace(); - componentLogEntry.timestamp = System.now().addDays(- 1 / 24); + componentLogEntry.timestamp = System.now().addDays(-1 / 24); componentLogEntries.add(componentLogEntry); Test.startTest(); @@ -177,7 +196,19 @@ private class ComponentLogger_Tests { ComponentLogger.saveComponentLogEntries(componentLogEntries); Test.stopTest(); - List logEntries = [SELECT Id, LoggingLevel__c, Message__c, ComponentApiName__c, ComponentFunctionName__c, ComponentType__c, OriginLocation__c, OriginType__c, Timestamp__c FROM LogEntry__c]; + List logEntries = [ + SELECT + Id, + LoggingLevel__c, + Message__c, + ComponentApiName__c, + ComponentFunctionName__c, + ComponentType__c, + OriginLocation__c, + OriginType__c, + Timestamp__c + FROM LogEntry__c + ]; System.assertEquals(1, logEntries.size()); LogEntry__c logEntry = logEntries.get(0); @@ -194,31 +225,31 @@ private class ComponentLogger_Tests { private static String getMockAuraComponentStackTrace() { // This is a copy of an actual stack trace generated from c/loggerAuraDemo - return 'Error' - + '\nat new eval (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:237)' - + '\nat i (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:139)' - + '\nat g._newEntry (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:2208)' - + '\nat g.info (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:1446)' - + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' - + '\nat HTMLElement. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:12752)' - + '\nat a. [as info] (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:455:415)' - + '\nat Object.info (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:135617)' - + '\nat saveLogAuraExample (https://ability-enterprise-5142.lightning.force.com/lightning/n/components/c/loggerAuraDemo.js:16:30)' - + '\nat J.Uc (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:537:177)'; + return 'Error' + + '\nat new eval (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:237)' + + '\nat i (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:139)' + + '\nat g._newEntry (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:2208)' + + '\nat g.info (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:1446)' + + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' + + '\nat HTMLElement. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:12752)' + + '\nat a. [as info] (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:455:415)' + + '\nat Object.info (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:135617)' + + '\nat saveLogAuraExample (https://ability-enterprise-5142.lightning.force.com/lightning/n/components/c/loggerAuraDemo.js:16:30)' + + '\nat J.Uc (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:537:177)'; } private static String getMockWebComponentStackTrace() { // This is a copy of an actual stack trace generated from c/loggerLWCDemo - return 'Error' - + '\nat new eval (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:237)' - + '\nat i (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:139)' - + '\nat g._newEntry (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:2208)' - + '\nat g.error (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:1365)' - + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' - + '\nat HTMLElement. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:12752)' - + '\nat Proxy. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:135933)' - + '\nat p.saveLogWebExample (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/loggerLWCDemo.js:4:2399)' - + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' - + '\nat https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:24297'; + return 'Error' + + '\nat new eval (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:237)' + + '\nat i (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:139)' + + '\nat g._newEntry (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:2208)' + + '\nat g.error (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/logger.js:4:1365)' + + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' + + '\nat HTMLElement. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:12752)' + + '\nat Proxy. (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:135933)' + + '\nat p.saveLogWebExample (https://ability-enterprise-5142.lightning.force.com/lightning/n/modules/c/loggerLWCDemo.js:4:2399)' + + '\nat callHook (https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:37:80204)' + + '\nat https://static.lightning.force.com/cs10/auraFW/javascript/YeF9IbuOAuhiq8yQ65xJFA/aura_prod.js:12:24297'; } } diff --git a/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/ComponentLogger_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls b/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls index 40136d297..7ef09276f 100644 --- a/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls +++ b/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls @@ -153,7 +153,17 @@ private class FlowCollectionLogEntry_Tests { Test.stopTest(); LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordCollectionType__c, RecordJson__c + SELECT + Id, + ExceptionMessage__c, + ExceptionType__c, + LoggingLevel__c, + Message__c, + OriginType__c, + OriginLocation__c, + RecordId__c, + RecordCollectionType__c, + RecordJson__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1 @@ -187,7 +197,17 @@ private class FlowCollectionLogEntry_Tests { Test.stopTest(); LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordCollectionType__c, RecordJson__c + SELECT + Id, + ExceptionMessage__c, + ExceptionType__c, + LoggingLevel__c, + Message__c, + OriginType__c, + OriginLocation__c, + RecordId__c, + RecordCollectionType__c, + RecordJson__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1 diff --git a/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/FlowLogEntry_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/FlowLogEntry_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/FlowLogEntry_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/FlowLogEntry_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/FlowLogger_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/FlowLogger_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/FlowLogger_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/FlowLogger_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls b/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls index 246dc9e99..b2ef4b6a9 100644 --- a/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls +++ b/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls @@ -5,48 +5,6 @@ @IsTest private class LogEntryEventBuilder_Tests { - private static Organization getOrganization() { - return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; - } - - private static String getOrganizationEnvironmentType(Organization organization) { - String orgEnvironmentType; - if (organization.IsSandbox == true && organization.TrialExpirationDate != null) { - orgEnvironmentType = 'Scratch Org'; - } else if (organization.IsSandbox == true) { - orgEnvironmentType = 'Sandbox'; - } else { - orgEnvironmentType = 'Production'; - } - return orgEnvironmentType; - } - - private static SObject getNetwork() { - if (Network.getNetworkId() == null) { - return null; - } - - String networkApiName = 'Network'; - // Networks (communities) may not be enabled in the org (no Network object), so run everything dynamically - Boolean networksEnabled = Schema.getGlobalDescribe().containsKey(networkApiName); - - if (!networksEnabled) { - return null; - } - - String queryString = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :Network.getNetworkId()'; - - return Database.query(queryString); - } - - private static User getUser() { - return [ - SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name - FROM User - WHERE Id = :UserInfo.getUserId() - ]; - } - static String getMessage() { return 'Hello, world'; } @@ -55,10 +13,19 @@ private class LogEntryEventBuilder_Tests { return new LogMessage('The current date is {0}', System.today()); } + static LogEntryDataMaskRule__mdt getSocialSecurityNumberDataMaskRule() { + return new LogEntryDataMaskRule__mdt( + IsEnabled__c = true, + ApplyToMessage__c = true, + ApplyToRecordJson__c = true, + SensitiveDataRegEx__c = '(\\d{3})[- ]*(\\d{2})[- ]*(\\d{4})', + ReplacementRegEx__c = 'XXX-XX-$3' + ); + } + @IsTest - static void it_should_short_circuit_when_not_enabled() { - Boolean shouldSave = false; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.DEBUG, shouldSave); + static void it_should_short_circuit_when_disabled() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.DEBUG, false); // Run all public and global methods to make sure no errors occur when not enabled (it's happened before) System.assertEquals(null, builder.setMessage(getLogMessage()).getLogEntryEvent()); @@ -78,24 +45,30 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.setRecordId(new User(Id = UserInfo.getUserId())).getLogEntryEvent()); System.assertEquals(null, builder.setRecord(UserInfo.getUserId()).getLogEntryEvent()); System.assertEquals(null, builder.setRecord(new User(Id = UserInfo.getUserId())).getLogEntryEvent()); - System.assertEquals(null, builder.setRecord(new List{new User(Id = UserInfo.getUserId())}).getLogEntryEvent()); - System.assertEquals(null, builder.addTags(new List{'tag-1', 'tag-2'}).getLogEntryEvent()); + System.assertEquals(null, builder.setRecord(new List{ new User(Id = UserInfo.getUserId()) }).getLogEntryEvent()); + System.assertEquals(null, builder.addTags(new List{ 'tag-1', 'tag-2' }).getLogEntryEvent()); System.assertEquals(null, builder.parseStackTrace(new DmlException().getStackTraceString()).getLogEntryEvent()); } @IsTest - static void it_should_short_circuit_when_enabled_logging_level_above_called_level() { - Boolean shouldSave = false; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, shouldSave); + static void it_should_not_run_queries_when_logging_disabled() { + Logger.getUserSettings().IsEnabled__c = false; + System.assertEquals(false, Logger.isEnabled()); + System.assertEquals(0, Limits.getQueries()); + new LogEntryEventBuilder(LoggingLevel.FINE, false).setMessage('some message').getLogEntryEvent(); + System.assertEquals(0, Limits.getQueries()); + } + + @IsTest + static void it_should_short_circuit_when_enabled_logging_level_above_called_level() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, false); System.assertEquals(null, builder.getLogEntryEvent()); } @IsTest static void it_should_not_short_circuit_when_enabledl() { - Boolean shouldSave = true; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, shouldSave); - + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, true); System.assertNotEquals(null, builder.getLogEntryEvent()); } @@ -103,16 +76,14 @@ private class LogEntryEventBuilder_Tests { static void it_should_set_message_fields_for_logMessage() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(null, builder.getLogEntryEvent().Message__c); - Test.startTest(); - LogMessage logMessage = new LogMessage('The time is {0}', System.now()); builder.setMessage(logMessage); - Test.stopTest(); - System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(logMessage.getMessage(), builder.getLogEntryEvent().Message__c); } @@ -120,27 +91,112 @@ private class LogEntryEventBuilder_Tests { static void it_should_set_message_fields_for_string() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(null, builder.getLogEntryEvent().Message__c); - Test.startTest(); - String message = 'The time is ' + String.valueOf(System.now()); builder.setMessage(message); - Test.stopTest(); - System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(message, builder.getLogEntryEvent().Message__c); } + @IsTest + static void it_should_apply_data_mask_rule_to_message_when_enabled() { + Logger.getUserSettings().ApplyDataMaskRules__c = true; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.ApplyToMessage__c = true; + rule.ApplyToRecordJson__c = false; + LogEntryEventBuilder.addMockDataMaskRule(rule); + + String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedMessage = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + Account account = new Account(Name = message); + String accountJson = JSON.serializePretty(account); + String expectedSanitizedAccountJson = JSON.serializePretty(new Account(Name = message)); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setMessage(message).setRecord(account); + + System.assertEquals(true, builder.getLogEntryEvent().MessageMasked__c); + System.assertNotEquals(message, builder.getLogEntryEvent().Message__c); + System.assertEquals(expectedSanitizedMessage, builder.getLogEntryEvent().Message__c); + System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); + System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(expectedSanitizedAccountJson, builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_apply_data_mask_rule_to_record_json_when_enabled() { + Logger.getUserSettings().ApplyDataMaskRules__c = true; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.ApplyToMessage__c = false; + rule.ApplyToRecordJson__c = true; + LogEntryEventBuilder.addMockDataMaskRule(rule); + + String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedMessage = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + Account account = new Account(Name = message); + String accountJson = JSON.serializePretty(account); + String expectedSanitizedAccountJson = JSON.serializePretty(new Account(Name = expectedSanitizedMessage)); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setMessage(message).setRecord(account); + + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); + System.assertEquals(message, builder.getLogEntryEvent().Message__c); + System.assertNotEquals(expectedSanitizedMessage, builder.getLogEntryEvent().Message__c); + System.assertEquals(true, builder.getLogEntryEvent().RecordJsonMasked__c); + System.assertNotEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(expectedSanitizedAccountJson, builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_not_data_mask_rule_when_disabled_for_message_and_json() { + Logger.getUserSettings().ApplyDataMaskRules__c = true; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.ApplyToMessage__c = false; + rule.ApplyToRecordJson__c = false; + LogEntryEventBuilder.addMockDataMaskRule(rule); + + String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + Account account = new Account(Name = message); + String accountJson = JSON.serializePretty(account); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setMessage(message).setRecord(account); + + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); + System.assertEquals(message, builder.getLogEntryEvent().Message__c); + System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); + System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_not_data_mask_rule_when_disabled_for_user() { + Logger.getUserSettings().ApplyDataMaskRules__c = false; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.ApplyToMessage__c = true; + rule.ApplyToRecordJson__c = true; + LogEntryEventBuilder.addMockDataMaskRule(rule); + + String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + Account account = new Account(Name = message); + String accountJson = JSON.serializePretty(account); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setMessage(message).setRecord(account); + + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); + System.assertEquals(message, builder.getLogEntryEvent().Message__c); + System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); + System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + } + @IsTest static void it_should_truncate_message_for_long_logMessage() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(null, builder.getLogEntryEvent().Message__c); - Test.startTest(); - Integer maxMessageLength = Schema.LogEntry__c.Message__c.getDescribe().getLength(); String baseMessage = 'z'.repeat(LogEntryEvent__e.Message__c.getDescribe().getLength() + 1); LogMessage logMessage = new LogMessage(baseMessage, 'something else'); @@ -148,8 +204,6 @@ private class LogEntryEventBuilder_Tests { System.assert(logMessage.getMessage().length() > maxMessageLength, 'Test message length should exceed the field length'); builder.setMessage(logMessage); - Test.stopTest(); - System.assertEquals(true, builder.getLogEntryEvent().MessageTruncated__c, 'Message should have been truncated'); System.assertEquals(logMessage.getMessage().left(maxMessageLength), builder.getLogEntryEvent().Message__c); } @@ -158,17 +212,14 @@ private class LogEntryEventBuilder_Tests { static void it_should_truncate_message_for_long_string() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(false, builder.getLogEntryEvent().MessageTruncated__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(null, builder.getLogEntryEvent().Message__c); - Test.startTest(); - Integer maxMessageLength = Schema.LogEntry__c.Message__c.getDescribe().getLength(); String message = 'z'.repeat(LogEntryEvent__e.Message__c.getDescribe().getLength() + 1); System.assert(message.length() > maxMessageLength, 'Test message length should exceed the field length'); builder.setMessage(message); - Test.stopTest(); - System.assertEquals(true, builder.getLogEntryEvent().MessageTruncated__c, 'Message should have been truncated'); System.assertEquals(message.left(maxMessageLength), builder.getLogEntryEvent().Message__c); } @@ -179,13 +230,9 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().ExceptionMessage__c); System.assertEquals(null, builder.getLogEntryEvent().ExceptionType__c); - Test.startTest(); - DmlException dmlException = new DmlException('Test DML exception'); builder.setExceptionDetails(dmlException); - Test.stopTest(); - System.assertEquals(dmlException.getMessage(), builder.getLogEntryEvent().ExceptionMessage__c); System.assertEquals(dmlException.getTypeName(), builder.getLogEntryEvent().ExceptionType__c); } @@ -199,40 +246,28 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(true, deleteResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(deleteResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(deleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest static void it_should_set_database_result_fields_for_failed_deleteResult() { Log__c log = new Log__c(TransactionId__c = '1234'); insert log; - // Delete the log twice to trigger a DeleteResult error delete log; - Database.DeleteResult deleteResult = Database.delete(log, false); System.assertEquals(false, deleteResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(deleteResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(deleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs @@ -259,16 +294,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(true, saveResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(saveResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(saveResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -277,16 +307,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(false, saveResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(saveResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(saveResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -299,16 +324,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(true, undeleteResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(undeleteResult); - Test.stopTest(); - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(undeleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -323,16 +343,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(false, undeleteResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(undeleteResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(undeleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -342,16 +357,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(true, upsertResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -361,16 +371,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(false, upsertResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResult); - Test.stopTest(); - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -384,16 +389,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(true, upsertResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResult); - Test.stopTest(); - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Update', logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName() + '.Update', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -414,16 +414,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(false, upsertResult.isSuccess()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResult); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('Single', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Update', logEntryEvent.DatabaseResultType__c); + System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName() + '.Update', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -441,16 +436,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(deleteResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(deleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -471,16 +461,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(deleteResults); - Test.stopTest(); - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(deleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs @@ -514,16 +499,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(saveResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(saveResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -539,16 +519,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(saveResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(saveResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -567,16 +542,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(undeleteResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(undeleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -597,16 +567,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(undeleteResults); - Test.stopTest(); - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(undeleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -623,16 +588,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -649,16 +609,11 @@ private class LogEntryEventBuilder_Tests { } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - Test.startTest(); builder.setDatabaseResult(upsertResults); - Test.stopTest(); - - LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - System.assertEquals('List', logEntryEvent.DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResults), logEntryEvent.DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName(), logEntryEvent.DatabaseResultType__c); + System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); + System.assertEquals(JSON.serializePretty(upsertResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.UpsertResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest @@ -670,13 +625,9 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - Id currentUserId = UserInfo.getUserId(); builder.setRecordId(currentUserId); - Test.stopTest(); - System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(currentUserId, builder.getLogEntryEvent().RecordId__c); System.assertEquals(null, builder.getLogEntryEvent().RecordJson__c); @@ -694,14 +645,10 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - Log__c log = new Log__c(TransactionId__c = '1234'); insert log; builder.setRecordId(log.Id); - Test.stopTest(); - System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(log.Id, builder.getLogEntryEvent().RecordId__c); System.assertEquals(null, builder.getLogEntryEvent().RecordJson__c); @@ -802,6 +749,34 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(LogStatus__mdt.SObjectType.getDescribe().getName(), builder.getLogEntryEvent().RecordSObjectType__c); } + @IsTest + static void it_should_skip_stripping_inaccessible_fields_for_aggregate_result() { + User standardUser = LoggerTestUtils.createStandardUser(); + AggregateResult mockAggregateResult = LoggerTestUtils.createMockAggregateResult(); + + LogEntryEventBuilder builder; + System.runAs(standardUser) { + Logger.getUserSettings().StripInaccessibleRecordFields__c = true; + builder = new LogEntryEventBuilder(LoggingLevel.INFO, true).setRecord(mockAggregateResult); + } + + System.assertEquals(JSON.serializePretty(mockAggregateResult), builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_skip_stripping_inaccessible_fields_for_aggregate_results() { + User standardUser = LoggerTestUtils.createStandardUser(); + List mockAggregateResults = new List{ LoggerTestUtils.createMockAggregateResult() }; + + LogEntryEventBuilder builder; + System.runAs(standardUser) { + Logger.getUserSettings().StripInaccessibleRecordFields__c = true; + builder = new LogEntryEventBuilder(LoggingLevel.INFO, true).setRecord(mockAggregateResults); + } + + System.assertEquals(JSON.serializePretty(mockAggregateResults), builder.getLogEntryEvent().RecordJson__c); + } + @IsTest static void it_should_set_record_fields_for_list_of_records() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); @@ -811,13 +786,9 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - List users = [SELECT Id, Name, Username, IsActive FROM User LIMIT 5]; builder.setRecord(users); - Test.stopTest(); - System.assertEquals('List', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordId__c); System.assertEquals(JSON.serializePretty(users), builder.getLogEntryEvent().RecordJson__c); @@ -830,13 +801,9 @@ private class LogEntryEventBuilder_Tests { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(null, builder.getLogEntryEvent().Tags__c); - Test.startTest(); - List tags = new List{ 'some-tag', 'another One', 'here\'s one more!' }; builder.addTags(tags); - Test.stopTest(); - String expectedTagsString = String.escapeSingleQuotes(String.join(tags, '\n')); System.assertEquals(expectedTagsString, builder.getLogEntryEvent().Tags__c); } @@ -846,13 +813,9 @@ private class LogEntryEventBuilder_Tests { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(null, builder.getLogEntryEvent().Tags__c); - Test.startTest(); - List tags = new List{ 'duplicate-tag', 'duplicate-tag', 'another One' }; builder.addTags(tags); - Test.stopTest(); - String expectedTagsString = 'duplicate-tag\nanother One'; System.assertEquals(expectedTagsString, builder.getLogEntryEvent().Tags__c); } @@ -861,14 +824,10 @@ private class LogEntryEventBuilder_Tests { static void it_should_set_stack_trace_and_origin_location_for_stack_trace_string() { DmlException stackTraceHandler = new DmlException(); - Boolean shouldSave = true; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, shouldSave); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, true); builder.getLogEntryEvent().OriginLocation__c = null; builder.getLogEntryEvent().StackTrace__c = null; - - Test.startTest(); builder.parseStackTrace(stackTraceHandler.getStackTraceString()); - Test.stopTest(); String expectedOriginLocation = stackTraceHandler.getStackTraceString().split('\n').get(0).substringBefore(':').substringAfter('Class.'); String expectedStackTrace = stackTraceHandler.getStackTraceString(); @@ -879,6 +838,22 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(expectedStackTrace, builder.getLogEntryEvent().StackTrace__c); } + @IsTest + static void it_should_set_stack_trace_and_origin_location_for_anonymous_apex_stack_trace_string() { + String anonymousApexOriginLocation = 'AnonymousBlock'; + String anonymousApexStackTraceString = 'AnonymousBlock: line 9, column 1'; + + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, true); + builder.getLogEntryEvent().OriginLocation__c = null; + builder.getLogEntryEvent().StackTrace__c = null; + builder.parseStackTrace(anonymousApexStackTraceString); + + System.assertNotEquals(null, builder.getLogEntryEvent().OriginLocation__c); + System.assertEquals(anonymousApexOriginLocation, builder.getLogEntryEvent().OriginLocation__c); + System.assertNotEquals(null, builder.getLogEntryEvent().StackTrace__c); + System.assertEquals(anonymousApexStackTraceString, builder.getLogEntryEvent().StackTrace__c); + } + @IsTest static void it_should_not_set_stack_trace_and_origin_location_for_invalid_stack_trace_string() { final String invalidStackTrace = '()'; @@ -887,10 +862,7 @@ private class LogEntryEventBuilder_Tests { // Clear out any auto-set values builder.getLogEntryEvent().OriginLocation__c = null; builder.getLogEntryEvent().StackTrace__c = null; - - Test.startTest(); builder.parseStackTrace(invalidStackTrace); - Test.stopTest(); System.assertEquals(null, builder.getLogEntryEvent().OriginLocation__c); System.assertEquals(null, builder.getLogEntryEvent().StackTrace__c); @@ -898,36 +870,24 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_return_value_of_shouldSave_when_true() { - Test.startTest(); - Boolean shouldSave = true; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, shouldSave); - Test.stopTest(); - - System.assertEquals(shouldSave, builder.shouldSave()); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + System.assertEquals(true, builder.shouldSave()); } @IsTest static void it_should_return_value_of_shouldSave_when_false() { - Test.startTest(); - Boolean shouldSave = false; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, shouldSave); - Test.stopTest(); - - System.assertEquals(shouldSave, builder.shouldSave()); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, false); + System.assertEquals(false, builder.shouldSave()); } @IsTest static void it_should_set_detailed_fields() { - Test.startTest(); - Boolean shouldSave = true; - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, shouldSave); - Test.stopTest(); - // Get expected data - Organization organization = getOrganization(); - String organizationEnvironmentType = getOrganizationEnvironmentType(organization); - SObject networkSite = getNetwork(); - User user = getUser(); + Organization organization = LoggerTestUtils.getOrganization(); + String organizationEnvironmentType = LoggerTestUtils.getOrganizationEnvironmentType(); + User user = LoggerTestUtils.getUser(); + + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); // Verify organization fields System.assertEquals(Url.getOrgDomainUrl().toExternalForm(), builder.getLogEntryEvent().OrganizationDomainUrl__c); @@ -956,7 +916,15 @@ private class LogEntryEventBuilder_Tests { DebugStringExample example = new DebugStringExample(); LogEntryEventBuilder builder = example.myMethod(); - System.assertEquals(DebugStringExample.class.getName() + '.myMethod' + '\n' + example.loggingString + ': ' + LoggingLevel.DEBUG.name(), builder.debugMessage); + System.assertEquals( + DebugStringExample.class.getName() + + '.myMethod' + + '\n' + + example.loggingString + + ': ' + + LoggingLevel.DEBUG.name(), + builder.debugMessage + ); } private class DebugStringExample { diff --git a/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/LogMessage_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/LogMessage_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/LogMessage_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/LogMessage_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls b/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls index d0379d5dd..2dd557ecc 100644 --- a/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls +++ b/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls @@ -25,10 +25,6 @@ private class Logger_Tests { } // Helper methods - static User getCurrentUser() { - return new User(Id = UserInfo.getUserId()); - } - static void setUserLoggingLevel(LoggingLevel loggingLevel) { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); } @@ -73,6 +69,7 @@ private class Logger_Tests { List logs = new List(); for (Integer i = 0; i < 3; i++) { Log__c log = new Log__c(TransactionId__c = '1234' + i); + logs.add(log); } insert logs; @@ -98,6 +95,7 @@ private class Logger_Tests { List logs = new List(); for (Integer i = 0; i < 3; i++) { Log__c log = new Log__c(TransactionId__c = '1234' + i); + logs.add(log); } return Database.insert(logs, false); @@ -139,6 +137,7 @@ private class Logger_Tests { List logs = new List(); for (Integer i = 0; i < 3; i++) { Log__c log = new Log__c(TransactionId__c = '1234' + i); + logs.add(log); } return Database.upsert(logs, false); @@ -167,6 +166,7 @@ private class Logger_Tests { List logs = new List(); for (Integer i = 0; i < 3; i++) { Log__c log = new Log__c(TransactionId__c = '1234' + i); + logs.add(log); } insert logs; delete logs; @@ -177,13 +177,15 @@ private class Logger_Tests { static String getOriginLocation() { String originLocation; for (String currentStackTraceLine : new DmlException().getStackTraceString().split('\n')) { - if (currentStackTraceLine.contains('Logger_Tests.getOriginLocation')) + if (currentStackTraceLine.contains('Logger_Tests.getOriginLocation')) { continue; - if (currentStackTraceLine.contains('.LogEntryEventBuilder.')) + } + if (currentStackTraceLine.contains('.LogEntryEventBuilder.')) { continue; - if (currentStackTraceLine.contains('.Logger.')) + } + if (currentStackTraceLine.contains('.Logger.')) { continue; - + } originLocation = currentStackTraceLine.substringBefore(':'); if (originLocation.startsWith('Class.')) { originLocation = originLocation.substringAfter('Class.'); @@ -194,7 +196,7 @@ private class Logger_Tests { return originLocation; } - @testSetup + @TestSetup static void setup() { LoggerSettings__c settings = LoggerSettings__c.getInstance(); settings.IsEnabled__c = true; @@ -241,7 +243,6 @@ private class Logger_Tests { static void it_should_set_transaction_entry_number() { for (Integer i = 0; i < 10; i++) { LogEntryEventBuilder builder = Logger.info('my log entry'); - System.assertEquals(i + 1, builder.getLogEntryEvent().TransactionEntryNumber__c); } } @@ -497,7 +498,7 @@ private class Logger_Tests { @IsTest static void it_should_save_accurate_timestamp_when_logging_user_has_different_time_zone() { - User automatedProcessUser = [SELECT Id, TimeZoneSidKey FROM User WHERE Name = 'Automated Process' AND Profile.Name = null]; + User automatedProcessUser = [SELECT Id, TimeZoneSidKey FROM User WHERE Name = 'Automated Process' AND Profile.Name = NULL]; User currentUser = new User(Id = UserInfo.getUserId(), TimeZoneSidKey = UserInfo.getTimeZone().getId()); // Make sure that the current user has a different time zone from the automated process user diff --git a/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls-meta.xml b/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls-meta.xml +++ b/nebula-logger/tests/logger-engine/classes/Logger_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml b/nebula-logger/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml new file mode 100644 index 000000000..37e1afad5 --- /dev/null +++ b/nebula-logger/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml @@ -0,0 +1,11 @@ + + + ComponentLogger_Tests + FlowCollectionLogEntry_Tests + FlowLogEntry_Tests + FlowLogger_Tests + FlowRecordLogEntry_Tests + LogEntryEventBuilder_Tests + Logger_Tests + LogMessage_Tests + diff --git a/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls b/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls index bca3e66b6..774a9cd22 100644 --- a/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls +++ b/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls @@ -39,7 +39,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_boolean_list_parameter_for_handler() { - List parameterValue = new List{true, false, true, true}; + List parameterValue = new List{ true, false, true, true }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyBooleanList', IsEnabled__c = true, @@ -53,7 +53,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_boolean_list_parameter_for_plugin() { - List parameterValue = new List{true, false, true, true}; + List parameterValue = new List{ true, false, true, true }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyBooleanList', IsEnabled__c = true, @@ -95,7 +95,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_date_list_parameter_for_handler() { - List parameterValue = new List{System.today(), System.today().addDays(10)}; + List parameterValue = new List{ System.today(), System.today().addDays(10) }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyDateList', IsEnabled__c = true, @@ -109,7 +109,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_date_list_parameter_for_plugin() { - List parameterValue = new List{System.today(), System.today().addDays(10)}; + List parameterValue = new List{ System.today(), System.today().addDays(10) }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyDateList', IsEnabled__c = true, @@ -151,7 +151,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_datetime_list_parameter_for_handler() { - List parameterValue = new List{System.now(), System.now().addDays(10)}; + List parameterValue = new List{ System.now(), System.now().addDays(10) }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyDatetimeList', IsEnabled__c = true, @@ -165,7 +165,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_datetime_list_parameter_for_plugin() { - List parameterValue = new List{System.now(), System.now().addDays(10)}; + List parameterValue = new List{ System.now(), System.now().addDays(10) }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyDatetimeList', IsEnabled__c = true, @@ -207,7 +207,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_decimal_list_parameter_for_handler() { - List parameterValue = new List{123.45, 678.09}; + List parameterValue = new List{ 123.45, 678.09 }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyDecimalList', IsEnabled__c = true, @@ -221,7 +221,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_decimal_list_parameter_for_plugin() { - List parameterValue = new List{123.45, 678.09}; + List parameterValue = new List{ 123.45, 678.09 }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyDecimalList', IsEnabled__c = true, @@ -263,7 +263,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_double_list_parameter_for_handler() { - List parameterValue = new List{123.45, 678.09}; + List parameterValue = new List{ 123.45, 678.09 }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyDoubleList', IsEnabled__c = true, @@ -277,7 +277,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_double_list_parameter_for_plugin() { - List parameterValue = new List{123.45, 678.09}; + List parameterValue = new List{ 123.45, 678.09 }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyDoubleList', IsEnabled__c = true, @@ -319,7 +319,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_id_list_parameter_for_handler() { - List parameterValue = new List{UserInfo.getUserId()}; + List parameterValue = new List{ UserInfo.getUserId() }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyIdList', IsEnabled__c = true, @@ -333,7 +333,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_id_list_parameter_for_plugin() { - List parameterValue = new List{UserInfo.getUserId()}; + List parameterValue = new List{ UserInfo.getUserId() }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyIdList', IsEnabled__c = true, @@ -375,7 +375,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_integer_list_parameter_for_handler() { - List parameterValue = new List{12345, 67809}; + List parameterValue = new List{ 12345, 67809 }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyIntegerList', IsEnabled__c = true, @@ -389,7 +389,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_integer_list_parameter_for_plugin() { - List parameterValue = new List{12345, 67809}; + List parameterValue = new List{ 12345, 67809 }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyIntegerList', IsEnabled__c = true, @@ -431,7 +431,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_long_list_parameter_for_handler() { - List parameterValue = new List{12345, 67809}; + List parameterValue = new List{ 12345, 67809 }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyLongList', IsEnabled__c = true, @@ -445,7 +445,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_long_list_parameter_for_plugin() { - List parameterValue = new List{12345, 67809}; + List parameterValue = new List{ 12345, 67809 }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyLongList', IsEnabled__c = true, @@ -487,7 +487,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_sobject_list_parameter_for_handler() { - List parameterValue = new List{getUserRecord()}; + List parameterValue = new List{ getUserRecord() }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MySObjectList', IsEnabled__c = true, @@ -501,7 +501,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_sobject_list_parameter_for_plugin() { - List parameterValue = new List{getUserRecord()}; + List parameterValue = new List{ getUserRecord() }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MySObjectList', IsEnabled__c = true, @@ -543,7 +543,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_string_list_parameter_for_handler() { - List parameterValue = new List{'Hello', 'Goodbye'}; + List parameterValue = new List{ 'Hello', 'Goodbye' }; LoggerSObjectHandlerParameter__mdt mockParameter = new LoggerSObjectHandlerParameter__mdt( DeveloperName = 'MyStringList', IsEnabled__c = true, @@ -557,7 +557,7 @@ private class LoggerParameter_Tests { @IsTest static void it_should_return_string_list_parameter_for_plugin() { - List parameterValue = new List{'Hello', 'Goodbye'}; + List parameterValue = new List{ 'Hello', 'Goodbye' }; LoggerSObjectHandlerPluginParameter__mdt mockParameter = new LoggerSObjectHandlerPluginParameter__mdt( DeveloperName = 'MyStringList', IsEnabled__c = true, diff --git a/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls-meta.xml b/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls-meta.xml index dd61d1f91..f8e5ab635 100644 --- a/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls-meta.xml +++ b/nebula-logger/tests/plugin-framework/classes/LoggerParameter_Tests.cls-meta.xml @@ -1,4 +1,4 @@ - + 52.0 Active diff --git a/nebula-logger/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml b/nebula-logger/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml new file mode 100644 index 000000000..a771fcaeb --- /dev/null +++ b/nebula-logger/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml @@ -0,0 +1,5 @@ + + + LoggerParameter_Tests + LoggerSObjectHandlerPlugin_Tests + diff --git a/package.json b/package.json index 8c2363a3c..719bd8525 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,8 @@ { "name": "nebula-logger", - "version": "4.6.6", + "version": "4.6.7", "description": "Designed for Salesforce admins, developers & architects. A robust logger for Apex, Flow, Process Builder & Integrations.", "scripts": { - "deploy": "npm run deploy:logger && npm run deploy:managedpackage && npm run deploy:extratests", - "deploy:logger": "sfdx force:source:deploy --sourcepath ./nebula-logger/", - "deploy:extratests": "sfdx force:source:deploy --sourcepath ./nebula-logger-recipes/", - "deploy:managedpackage": "sfdx force:source:deploy --sourcepath ./managed-package/managed-package-metadata", "devhub:details": "pwsh ./scripts/get-devhub-org-details.ps1", "devhub:limits": "pwsh ./scripts/get-devhub-org-limits.ps1", "devhub:open": "pwsh ./scripts/open-devhub-org.ps1", @@ -23,17 +19,12 @@ "org:open": "sfdx force:org:open", "package:version:create:managed": "pwsh ./scripts/switch-to-managed-package-project-json.ps1 && sfdx force:package:version:create --json --package \"Nebula Logger - Managed Package\" --codecoverage --installationkeybypass --wait 30 && pwsh ./scripts/restore-unlocked-package-project-json.ps1", "package:version:create:unlocked": "sfdx force:package:version:create --json --package \"Nebula Logger - Unlocked Package\" --codecoverage --installationkeybypass --wait 30", - "package:version:list": "sfdx force:package:version:list --json --verbose --orderby PatchVersion", - "package:version:list:released": "sfdx force:package:version:list --json --verbose --released --orderby PatchVersion", - "package:version:list:managed": "pwsh ./scripts/switch-to-managed-package-project-json.ps1 && sfdx force:package:version:list --json --verbose --orderby PatchVersion --packages \"Nebula Logger - Managed Package\" && pwsh ./scripts/restore-unlocked-package-project-json.ps1", - "package:version:list:managed:released": "pwsh ./scripts/switch-to-managed-package-project-json.ps1 && sfdx force:package:version:list --json --verbose --released --orderby PatchVersion --packages \"Nebula Logger - Managed Package\" && pwsh ./scripts/restore-unlocked-package-project-json.ps1", - "package:version:list:unlocked": "sfdx force:package:version:list --json --verbose --orderby PatchVersion --packages \"Nebula Logger - Unlocked Package\"", - "package:version:list:unlocked:released": "sfdx force:package:version:list --json --verbose --released --orderby PatchVersion --packages \"Nebula Logger - Unlocked Package\"", "permset:assign:admin": "sfdx force:user:permset:assign --permsetname LoggerAdmin", "prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", "prettier:verify": "prettier --list-different \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", + "scan": "sfdx scanner:run --pmdconfig config/pmd-ruleset.xml --target . --engine pmd --severity-threshold 3", "test": "npm run test:lwc && npm run test:apex", - "test:apex": "sfdx force:apex:test:run --verbose --testlevel RunLocalTests --wait 30 --resultformat human --codecoverage --outputdir ./tests/apex", + "test:apex": "sfdx force:apex:test:run --verbose --testlevel RunLocalTests --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./tests/apex", "test:lwc": "sfdx-lwc-jest --coverage" }, "repository": { @@ -60,10 +51,14 @@ "npm": ">= 6.14.0" }, "devDependencies": { + "@babel/core": "latest", + "@babel/eslint-parser": "latest", "@cparra/apexdocs": "latest", + "@lwc/eslint-plugin-lwc": "latest", "@prettier/plugin-xml": "latest", "@salesforce/eslint-config-lwc": "latest", "@salesforce/eslint-plugin-aura": "latest", + "@salesforce/eslint-plugin-lightning": "latest", "@salesforce/sfdx-lwc-jest": "latest", "@salesforce/sfdx-scanner": "latest", "eslint": "latest", diff --git a/scripts/apex/create-sample-log-entries.apex b/scripts/apex/create-sample-log-entries.apex index 1b32be5ed..aeb9ab1d8 100644 --- a/scripts/apex/create-sample-log-entries.apex +++ b/scripts/apex/create-sample-log-entries.apex @@ -1,15 +1,19 @@ -Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); +Logger.getUserSettings().LoggingLevel__c = LoggingLevel.INFO.name(); +Logger.getUserSettings().ApplyDataMaskRules__c = true; User currentUser = [SELECT Id, Name, Username, Profile.Name FROM User WHERE Id = :UserInfo.getUserId()]; +currentUser.AboutMe = 'I hope you dont leak my social, which is 400-11-9999, btw.'; -new ExampleClassWithLogging().doSomething(); +// new ExampleClassWithLogging().doSomething(); -Logger.error('Add log entry using Nebula Logger with logging level == ERROR', new DmlException('fake DML exception')).addTag('some important tag'); -Logger.warn('Add log entry using Nebula Logger with logging level == WARN', currentUser).addTag('some important tag'); -Logger.info('Add log entry using Nebula Logger with logging level == INFO'); -Logger.debug('Add log entry using Nebula Logger with logging level == DEBUG', currentUser); -Logger.fine('Add log entry using Nebula Logger with logging level == FINE'); -Logger.finer('Add log entry using Nebula Logger with logging level == FINER'); -Logger.finest('Add log entry using Nebula Logger with logging level == FINEST'); + +// Logger.error('Example ERROR entry', new DmlException('fake DML exception')).addTag('some important tag'); +Logger.error('Here is my fake Visa credit card 4000-1111-2222-0004, please don\'t steal it').addTag('data masking rule').addTag('credit card masking'); +Logger.warn('Here is my fake Mastercard credit card 5000-1111-2222-0005, please don\'t steal it').addTag('data masking rule').addTag('credit card masking'); +Logger.info('In case you want to steal my identity, my fake social is 400-11-9999, thanks', currentUser).addTag('data masking rule').addTag('an informational tag'); +Logger.debug('Example DEBUG entry', currentUser); +Logger.fine('Example FINE entry'); +Logger.finer('Example FINER entry'); +Logger.finest('Example FINEST entry'); Logger.saveLog(); diff --git a/scripts/create-and-install-unvalidated-package-version.ps1 b/scripts/create-and-install-unvalidated-package-version.ps1 new file mode 100644 index 000000000..096bc1a7b --- /dev/null +++ b/scripts/create-and-install-unvalidated-package-version.ps1 @@ -0,0 +1,15 @@ +# This script is used to create an unvalidated package version & install it into an org, using the specified target username +# This provides a way to ensure that the package can be successfully installed/upgraded into an org, without burning a call to package:version:create with validation/code coverage +param ([string]$targetusername) + +Write-Output "Target Username: $targetusername" + +sfdx force:package:version:create --json --package "Nebula Logger - Unlocked Package" --skipvalidation --installationkeybypass --wait 30 > package-create-output.json +$packageVersionCreateOutput = Get-Content -Path ./package-create-output.json | ConvertFrom-Json +Write-Output "Package Version Create Output: $packageVersionCreateOutput" + +$unvalidatedPackageVersionId = $packageVersionCreateOutput[0].result.SubscriberPackageVersionId +Write-Output "Unvalidated Package Version ID: $unvalidatedPackageVersionId" + +Write-Output "Installing package in org: $targetusername" +sfdx force:package:install --noprompt --targetusername $targetusername --wait 20 --package $unvalidatedPackageVersionId diff --git a/scripts/install-latest-released-unlocked-package-version.ps1 b/scripts/install-latest-released-unlocked-package-version.ps1 new file mode 100644 index 000000000..41dfa090a --- /dev/null +++ b/scripts/install-latest-released-unlocked-package-version.ps1 @@ -0,0 +1,18 @@ +# This script is used to install the latest promoted package version into an org, using the specified target username +param ([string]$targetusername) + +Write-Output "Target Username: $targetusername" + +sfdx force:package:version:list --json --concise --released --orderby CreatedDate > released-package-versions.json +$releasedPackageVersionsOutput = Get-Content -Raw -Path ./released-package-versions.json | ConvertFrom-Json +Write-Output "Package Version Create Output: $releasedPackageVersionsOutput" + +$countOfReleasedPackageVersions = ($releasedPackageVersionsOutput).result.Count +$latestReleasedPackageVersion = ($releasedPackageVersionsOutput).result[$countOfReleasedPackageVersions – 1] +Write-Output "Latest Released Package Version: $latestReleasedPackageVersion" + +$latestReleasedPackageVersionId = ($latestReleasedPackageVersion).SubscriberPackageVersionId +Write-Output "Latest Released Package Version ID: $latestReleasedPackageVersionId" + +Write-Output "Installing package in org: $targetusername" +sfdx force:package:install --noprompt --targetusername $targetusername --wait 20 --package $latestReleasedPackageVersionId diff --git a/sfdx-project.json b/sfdx-project.json index 228eb9045..9ac8d9e5c 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -8,9 +8,9 @@ "path": "nebula-logger", "default": false, "definitionFile": "config/project-scratch-def-with-experience-cloud.json", - "versionNumber": "4.6.6.0", - "versionName": "Configurable Apex Debug Log Syntax", - "versionDescription": "The output of System.debug() can now be configured using merge field syntax in the new field LoggerSettings__c.SystemLogMessageFormat__c", + "versionNumber": "4.6.7.0", + "versionName": "Security Enhancements", + "versionDescription": "Added data mask rules & the ability to strip inaccessible fields in record JSON", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases" }, { @@ -27,7 +27,7 @@ "default": false }, { - "path": "nebula-logger-recipes", + "path": "extra-tests", "default": true } ], @@ -49,6 +49,7 @@ "Nebula Logger - Unlocked Package@4.6.4-0-logger-for-lwc-and-aura": "04t5Y0000015kgjQAA", "Nebula Logger - Unlocked Package@4.6.5-0-internal-trigger-handler-optimizations": "04t5Y0000015kh3QAA", "Nebula Logger - Unlocked Package@4.6.6-0-configurable-apex-debug-log-syntax": "04t5Y0000015khXQAQ", + "Nebula Logger - Unlocked Package@4.6.7-0-security-enhancements": "04t5Y0000015klZQAQ", "Nebula Logger Plugin - Slack": "0Ho5e000000oM3pCAE", "Nebula Logger Plugin - Slack@0.9.0-0-beta-release": "04t5e00000061lHAAQ", "Nebula Logger Plugin - Slack@0.9.1-0-beta-release-round-2": "04t5e00000065xiAAA"
Apex Debug StatementsSystem.debug() is automatically called - the output can be configured with LoggerSettings__c.SystemLogMessageFormat__c to use any field on LogEntryEvent__eSystem.debug() is automatically called - the output can be configured with LoggerSettings__c.SystemLogMessageFormat__c to use any field on LogEntryEvent__e Requires adding your own calls for System.debug() due to Salesforce limitations with managed packages
Automatically stored in LogEntry__c.StackTrace__c when calling methods like Logger.debug('my message'); Requires calling parseStackTrace() due to Salesforce limitations with managed packages. For example:
Logger.debug('my message').parseStackTrace(new DmlException().getStackTrace());
Assign Topics (Tagging/Labeling System)Provide List<String> topics in Apex or Flow to dynamically assign Salesforce Topics to Log__c and LogEntry__c recordsThis functionality is not currently available in the managed package
Logger Plugin FrameworkLeverage Apex or Flow to build your own "plugins" for Logger - to add your own automation to the Log__c or LogEntry__c objects. The logger system will then automatically run your plugins after each trigger event (BEFORE_INSERT, BEFORE_UPDATE, AFTER_INSERT, AFTER_UPDATE, and so on).Leverage Apex or Flow to build your own "plugins" for Logger - easily add your own automation to the any of the included objects: LogEntryEvent__e, Log__c, LogEntry__c, LogEntryTag__c and LoggerTag__c. The logger system will then automatically run your plugins for each trigger event (BEFORE_INSERT, BEFORE_UPDATE, AFTER_INSERT, AFTER_UPDATE, and so on). This functionality is not currently available in the managed package