Skip to content

Commit 3e3e41b

Browse files
committed
refactor
1 parent 51e8c1a commit 3e3e41b

File tree

18 files changed

+386
-621
lines changed

18 files changed

+386
-621
lines changed

lib/common_exports.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
export { LogLevel, LogHandler, getLogger, setLogHandler } from './modules/logging';
17+
// export { LogLevel, LogHandler, getLogger, setLogHandler } from './modules/logging';
1818
export { LOG_LEVEL } from './utils/enums';
1919
export { createLogger } from './plugins/logger';
2020
export { createStaticProjectConfigManager } from './project_config/config_manager_factory';

lib/modules/logging/index.ts renamed to lib/error/error_handler.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2019, Optimizely
2+
* Copyright 2019, 2025, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -13,6 +13,14 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
export * from './errorHandler'
17-
export * from './models'
18-
export * from './logger'
16+
/**
17+
* @export
18+
* @interface ErrorHandler
19+
*/
20+
export interface ErrorHandler {
21+
/**
22+
* @param {Error} exception
23+
* @memberof ErrorHandler
24+
*/
25+
handleError(exception: Error): void
26+
}

lib/error/error_notifier.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { sprintf } from "../utils/fns";
2+
import { ErrorHandler } from "./error_handler";
3+
import { OptimizelyError } from "./optimizly_error";
4+
5+
export interface ErrorNotifier {
6+
notify(error: OptimizelyError): void;
7+
child(name: string): ErrorNotifier;
8+
}
9+
10+
export interface ErrorMessageResolver {
11+
resolve(baseMessage: string): string;
12+
}
13+
14+
export class DefaultErrorNotifier implements ErrorNotifier {
15+
private name: string;
16+
private errorHandler: ErrorHandler;
17+
private messageResolver: ErrorMessageResolver;
18+
19+
constructor(errorHandler: ErrorHandler, messageResolver: ErrorMessageResolver, name?: string) {
20+
this.errorHandler = errorHandler;
21+
this.messageResolver = messageResolver;
22+
this.name = name || '';
23+
}
24+
25+
notify(error: OptimizelyError): void {
26+
const ErrorMessage = error.getErrorMessage();
27+
const resolvedBase = this.messageResolver.resolve(ErrorMessage.baseMessage);
28+
const messagePrefix = this.name ? `${this.name}: ` : '';
29+
const message = `${messagePrefix}${sprintf(resolvedBase, ...ErrorMessage.params)}`;
30+
error.setMessage(message);
31+
this.errorHandler.handleError(error);
32+
}
33+
34+
child(name: string): ErrorNotifier {
35+
return new DefaultErrorNotifier(this.errorHandler, this.messageResolver, name);
36+
}
37+
}

lib/error/error_reporter.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { LoggerFacade } from "../logging/logger";
2+
import { ErrorNotifier } from "./error_notifier";
3+
import { OptimizelyError } from "./optimizly_error";
4+
5+
export class ErrorReporter {
6+
private logger?: LoggerFacade;
7+
private errorNotifier?: ErrorNotifier;
8+
9+
constructor(logger?: LoggerFacade, errorNotifier?: ErrorNotifier) {
10+
this.logger = logger;
11+
this.errorNotifier = errorNotifier;
12+
}
13+
14+
report(error: OptimizelyError): void;
15+
report(baseMessage: string, ...params: any[]): void;
16+
17+
report(error: OptimizelyError | string, ...params: any[]): void {
18+
if (typeof error === 'string') {
19+
error = new OptimizelyError(error, ...params);
20+
this.report(error);
21+
return;
22+
}
23+
24+
const errorMessage = error.getErrorMessage();
25+
26+
if (this.errorNotifier) {
27+
this.errorNotifier.notify(error);
28+
}
29+
30+
if (this.logger) {
31+
this.logger.error(errorMessage.baseMessage, ...errorMessage.params);
32+
}
33+
}
34+
35+
setLogger(logger: LoggerFacade): void {
36+
this.logger = logger;
37+
}
38+
39+
setErrorNotifier(errorNotifier: ErrorNotifier): void {
40+
this.errorNotifier = errorNotifier;
41+
}
42+
}

lib/error/optimizly_error.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
type ErrorMessage = {
2+
baseMessage: string;
3+
params: any[];
4+
};
5+
6+
export class OptimizelyError extends Error {
7+
private baseMessage: string;
8+
private params: any[];
9+
constructor(baseMessage: string, ...params: any[]) {
10+
super();
11+
this.name = 'OptimizelyError';
12+
this.baseMessage = baseMessage;
13+
this.params = params;
14+
}
15+
16+
getErrorMessage(): ErrorMessage {
17+
return {
18+
baseMessage: this.baseMessage,
19+
params: this.params,
20+
};
21+
}
22+
23+
setMessage(message: string): void {
24+
this.message = message;
25+
}
26+
}

