Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BigObject support as the logging location #117

Closed
jamessimone opened this issue Mar 23, 2021 · 12 comments · Fixed by #298
Closed

Add BigObject support as the logging location #117

jamessimone opened this issue Mar 23, 2021 · 12 comments · Fixed by #298
Labels
Feature: Plugin Framework Items related to Nebula Logger's plugin framework Layer: Configuration Items related to the custom hierarchy setting LoggerSettings__c or any included custom metadata type Layer: Logger Engine Items related to the core logging engine Package Type: Unlocked Package Issues and enhancements that specifically apply to the unlocked package Plugin: Big Object Archiving Items related to archiving logging data into the LogEntryArchive__b big object Type: Enhancement New feature or request

Comments

@jamessimone
Copy link
Collaborator

Larger orgs with significant logging volume may be leery of using a custom object to store the Log__c and LogEntry__c items, due to storage space alone. With a high enough throughput, multiple LogBatchPurger jobs would be necessary per hour purely to keep storage space at a sane level. For orgs like this, using BigObjects to store the Log and Log Entry items would be a happier path to success. If this were configurable within Nebula Logger itself, people could choose whether or not their log items were appended to BigObjects or the traditional custom object locations.

@jongpie
Copy link
Owner

jongpie commented Mar 23, 2021

I love this idea - I think the feature makes a lot of sense to add as a configurable option, probably with 4 possible configurations:

  1. Enable only log & log entry creation - create Log__c and LogEntry__c records (existing functionality) / don't create BigObject records
  2. Enable only big object creation - don't create Log__c and LogEntry__c records/ only create BigObject records
  3. Enable everything - create Log__c and LogEntry__c AND BigObject records
  4. Disable everything - don't create Log__c, LogEntry__c or BigObject records

