Skip to content

Conversation

@gtamanaha
Copy link
Contributor

@gtamanaha gtamanaha commented Nov 25, 2025

Background

This PR introduces a new server-side logging service that enables the mParticle Web SDK to send error and warning logs to mParticle's backend for improved monitoring and debugging. The implementation includes creating a new ReportingLogger service that can send logs to the server when enabled.

Important: Next PR will include the reporting service call from Logger.ts

What Has Changed

Major Features

  • New ReportingLogger service for server-side log submission
  • API Client enhanced with sendLogToServer() method
  • New logging infrastructure (logRequest, errorCodes, etc.)
  • Configuration option isWebSdkLoggingEnabled added
  • Test coverage added for all new functionality

Technical Highlights

  • Rate limiting: 10 logs per severity type
  • Conditional enabling: Only active when Rokt domain is present + feature flag or debug mode

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)

@gtamanaha gtamanaha changed the base branch from master to blackout2025 November 25, 2025 16:24
@gtamanaha gtamanaha changed the title feat: Create Loggin Service feat: Create Logging Service Nov 25, 2025
@gtamanaha gtamanaha marked this pull request as ready for review December 1, 2025 12:32
@gtamanaha gtamanaha changed the title feat: Create Logging Service feat: Create Logging Service SDKE-511 Dec 1, 2025
@gtamanaha gtamanaha requested a review from rmi22186 December 1, 2025 12:38
@@ -0,0 +1,5 @@
export type ErrorCodes = (typeof ErrorCodes)[keyof typeof ErrorCodes];

export const ErrorCodes = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this should be ErrorMessages. ErrorCodes sounds like they'd be something numerical like HTTP Error Codes (404, 429, etc).

Are you naming this ErrorMessages because that's something defined on the server side?

@@ -0,0 +1,21 @@
import { ErrorCodes } from "./errorCodes";

export enum LogRequestSeverity {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have a type for LogLevelType. Is there any way we can consolidate these into one thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would prefer to keep them separated because these ones depends on the API contract.

Comment on lines +138 to +140
[LogRequestSeverity.Error, 10],
[LogRequestSeverity.Warning, 10],
[LogRequestSeverity.Info, 10],
Copy link
Collaborator

Choose a reason for hiding this comment

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

If each of these default to 10, should we just make this a constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would like to discuss if these amounts are good amount first. @mattbodle @rmi22186 what do you think about these limits?

Choose a reason for hiding this comment

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

Can we use the same rate limits and logic from WSDK?


public incrementAndCheck(severity: LogRequestSeverity): boolean {
const count = this.logCount.get(severity) || 0;
const limit = this.rateLimits.get(severity) || 10;
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we want 10 to be the default rate limit, we can then reuse a constant here.

}

private getUrl(): string {
return window.location.href;
Copy link
Collaborator

Choose a reason for hiding this comment

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

In these cases where you're using window, you should first check if window exists, especially if this module is going to log errors that are independent of the SDK itself.

We've had problems in the past of customers and partners using the Web SDK server side and window will not exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added null conditional operator

headers: {
Accept: 'text/plain;charset=UTF-8',
'Content-Type': 'text/plain;charset=UTF-8',
'rokt-account-id': this.accountId
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens here if accountId is undefined or null?

Copy link
Contributor Author

@gtamanaha gtamanaha Dec 10, 2025

Choose a reason for hiding this comment

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

Added default value 0, which is the same behavior from rokt wsdk.

global.fetch = mockFetch;

mpInstance = {
_Helpers: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This may be future work but if it's easy enough, we should rewrite createServiceUrl so that it isn't as tightly coupled to the full SDK instance or Store, or make it a function within Store.

If it's future work, we should collect some of these refactors into a launch pad.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed mpInstance

@gtamanaha gtamanaha self-assigned this Dec 9, 2025
…tion with valueof utility and update ReportingLogger to use baseUrl; adjust tests accordingly
…in ReportingLogger, with corresponding tests for fallback behavior
@sonarqubecloud
Copy link

return window.
mParticle?.
config?.
isWebSdkLoggingEnabled ?? false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should pass this in as a param in the constructor so that we're not tightly coupled to the window.


private isDebugModeEnabled(): boolean {
return (
window.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here. We should not be tightly coupled to the window. There should be a utility method to get url params.

private readonly rateLimiter: IRateLimiter;
private readonly DEFAULT_ACCOUNT_ID: string = '0';
private readonly DEFAULT_USER_AGENT: string = 'no-user-agent-set';
private readonly DEFAULT_URL: string = 'no-url-set';

Choose a reason for hiding this comment

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

Add rokt-launcher-instance-guid as a default header

Info = 'info',
}

export interface LogRequest {

Choose a reason for hiding this comment

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

Copy the exact types from WSDK:

export type WSDKErrorSeverity = (typeof WSDKErrorSeverity)[keyof typeof WSDKErrorSeverity];
export const WSDKErrorSeverity = {
  ERROR: 'ERROR',
  INFO: 'INFO',
  WARNING: 'WARNING',
} as const;

export interface IWSDKError {
  name: string;
  message: string;
  stack?: string;
  code?: ErrorCode;
  reporter?: string;
  integration?: string;
  severity?: WSDKErrorSeverity;
  additionalInformation?: Record<string, string>;
  handled?: boolean;
}

private readonly reporter: string = 'mp-wsdk';
private readonly integration: string = 'mp-wsdk';
private readonly rateLimiter: IRateLimiter;
private readonly DEFAULT_ACCOUNT_ID: string = '0';

Choose a reason for hiding this comment

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

No need to set default, do not add account id header if it doesn't exist

private readonly integration: string = 'mp-wsdk';
private readonly rateLimiter: IRateLimiter;
private readonly DEFAULT_ACCOUNT_ID: string = '0';
private readonly DEFAULT_USER_AGENT: string = 'no-user-agent-set';

Choose a reason for hiding this comment

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

Is this required??

private readonly rateLimiter: IRateLimiter;
private readonly DEFAULT_ACCOUNT_ID: string = '0';
private readonly DEFAULT_USER_AGENT: string = 'no-user-agent-set';
private readonly DEFAULT_URL: string = 'no-url-set';

Choose a reason for hiding this comment

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

Is this required? When do we not get a href?

}

public error(msg: string, code?: ErrorCodes, stackTrace?: string) {
this.sendLog(LogRequestSeverity.Error, msg, code ?? ErrorCodes.UNHANDLED_EXCEPTION, stackTrace);

Choose a reason for hiding this comment

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

Can we make code a mandatory parameter?
UNHANDLED_EXCEPTION is a code we specifically use when an error escapes any catch clause and is receeived by the window

const logRequest: LogRequest = {
additionalInformation: {
message: msg,
version: this.sdkVersion,

Choose a reason for hiding this comment

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

Should version be here?

code: code,
url: this.getUrl(),
deviceInfo: this.getUserAgent(),
stackTrace: stackTrace ?? '',

Choose a reason for hiding this comment

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

stacktrace or stack?

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