Skip to content

Commit 2dbbf9f

Browse files
authored
Added support for custom field mappings (#664)
* Added the ability to set & map custom fields, using a new CMDT LoggerFieldMapping__mdt and new LogEntryEventBuilder instance method overloads setField(Schema.SObjectField field, Object fieldValue) and setField(Map<Schema.SObjectField, Object> fieldToValue) * Added some CMDT records to the extra-tests directory that map the included custom fields (also stored in the extra-tests directory). These CMDT records are just to help with functionally/manually testing in a scratch org - they won't be included in any of the packages * Scope creep: Updated several config classes to consistently have test-visible private methods before non-test-visible private methods * Updated README.md to add details about custom field mappings, and cleaned up/updated some other README contents * Added .github/FUNDING.yml so the repo has a sponsor button
1 parent 48ea5fe commit 2dbbf9f

43 files changed

Lines changed: 1093 additions & 76 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [jongpie]

README.md

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.
77

8-
## Unlocked Package - v4.13.13
8+
## Unlocked Package - v4.13.14
99

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

14-
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oDsQAI`
14+
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oE2QAI`
1515

16-
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oDsQAI`
16+
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oE2QAI`
1717

1818
---
1919

@@ -31,7 +31,7 @@ The most robust logger for Salesforce. Works with Apex, Lightning Components, Fl
3131

3232
## Features
3333

34-
1. Easily add log entries via Apex, Lightning Components (lwc & aura), Flow & Process Builder to generate 1 consolidated, unified log
34+
1. Easily add log entries via Apex, Lightning Components (lightning web components (LWCs) & aura components), Flow & Process Builder to generate 1 consolidated, unified log
3535
2. Manage & report on logging data using the `Log__c` and `LogEntry__c` objects
3636
3. Leverage `LogEntryEvent__e` platform events for real-time monitoring & integrations
3737
4. Enable logging and set the logging level for different users & profiles using `LoggerSettings__c` custom hierarchy setting
@@ -86,11 +86,6 @@ Nebula Logger is available as both an unlocked package and a managed package. Th
8686
<td><code>System.debug()</code> is automatically called - the output can be configured with <code>LoggerSettings__c.SystemLogMessageFormat__c</code> to use any field on <code>LogEntryEvent__e</code></td>
8787
<td>Requires adding your own calls for <code>System.debug()</code> due to Salesforce limitations with managed packages</td>
8888
</tr>
89-
<tr>
90-
<td>Apex Stack Traces</td>
91-
<td>Automatically stored in <code>LogEntry__c.StackTrace__c</code> when calling methods like <code>Logger.debug('my message');</code></td>
92-
<td>Requires calling <code>parseStackTrace()</code> due to Salesforce limitations with managed packages. For example:<br><code>Logger.debug('my message').parseStackTrace(new DmlException().getStackTrace());</code></td>
93-
</tr>
9489
<tr>
9590
<td>Logger Plugin Framework</td>
9691
<td>Leverage Apex or Flow to build your own "plugins" for Logger - easily add your own automation to the any of the included objects: <code>LogEntryEvent__e</code>, <code>Log__c</code>, <code>LogEntry__c</code>, <code>LogEntryTag__c</code> and <code>LoggerTag__c</code>. The logger system will then automatically run your plugins for each trigger event (BEFORE_INSERT, BEFORE_UPDATE, AFTER_INSERT, AFTER_UPDATE, and so on).</td>
@@ -142,20 +137,21 @@ This results in 1 `Log__c` record with several related `LogEntry__c` records.
142137

143138
### Logger for Lightning Components: Quick Start
144139

145-
For lightning component developers, the `logger` lwc provides very similar functionality that is offered in Apex. Simply embed the `logger` lwc in your component, and call the desired logging methods within your code.
140+
For lightning component developers, the `logger` LWC provides very similar functionality that is offered in Apex. Simply incorporate the `logger` LWC into your component, and call the desired logging methods within your code.
146141

147142
```javascript
148-
// For lwc, retrieve logger from your component's template
149-
const logger = this.template.querySelector('c-logger');
143+
// For LWC, import logger's createLogger() function into your component
144+
import { createLogger } from 'c/logger';
150145

151-
logger.error('Hello, world!').addTag('some important tag');
152-
logger.warn('Hello, world!');
153-
logger.info('Hello, world!');
154-
logger.debug('Hello, world!');
155-
logger.fine('Hello, world!');
156-
logger.finer('Hello, world!');
157-
logger.finest('Hello, world!');
158-
logger.saveLog();
146+
export default class LoggerLWCDemo extends LightningElement {
147+
logger;
148+
149+
async connectedCallback() {
150+
this.logger = await createLogger();
151+
this.logger.info('Hello, world');
152+
this.logger.saveLog();
153+
}
154+
}
159155
```
160156

161157
```javascript
@@ -388,7 +384,7 @@ For more details, check out the `LogMessage` class [documentation](https://jongp
388384

389385
## Features for Lightning Component Developers
390386

391-
For lightning component developers, the included `logger` lwc can be used in other lwc & aura components for frontend logging. Similar to `Logger` and `LogEntryBuilder` Apex classes, the lwc has both `logger` and `logEntryBuilder` classes. This provides a fluent API for javascript developers so they can chain the method calls.
387+
For lightning component developers, the included `logger` LWC can be used in other LWCs & aura components for frontend logging. Similar to `Logger` and `LogEntryBuilder` Apex classes, the LWC has both `logger` and `logEntryBuilder` classes. This provides a fluent API for JavaScript developers so they can chain the method calls.
392388

393389
Once you've incorporated `logger` into your lightning components, you can see your `LogEntry__c` records using the included list view "All Component Log Entries'.
394390

@@ -400,34 +396,48 @@ Each `LogEntry__c` record automatically stores the component's type ('Aura' or '
400396
401397
#### Example LWC Usage
402398
403-
To use the logger component, it has to be added to your lwc's markup:
399+
For lightning component developers, the `logger` LWC provides very similar functionality that is offered in Apex. Simply import the `logger` LWC in your component, and call the desired logging methods within your code.
404400
405-
```html
406-
<template>
407-
<c-logger></c-logger>
401+
```javascript
402+
// For LWC, import logger's createLogger() function into your component
403+
import { createLogger } from 'c/logger';
408404

409-
<div>My component</div>
410-
</template>
411-
```
405+
export default class LoggerLWCDemo extends LightningElement {
406+
logger;
412407

413-
Once you've added logger to your markup, you can call it in your lwc's controller:
408+
async connectedCallback() {
409+
// Call createLogger() once per component
410+
this.logger = await createLogger();
414411

415-
```javascript
416-
import { LightningElement } from 'lwc';
412+
this.logger.setScenario('some scenario');
413+
this.logger.finer('initialized demo LWC');
414+
}
417415

418-
export default class LoggerDemo extends LightningElement {
419416
logSomeStuff() {
420-
const logger = this.template.querySelector('c-logger');
421-
422-
logger.error('Hello, world!').addTag('some important tag');
423-
logger.warn('Hello, world!');
424-
logger.info('Hello, world!');
425-
logger.debug('Hello, world!');
426-
logger.fine('Hello, world!');
427-
logger.finer('Hello, world!');
428-
logger.finest('Hello, world!');
417+
this.logger.error('Add log entry using Nebula Logger with logging level == ERROR').addTag('some important tag');
418+
this.logger.warn('Add log entry using Nebula Logger with logging level == WARN');
419+
this.logger.info('Add log entry using Nebula Logger with logging level == INFO');
420+
this.logger.debug('Add log entry using Nebula Logger with logging level == DEBUG');
421+
this.logger.fine('Add log entry using Nebula Logger with logging level == FINE');
422+
this.logger.finer('Add log entry using Nebula Logger with logging level == FINER');
423+
this.logger.finest('Add log entry using Nebula Logger with logging level == FINEST');
424+
425+
this.logger.saveLog();
426+
}
429427

430-
logger.saveLog();
428+
doSomething(event) {
429+
this.logger.finest('Starting doSomething() with event: ' + JSON.stringify(event));
430+
try {
431+
this.logger.debug('TODO - finishing implementation of doSomething()').addTag('another tag');
432+
// TODO add the function's implementation below
433+
} catch (thrownError) {
434+
this.logger
435+
.error('An unexpected error log entry using Nebula Logger with logging level == ERROR')
436+
.setError(thrownError)
437+
.addTag('some important tag');
438+
} finally {
439+
this.logger.saveLog();
440+
}
431441
}
432442
}
433443
```
@@ -584,6 +594,53 @@ Once you've implementing log entry tagging within Apex or Flow, you can choose h
584594
585595
---
586596
597+
## Adding Custom Fields to Nebula Logger's Data Model
598+
599+
As of `v4.13.14`, Nebula Logger supports defining, setting, and mapping custom fields within Nebula Logger's data model. This is helpful in orgs that want to extend Nebula Logger's included data model by creating their own org/project-specific fields.
600+
601+
This feature requires that you populate your custom fields yourself, and is only available in Apex currently. The plan is to add in a future release the ability to also set custom fields via JavaScript & Flow.
602+
603+
### Adding Custom Fields to the Platform Event `LogEntryEvent__e`
604+
605+
The first step is to add a field to the platform event `LogEntryEvent__e`
606+
607+
- Create a custom field on `LogEntryEvent__e`. Any data type supported by platform events can be used.
608+
609+
- In this example, a custom text field called `SomeCustomField__c` has been added:
610+
611+
![Custom Field on LogEntryEvent__e](./images/custom-field-log-entry-event.png)
612+
613+
- Populate your field(s) in Apex by calling the instance method overloads `LogEntryEventBuilder.setField(Schema.SObjectField field, Object fieldValue)` or `LogEntryEventBuilder.setField(Map<Schema.SObjectField, Object> fieldToValue)`
614+
615+
```apex
616+
Logger.info('hello, world')
617+
// Set a single field
618+
.setField(LogEntryEvent__e.SomeCustomTextField__c, 'some text value')
619+
// Set multiple fields
620+
.setFields(new Map<Schema.SObjectField, Object>{
621+
LogEntryEvent__e.AnotherCustomTextField__c => 'another text value',
622+
LogEntryEvent__e.SomeCustomDatetimeField__c => System.now()
623+
});
624+
```
625+
626+
### Adding Custom Fields to the Custom Objects `Log__c`, `LogEntry__c`, and `LoggerScenario__c`
627+
628+
If you want to store the data in one of Nebula Logger's custom objects, you can follow the above steps, and also...
629+
630+
- Create an equivalent custom field on one of Nebula Logger's custom objects - right now, only `Log__c`, `LogEntry__c`, and `LoggerScenario__c` are supported.
631+
632+
- In this example, a custom text field _also_ called `SomeCustomField__c` has been added to `Log__c` object - this will be used to store the value of the field `LogEntryEvent__e.SomeCustomField__c`:
633+
634+
![Custom Field on LogEntryEvent__e](./images/custom-field-log.png)
635+
636+
- Create a record in the new CMDT `LoggerFieldMapping__mdt` to map the `LogEntryEvent__e` custom field to the custom object's custom field, shown below. Nebula Logger will automatically populate the custom object's target field with the value of the source `LogEntryEvent__e` field.
637+
638+
- In this example, a custom text field called `SomeCustomField__c` has been added to both `LogEntryEvent__e` and `Log__c`.
639+
640+
![Custom Field on LogEntryEvent__e](./images/custom-field-mapping.png)
641+
642+
---
643+
587644
## Log Management
588645

589646
### Logger Console App
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
layout: default
3+
---
4+
5+
## LoggerFieldMapper class
6+
7+
Maps fields values from custom fields on `LogEntryEvent__e` to equivalent fields on `Log__c`, `LogEntry__c`, and `LoggerScenario__c`
8+
9+
---
10+
11+
### Methods
12+
13+
#### `mapFieldValues(SObject sourceRecord, SObject targetRecord)``void`
14+
15+
Copies field values from the `sourceRecord` to the `targetRecord`, based on rules configured in `LoggerFieldMapping_t`
16+
17+
##### Parameters
18+
19+
| Param | Description |
20+
| -------------- | ------------------------------------------------------------------------------- |
21+
| `sourceRecord` | The source `SObject` record containing the data to copy |
22+
| `targetRecord` | The target `SObject` record that should have fields &amp; field values appended |
23+
24+
---

docs/apex/Logger-Engine/LogEntryEventBuilder.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,47 @@ LogEntryEventBuilder
400400

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

403+
#### `setField(Schema.SObjectField field, Object fieldValue)``LogEntryEventBuilder`
404+
405+
Sets a field values on the builder&apos;s `LogEntryEvent__e` record
406+
407+
##### Parameters
408+
409+
| Param | Description |
410+
| ------------ | -------------------------------------------------------- |
411+
| `field` | The `Schema.SObjectField` token of the field to populate |
412+
| `fieldValue` | The `Object` value to populate in the provided field |
413+
414+
##### Return
415+
416+
**Type**
417+
418+
LogEntryEventBuilder
419+
420+
**Description**
421+
422+
The same instance of `LogEntryEventBuilder`, useful for chaining methods
423+
424+
#### `setField(Map<Schema.SObjectField, Object> fieldToValue)``LogEntryEventBuilder`
425+
426+
Sets multiple field values on the builder&apos;s `LogEntryEvent__e` record
427+
428+
##### Parameters
429+
430+
| Param | Description |
431+
| -------------- | ---------------------------------------------------------------------- |
432+
| `fieldToValue` | An instance of `Map&lt;Schema.SObjectField, Object&gt;` containing the |
433+
434+
##### Return
435+
436+
**Type**
437+
438+
LogEntryEventBuilder
439+
440+
**Description**
441+
442+
The same instance of `LogEntryEventBuilder`, useful for chaining methods
443+
403444
#### `setHttpRequestDetails(System.HttpRequest request)``LogEntryEventBuilder`
404445

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

docs/apex/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ Class used by the logging system for batch contextual details
150150

151151
Class used to cache query results returned by the selector classes
152152

153+
### [LoggerFieldMapper](Configuration/LoggerFieldMapper)
154+
155+
Maps fields values from custom fields on `LogEntryEvent__e` to equivalent fields on `Log__c`, `LogEntry__c`, and `LoggerScenario__c`
156+
153157
### [LoggerParameter](Configuration/LoggerParameter)
154158

155159
Provides a centralized way to load parameters for SObject handlers &amp; plugins, and casts the parameters to common data types
128 KB
Loading

images/custom-field-log.png

139 KB
Loading

images/custom-field-mapping.png

122 KB
Loading

0 commit comments

Comments
 (0)