I think that would cover all scenarios (the LogEntryEvent__e platform events would always be created since they're the starting pointing for logging)

@jongpie jongpie added Plugin: Big Object Archiving Items related to archiving logging data into the LogEntryArchive__b big object Type: Enhancement New feature or request Layer: Configuration Items related to the custom hierarchy setting LoggerSettings__c or any included custom metadata type labels Mar 23, 2021
@jongpie
Copy link
Owner

jongpie commented Mar 23, 2021

@jamessimone one other thought on this - if we have LoggerSettings__c hierarchy setting control the behavior, then that opens up a lot of possibilities with the 4 scenarios that I mentioned above. For example, you could have big objects enabled for the entire org (org defaults), and for certain profiles/users, you could also configure the settings to have have Log__c/LogEntry__c records still created, letting you could mix & match which records get created.

@arvindnarsimhan
Copy link
Contributor

arvindnarsimhan commented Mar 25, 2021

Thanks, @jamessimone for considering this feature. Also, would like to look into the option of writing to BigObjects directly using Queable or Future Apex instead of using Platform Events. Large organizations might want to preserve the limits for Platform Events for Business use cases like CDC etc instead of logging.

@jamessimone
Copy link
Collaborator Author

@arvindnarsimhan as an aside, Nebula Logger already supports the usage of Queueables as the log saving implementation - the saveLog method exposed via the Logger class allows for you to stipulate Logger.SaveMethod.QUEUEABLE to achieve this. Once Big Object support is implemented, you’ll have all the tools you need!

@arvindnarsimhan
Copy link
Contributor

@jamessimone The QueableSaver.execute method again publishes the log to the EventBus. The publishing of events is what happens in the Queable Apex. Was looking to write the log to the BigObject directly instead of using PlatformEvents pub/sub model.

@jongpie
Copy link
Owner

jongpie commented Mar 30, 2021

@arvindnarsimhan that should be fine - I think 2 parts of incorporating BigObject support are:

  • Add field(s) on the custom setting to control if it writes to Platform Event or BigObject (or both)
  • Update the current queueable job to insert BigObject records directly when writing directly to the BigObject is enabled (if Platform Events are enabled, it'll still use the current EventBus approach)

@arvindnarsimhan
Copy link
Contributor

@arvindnarsimhan that should be fine - I think 2 parts of incorporating BigObject support are:

  • Add field(s) on the custom setting to control if it writes to Platform Event or BigObject (or both)
  • Update the current queueable job to insert BigObject records directly when writing directly to the BigObject is enabled (if Platform Events are enabled, it'll still use the current EventBus approach)

@jongpie Here is my suggestion. The strategy to move the logs(Platform Events or Future Apex ) and medium to persist the logs (Big Object vs Custom Object ) should be 2 different separate options.

This should give the flexibility to use

  1. Platform Events + Custom Objects ( Current approach )
  2. Platform Events + Big Object
  3. Future APEX method + Custom Object
  4. Future APEX method + Big Object

Also, if we discussed an option to write to both Custom Object + Big Object

Here is my approach

  1. Add the 4th option to the SaveMethod enum FUTURE_METHOD
  2. Config option called LogStorage for NONE, BIG_OBJECTS_ONLY, CUSTOM_OBJECT_ONLY, BIG_AND_CUSTOM_OBJECTS

@jongpie
Copy link
Owner

jongpie commented Apr 1, 2021

@arvindnarsimhan conceptually I like the approach, but a couple of follow up thoughts

  • Future method: what's your thought process behind wanting to include a future method? I don't see any benefit to it - the queueable job serves the same purpose of saving asynchronously (we'll update the existing queueable class to support saving to BigObject), and future methods are much more limited overall compared to queueable classes. But let me know if there's a particular scenario where you think a future method would be more advantageous.

  • Config options: your list of LogStorage config options doesn't cover one scenario that I think should be handled for Platform Events

    • Publish platform events, but do not store them in custom objects: This scenario isn't covered with your approach. Some orgs will still want to publish the platform events, but not store them in the custom objects. This can happen in orgs that want to continue using the benefits of the pub/sub model without using up data storage. I think using 3 checkbox fields (examples shown in image below) will give more control over the different combinations/scenarios. And since custom settings don't support picklist fields, using checkboxes is less error prone than a text field.

    image

@arvindnarsimhan
Copy link
Contributor

@jongpie -

  1. Yes you are right. We can augment the current QueableSaver to persist the events in BigObjects or Custom Object. No particular advantage on using Future methods.

  2. Your design is very neat. Does it make sense to call LogEntryEventHandler.insertLogEntries directly in QueableSaver.execute to bypass Platform Events?

  3. Also, if Platform Events are enabled, we can use the current pub/sub model. The documentation says limits for event delivery only apply for CometD and empApi. We should be good.

  4. Think we should have a LogWriter interface with 2 implementations CustomObjectLogWriter and BigObjectLogWriter. We can have an array of LogWriter in LogEntryEventHandler. The array will have CustomObjectLogWriter or BigObjectLogWriter or both depending on user preference. The write method LogWriter will abstract the logic for writing to Big Objects or Custom Object

@jongpie
Copy link
Owner

jongpie commented Apr 8, 2021

@arvindnarsimhan sorry for the late reply!

I've talked with @jamessimone some about how to best approach this - right now, we're planning to have the Logger class internally handle creating LogEntryEvent__e platform event records and/or LogEntryArchive__b BigObject records (new object). The problem with putting the logic into LogEntryEventHandler is that that class is really intended to handle the platform events - so if orgs want to bypass platform events altogether and only use BigObjects, then LogEntryEventHandler won't execute/shouldn't execute (it only executes after insert on LogEntryEvent__e). I think having Logger handle determining where to store the logs is will be a cleaner approach. We'll keep you updated on our progress!

@jongpie
Copy link
Owner

jongpie commented Mar 15, 2022

I think we're going to finally revisit this item - we'll be releasing this functionality as a plugin initially. Long-term, I'd like to make this part of the core package, but starting with it as a plugin will give us the flexibility to make changes to things like the big object's index, which is hard/impossible to change later on.

A few MVP goals for the first release of the plugin:

  • It should support logging to a new big object called LogEntryArchive__b - it will look nearly identical to the platform event object LogEntryEvent__e
  • The plugin should be able to provide its own save method (BIG_OBJECT or something similar) that can be selected in the LWC loggerSettings
    • When the user's save method is BIG_OBJECT, then log entries should only be saved in the big object - it should not use platform events, and it should not store any data in Log__c or LogEntry__c
  • The plugin should run on BEFORE_INSERT for LogEntryEvent__e
  • The plugin should include an LWC + custom tab to display & filter on LogEntryArchive__b records. Long term, this custom tab will become part of the Logger Console app, once the plugin is merged into core
  • The plugin should include an LWC that can be embedded on a record page (using the target lightning__RecordPage), and only display LogEntryArchive__b records for the current record (based on the field RecordId__c
    • Due to how SOQL & indexes work for big objects, this might involve having a second big object that only contains log entries with a RecordId__c value. If that ends up being necessary, then this big object will be called RecordLogEntryArchive__b or something similar

@jongpie jongpie added Package Type: Unlocked Package Issues and enhancements that specifically apply to the unlocked package and removed on hold labels Mar 15, 2022
jamessimone added a commit that referenced this issue Mar 16, 2022
jamessimone added a commit that referenced this issue Mar 16, 2022
… up some picklist values for LoggerPlugin__mdt.PluginType__c with an eye towards future BigObject changes
jongpie added a commit that referenced this issue Mar 17, 2022
* Picking #117 back up with @jongpie to finally add BigObject support through Logger plugin package - includes a new BigObject LogEntryArchive__b and new plugin class

* Cleaned up some picklist values for LoggerPlugin__mdt.PluginType__c with an eye towards future BigObject changes

* Added an permission set LoggerLogEntryArchiveAdmin within BigObject plugin to grant access to the BigObject LogEntryArchive__b

* Switched to lazy-loading the instance of SObjectHandlerInput - tests were previously failing because of the input being generated too early by the trigger framework

* Added apex script with sample query for LogEntryArchive__b that includes filters on the indexed fields

* Added plugins folder to the script for generating apex doc files, generated updated docs for Apex

* Bumped package version number for the managed package

* Added 5 minute wait between unlocked package version creation & package installation, added deprecated LoggerPlugin__mdt validation rule & field back into the managed-package folder, cleaned up some docs markdown files

Co-authored-by: Jonathan Gillespie <[email protected]>
jongpie added a commit that referenced this issue Mar 22, 2022
jongpie added a commit that referenced this issue Mar 27, 2022
…BigObject plugin (#288)

* Replaced LoggerSObjectHandlerPlugin abstract class with new class LoggerPlugin that contains 2 interfaces + helper methods, switched to using multiple fields on LoggerPlugin__mdt to indicate Apex classes & Flows to run for a plugin, removed SObject-specific fields on LoggerPlugin__mdt, added new fields Log__c.LogPurgeAction__c and LoggerSettings__c.DefaultLogPurgeAction__c

* Added tests in LoggerSettingsController_Tests & LogHandler_Tests for new custom setting LoggerSettings__c.DefaultLogPurgeAction__c

* Updated LoggerSObjectHandler & plugin classes to use the NEW new plugin overhaul changes via LoggerPlugin class, removed old class LoggerSObjectHanderPlugin

* Expanded the plugin framework to support some aspects of #128 by adding the ability to create plugins for LogBatchPurger, using the interface LoggerPlugin.Batchable
    - The BigObject plugin (and other plugins) can then leverage this to run additional logic before Log__c, LogEntry__c & LogEntryTag__c records are hard-deleted
    - For the BigObject plugin, it will be able to archive data into LogEntryArchive__b before LogBatchPurger deletes the data within the custom objects
    - Also finished some test improvements for triggerable plugins within LoggerSObjectHandler

* Renamed BigObject plugin's CMDT file for save method to reflect the naming convention change ('CustomSaveMethodBigObject' instead of 'AdditionalSaveMethodsBigObject'), and renamed plugin CMDT file from 'BigObjectArchiving' to 'LogEntryArchiving', updated labels on some deprecated fields

* Added 'deprecated' to the label of several deprecated fields on LoggerPlugin__mdt & removed the related handler methods

* WIP Made progress on #128 - Split part of LogEntryArchiveBuilder into a new class, LogEntryArchivePlugin, and implemented interface LoggerPlugin.Batchable so that Log__c/LogEntry__c/LogEntryTag__c records can be archived via LogBatchPurger before they're deleted
- The plugin class handles talking with Logger, and builder class handles converting LogEntryEvent__e or LogEntry__c records to LogEntryArchive__b records

* Added tests for LogBatchPurger integration in LogEntryArchivePlugin_Tests

* WIP Stubbed out a new LWC + controller class + custom tab for viewing LogEntryArchive__b as part of #117

* Standardized test-visible method naming conventions to start with `setMock` & updated approaches to use a Map instead of List for CMDT records

* Finished some TODOs & standardized mocking approach for CMDT in LogHandler

* Added Log__c list view to show logs that will be purged in the next 10 days, fixed LogEntryArchiveBuilder using the wrong value for LoggedById__c, updated index on LogEntryArchive__b again (still a WIP), retrieved & formatted metadata for LogEntryArchive__b, updated Admin.profile

* Fixed some FLS  issues

* More improvements for CMDT records used in the classes LoggerParameter & LoggerPlugin
    - Added LoggerParameter.matchOnPrefix() to return CMDT records with a specified prefix in the DeveloperName field
    - Added inner Comparable class in LoggerPlugin to handle custom sorting, since there are some limitations with SOQL queries for CMDT
    - Classes like LogBatchPurger, LoggerSObjectHandler, and LoggerSettingsController no longer need to track their own mock CMDT records, the LoggerPlugin & LoggerParameter classes now fully handle mocks for their corresponding CMDT objects
    - LoggerParameter & LoggerPlugin now require mock CMDT records to have DeveloperName populated - they'll throw errors if the field is null
    - Also added System namespace to some calls for Test.isRunningTest() to handle crazy orgs that have a custom Test class deployed

* Added the ability to disable all triggers during tests via new @testvisible method LoggerSObjectHandler.shouldExecute(Boolean)

* Removed old integration test class + Flow for testing Flow plugins in LoggerSObjectHandler - I'll reimplement new tests when I also implement Flow plugins for LogBatchPurger

* Moved LoggerTestUtils to the configuration folder, added public methods for mocking all CMDT records

* Consolidated plugin-framework folders back into the configuration folders
jongpie added a commit that referenced this issue May 2, 2022
…on Rules plugin (#298)

- Replaced `LoggerSObjectHandlerPlugin` abstract class with new class `LoggerPlugin` that contains 2 interfaces + helper methods, switched to using multiple fields on `LoggerPlugin__mdt` to indicate Apex classes & Flows to run for a plugin, removed SObject-specific fields on `LoggerPlugin__mdt`, added new fields `Log__c.LogPurgeAction__c` and `LoggerSettings__c.DefaultLogPurgeAction__c`

- Added support for plugins within LogBatchPurger + added archiving in BigObject plugin (#288)

- Added SObject-specific 'execution order' fields on `LoggerPlugin__mdt`

- Added picklist values for API versions in calendar year 2022

- Reintroduced the ability to disable trigger handler classes by adding new `LoggerParameter__mdt` records to control via configuration

- Renamed CMDT records that control each trigger handler

- Added new abstract methods in LoggerSObjectHandler for retrieving each handler's related records in `LoggerParameter__mdt` & `LoggerPlugin__mdt`

- Added the ability to configure the list of save methods shown in `loggerSettings` LWC via `LoggerParameter__mdt`, using the prefix 'CustomSaveMethod'

- Standardized test-visible method naming conventions to start with `setMock` & updated approaches to use a Map instead of List for CMDT records

- Fixed issues in LoggerSObjectHandler for invalid Apex & Flow plugins, started new test class LoggerSObjectHandler_Tests

- Added `Log__c` list view to show logs that will be purged in the next 10 days, fixed LogEntryArchiveBuilder using the wrong value for LoggedById**c, updated index on LogEntryArchive**b again (still a WIP), retrieved & formatted metadata for LogEntryArchive\*\*b, updated Admin.profile

- Closed #226 by adding new "Log Retentions Rule" plugin, based on my other project, ApexValidationRules

- @jamessimone closed #117, and I closed #228 by adding new "Big Object Archiving" plugin

- Lowercased the plugin directories

- Added plugins folder to the script for generating apex doc files, generated updated docs for Apex

- Bumped package version number for the managed package

- Added 5 minute wait between unlocked package version creation & package installation, added deprecated `LoggerPlugin__mdt` validation rule & field back into the managed-package folder, cleaned up some docs markdown files

- Added tests in LoggerSettingsController_Tests & LogHandler_Tests for new custom setting LoggerSettings**c.DefaultLogPurgeAction**c

- Added 'deprecated' to the label of several deprecated fields on `LoggerPlugin__mdt` & removed the related handler methods

- More improvements for CMDT records used in the classes LoggerParameter & LoggerPlugin

  - Added LoggerParameter.matchOnPrefix() to return CMDT records with a specified prefix in the DeveloperName field
  - Added inner Comparable class in LoggerPlugin to handle custom sorting, since there are some limitations with SOQL queries for CMDT
  - Classes like LogBatchPurger, LoggerSObjectHandler, and LoggerSettingsController no longer need to track their own mock CMDT records, the LoggerPlugin & LoggerParameter classes now fully handle mocks for their corresponding CMDT objects
  - LoggerParameter & LoggerPlugin now require mock CMDT records to have DeveloperName populated - they'll throw errors if the field is null
  - Also added System namespace to some calls for Test.isRunningTest() to handle crazy orgs that have a custom Test class deployed

- Added the ability to disable all triggers during tests via new @testvisible method LoggerSObjectHandler.shouldExecute(Boolean)

- Moved LoggerTestUtils to the configuration folder, added public methods for mocking all CMDT records

- Consolidated plugin-framework folders back into the configuration folders

- Moved demo experience cloud metadata under config, instead of under nebula-logger, updated build.yml to deploy instead of push metadata

- Updated test classes to use new overloads for LoggerTestUtils.setMock()

- Added new class LoggerDataStore to centralize all database, event bus & queueable operations

- Closed #193 by adding classes `LoggerMockDataCreator` for generic mock & data creation (part of configuration layer), `LoggerTestConfigurator` forNebula Logger-specific mocking & setup (part of the log-management layer), and `LoggerMockDataStore` for mocking database & event bus operations throughout the codebase

- Started work on #292 by adding businessStatus, complianceGroup & securityClassification nodes to several custom fields (still a WIP)

- Rewrote tests in `LogEntryEventBuilder_Tests` to use new methods in `LoggerMockDataCreator` for creating mock instances of database result classes

- Scope creep: added fallback fields for setting `RecordName__c` in LogEntryHandler on objects that don't have a display name field, also added some caching

- Moved permissionSets and customPermissions folders from configuration to log-management

  - This should make the configuration folder fully standalone (i.e., it could be deployed by itself)
  - The perm sets were already referencing all of the objects within log-management, so it seems like it's better to keep the perm sets organized with

- Changed labels to just "Entry #" on both `LogEntryEvent__e` and `LogEntryArchive__b`

- Fixed an issue in `LogEntryEventBuilder` where some stack trace lines would be duplicated

- Scope creeped a bit by adding new fields `DatabaseResultCollectionSize__c` and `RecordCollectionSize__c` - I had planned to add these as part of #222, but decided to add them now so I could duplicate the fields to the `LogEntryArchive__b` big object as well. This also helped to identify (and fix) some issues with missing asserts in LogEntryEventHandler_Tests.

- Replaced settings field `IsPlatformEventStorageEnabled__c` with new field `DefaultPlatformEventStorageLocation__**__c`, providing a way for plugins (big object plugin in particular) to provide additional storage location. The big object plugin provides a custom option BIG_OBJECT, in addition to the default value CUSTOM_OBJECTS that will now be used out of the box

- Added stack trace fields to the Slack message created via SlackLoggerPlugin

- Updated most test classes to use `@IsTest(isParallel=true)`. A few tests (especially integration tests) that do DML on User can't use parallel testing, but most test classes are now using it

- Partially implemented #240 by adding HTTP Request & HTTP Response fields to `LogEntryEvent__e`, `LogEntry__c` and `LogEntryArchive__b`. More scope creep yet again, but this will save some headaches long term - since Big Objects can't (easily) have new fields added, I wanted to go ahead and get these new fields added to the data model before the first release of the Big Object plugin. I'll probably add some logging overloads in Logger for these items in a future release, but for now, only LogEntryEventBuilder has new methods for HttpRequest & HttpResponse

- Updated some internal debug messages in various places to use Logger's logging methods, instead of `System.debug()`

- Deprecated the fields `LogEntryDataMaskRule__mdt.ApplyToMessage__c` and `LogEntryDataMaskRule__mdt.ApplyToRecordJson__c`

- Fixed test failures that occur when email deliverability is disabled in an org

Co-authored-by: James Simone <[email protected]>
@jongpie
Copy link
Owner

jongpie commented May 3, 2022

@arvindnarsimhan, it took over a year to get this completed, but the v4.7.1 release introduced a new Big Object Archiving plugin that can be used for archiving logging data into a Big Object (closing this issue, as well as the related issue #128).

Let me know if you/your team try out the new plugin, I'd love to hear any feedback that you have!

@jongpie jongpie added the Feature: Plugin Framework Items related to Nebula Logger's plugin framework label May 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Plugin Framework Items related to Nebula Logger's plugin framework Layer: Configuration Items related to the custom hierarchy setting LoggerSettings__c or any included custom metadata type Layer: Logger Engine Items related to the core logging engine Package Type: Unlocked Package Issues and enhancements that specifically apply to the unlocked package Plugin: Big Object Archiving Items related to archiving logging data into the LogEntryArchive__b big object Type: Enhancement New feature or request
Projects
None yet
3 participants