Skip to content

Commit c1402a9

Browse files
vikashkrmljongpie
andauthored
Fix #760: Capture Apex cursor transaction limits (#892)
* Created new number fields on LogEntryEvent__e and LogEntry__c for storing Apex cursor limits * Added backend logic to capture & map Apex cursor limits to the new fields * Added new formula fields on LogEntry__c (and flexipage) to show cursor limits used vs max (similar to the other transaction limits fields) * Scope creep: fixed an issue in the pipeline that caused Apex code coverage to not be updated on the main branch --------- Co-authored-by: Jonathan Gillespie <[email protected]>
1 parent 2ab4af9 commit c1402a9

23 files changed

+307
-44
lines changed

.github/workflows/build.yml

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,32 @@ jobs:
250250
- name: 'Run Apex Tests Synchronously'
251251
run: npm run test:apex:nocoverage -- --synchronous
252252

253+
# This is the only place in Nebula Logger's pipeline where the `LoggerCore` test suite runs & the results are sent to Codecov.io.
254+
# This is specifically done in the base scratch org, using only the `LoggerCore test` suite, in order to help validate that the core metadata
255+
# provides sufficient code coverage for teams that deploy Nebula Logger's metadata directly to their org, instead of installing one of Nebula Logger's 2GP packages.
256+
# 1. Many teams cannot use one of the 2GP packages for various reasons, including company policies, security concerns, etc.,
257+
# and being able to deploy the core metadata is something that should be supported.
258+
# 2. And even though the pipeline runs the `extra-tests` directory to validate logging works correctly in various types of scratch orgs,
259+
# for teams that are trying to deploy Nebula Logger's metadata, it's critical that the core tests have sufficient code coverage to be deployed to a prod org.
260+
# - In the past, this has not always been the case, resulting in some teams having deployment issues & project delays due to the low code coverage
261+
# that was (formerly) provided by some of the core tests classes.
262+
# - In orgs that do not have some optional Salesforce features enabled/available (e.g., orgs without Experience Cloud, OmniStudio, Platform Cache, etc.),
263+
# the code coverage can be especially low, so using the base scratch org acts
264+
#
265+
266+
# So now only the core test suite's results, from a base scratch org, are used for reporting code coverage, even though the project's overall code coverage
267+
# is much higher when using the `extra-tests` directory.
268+
- name: 'Get Core Test Suite Code Coverage'
269+
run: npm run test:apex:suite:core
270+
271+
# This is the only scratch org that's used for uploading code coverage
272+
- name: 'Upload Apex test code coverage to Codecov.io'
273+
uses: codecov/codecov-action@v4
274+
with:
275+
fail_ci_if_error: true
276+
flags: Apex
277+
token: ${{ secrets.CODECOV_TOKEN }}
278+
253279
- name: 'Delete Scratch Org'
254280
run: npx sf org delete scratch --no-prompt
255281
if: ${{ always() }}
@@ -621,32 +647,6 @@ jobs:
621647
- name: 'Create & Install Package Version'
622648
run: npx pwsh ./scripts/build/create-and-install-package-version.ps1 -targetpackagealias '"Nebula Logger - Core"' -targetreadme ./README.md -targetusername base_package_subscriber_scratch_org
623649

624-
# This is the only place in Nebula Logger's pipeline where the `LoggerCore` test suite runs & the results are sent to Codecov.io.
625-
# This is specifically done in the base scratch org, using only the `LoggerCore test` suite, in order to help validate that the core metadata
626-
# provides sufficient code coverage for teams that deploy Nebula Logger's metadata directly to their org, instead of installing one of Nebula Logger's 2GP packages.
627-
# 1. Many teams cannot use one of the 2GP packages for various reasons, including company policies, security concerns, etc.,
628-
# and being able to deploy the core metadata is something that should be supported.
629-
# 2. And even though the pipeline runs the `extra-tests` directory to validate logging works correctly in various types of scratch orgs,
630-
# for teams that are trying to deploy Nebula Logger's metadata, it's critical that the core tests have sufficient code coverage to be deployed to a prod org.
631-
# - In the past, this has not always been the case, resulting in some teams having deployment issues & project delays due to the low code coverage
632-
# that was (formerly) provided by some of the core tests classes.
633-
# - In orgs that do not have some optional Salesforce features enabled/available (e.g., orgs without Experience Cloud, OmniStudio, Platform Cache, etc.),
634-
# the code coverage can be especially low, so using the base scratch org acts
635-
#
636-
637-
# So now only the core test suite's results, from a base scratch org, are used for reporting code coverage, even though the project's overall code coverage
638-
# is much higher when using the `extra-tests` directory.
639-
- name: 'Get Core Test Suite Code Coverage'
640-
run: npm run test:apex:suite:core
641-
642-
# This is the only scratch org that's used for uploading code coverage
643-
- name: 'Upload Apex test code coverage to Codecov.io'
644-
uses: codecov/codecov-action@v4
645-
with:
646-
fail_ci_if_error: true
647-
flags: Apex
648-
token: ${{ secrets.CODECOV_TOKEN }}
649-
650650
# The metadata API / sf CLI support deploying metadata using package manifest XML files - see docs for more details:
651651
# Docs: https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/manifest_samples.htm
652652
# _Some_ people (@jongpie) dislike using manifest files, and find them to be unnecessary for most teams/projects/implementations.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55

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