lib/error_messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
export const NOTIFICATION_LISTENER_EXCEPTION = 'Notification listener for (%s) threw exception: %s';
1617
export const BROWSER_ODP_MANAGER_INITIALIZATION_FAILED = '%s: Error initializing Browser ODP Manager.';
1718
export const CONDITION_EVALUATOR_ERROR = '%s: Error evaluating audience condition of type %s: %s';
1819
export const DATAFILE_AND_SDK_KEY_MISSING =

lib/index.node.ts

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { getLogger, setErrorHandler, getErrorHandler, LogLevel, setLogHandler, setLogLevel } from './modules/logging';
17+
// import { getLogger, setErrorHandler, getErrorHandler, LogLevel, setLogHandler, setLogLevel } from './modules/logging';
1818
import Optimizely from './optimizely';
1919
import * as enums from './utils/enums';
2020
import * as loggerPlugin from './plugins/logger';
@@ -30,9 +30,6 @@ import { createVuidManager } from './vuid/vuid_manager_factory.node';
3030
import { createOdpManager } from './odp/odp_manager_factory.node';
3131
import { ODP_DISABLED } from './log_messages';
3232

33-
const logger = getLogger();
34-
setLogLevel(LogLevel.ERROR);
35-
3633
const DEFAULT_EVENT_BATCH_SIZE = 10;
3734
const DEFAULT_EVENT_FLUSH_INTERVAL = 30000; // Unit is ms, default is 30s
3835
const DEFAULT_EVENT_MAX_QUEUE_SIZE = 10000;
@@ -45,54 +42,20 @@ const DEFAULT_EVENT_MAX_QUEUE_SIZE = 10000;
4542
*/
4643
const createInstance = function(config: Config): Client | null {
4744
try {
48-
let hasLogger = false;
49-
let isValidInstance = false;
50-
51-
// TODO warn about setting per instance errorHandler / logger / logLevel
52-
if (config.errorHandler) {
53-
setErrorHandler(config.errorHandler);
54-
}
55-
if (config.logger) {
56-
// only set a logger in node if one is provided, by not setting we are noop-ing
57-
hasLogger = true;
58-
setLogHandler(config.logger);
59-
// respect the logger's shouldLog functionality
60-
setLogLevel(LogLevel.NOTSET);
61-
}
62-
if (config.logLevel !== undefined) {
63-
setLogLevel(config.logLevel);
64-
}
65-
try {
66-
configValidator.validate(config);
67-
isValidInstance = true;
68-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
69-
} catch (ex) {
70-
if (hasLogger) {
71-
logger.error(ex);
72-
} else {
73-
console.error(ex.message);
74-
}
75-
}
76-
77-
const errorHandler = getErrorHandler();
78-
const notificationCenter = createNotificationCenter({ logger: logger, errorHandler: errorHandler });
45+
configValidator.validate(config);
7946

8047
const { clientEngine, clientVersion } = config;
8148

8249
const optimizelyOptions = {
8350
...config,
8451
clientEngine: clientEngine || enums.NODE_CLIENT_ENGINE,
8552
clientVersion: clientVersion || enums.CLIENT_VERSION,
86-
logger,
87-
errorHandler,
88-
notificationCenter,
89-
isValidInstance,
9053
};
9154

9255
return new Optimizely(optimizelyOptions);
9356
// eslint-disable-next-line @typescript-eslint/no-explicit-any
9457
} catch (e) {
95-
logger.error(e);
58+
// logger.error(e);
9659
return null;
9760
}
9861
};
@@ -105,8 +68,6 @@ export {
10568
defaultErrorHandler as errorHandler,
10669
defaultEventDispatcher as eventDispatcher,
10770
enums,
108-
setLogHandler as setLogger,
109-
setLogLevel,
11071
createInstance,
11172
OptimizelyDecideOption,
11273
createPollingProjectConfigManager,
@@ -124,8 +85,6 @@ export default {
12485
errorHandler: defaultErrorHandler,
12586
eventDispatcher: defaultEventDispatcher,
12687
enums,
127-
setLogger: setLogHandler,
128-
setLogLevel,
12988
createInstance,
13089
OptimizelyDecideOption,
13190
createPollingProjectConfigManager,

lib/log_messages.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export const INVALID_OBJECT = '%s: Optimizely object is not valid. Failing %s.';
3030
export const INVALID_CLIENT_ENGINE = '%s: Invalid client engine passed: %s. Defaulting to node-sdk.';
3131
export const INVALID_DEFAULT_DECIDE_OPTIONS = '%s: Provided default decide options is not an array.';
3232
export const INVALID_DECIDE_OPTIONS = '%s: Provided decide options is not an array. Using default decide options.';
33-
export const NOTIFICATION_LISTENER_EXCEPTION = '%s: Notification listener for (%s) threw exception: %s';
3433
export const NO_ROLLOUT_EXISTS = '%s: There is no rollout of feature %s.';
3534
export const NOT_ACTIVATING_USER = '%s: Not activating user %s for experiment %s.';
3635
export const NOT_TRACKING_USER = '% s: Not tracking user %s.';
File renamed without changes.

lib/logging/logger.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
* Copyright 2019, 2024, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { sprintf } from '../utils/fns'
17+
18+
export enum LogLevel {
19+
Debug,
20+
Info,
21+
Warn,
22+
Error,
23+
}
24+
25+
export interface LoggerFacade {
26+
log(logLevel: LogLevel, message: string | Error, ...splat: any[]): void;
27+
info(message: string | Error, ...splat: any[]): void;
28+
debug(message: string | Error, ...splat: any[]): void;
29+
warn(message: string | Error, ...splat: any[]): void;
30+
error(message: string | Error, ...splat: any[]): void;
31+
child(name: string): LoggerFacade;
32+
}
33+
34+
export interface LogHandler {
35+
log(level: LogLevel, message: string, ...splat: any[]): void
36+
}
37+
38+
export class ConsoleLogHandler implements LogHandler {
39+
private prefix: string
40+
41+
constructor(prefix?: string) {
42+
this.prefix = prefix || '[OPTIMIZELY]'
43+
}
44+
45+
log(level: LogLevel, message: string) : void {
46+
const log = `${this.prefix} - ${level} ${this.getTime()} ${message}`
47+
this.consoleLog(level, log)
48+
}
49+
50+
private getTime(): string {
51+
return new Date().toISOString()
52+
}
53+
54+
private consoleLog(logLevel: LogLevel, log: string) : void {
55+
const methodName = LogLevel[logLevel].toLowerCase()
56+
const method: any = console[methodName as keyof Console] || console.log;
57+
method.bind(console)(log);
58+
}
59+
}
60+
61+
export interface LogResolver {
62+
log(msg: string): string;
63+
err(msg: string): string;
64+
}
65+
66+
type OptimizelyLoggerConfig = {
67+
logHandler: LogHandler,
68+
logResolver?: LogResolver,
69+
level: LogLevel,
70+
name?: string,
71+
};
72+
73+
export class OptimizelyLogger implements LoggerFacade {
74+
private name?: string;
75+
private prefix: string;
76+
private logHandler: LogHandler;
77+
private logResolver?: LogResolver;
78+
private level: LogLevel;
79+
80+
constructor(config: OptimizelyLoggerConfig) {
81+
this.logHandler = config.logHandler;
82+
this.logResolver = config.logResolver;
83+
this.level = config.level;
84+
this.name = config.name;
85+
this.prefix = this.name ? `${this.name}: ` : '';
86+
}
87+
88+
child(name: string): OptimizelyLogger {
89+
return new OptimizelyLogger({
90+
logHandler: this.logHandler,
91+
logResolver: this.logResolver,
92+
level: this.level,
93+
name: `${this.name}.${name}`,
94+
});
95+
}
96+
97+
info(message: string | Error, ...splat: any[]): void {
98+
this.log(LogLevel.Info, message, ...splat)
99+
}
100+
101+
debug(message: string | Error, ...splat: any[]): void {
102+
this.log(LogLevel.Debug, message, ...splat)
103+
}
104+
105+
warn(message: string | Error, ...splat: any[]): void {
106+
this.log(LogLevel.Warn, message, ...splat)
107+
}
108+
109+
error(message: string | Error, ...splat: any[]): void {
110+
this.log(LogLevel.Error, message, ...splat)
111+
}
112+
113+
private handleLog(level: LogLevel, message: string, ...splat: any[]) {
114+
const log = `${this.prefix}${sprintf(message, splat)}`
115+
this.logHandler.log(level, log);
116+
}
117+
118+
log(level: LogLevel, message: string | Error, ...splat: any[]): void {
119+
if (level < this.level) {
120+
return;
121+
}
122+
123+
if (message instanceof Error) {
124+
this.handleLog(level, message.toString());
125+
return;
126+
}
127+
128+
if (!this.logResolver) {
129+
this.handleLog(level, message, ...splat);
130+
return;
131+
}
132+
133+
const resolvedMessage = level < LogLevel.Warn ? this.logResolver.log(message)
134+
: this.logResolver.err(message);
135+
136+
if (resolvedMessage) {
137+
this.handleLog(level, resolvedMessage, ...splat);
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)