Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions src/Rokt-Kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,22 +647,12 @@ class LoggingService {

log(entry: LogEntry | null | undefined): void {
if (!entry) return;
this._transport.send(
this._loggingUrl,
WSDKErrorSeverity.INFO,
entry.message,
entry.code,
undefined,
(error: Error) => {
if (this._errorReportingService) {
this._errorReportingService.report({
message: 'LoggingService: Failed to send log: ' + error.message,
code: ErrorCodes.UNKNOWN_ERROR,
severity: WSDKErrorSeverity.ERROR,
});
}
},
);
// Fire-and-forget: a failed diagnostics-log send must NOT be re-reported as an
// error beacon. Doing so creates a feedback loop — when /v1/log is rate-limited,
// the 429 surfaces to fetch as "Failed to fetch", and reporting it would emit a
// /v1/errors beacon that is itself rate-limited, amplifying load at the log
// frequency. ReportingTransport already logs the failure to the console.
this._transport.send(this._loggingUrl, WSDKErrorSeverity.INFO, entry.message, entry.code);
}
}

Expand Down
10 changes: 5 additions & 5 deletions test/src/tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6338,24 +6338,24 @@ describe('Rokt Forwarder', () => {
expect(body.additionalInformation.message).toBe('log entry');
});

it('should report failure through ErrorReportingService on fetch error', async () => {
it('should NOT report failure as an error beacon on fetch error (fire-and-forget, no feedback loop)', async () => {
const errorReports: any[] = [];
const errorService = {
report: (error: any) => {
errorReports.push(error);
},
};
(window as any).fetch = () => Promise.reject(new Error('Network failure'));
(window as any).fetch = () => Promise.reject(new Error('Failed to fetch'));
const originalConsoleError = console.error;
console.error = () => {};

const service = new LoggingServiceClass({ isLoggingEnabled: true }, errorService, '1.0.0', 'test-guid');
service.log({ message: 'test' });

await new Promise((resolve) => setTimeout(resolve, 50));
expect(errorReports.length).toBeGreaterThan(0);
expect(errorReports[0].severity).toBe('ERROR');
expect(errorReports[0].message).toContain('Failed to send log');
// A failed /v1/log send must not generate a /v1/errors beacon — otherwise a
// rate-limited log send amplifies into rate-limited error traffic.
expect(errorReports.length).toBe(0);
console.error = originalConsoleError;
});

Expand Down