8-
## Unlocked Package - v4.16.4
8+
## Unlocked Package - v4.16.5
99

10-
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tKe0000011MyWIAU)
11-
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tKe0000011MyWIAU)
10+
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tKe0000011N4KIAUAGE)
11+
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tKe0000011N4KIAUAGE)
1212
[![View Documentation](./images/btn-view-documentation.png)](https://github.com/jongpie/NebulaLogger/wiki)
1313

14-
`sf package install --wait 20 --security-type AdminsOnly --package 04tKe0000011MyWIAU`
14+
`sf package install --wait 20 --security-type AdminsOnly --package 04tKe0000011N4KIAUAGE`
1515

1616
---
1717

nebula-logger/core.package.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@
175175
<members>LogEntryEvent__e.LimitsAggregateQueriesMax__c</members>
176176
<members>LogEntryEvent__e.LimitsAggregateQueriesUsed__c</members>
177177
<members>LogEntryEvent__e.LimitsAggregateQueryMax__c</members>
178+
<members>LogEntryEvent__e.LimitsApexCursorFetchCallsMax__c</members>
179+
<members>LogEntryEvent__e.LimitsApexCursorFetchCallsUsed__c</members>
180+
<members>LogEntryEvent__e.LimitsApexCursorRowsMax__c</members>
181+
<members>LogEntryEvent__e.LimitsApexCursorRowsUsed__c</members>
178182
<members>LogEntryEvent__e.LimitsAsyncCallsMax__c</members>
179183
<members>LogEntryEvent__e.LimitsAsyncCallsUsed__c</members>
180184
<members>LogEntryEvent__e.LimitsCalloutsMax__c</members>
@@ -418,6 +422,12 @@
418422
<members>LogEntry__c.LimitsAggregateQueriesMax__c</members>
419423
<members>LogEntry__c.LimitsAggregateQueriesUsed__c</members>
420424
<members>LogEntry__c.LimitsAggregateQueries__c</members>
425+
<members>LogEntry__c.LimitsApexCursorFetchCallsMax__c</members>
426+
<members>LogEntry__c.LimitsApexCursorFetchCallsUsed__c</members>
427+
<members>LogEntry__c.LimitsApexCursorFetchCalls__c</members>
428+
<members>LogEntry__c.LimitsApexCursorRowsMax__c</members>
429+
<members>LogEntry__c.LimitsApexCursorRowsUsed__c</members>
430+
<members>LogEntry__c.LimitsApexCursorRows__c</members>
421431
<members>LogEntry__c.LimitsAsyncCallsMax__c</members>
422432
<members>LogEntry__c.LimitsAsyncCallsUsed__c</members>
423433
<members>LogEntry__c.LimitsAsyncCalls__c</members>

nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler {
303303
HttpResponseStatusCode__c = logEntryEvent.HttpResponseStatusCode__c,
304304
LimitsAggregateQueriesMax__c = logEntryEvent.LimitsAggregateQueriesMax__c,
305305
LimitsAggregateQueriesUsed__c = logEntryEvent.LimitsAggregateQueriesUsed__c,
306+
LimitsApexCursorFetchCallsMax__c = logEntryEvent.LimitsApexCursorFetchCallsMax__c,
307+
LimitsApexCursorFetchCallsUsed__c = logEntryEvent.LimitsApexCursorFetchCallsUsed__c,
308+
LimitsApexCursorRowsMax__c = logEntryEvent.LimitsApexCursorRowsMax__c,
309+
LimitsApexCursorRowsUsed__c = logEntryEvent.LimitsApexCursorRowsUsed__c,
306310
LimitsAsyncCallsMax__c = logEntryEvent.LimitsAsyncCallsMax__c,
307311
LimitsAsyncCallsUsed__c = logEntryEvent.LimitsAsyncCallsUsed__c,
308312
LimitsCalloutsMax__c = logEntryEvent.LimitsCalloutsMax__c,

nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,26 @@
854854
<identifier>RecordLimitsAggregateQueries__cField</identifier>
855855
</fieldInstance>
856856
</itemInstances>
857+
<itemInstances>
858+
<fieldInstance>
859+
<fieldInstanceProperties>
860+
<name>uiBehavior</name>
861+
<value>readonly</value>
862+
</fieldInstanceProperties>
863+
<fieldItem>Record.LimitsApexCursorFetchCalls__c</fieldItem>
864+
<identifier>RecordLimitsApexCursorFetchCalls__cField</identifier>
865+
</fieldInstance>
866+
</itemInstances>
867+
<itemInstances>
868+
<fieldInstance>
869+
<fieldInstanceProperties>
870+
<name>uiBehavior</name>
871+
<value>readonly</value>
872+
</fieldInstanceProperties>
873+
<fieldItem>Record.LimitsApexCursorRows__c</fieldItem>
874+
<identifier>RecordLimitsApexCursorRows__cField</identifier>
875+
</fieldInstance>
876+
</itemInstances>
857877
<itemInstances>
858878
<fieldInstance>
859879
<fieldInstanceProperties>
@@ -913,7 +933,11 @@
913933
<fieldItem>Record.LimitsEmailInvocations__c</fieldItem>
914934
<identifier>RecordLimitsEmailInvocations__cField</identifier>
915935
</fieldInstance>
916-
</itemInstances>
936+
</itemInstances>
937+
<name>Facet-8e5572ea-8a8e-4426-8154-004cbbcb1314</name>
938+
<type>Facet</type>
939+
</flexiPageRegions>
940+
<flexiPageRegions>
917941
<itemInstances>
918942
<fieldInstance>
919943
<fieldInstanceProperties>
@@ -924,10 +948,6 @@
924948
<identifier>RecordLimitsFutureCalls__cField</identifier>
925949
</fieldInstance>
926950
</itemInstances>
927-
<name>Facet-8e5572ea-8a8e-4426-8154-004cbbcb1314</name>
928-
<type>Facet</type>
929-
</flexiPageRegions>
930-
<flexiPageRegions>
931951
<itemInstances>
932952
<fieldInstance>
933953
<fieldInstanceProperties>
@@ -2079,6 +2099,10 @@
20792099
<flexiPageRegions>
20802100
<itemInstances>
20812101
<componentInstance>
2102+
<componentInstanceProperties>
2103+
<name>label</name>
2104+
<value>Tabs</value>
2105+
</componentInstanceProperties>
20822106
<componentInstanceProperties>
20832107
<name>tabs</name>
20842108
<value>Facet-ec9d7630-d727-4e4a-9a1a-3ebabfc68c45</value>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>LimitsApexCursorFetchCallsMax__c</fullName>
4+
<externalId>false</externalId>
5+
<label>Apex Cursor Fetch Calls Max</label>
6+
<precision>10</precision>
7+
<required>false</required>
8+
<scale>0</scale>
9+
<trackTrending>false</trackTrending>
10+
<type>Number</type>
11+
<unique>false</unique>
12+
</CustomField>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>LimitsApexCursorFetchCallsUsed__c</fullName>
4+
<externalId>false</externalId>
5+
<label>Apex Cursor Fetch Calls Used</label>
6+
<precision>10</precision>
7+
<required>false</required>
8+
<scale>0</scale>
9+
<trackTrending>false</trackTrending>
10+
<type>Number</type>
11+
<unique>false</unique>
12+
</CustomField>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>LimitsApexCursorFetchCalls__c</fullName>
4+
<businessStatus>Active</businessStatus>
5+
<complianceGroup>None</complianceGroup>
6+
<externalId>false</externalId>
7+
<formula>IF(
8+
(LimitsApexCursorFetchCallsUsed__c / LimitsApexCursorFetchCallsMax__c * 100) &gt;= 90,
9+
&quot;&quot;,
10+
IF(
11+
(LimitsApexCursorFetchCallsUsed__c / LimitsApexCursorFetchCallsMax__c * 100) &lt; 90 &amp;&amp; (LimitsApexCursorFetchCallsUsed__c / LimitsApexCursorFetchCallsMax__c * 100) &gt;= 80,
12+
&quot;⚠️&quot;,
13+
&quot;&quot;
14+
)
15+
)
16+
+ &apos; &apos; + IF(LimitsApexCursorFetchCallsMax__c = 0, &apos;100&apos;, TEXT(ROUND(LimitsApexCursorFetchCallsUsed__c / LimitsApexCursorFetchCallsMax__c * 100, 2))) + &apos;% (&apos;
17+
+ TEXT(LimitsApexCursorFetchCallsUsed__c) + &apos; / &apos; + TEXT(LimitsApexCursorFetchCallsMax__c) + &apos;)&apos;</formula>
18+
<formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>
19+
<inlineHelpText>✅ when 80% or less of the limit is used, ⚠️ when 80.1-89.9% is used, or ⛔ when 90% or more is used</inlineHelpText>
20+
<label>Apex Cursor Fetch Calls</label>
21+
<required>false</required>
22+
<securityClassification>Confidential</securityClassification>
23+
<trackTrending>false</trackTrending>
24+
<type>Text</type>
25+
<unique>false</unique>
26+
</CustomField>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>LimitsApexCursorRowsMax__c</fullName>
4+
<externalId>false</externalId>
5+
<label>Apex Cursor Rows Max</label>
6+
<precision>10</precision>
7+
<required>false</required>
8+
<scale>0</scale>
9+
<trackTrending>false</trackTrending>
10+
<type>Number</type>
11+
<unique>false</unique>
12+
</CustomField>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>LimitsApexCursorRowsUsed__c</fullName>
4+
<externalId>false</externalId>
5+
<label>Apex Cursor Rows Used</label>
6+
<precision>10</precision>
7+
<required>false</required>
8+
<scale>0</scale>
9+
<trackTrending>false</trackTrending>
10+
<type>Number</type>
11+
<unique>false</unique>
12+
</CustomField>

0 commit comments

Comments
 (0)