Skip to content

Conversation

@alexs-mparticle
Copy link
Collaborator

Background

  • {Explain the context of the change, including the problem it addresses or relevant background information}

What Has Changed

  • {Describe the changes introduced by this PR}

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

  • {Any additional information or context relevant to this PR}

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
gtamanaha and others added 16 commits December 17, 2025 16:51
… and update tests for new rate limiting behavior
…rtingLogger for better encapsulation and update related tests
…uctor to accept accountId, with corresponding test adjustments
…tion with valueof utility and update ReportingLogger to use baseUrl; adjust tests accordingly
…in ReportingLogger, with corresponding tests for fallback behavior
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.

Comment on lines 62 to 65
private sendLog(
severity: WSDKErrorSeverity,
msg: string,
code: ErrorCodes,
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The sendLog() method signature shows 'code: ErrorCodes' as required, but since error() and warning() methods should accept optional codes, this should also be optional ('code?: ErrorCodes'). Additionally, when code is undefined, the logRequest object should handle this appropriately (possibly omitting the code field or using a default value).

Copilot uses AI. Check for mistakes.

Choose a reason for hiding this comment

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

Yeah this

Choose a reason for hiding this comment

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

It should default to "UNKNOWN_ERROR"

Comment on lines 51 to 55
};

public warning(msg: string, code: ErrorCodes) {
this.sendLog(WSDKErrorSeverity.WARNING, msg, code);
};
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Unnecessary semicolon after the method body. Remove the trailing semicolon for consistency with JavaScript/TypeScript conventions.

Suggested change
};
public warning(msg: string, code: ErrorCodes) {
this.sendLog(WSDKErrorSeverity.WARNING, msg, code);
};
}
public warning(msg: string, code: ErrorCodes) {
this.sendLog(WSDKErrorSeverity.WARNING, msg, code);
}

Copilot uses AI. Check for mistakes.
return ++count > 3;
}),
};
logger = new ReportingLogger(baseUrl, sdkVersion, accountId, mockRateLimiter);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

Same issue as line 27 - the ReportingLogger constructor signature doesn't match what's being called in the test. The correct signature is (sdkVersion, rateLimiter?, launcherInstanceGuid?). Update to match the actual constructor signature.

Copilot uses AI. Check for mistakes.
Comment on lines 127 to 128
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Error)).toBe(true);
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Error)).toBe(true);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The test uses LogRequestSeverity.Error but should use WSDKErrorSeverity.ERROR to match the actual implementation.

Copilot uses AI. Check for mistakes.

it('allows up to 10 warning logs then rate limits', () => {
for (let i = 0; i < 10; i++) {
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Warning)).toBe(false);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The test uses LogRequestSeverity.Warning but should use WSDKErrorSeverity.WARNING to match the actual implementation.

Copilot uses AI. Check for mistakes.
for (let i = 0; i < 10; i++) {
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Info)).toBe(false);
}
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Info)).toBe(true);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The base expression of this property access is always undefined.

Copilot uses AI. Check for mistakes.
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Info)).toBe(false);
}
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Info)).toBe(true);
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Info)).toBe(true);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The base expression of this property access is always undefined.

Copilot uses AI. Check for mistakes.

it('tracks rate limits independently per severity', () => {
for (let i = 0; i < 10; i++) {
rateLimiter.incrementAndCheck(LogRequestSeverity.Error);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The base expression of this property access is always undefined.

Copilot uses AI. Check for mistakes.
for (let i = 0; i < 10; i++) {
rateLimiter.incrementAndCheck(LogRequestSeverity.Error);
}
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Error)).toBe(true);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The base expression of this property access is always undefined.

Copilot uses AI. Check for mistakes.
rateLimiter.incrementAndCheck(LogRequestSeverity.Error);
}
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Error)).toBe(true);
expect(rateLimiter.incrementAndCheck(LogRequestSeverity.Warning)).toBe(false);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

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

The base expression of this property access is always undefined.

Copilot uses AI. Check for mistakes.
code: code,
url: this.getUrl(),
deviceInfo: this.getUserAgent(),
stackTrace: stackTrace ?? 'this is my stack trace',

Choose a reason for hiding this comment

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

Assuming this is temporary as we don't need a fallback?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@mattbodle should we have it default to an empty string or undefined?

Logger.error('Error sending identity request to servers' + ' - ' + errorMessage);
Logger.error(
'Error sending identity request to servers' + ' - ' + errorMessage,
ErrorCodes.UNHANDLED_EXCEPTION

Choose a reason for hiding this comment

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

I would use this error code as a fallback if there is no errorcode. In this example I would create a code similar to IDENTITY_REQUEST

private readonly rateLimiter: IRateLimiter;
private loggingUrl: string;
private errorUrl: string;
private accountId: string;

Choose a reason for hiding this comment

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

Why do we need to maintain this here? Should it be stored as state elsewhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note: We should inject _Store so we can persist accountId and grab other properties later.

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.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants