Skip to content

Commit b972c57

Browse files
Revise implementation of ReportingLogger
1 parent f3e25fe commit b972c57

File tree

9 files changed

+150
-73
lines changed

9 files changed

+150
-73
lines changed

src/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ const Constants = {
139139
identityUrl: 'identity.mparticle.com/v1/',
140140
aliasUrl: 'jssdks.mparticle.com/v1/identity/',
141141
userAudienceUrl: 'nativesdks.mparticle.com/v1/',
142+
loggingUrl: 'apps.rokt.com/v1/log/',
143+
errorUrl: 'apps.rokt.com/v1/errors/',
142144
},
143145
// These are the paths that are used to construct the CNAME urls
144146
CNAMEUrlPaths: {
@@ -148,6 +150,8 @@ const Constants = {
148150
configUrl: '/tags/JS/v2/',
149151
identityUrl: '/identity/v1/',
150152
aliasUrl: '/webevents/v1/identity/',
153+
loggingUrl: '/v1/log/',
154+
errorUrl: '/v1/errors/',
151155
},
152156
Base64CookieKeys: {
153157
csm: 1,

src/identityApiClient.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
IIdentityResponse,
2626
} from './identity-user-interfaces';
2727
import { IMParticleWebSDKInstance } from './mp-instance';
28+
import { ErrorCodes } from './logging/errorCodes';
2829

2930
const { HTTPCodes, Messages, IdentityMethods } = Constants;
3031

@@ -300,10 +301,13 @@ export default function IdentityAPIClient(
300301
);
301302
} catch (err) {
302303
mpInstance._Store.identityCallInFlight = false;
303-
304+
304305
const errorMessage = (err as Error).message || err.toString();
305306

306-
Logger.error('Error sending identity request to servers' + ' - ' + errorMessage);
307+
Logger.error(
308+
'Error sending identity request to servers' + ' - ' + errorMessage,
309+
ErrorCodes.UNHANDLED_EXCEPTION
310+
);
307311
invokeCallback(
308312
callback,
309313
HTTPCodes.noHttpCoverage,

src/logger.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
import { LogLevelType, SDKInitConfig, SDKLoggerApi } from './sdkRuntimeModels';
2+
import { IReportingLogger } from './logging/reportingLogger';
3+
import { ErrorCodes } from './logging/errorCodes';
24

35
export type ILoggerConfig = Pick<SDKInitConfig, 'logLevel' | 'logger'>;
46
export type IConsoleLogger = Partial<Pick<SDKLoggerApi, 'error' | 'warning' | 'verbose'>>;
57

68
export class Logger {
79
private logLevel: LogLevelType;
810
private logger: IConsoleLogger;
11+
private reportingLogger: IReportingLogger;
912

10-
constructor(config: ILoggerConfig) {
13+
constructor(config: ILoggerConfig,
14+
reportingLogger?: IReportingLogger,
15+
) {
1116
this.logLevel = config.logLevel ?? LogLevelType.Warning;
1217
this.logger = config.logger ?? new ConsoleLogger();
18+
this.reportingLogger = reportingLogger;
1319
}
1420

1521
public verbose(msg: string): void {
@@ -21,22 +27,24 @@ export class Logger {
2127
}
2228
}
2329

24-
public warning(msg: string): void {
30+
public warning(msg: string, code?: ErrorCodes): void {
2531
if(this.logLevel === LogLevelType.None)
2632
return;
2733

2834
if (this.logger.warning &&
2935
(this.logLevel === LogLevelType.Verbose || this.logLevel === LogLevelType.Warning)) {
3036
this.logger.warning(msg);
37+
this.reportingLogger.warning(msg, code);
3138
}
3239
}
3340

34-
public error(msg: string): void {
41+
public error(msg: string, code?: ErrorCodes): void {
3542
if(this.logLevel === LogLevelType.None)
3643
return;
3744

3845
if (this.logger.error) {
3946
this.logger.error(msg);
47+
this.reportingLogger.error(msg, code);
4048
}
4149
}
4250

@@ -63,4 +71,4 @@ export class ConsoleLogger implements IConsoleLogger {
6371
console.warn(msg);
6472
}
6573
}
66-
}
74+
}

src/logging/logRequest.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { ErrorCodes } from "./errorCodes";
2+
export type ErrorCode = ErrorCodes | string;
23

3-
export enum LogRequestSeverity {
4-
Error = 'error',
5-
Warning = 'warning',
6-
Info = 'info',
7-
}
4+
export type WSDKErrorSeverity = (typeof WSDKErrorSeverity)[keyof typeof WSDKErrorSeverity];
5+
export const WSDKErrorSeverity = {
6+
ERROR: 'ERROR',
7+
INFO: 'INFO',
8+
WARNING: 'WARNING',
9+
} as const;
810

9-
export interface LogRequest {
10-
additionalInformation: {
11-
message: string;
12-
version: string;
13-
};
14-
severity: LogRequestSeverity;
15-
code: ErrorCodes;
16-
url: string;
17-
deviceInfo: string;
18-
stackTrace: string;
19-
reporter: string;
20-
integration: string;
21-
}
11+
12+
export type ErrorsRequestBody = {
13+
additionalInformation?: Record<string, string>;
14+
code: ErrorCode;
15+
severity: WSDKErrorSeverity;
16+
stackTrace?: string;
17+
deviceInfo?: string;
18+
integration?: string;
19+
reporter?: string;
20+
url?: string;
21+
};
22+
23+
export type LogRequestBody = ErrorsRequestBody;

src/logging/reportingLogger.ts

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,83 @@
1-
21
import { ErrorCodes } from "./errorCodes";
3-
import { LogRequest, LogRequestSeverity } from "./logRequest";
4-
import { FetchUploader, XHRUploader } from "../uploaders";
2+
import { LogRequestBody, WSDKErrorSeverity } from "./logRequest";
3+
import { FetchUploader, IFetchPayload } from "../uploaders";
54

5+
// QUESTION: Should we collapse the interface with the class?
66
export interface IReportingLogger {
7-
error(msg: string, code?: ErrorCodes, stackTrace?: string): void;
8-
warning(msg: string, code?: ErrorCodes): void;
7+
error(msg: string, code: ErrorCodes, stackTrace?: string): void;
8+
warning(msg: string, code: ErrorCodes): void;
99
}
1010

1111
export class ReportingLogger implements IReportingLogger {
1212
private readonly isEnabled: boolean;
1313
private readonly reporter: string = 'mp-wsdk';
1414
private readonly integration: string = 'mp-wsdk';
1515
private readonly rateLimiter: IRateLimiter;
16-
private readonly DEFAULT_ACCOUNT_ID: string = '0';
17-
private readonly DEFAULT_USER_AGENT: string = 'no-user-agent-set';
18-
private readonly DEFAULT_URL: string = 'no-url-set';
19-
16+
private loggingUrl: string;
17+
private errorUrl: string;
18+
private accountId: string;
19+
private integrationName: string;
20+
2021
constructor(
21-
private baseUrl: string,
2222
private readonly sdkVersion: string,
23-
private readonly accountId: string,
24-
rateLimiter?: IRateLimiter,
23+
rateLimiter?: IRateLimiter, // QUESTION: Do we need this in the constructor?
24+
private readonly launcherInstanceGuid?: string,
2525
) {
2626
this.isEnabled = this.isReportingEnabled();
27+
console.warn('ReportingLogger: isEnabled', this.isEnabled);
2728
this.rateLimiter = rateLimiter ?? new RateLimiter();
2829
}
2930

30-
public error(msg: string, code?: ErrorCodes, stackTrace?: string) {
31-
this.sendLog(LogRequestSeverity.Error, msg, code ?? ErrorCodes.UNHANDLED_EXCEPTION, stackTrace);
31+
public setLoggingUrl(url: string) {
32+
this.loggingUrl = url;
33+
}
34+
35+
public setErrorUrl(url: string) {
36+
this.errorUrl = url;
37+
}
38+
39+
public setAccountId(accountId: string) {
40+
this.accountId = accountId;
41+
}
42+
43+
public setIntegrationName(integrationName: string) {
44+
this.integrationName = integrationName;
45+
}
46+
47+
// TODO: Add an `info` method to the logger for `/v1/log`
48+
49+
public error(msg: string, code: ErrorCodes, stackTrace?: string) {
50+
this.sendLog(WSDKErrorSeverity.ERROR, msg, code, stackTrace);
3251
};
3352

34-
public warning(msg: string, code?: ErrorCodes) {
35-
this.sendLog(LogRequestSeverity.Warning, msg, code ?? ErrorCodes.UNHANDLED_EXCEPTION);
53+
public warning(msg: string, code: ErrorCodes) {
54+
this.sendLog(WSDKErrorSeverity.WARNING, msg, code);
3655
};
3756

57+
private getVersion(): string {
58+
return this.integrationName ?? this.sdkVersion;
59+
}
60+
61+
// QUESTION: Should we split this into `sendError` and `sendLog`?
3862
private sendLog(
39-
severity: LogRequestSeverity,
63+
severity: WSDKErrorSeverity,
4064
msg: string,
4165
code: ErrorCodes,
4266
stackTrace?: string
4367
): void {
4468
if(!this.canSendLog(severity))
4569
return;
4670

47-
const logRequest: LogRequest = {
71+
const logRequest: LogRequestBody = {
4872
additionalInformation: {
4973
message: msg,
50-
version: this.sdkVersion,
74+
version: this.getVersion(),
5175
},
5276
severity: severity,
5377
code: code,
5478
url: this.getUrl(),
5579
deviceInfo: this.getUserAgent(),
56-
stackTrace: stackTrace ?? '',
80+
stackTrace: stackTrace ?? 'this is my stack trace',
5781
reporter: this.reporter,
5882
integration: this.integration,
5983
};
@@ -62,6 +86,8 @@ export class ReportingLogger implements IReportingLogger {
6286
}
6387

6488
private isReportingEnabled(): boolean {
89+
// QUESTION: Should isDebugModeEnabled take precedence over
90+
// isFeatureFlagEnabled and rokt domain present?
6591
return (
6692
this.isRoktDomainPresent() &&
6793
(this.isFeatureFlagEnabled() ||
@@ -90,53 +116,62 @@ export class ReportingLogger implements IReportingLogger {
90116
);
91117
}
92118

93-
private canSendLog(severity: LogRequestSeverity): boolean {
119+
private canSendLog(severity: WSDKErrorSeverity): boolean {
94120
return this.isEnabled && !this.isRateLimited(severity);
95121
}
96122

97-
private isRateLimited(severity: LogRequestSeverity): boolean {
123+
private isRateLimited(severity: WSDKErrorSeverity): boolean {
98124
return this.rateLimiter.incrementAndCheck(severity);
99125
}
100126

101127
private getUrl(): string {
102-
return window?.location?.href ?? this.DEFAULT_URL;
128+
return window.location.href;
103129
}
104130

105131
private getUserAgent(): string {
106-
return window?.navigator?.userAgent ?? this.DEFAULT_USER_AGENT;
132+
return window.navigator.userAgent;
107133
}
108134

109-
private sendLogToServer(logRequest: LogRequest) {
110-
const uploadUrl = `${this.baseUrl}/v1/log`;
111-
const uploader = window.fetch
112-
? new FetchUploader(uploadUrl)
113-
: new XHRUploader(uploadUrl);
135+
private getLoggingUrl = (): string => `https://${this.loggingUrl}`;
136+
private getErrorUrl = (): string => `https://${this.errorUrl}`;
137+
138+
private getHeaders(): IFetchPayload['headers'] {
139+
const headers: Record<string, string> = {
140+
Accept: 'text/plain;charset=UTF-8',
141+
'Content-Type': 'application/json',
142+
'rokt-launcher-instance-guid': this.launcherInstanceGuid,
143+
'rokt-launcher-version': this.getVersion(),
144+
'rokt-wsdk-version': 'joint',
145+
};
146+
return headers as IFetchPayload['headers'];
147+
}
114148

115-
uploader.upload({
149+
private sendLogToServer(logRequest: LogRequestBody) {
150+
const uploadUrl = this.getErrorUrl();
151+
const uploader = new FetchUploader(uploadUrl);
152+
const payload: IFetchPayload = {
116153
method: 'POST',
117-
headers: {
118-
Accept: 'text/plain;charset=UTF-8',
119-
'Content-Type': 'text/plain;charset=UTF-8',
120-
'rokt-account-id': this.accountId || this.DEFAULT_ACCOUNT_ID
121-
},
154+
headers: this.getHeaders(),
122155
body: JSON.stringify(logRequest),
123-
});
156+
};
157+
158+
uploader.upload(payload);
124159
};
125160
}
126161

127162
export interface IRateLimiter {
128-
incrementAndCheck(severity: LogRequestSeverity): boolean;
163+
incrementAndCheck(severity: WSDKErrorSeverity): boolean;
129164
}
130165

131166
export class RateLimiter implements IRateLimiter {
132-
private readonly rateLimits: Map<LogRequestSeverity, number> = new Map([
133-
[LogRequestSeverity.Error, 10],
134-
[LogRequestSeverity.Warning, 10],
135-
[LogRequestSeverity.Info, 10],
167+
private readonly rateLimits: Map<WSDKErrorSeverity, number> = new Map([
168+
[WSDKErrorSeverity.ERROR, 10],
169+
[WSDKErrorSeverity.WARNING, 10],
170+
[WSDKErrorSeverity.INFO, 10],
136171
]);
137-
private logCount: Map<LogRequestSeverity, number> = new Map();
172+
private logCount: Map<WSDKErrorSeverity, number> = new Map();
138173

139-
public incrementAndCheck(severity: LogRequestSeverity): boolean {
174+
public incrementAndCheck(severity: WSDKErrorSeverity): boolean {
140175
const count = this.logCount.get(severity) || 0;
141176
const limit = this.rateLimits.get(severity) || 10;
142177

0 commit comments

Comments
 (0)