Skip to content

feat: Create logging service#1137

Merged
alexs-mparticle merged 13 commits intodevelopmentfrom
feat/SDKE-511-create-logging-service-v2-revised
Feb 24, 2026
Merged

feat: Create logging service#1137
alexs-mparticle merged 13 commits intodevelopmentfrom
feat/SDKE-511-create-logging-service-v2-revised

Conversation

@alexs-mparticle
Copy link
Collaborator

@alexs-mparticle alexs-mparticle commented Dec 17, 2025

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

  • Created ReportingLogger class that sends error/warning/info logs to remote endpoints with rate limiting (10 per severity level)
  • Added supporting types (errorCodes.ts, logRequest.ts) and comprehensive test suite (13 tests, all passing)
  • Integrated ReportingLogger into existing Logger class to automatically report errors and warnings
  • Extended Store to track roktAccountId and integrationName (used in log request headers)
  • Modified RoktManager.attachKit() to capture and store integration name from kits

Screenshots/Video

  • {Include any screenshots or video demonstrating the new feature or fix, if applicable}

Checklist

  • I have performed a self-review of my own code.
  • I have made corresponding changes to the documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have tested this locally.

Additional Notes

Reference Issue (For employees only. Ignore if you are an outside contributor)

@alexs-mparticle alexs-mparticle changed the title Feat/sdke 511 create logging service v2 revised feat: Create logging service Dec 17, 2025
@alexs-mparticle alexs-mparticle changed the base branch from development to blackout2025 December 17, 2025 21:45
@alexs-mparticle alexs-mparticle force-pushed the feat/SDKE-511-create-logging-service-v2-revised branch from 5078a52 to b972c57 Compare December 17, 2025 21:52
Copy link

@mattbodle mattbodle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the description please

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

        logger = new ReportingLogger(baseUrl, sdkVersion, accountId, mockRateLimiter);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@mattbodle mattbodle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add an integration test as part of this PR?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@gtamanaha gtamanaha changed the base branch from blackout2025 to development January 15, 2026 00:47
@gtamanaha gtamanaha changed the base branch from development to blackout2025 January 15, 2026 00:48
@gtamanaha gtamanaha force-pushed the feat/SDKE-511-create-logging-service-v2-revised branch from 06e9d53 to 22114bf Compare January 15, 2026 00:56
@gtamanaha gtamanaha changed the base branch from blackout2025 to development January 15, 2026 00:57
@gtamanaha gtamanaha marked this pull request as ready for review January 15, 2026 11:22
@mattbodle
Copy link

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?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 325 to 327
this.SDKConfig.flags = {};
}

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
if (config.hasOwnProperty('logLevel')) {
this.SDKConfig.logLevel = config.logLevel as LogLevelType;
}

Copilot uses AI. Check for mistakes.
const roktConfig: IKitConfigs = parseConfig(config, 'Rokt', 181);
if (roktConfig) {
const accountId = roktConfig.settings?.accountId;
mpInstance._Store.setRoktAccountId(accountId);
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
mpInstance._Store.setRoktAccountId(accountId);

Copilot uses AI. Check for mistakes.
Copy link

@mattbodle mattbodle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we tested this in stage against the API?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +8 to 9
'rokt-account-id'?: string;
};
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
};
body: string;
}

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
/**
* 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`.
*/

Copilot uses AI. Check for mistakes.
Comment on lines +126 to +128
// Always initialize flags to at least an empty object to prevent undefined access
sdkConfig.flags = sdkConfig.flags || {};

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
// Always initialize flags to at least an empty object to prevent undefined access
sdkConfig.flags = sdkConfig.flags || {};

Copilot uses AI. Check for mistakes.
const roktConfig: IKitConfigs = parseConfig(config, 'Rokt', 181);
if (roktConfig) {
const accountId = roktConfig.settings?.accountId;
mpInstance._Store.setRoktAccountId(accountId);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
mpInstance._Store.setRoktAccountId(accountId);
if (accountId != null) {
mpInstance._Store.setRoktAccountId(accountId);
}

Copilot uses AI. Check for mistakes.
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)
@alexs-mparticle alexs-mparticle force-pushed the feat/SDKE-511-create-logging-service-v2-revised branch from c0d4421 to c93096d Compare February 24, 2026 00:37
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
4.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@alexs-mparticle alexs-mparticle merged commit ae5b87f into development Feb 24, 2026
50 of 56 checks passed
github-actions bot pushed a commit that referenced this pull request Feb 24, 2026
# [2.58.0](v2.57.0...v2.58.0) (2026-02-24)

### Features

*  Create logging service ([#1137](#1137)) ([ae5b87f](ae5b87f))
@mparticle-automation
Copy link
Collaborator

🎉 This PR is included in version 2.58.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants