feat: Create logging service#1137
Conversation
5078a52 to
b972c57
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a centralized logging service infrastructure to the mParticle Web SDK, enabling remote error and warning reporting to Rokt endpoints. The implementation includes a ReportingLogger class with rate limiting, feature flag controls, and integration with the existing Logger class.
Key changes:
- Adds ReportingLogger service with rate limiting and conditional enablement
- Integrates remote logging into the existing Logger class
- Adds support for error codes and stack trace reporting
- Configures logging and error URL endpoints via SDK configuration
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 65 comments.
Show a summary per file
| File | Description |
|---|---|
| test/jest/reportingLogger.spec.ts | Adds comprehensive test coverage for ReportingLogger and RateLimiter classes |
| src/logging/reportingLogger.ts | Implements the core ReportingLogger service with rate limiting and conditional logging |
| src/logging/logRequest.ts | Defines request body types and severity enum for logging API |
| src/logging/errorCodes.ts | Defines ErrorCodes enum for error categorization |
| src/logger.ts | Integrates ReportingLogger into existing Logger class |
| src/mp-instance.ts | Initializes ReportingLogger during SDK setup and wires configuration |
| src/sdkRuntimeModels.ts | Updates SDKLoggerApi and SDKInitConfig interfaces to support error codes |
| src/store.ts | Adds loggingUrl and errorUrl to SDKConfig interface |
| src/uploaders.ts | Extends IFetchPayload headers to support rokt-account-id header |
| src/constants.ts | Adds default logging and error URLs for both standard and CNAME configurations |
| src/identityApiClient.ts | Updates error logging to include ErrorCodes |
| src/roktManager.ts | Adds TODO comment for future enhancement |
Comments suppressed due to low confidence (1)
test/jest/reportingLogger.spec.ts:91
- Superfluous argument passed to constructor of class ReportingLogger.
logger = new ReportingLogger(baseUrl, sdkVersion, accountId, mockRateLimiter);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mattbodle
left a comment
There was a problem hiding this comment.
Could we add an integration test as part of this PR?
06e9d53 to
22114bf
Compare
|
A general question about this repo, are we using snake case or camel case for file names? Can we choose one and add to linting rules? |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 27 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| this.SDKConfig.flags = {}; | ||
| } | ||
|
|
There was a problem hiding this comment.
The removed comment describes important behavior about config processing. While removing outdated comments can improve code clarity, this comment explains the dual processing of config (initial and server-provided). Consider whether this context is valuable for future maintainers, or if it's documented elsewhere. If the behavior is still relevant, the comment should be updated rather than removed.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
src/mp-instance.ts:264
- The _resetForTests method doesn't reinitialize or update the instance._ReportingLogger, which could cause test failures or inconsistent test behavior. When a test resets the SDK state and creates a new Store (line 256), the existing ReportingLogger will still reference the old Store instance, leading to stale data being used in logs. Consider either: 1) reinitializing instance._ReportingLogger similar to how Logger is reinitialized on line 255, or 2) calling instance._ReportingLogger.setStore(instance._Store) after creating the new Store to update its reference.
this._resetForTests = function(config, keepPersistence, instance, reportingLogger?: ReportingLogger) {
if (instance._Store) {
delete instance._Store;
}
instance.Logger = new Logger(config, reportingLogger);
instance._Store = new Store(config, instance);
instance._Store.isLocalStorageAvailable = instance._Persistence.determineLocalStorageAvailability(
window.localStorage
);
instance._Events.stopTracking();
if (!keepPersistence) {
instance._Persistence.resetPersistence();
}
instance._Persistence.forwardingStatsBatches.uploadsTable = {};
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
|
|
||
| this.SDKConfig.useNativeSdk = !!config.useNativeSdk; | ||
|
|
There was a problem hiding this comment.
The removal of the comment and the logLevel check is inconsistent with other config processing patterns in the codebase. The removed code at lines 351-354 checked if the config had a 'logLevel' property before applying it to SDKConfig, which is a defensive pattern used elsewhere in this function (e.g., line 333 checks hasOwnProperty for isDevelopmentMode). The logLevel configuration still exists in SDKConfig interface and is used throughout the codebase, so this removal may allow undefined logLevel values to overwrite existing values. Consider restoring the hasOwnProperty check or provide justification for why logLevel should be treated differently from other config properties.
| if (config.hasOwnProperty('logLevel')) { | |
| this.SDKConfig.logLevel = config.logLevel as LogLevelType; | |
| } |
| const roktConfig: IKitConfigs = parseConfig(config, 'Rokt', 181); | ||
| if (roktConfig) { | ||
| const accountId = roktConfig.settings?.accountId; | ||
| mpInstance._Store.setRoktAccountId(accountId); |
There was a problem hiding this comment.
The roktAccountId is set twice in the initialization flow, which could lead to confusion and potential race conditions. It's first set in completeSDKInitialization at lines 1456-1457 from the roktConfig.settings, and then set again in RoktManager.attachKit at lines 193-195 from the kit.settings. If these values differ or if the timing of kit attachment changes, this could cause inconsistent behavior. Consider removing one of these assignments or documenting why both are necessary. The initialization at line 1456-1457 appears sufficient since it happens earlier in the SDK lifecycle and uses the same source (roktConfig.settings.accountId).
| mpInstance._Store.setRoktAccountId(accountId); |
mattbodle
left a comment
There was a problem hiding this comment.
Have we tested this in stage against the API?
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 'rokt-account-id'?: string; | ||
| }; |
There was a problem hiding this comment.
Adding 'rokt-account-id' as an optional header to the base IFetchPayload interface makes it available for all fetch operations, not just reporting logger operations. While this works, it would be cleaner to keep Rokt-specific headers in the IReportingLoggerPayload interface extension. Consider moving this header definition to IReportingLoggerPayload instead.
| }; | ||
| body: string; | ||
| } | ||
|
|
There was a problem hiding this comment.
The ReportingLogger class lacks JSDoc documentation. Following the codebase convention (seen in BatchUploader, RoktManager, etc.), exported classes should have JSDoc comments describing their purpose, responsibilities, and high-level behavior. Consider adding a JSDoc comment block above the class declaration.
| /** | |
| * Logger responsible for reporting Web SDK logs and errors to the configured backend services. | |
| * | |
| * This class builds and sends log payloads (such as info and error events) using the configured | |
| * logging and error endpoints, SDK/store configuration, and an optional launcher instance GUID. | |
| * It also applies rate limiting via an {@link IRateLimiter} implementation to avoid excessive | |
| * reporting and respects feature flags such as `isWebSdkLoggingEnabled`. | |
| */ |
| // Always initialize flags to at least an empty object to prevent undefined access | ||
| sdkConfig.flags = sdkConfig.flags || {}; | ||
|
|
There was a problem hiding this comment.
The flags property is being initialized in createSDKConfig, but it gets immediately overwritten in the Store constructor at line 328. This makes the initialization at line 127 unnecessary and potentially confusing. The flags should either be initialized once in createSDKConfig and not overwritten, or the initialization should be removed from createSDKConfig.
| // Always initialize flags to at least an empty object to prevent undefined access | |
| sdkConfig.flags = sdkConfig.flags || {}; |
| const roktConfig: IKitConfigs = parseConfig(config, 'Rokt', 181); | ||
| if (roktConfig) { | ||
| const accountId = roktConfig.settings?.accountId; | ||
| mpInstance._Store.setRoktAccountId(accountId); |
There was a problem hiding this comment.
The setRoktAccountId method is called with potentially undefined value at line 1459 (roktConfig.settings?.accountId), which could be undefined if settings doesn't exist or accountId is undefined. This would set this.roktAccountId to undefined instead of the initialized null value. Consider adding a guard to only call setRoktAccountId if accountId is defined, or add validation within setRoktAccountId to reject undefined/null values.
| mpInstance._Store.setRoktAccountId(accountId); | |
| if (accountId != null) { | |
| mpInstance._Store.setRoktAccountId(accountId); | |
| } |
Update property name to match server configuration property. This fixes the issue where logging was not appearing for CNAME customers when isLoggingEnabled was set to true. Changes: - Renamed config property in ReportingLogger, SDKConfig, and SDKInitConfig - Updated all test files to use new property name - All Jest tests passing (28 tests)
c0d4421 to
c93096d
Compare
|
# [2.58.0](v2.57.0...v2.58.0) (2026-02-24) ### Features * Create logging service ([#1137](#1137)) ([ae5b87f](ae5b87f))
|
🎉 This PR is included in version 2.58.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |


Background
The Web SDK needs the ability to capture and report errors, warnings, and diagnostic information to a remote logging service for monitoring and debugging purposes. This is particularly important for Rokt integrations where we need visibility into SDK behavior in production environments. Previously, the SDK only logged to the browser console, making it difficult to diagnose issues in production.
This PR introduces a ReportingLogger service that sends logs to remote endpoints when specific conditions are met (ROKT_DOMAIN present and either a feature flag is enabled or debug mode is active via query parameter).
What Has Changed
Screenshots/Video
Checklist
Additional Notes
Reference Issue (For employees only. Ignore if you are an outside contributor)