From 5c562dc03454a43c69b616b26bb22ae08be8ee2c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 16 Mar 2021 17:04:08 -0300 Subject: [PATCH 1/3] pluggable loggers --- src/logger/browser/debugLogger.ts | 9 + src/logger/browser/errorLogger.ts | 5 + src/logger/browser/infoLogger.ts | 7 + src/logger/browser/warnLogger.ts | 6 + src/logger/constants.ts | 272 +++++++++--------- src/logger/index.ts | 23 +- src/logger/messages/debug.ts | 44 +++ src/logger/messages/debugBrowser.ts | 6 + src/logger/messages/debugNode.ts | 14 + src/logger/messages/error.ts | 37 +++ src/logger/messages/errorNode.ts | 7 + src/logger/messages/info.ts | 26 ++ src/logger/messages/warn.ts | 29 ++ src/logger/messages/warnNode.ts | 5 + src/logger/types.ts | 8 +- .../__tests__/attributes.spec.ts | 3 +- .../logger/builtinLogger.ts | 29 +- .../logger/pluggableLogger.ts | 24 +- 18 files changed, 379 insertions(+), 175 deletions(-) create mode 100644 src/logger/browser/debugLogger.ts create mode 100644 src/logger/browser/errorLogger.ts create mode 100644 src/logger/browser/infoLogger.ts create mode 100644 src/logger/browser/warnLogger.ts create mode 100644 src/logger/messages/debug.ts create mode 100644 src/logger/messages/debugBrowser.ts create mode 100644 src/logger/messages/debugNode.ts create mode 100644 src/logger/messages/error.ts create mode 100644 src/logger/messages/errorNode.ts create mode 100644 src/logger/messages/info.ts create mode 100644 src/logger/messages/warn.ts create mode 100644 src/logger/messages/warnNode.ts diff --git a/src/logger/browser/debugLogger.ts b/src/logger/browser/debugLogger.ts new file mode 100644 index 00000000..84962c0d --- /dev/null +++ b/src/logger/browser/debugLogger.ts @@ -0,0 +1,9 @@ +import { Logger } from '../index'; +import { codesError } from '../messages/error'; +import { codesWarn } from '../messages/warn'; +import { codesInfo } from '../messages/info'; +import { codesDebug } from '../messages/debug'; +import { codesDebugBrowser } from '../messages/debugBrowser'; +import { _Map } from '../../utils/lang/maps'; + +export const debugLogger = new Logger('splitio', { logLevel: 'DEBUG' }, new _Map(codesError.concat(codesWarn).concat(codesInfo).concat(codesDebug).concat(codesDebugBrowser))); diff --git a/src/logger/browser/errorLogger.ts b/src/logger/browser/errorLogger.ts new file mode 100644 index 00000000..e9f84c2e --- /dev/null +++ b/src/logger/browser/errorLogger.ts @@ -0,0 +1,5 @@ +import { Logger } from '../index'; +import { codesError } from '../messages/error'; +import { _Map } from '../../utils/lang/maps'; + +export const errorLogger = new Logger('splitio', { logLevel: 'ERROR' }, new _Map(codesError)); diff --git a/src/logger/browser/infoLogger.ts b/src/logger/browser/infoLogger.ts new file mode 100644 index 00000000..196d2874 --- /dev/null +++ b/src/logger/browser/infoLogger.ts @@ -0,0 +1,7 @@ +import { Logger } from '../index'; +import { codesError } from '../messages/error'; +import { codesWarn } from '../messages/warn'; +import { codesInfo } from '../messages/info'; +import { _Map } from '../../utils/lang/maps'; + +export const infoLogger = new Logger('splitio', { logLevel: 'INFO' }, new _Map(codesError.concat(codesWarn).concat(codesInfo))); diff --git a/src/logger/browser/warnLogger.ts b/src/logger/browser/warnLogger.ts new file mode 100644 index 00000000..21fce48d --- /dev/null +++ b/src/logger/browser/warnLogger.ts @@ -0,0 +1,6 @@ +import { Logger } from '../index'; +import { codesError } from '../messages/error'; +import { codesWarn } from '../messages/warn'; +import { _Map } from '../../utils/lang/maps'; + +export const warnLogger = new Logger('splitio', { logLevel: 'WARN' }, new _Map(codesError.concat(codesWarn))); diff --git a/src/logger/constants.ts b/src/logger/constants.ts index eecf9f1c..77ef7339 100644 --- a/src/logger/constants.ts +++ b/src/logger/constants.ts @@ -1,151 +1,151 @@ // commons -export const DEBUG_0 = 'splitio-engine:combiner => [andCombiner] evaluates to %s'; -export const DEBUG_1 = 'splitio-engine:combiner => Treatment found: %s'; -export const DEBUG_2 = 'splitio-engine:combiner => All predicates evaluated, no treatment found.'; -export const DEBUG_3 = 'splitio-engine => [engine] using algo \'murmur\' bucket %s for key %s using seed %s - treatment %s'; -export const DEBUG_4 = 'splitio-engine:matcher => [allMatcher] is always true'; -export const DEBUG_5 = 'splitio-engine:matcher => [betweenMatcher] is %s between %s and %s? %s'; -export const DEBUG_6 = 'splitio-engine:matcher => [booleanMatcher] %s === %s'; -export const DEBUG_7 = 'splitio-engine:matcher => [containsAllMatcher] %s contains all elements of %s? %s'; -export const DEBUG_8 = 'splitio-engine:matcher => [containsAnyMatcher] %s contains at least an element of %s? %s'; -export const DEBUG_9 = 'splitio-engine:matcher => [containsStringMatcher] %s contains %s? %s'; -export const DEBUG_10 = 'splitio-engine:matcher => [dependencyMatcher] Parent split "%s" evaluated to "%s" with label "%s". %s evaluated treatment is part of [%s] ? %s.'; -export const DEBUG_11 = 'splitio-engine:matcher => [dependencyMatcher] will evaluate parent split: "%s" with key: %s %s'; -export const DEBUG_12 = 'splitio-engine:matcher => [equalToMatcher] is %s equal to %s? %s'; -export const DEBUG_13 = 'splitio-engine:matcher => [equalToSetMatcher] is %s equal to set %s? %s'; -export const DEBUG_14 = 'splitio-engine:matcher => [endsWithMatcher] %s ends with %s? %s'; -export const DEBUG_15 = 'splitio-engine:matcher => [greaterThanEqualMatcher] is %s greater than %s? %s'; -export const DEBUG_16 = 'splitio-engine:matcher => [lessThanEqualMatcher] is %s less than %s? %s'; -export const DEBUG_17 = 'splitio-engine:matcher => [partOfMatcher] %s is part of %s? %s'; -export const DEBUG_18 = 'splitio-engine:matcher => [asyncSegmentMatcher] evaluated %s / %s => %s'; -export const DEBUG_19 = 'splitio-engine:matcher => [segmentMatcher] evaluated %s / %s => %s'; -export const DEBUG_20 = 'splitio-engine:matcher => [stringMatcher] does %s matches with %s? %s'; -export const DEBUG_21 = 'splitio-engine:matcher => [stringMatcher] %s is an invalid regex'; -export const DEBUG_22 = 'splitio-engine:matcher => [startsWithMatcher] %s starts with %s? %s'; -export const DEBUG_23 = 'splitio-engine:matcher => [whitelistMatcher] evaluated %s in [%s] => %s'; -export const DEBUG_24 = 'splitio-engine:value => Extracted attribute [%s], [%s] will be used for matching.'; -export const DEBUG_25 = 'splitio-engine:sanitize => Attempted to sanitize [%s] which should be of type [%s]. \n Sanitized and processed value => [%s]'; -export const DEBUG_31 = 'splitio => Retrieving SDK client.'; -export const DEBUG_32 = 'splitio => Retrieving default SDK client.'; // @TODO remove and use 'splitio => Retrieving SDK client.' -export const DEBUG_33 = 'splitio => Retrieving existing SDK client.'; -export const DEBUG_36 = 'splitio-producer:offline => Splits data: '; -export const DEBUG_42 = 'splitio-sync:split-changes => Spin up split update using since = %s'; -export const DEBUG_43 = 'splitio-sync:split-changes => New splits %s'; -export const DEBUG_44 = 'splitio-sync:split-changes => Removed splits %s'; -export const DEBUG_45 = 'splitio-sync:split-changes => Segment names collected %s'; -export const DEBUG_46 = 'splitio-sync:sse-handler => New SSE message received, with data: %s.'; -export const DEBUG_47 = 'splitio-sync:task => Starting %s. Running each %s millis'; -export const DEBUG_48 = 'splitio-sync:task => Running %s'; -export const DEBUG_49 = 'splitio-sync:task => Stopping %s'; -export const DEBUG_50 = 'splitio-client:impressions-tracker => Successfully stored %s impression%s.'; -export const DEBUG_51 = 'Factory instantiation: splits filtering criteria is \'%s\'.'; +export const DEBUG_0 = 0; +export const DEBUG_1 = 1; +export const DEBUG_2 = 2; +export const DEBUG_3 = 3; +export const DEBUG_4 = 4; +export const DEBUG_5 = 5; +export const DEBUG_6 = 6; +export const DEBUG_7 = 7; +export const DEBUG_8 = 8; +export const DEBUG_9 = 9; +export const DEBUG_10 = 10; +export const DEBUG_11 = 11; +export const DEBUG_12 = 12; +export const DEBUG_13 = 13; +export const DEBUG_14 = 14; +export const DEBUG_15 = 15; +export const DEBUG_16 = 16; +export const DEBUG_17 = 17; +export const DEBUG_18 = 18; +export const DEBUG_19 = 19; +export const DEBUG_20 = 20; +export const DEBUG_21 = 21; +export const DEBUG_22 = 22; +export const DEBUG_23 = 23; +export const DEBUG_24 = 24; +export const DEBUG_25 = 25; +export const DEBUG_31 = 31; +export const DEBUG_32 = 32; // @TODO remove and use DEBUG_31 ('splitio => Retrieving SDK client.') +export const DEBUG_33 = 33; +export const DEBUG_36 = 36; +export const DEBUG_42 = 42; +export const DEBUG_43 = 43; +export const DEBUG_44 = 44; +export const DEBUG_45 = 45; +export const DEBUG_46 = 46; +export const DEBUG_47 = 47; +export const DEBUG_48 = 48; +export const DEBUG_49 = 49; +export const DEBUG_50 = 50; +export const DEBUG_51 = 51; // browser -export const DEBUG_26 = 'splitio-client:cleanup => Registering flush handler when unload page event is triggered.'; -export const DEBUG_27 = 'splitio-client:cleanup => Deregistering flush handler when unload page event is triggered.'; +export const DEBUG_26 = 26; +export const DEBUG_27 = 27; // node -export const DEBUG_28 = 'splitio-client:cleanup => Registering cleanup handlers.'; -export const DEBUG_29 = 'splitio-client:cleanup => Deregistering cleanup handlers.'; -export const DEBUG_30 = 'splitio-client:cleanup => Split SDK graceful shutdown after SIGTERM.'; -export const DEBUG_39 = 'splitio-sync:segment-changes => Processed %s with till = %s. Added: %s. Removed: %s'; -export const DEBUG_40 = 'splitio-sync:segment-changes => Processing segment %s'; -export const DEBUG_41 = 'splitio-sync:segment-changes => Started segments update'; -export const DEBUG_34 = 'splitio-offline:splits-fetcher => Ignoring empty line or comment at #%s'; -export const DEBUG_35 = 'splitio-offline:splits-fetcher => Ignoring line since it does not have exactly two columns #%s'; -export const DEBUG_37 = 'splitio-sync:polling-manager => Splits will be refreshed each %s millis'; // @TODO remove since we already log it in syncTask debug log? -export const DEBUG_38 = 'splitio-sync:polling-manager => Segments will be refreshed each %s millis'; // @TODO remove since we already log it in syncTask debug log? +export const DEBUG_28 = 28; +export const DEBUG_29 = 29; +export const DEBUG_30 = 30; +export const DEBUG_39 = 39; +export const DEBUG_40 = 40; +export const DEBUG_41 = 41; +export const DEBUG_34 = 34; +export const DEBUG_35 = 35; +export const DEBUG_37 = 37; // @TODO remove since we already log it in syncTask debug log? +export const DEBUG_38 = 38; // @TODO remove since we already log it in syncTask debug log? // commons -export const ERROR_0 = 'splitio-engine:combiner => Invalid Split provided, no valid conditions found'; -export const ERROR_2 = 'splitio-utils:logger => Invalid Log Level - No changes to the logs will be applied.'; -export const ERROR_3 = 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'; -export const ERROR_4 = 'splitio => Manager instance is not available. Provide the manager module on settings.'; -export const ERROR_5 = 'splitio-services:service => %s The SDK will not get ready.'; -export const ERROR_7 = 'splitio-producer:offline => There was an issue loading the mock Splits data, no changes will be applied to the current cache. %s'; -export const ERROR_9 = 'splitio-sync:sse-handler => Fail to connect to streaming, with error message: %s'; -export const ERROR_10 = 'splitio-sync:push-manager => Failed to authenticate for streaming. Error: "%s".'; -export const ERROR_11 = 'splitio-client:impressions-tracker => Could not store impressions bulk with %s impression%s. Error: %s'; -export const ERROR_12 = 'splitio-client:impressions-tracker => Impression listener logImpression method threw: %s.'; -export const ERROR_13 = '%s: attributes must be a plain object.'; -export const ERROR_14 = '%s: you passed "%s", event_type must adhere to the regular expression /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/g. This means an event_type must be alphanumeric, cannot be more than 80 characters long, and can only include a dash, underscore, period, or colon as separators of alphanumeric characters.'; -export const ERROR_15 = '%s: you passed a null or undefined event_type, event_type must be a non-empty string.'; -export const ERROR_16 = '%s: you passed an invalid event_type, event_type must be a non-empty string.'; -export const ERROR_17 = '%s: you passed an empty event_type, event_type must be a non-empty string.'; -export const ERROR_18 = '%s: properties must be a plain object.'; -export const ERROR_19 = '%s: The maximum size allowed for the properties is 32768 bytes, which was exceeded. Event not queued.'; -export const ERROR_20 = '%s: value must be a finite number.'; -export const ERROR_21 = 'Client has already been destroyed - no calls possible.'; -export const ERROR_22 = '%s: you passed a null or undefined %s, %s must be a non-empty string.'; -export const ERROR_23 = '%s: %s too long, %s must be 250 characters or less.'; -export const ERROR_24 = '%s: you passed an invalid %s type, %s must be a non-empty string.'; -export const ERROR_25 = '%s: you passed an empty string, %s must be a non-empty string.'; -export const ERROR_26 = '%s: Key must be an object with bucketingKey and matchingKey with valid string properties.'; -export const ERROR_32 = '%s: you passed an invalid %s, %s must be a non-empty string.'; -export const ERROR_33 = '%s: you passed an empty %s, %s must be a non-empty string.'; -export const ERROR_34 = '%s: %s must be a non-empty array.'; -export const ERROR_35 = '%s: you passed a null or undefined traffic_type_name, traffic_type_name must be a non-empty string.'; -export const ERROR_36 = '%s: you passed an invalid traffic_type_name, traffic_type_name must be a non-empty string.'; -export const ERROR_37 = '%s: you passed an empty traffic_type_name, traffic_type_name must be a non-empty string.'; -export const ERROR_38 = 'splitio-settings => You passed an invalid impressionsMode, impressionsMode should be one of the following values: \'%s\' or \'%s\'. Defaulting to \'%s\' mode.'; -export const ERROR_39 = 'Response status is not OK. Status: %s. URL: %s. Message: %s'; -export const ERROR_API_KEY = 'Factory instantiation: %s, api_key must be a non-empty string'; +export const ERROR_0 = 300; +export const ERROR_2 = 302; +export const ERROR_3 = 303; +export const ERROR_4 = 304; +export const ERROR_5 = 305; +export const ERROR_7 = 307; +export const ERROR_9 = 309; +export const ERROR_10 = 310; +export const ERROR_11 = 311; +export const ERROR_12 = 312; +export const ERROR_13 = 313; +export const ERROR_14 = 314; +export const ERROR_15 = 315; +export const ERROR_16 = 316; +export const ERROR_17 = 317; +export const ERROR_18 = 318; +export const ERROR_19 = 319; +export const ERROR_20 = 320; +export const ERROR_21 = 321; +export const ERROR_22 = 322; +export const ERROR_23 = 323; +export const ERROR_24 = 324; +export const ERROR_25 = 325; +export const ERROR_26 = 326; +export const ERROR_32 = 332; +export const ERROR_33 = 333; +export const ERROR_34 = 334; +export const ERROR_35 = 335; +export const ERROR_36 = 336; +export const ERROR_37 = 337; +export const ERROR_38 = 338; +export const ERROR_39 = 339; +export const ERROR_API_KEY = 340; // node -export const ERROR_1 = 'splitio-client:cleanup => Error with Split graceful shutdown: %s'; -export const ERROR_8 = 'splitio-sync:segment-changes => Factory instantiation: you passed a Browser type authorizationKey, please grab an Api Key from the Split web console that is of type SDK.'; -export const ERROR_6 = 'splitio-offline:splits-fetcher => Ignoring entry on YAML since the format is incorrect.'; +export const ERROR_1 = 301; +export const ERROR_8 = 308; +export const ERROR_6 = 306; // commons -export const INFO_0 = 'Split SDK is ready from cache.'; -export const INFO_1 = 'Split SDK is ready.'; -export const INFO_2 = 'splitio-client => Split: %s. Key: %s. Evaluation: %s. Label: %s'; -export const INFO_3 = 'splitio-client => Queueing corresponding impression.'; -export const INFO_4 = 'splitio => New shared client instance created.'; -export const INFO_5 = 'splitio => New Split SDK instance created.'; -export const INFO_6 = 'splitio => Manager instance retrieved.'; -export const INFO_7 = 'splitio-sync:polling-manager => Turning segments data polling %s.'; -export const INFO_8 = 'splitio-sync:polling-manager => Starting polling'; -export const INFO_9 = 'splitio-sync:polling-manager => Stopping polling'; -export const INFO_10 = 'splitio-sync:split-changes => Retrying download of splits #%s. Reason: %s'; -export const INFO_11 = 'splitio-sync:push-manager => Refreshing streaming token in %s seconds.'; -export const INFO_12 = 'splitio-sync:push-manager => Attempting to reconnect in %s seconds.'; -export const INFO_13 = 'splitio-sync:push-manager => Connecting to push streaming.'; -export const INFO_14 = 'splitio-sync:push-manager => Streaming is not available. Switching to polling mode.'; -export const INFO_15 = 'splitio-sync:push-manager => Disconnecting from push streaming.'; -export const INFO_16 = 'splitio-sync:submitters => Flushing full events queue and reseting timer.'; -export const INFO_17 = 'splitio-sync:submitters => Pushing %s %s.'; -export const INFO_18 = 'splitio-sync:sync-manager => Streaming not available. Starting periodic fetch of data.'; -export const INFO_19 = 'splitio-sync:sync-manager => Streaming couldn\'t connect. Continue periodic fetch of data.'; -export const INFO_20 = 'splitio-sync:sync-manager => PUSH (re)connected. Syncing and stopping periodic fetch of data.'; -export const INFO_21 = 'splitio-client:event-tracker => Successfully qeued %s'; +export const INFO_0 = 100; +export const INFO_1 = 101; +export const INFO_2 = 102; +export const INFO_3 = 103; +export const INFO_4 = 104; +export const INFO_5 = 105; +export const INFO_6 = 106; +export const INFO_7 = 107; +export const INFO_8 = 108; +export const INFO_9 = 109; +export const INFO_10 = 110; +export const INFO_11 = 111; +export const INFO_12 = 112; +export const INFO_13 = 113; +export const INFO_14 = 114; +export const INFO_15 = 115; +export const INFO_16 = 116; +export const INFO_17 = 117; +export const INFO_18 = 118; +export const INFO_19 = 119; +export const INFO_20 = 120; +export const INFO_21 = 121; // commons -export const WARN_0 = 'splitio-engine:value => Value %s %sdoesn\'t match with expected type.'; -export const WARN_1 = 'splitio-engine:value => Defined attribute [%s], no attributes received.'; -export const WARN_2 = 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'; -export const WARN_4 = 'splitio-sync:my-segments => Retrying download of segments #%s. Reason: %s'; -export const WARN_5 = 'splitio-sync:split-changes => Error while doing fetch of Splits. %s'; -export const WARN_6 = 'splitio-sync:sse-handler => Error parsing SSE error notification: %s'; -export const WARN_7 = 'splitio-sync:sse-handler => Error parsing new SSE message notification: %s'; -export const WARN_8 = 'splitio-sync:push-manager => %sFalling back to polling mode.'; -export const WARN_9 = 'splitio-sync:submitters => Droping %s %s after retry. Reason %s.'; -export const WARN_10 = 'splitio-sync:submitters => Failed to push %s %s, keeping data to retry on next iteration. Reason %s.'; -export const WARN_11 = 'splitio-client:event-tracker => Failed to queue %s'; -export const WARN_12 = '%s: Property %s is of invalid type. Setting value to null.'; -export const WARN_13 = '%s: Event has more than 300 properties. Some of them will be trimmed when processed.'; -export const WARN_14 = '%s: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method.'; -export const WARN_15 = '%s: %s "%s" is not of type string, converting.'; -export const WARN_17 = '%s: %s "%s" has extra whitespace, trimming.'; -export const WARN_18 = '%s: you passed "%s" that does not exist in this environment, please double check what Splits exist in the web console.'; -export const WARN_19 = '%s: traffic_type_name should be all lowercase - converting string to lowercase.'; -export const WARN_20 = '%s: Traffic Type %s does not have any corresponding Splits in this environment, make sure you\'re tracking your events to a valid traffic type defined in the Split console.'; -export const WARN_21 = 'splitio-settings => %s integration %s at settings %s invalid. %s'; -export const WARN_22 = 'Factory instantiation: split filters have been configured but will have no effect if mode is not \'%s\', since synchronization is being deferred to an external tool.'; -export const WARN_23 = 'Factory instantiation: split filter at position \'%s\' is invalid. It must be an object with a valid filter type (\'byName\' or \'byPrefix\') and a list of \'values\'.'; -export const WARN_24 = 'Factory instantiation: splitFilters configuration must be a non-empty array of filter objects.'; -export const WARN_25 = 'splitio-settings => The provided storage is invalid. Fallbacking into default MEMORY storage'; -export const WARN_API_KEY = 'Factory instantiation: %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'; +export const WARN_0 = 200; +export const WARN_1 = 201; +export const WARN_2 = 202; +export const WARN_4 = 204; +export const WARN_5 = 205; +export const WARN_6 = 206; +export const WARN_7 = 207; +export const WARN_8 = 208; +export const WARN_9 = 209; +export const WARN_10 = 210; +export const WARN_11 = 211; +export const WARN_12 = 212; +export const WARN_13 = 213; +export const WARN_14 = 214; +export const WARN_15 = 215; +export const WARN_17 = 217; +export const WARN_18 = 218; +export const WARN_19 = 219; +export const WARN_20 = 220; +export const WARN_21 = 221; +export const WARN_22 = 222; +export const WARN_23 = 223; +export const WARN_24 = 224; +export const WARN_25 = 225; +export const WARN_API_KEY = 226; // node -export const WARN_3 = 'splitio-offline:splits-fetcher => .split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.'; +export const WARN_3 = 203; diff --git a/src/logger/index.ts b/src/logger/index.ts index 5513fb39..27b43ab0 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -2,6 +2,7 @@ import objectAssign from 'object-assign'; import { ILoggerOptions, ILogger } from './types'; import { find } from '../utils/lang'; import { LogLevel } from '../types'; +import { IMap, _Map } from '../utils/lang/maps'; export const LogLevels: { [level: string]: LogLevel } = { DEBUG: 'DEBUG', @@ -31,36 +32,42 @@ export class Logger implements ILogger { private category: string; private options: Required; + private codes: IMap; - constructor(category: string, options?: ILoggerOptions) { + constructor(category: string, options?: ILoggerOptions, codes?: IMap) { this.category = category; this.options = objectAssign({}, defaultOptions, options); + this.codes = codes || new _Map(); } setLogLevel(logLevel: LogLevel) { this.options.logLevel = logLevel; } - debug(msg: string, args?: any[]) { + debug(msg: string | number, args?: any[]) { this._log(LogLevels.DEBUG, msg, args); } - info(msg: string, args?: any[]) { + info(msg: string | number, args?: any[]) { this._log(LogLevels.INFO, msg, args); } - warn(msg: string, args?: any[]) { + warn(msg: string | number, args?: any[]) { this._log(LogLevels.WARN, msg, args); } - error(msg: string, args?: any[]) { + error(msg: string | number, args?: any[]) { this._log(LogLevels.ERROR, msg, args); } - private _log(level: LogLevel, text: string, args?: any[]) { + private _log(level: LogLevel, msg: string | number, args?: any[]) { if (this._shouldLog(level)) { - if (args) text = sprintf(text, args); - const formattedText = this._generateLogMessage(level, text); + if (typeof msg === 'number') { + const format = this.codes.get(msg); + if (format) msg = sprintf(format, args); + else msg = `Message code ${msg}${args ? ', with args: ' + args.toString() : ''}`; + } + const formattedText = this._generateLogMessage(level, msg); console.log(formattedText); } diff --git a/src/logger/messages/debug.ts b/src/logger/messages/debug.ts new file mode 100644 index 00000000..dec2f5b7 --- /dev/null +++ b/src/logger/messages/debug.ts @@ -0,0 +1,44 @@ +import { DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5, DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, DEBUG_10, DEBUG_11, DEBUG_12, DEBUG_13, DEBUG_14, DEBUG_15, DEBUG_16, DEBUG_17, DEBUG_18, DEBUG_19, DEBUG_20, DEBUG_21, DEBUG_22, DEBUG_23, DEBUG_24, DEBUG_25, DEBUG_31, DEBUG_32, DEBUG_33, DEBUG_36, DEBUG_42, DEBUG_43, DEBUG_44, DEBUG_45, DEBUG_46, DEBUG_47, DEBUG_48, DEBUG_49, DEBUG_50, DEBUG_51 } from '../constants'; + +export const codesDebug: [number, string][] = [ + [DEBUG_0, 'splitio-engine:combiner => [andCombiner] evaluates to %s'], + [DEBUG_1, 'splitio-engine:combiner => Treatment found: %s'], + [DEBUG_2, 'splitio-engine:combiner => All predicates evaluated, no treatment found.'], + [DEBUG_3, 'splitio-engine => [engine] using algo "murmur" bucket %s for key %s using seed %s - treatment %s'], + [DEBUG_4, 'splitio-engine:matcher => [allMatcher] is always true'], + [DEBUG_5, 'splitio-engine:matcher => [betweenMatcher] is %s between %s and %s? %s'], + [DEBUG_6, 'splitio-engine:matcher => [booleanMatcher] %s === %s'], + [DEBUG_7, 'splitio-engine:matcher => [containsAllMatcher] %s contains all elements of %s? %s'], + [DEBUG_8, 'splitio-engine:matcher => [containsAnyMatcher] %s contains at least an element of %s? %s'], + [DEBUG_9, 'splitio-engine:matcher => [containsStringMatcher] %s contains %s? %s'], + [DEBUG_10, 'splitio-engine:matcher => [dependencyMatcher] Parent split "%s" evaluated to "%s" with label "%s". %s evaluated treatment is part of [%s] ? %s.'], + [DEBUG_11, 'splitio-engine:matcher => [dependencyMatcher] will evaluate parent split: "%s" with key: %s %s'], + [DEBUG_12, 'splitio-engine:matcher => [equalToMatcher] is %s equal to %s? %s'], + [DEBUG_13, 'splitio-engine:matcher => [equalToSetMatcher] is %s equal to set %s? %s'], + [DEBUG_14, 'splitio-engine:matcher => [endsWithMatcher] %s ends with %s? %s'], + [DEBUG_15, 'splitio-engine:matcher => [greaterThanEqualMatcher] is %s greater than %s? %s'], + [DEBUG_16, 'splitio-engine:matcher => [lessThanEqualMatcher] is %s less than %s? %s'], + [DEBUG_17, 'splitio-engine:matcher => [partOfMatcher] %s is part of %s? %s'], + [DEBUG_18, 'splitio-engine:matcher => [asyncSegmentMatcher] evaluated %s / %s => %s'], + [DEBUG_19, 'splitio-engine:matcher => [segmentMatcher] evaluated %s / %s => %s'], + [DEBUG_20, 'splitio-engine:matcher => [stringMatcher] does %s matches with %s? %s'], + [DEBUG_21, 'splitio-engine:matcher => [stringMatcher] %s is an invalid regex'], + [DEBUG_22, 'splitio-engine:matcher => [startsWithMatcher] %s starts with %s? %s'], + [DEBUG_23, 'splitio-engine:matcher => [whitelistMatcher] evaluated %s in [%s] => %s'], + [DEBUG_24, 'splitio-engine:value => Extracted attribute [%s], [%s] will be used for matching.'], + [DEBUG_25, 'splitio-engine:sanitize => Attempted to sanitize [%s] which should be of type [%s]. \n Sanitized and processed value => [%s]'], + [DEBUG_31, 'splitio => Retrieving SDK client.'], + [DEBUG_32, 'splitio => Retrieving default SDK client.'], // @TODO remove and use 'splitio => Retrieving SDK client.' + [DEBUG_33, 'splitio => Retrieving existing SDK client.'], + [DEBUG_36, 'splitio-producer:offline => Splits data: '], + [DEBUG_42, 'splitio-sync:split-changes => Spin up split update using since = %s'], + [DEBUG_43, 'splitio-sync:split-changes => New splits %s'], + [DEBUG_44, 'splitio-sync:split-changes => Removed splits %s'], + [DEBUG_45, 'splitio-sync:split-changes => Segment names collected %s'], + [DEBUG_46, 'splitio-sync:sse-handler => New SSE message received, with data: %s.'], + [DEBUG_47, 'splitio-sync:task => Starting %s. Running each %s millis'], + [DEBUG_48, 'splitio-sync:task => Running %s'], + [DEBUG_49, 'splitio-sync:task => Stopping %s'], + [DEBUG_50, 'splitio-client:impressions-tracker => Successfully stored %s impression%s.'], + [DEBUG_51, 'Factory instantiation: splits filtering criteria is "%s".'] +]; diff --git a/src/logger/messages/debugBrowser.ts b/src/logger/messages/debugBrowser.ts new file mode 100644 index 00000000..86732fcf --- /dev/null +++ b/src/logger/messages/debugBrowser.ts @@ -0,0 +1,6 @@ +import { DEBUG_26, DEBUG_27 } from '../constants'; + +export const codesDebugBrowser: [number, string][] = [ + [DEBUG_26, 'splitio-client:cleanup => Registering flush handler when unload page event is triggered.'], + [DEBUG_27, 'splitio-client:cleanup => Deregistering flush handler when unload page event is triggered.'], +]; diff --git a/src/logger/messages/debugNode.ts b/src/logger/messages/debugNode.ts new file mode 100644 index 00000000..9bb08f6b --- /dev/null +++ b/src/logger/messages/debugNode.ts @@ -0,0 +1,14 @@ +import { DEBUG_28, DEBUG_29, DEBUG_30, DEBUG_39, DEBUG_40, DEBUG_41, DEBUG_34, DEBUG_35, DEBUG_37, DEBUG_38 } from '../constants'; + +export const codesDebugNode: [number, string][] = [ + [DEBUG_28, 'splitio-client:cleanup => Registering cleanup handlers.'], + [DEBUG_29, 'splitio-client:cleanup => Deregistering cleanup handlers.'], + [DEBUG_30, 'splitio-client:cleanup => Split SDK graceful shutdown after SIGTERM.'], + [DEBUG_39, 'splitio-sync:segment-changes => Processed %s with till = %s. Added: %s. Removed: %s'], + [DEBUG_40, 'splitio-sync:segment-changes => Processing segment %s'], + [DEBUG_41, 'splitio-sync:segment-changes => Started segments update'], + [DEBUG_34, 'splitio-offline:splits-fetcher => Ignoring empty line or comment at #%s'], + [DEBUG_35, 'splitio-offline:splits-fetcher => Ignoring line since it does not have exactly two columns #%s'], + [DEBUG_37, 'splitio-sync:polling-manager => Splits will be refreshed each %s millis'], // @TODO remove since we already log it in syncTask debug log? + [DEBUG_38, 'splitio-sync:polling-manager => Segments will be refreshed each %s millis'], // @TODO remove since we already log it in syncTask debug log? +]; diff --git a/src/logger/messages/error.ts b/src/logger/messages/error.ts new file mode 100644 index 00000000..9c2cbf1f --- /dev/null +++ b/src/logger/messages/error.ts @@ -0,0 +1,37 @@ +import { ERROR_0, ERROR_2, ERROR_3, ERROR_4, ERROR_5, ERROR_7, ERROR_9, ERROR_10, ERROR_11, ERROR_12, ERROR_13, ERROR_14, ERROR_15, ERROR_16, ERROR_17, ERROR_18, ERROR_19, ERROR_20, ERROR_21, ERROR_22, ERROR_23, ERROR_24, ERROR_25, ERROR_26, ERROR_32, ERROR_33, ERROR_34, ERROR_35, ERROR_36, ERROR_37, ERROR_38, ERROR_39, ERROR_API_KEY } from '../constants'; + +export const codesError: [number, string][] = [ + [ERROR_0, 'splitio-engine:combiner => Invalid Split provided, no valid conditions found'], + [ERROR_2, 'splitio-utils:logger => Invalid Log Level - No changes to the logs will be applied.'], + [ERROR_3, 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'], + [ERROR_4, 'splitio => Manager instance is not available. Provide the manager module on settings.'], + [ERROR_5, 'splitio-services:service => %s The SDK will not get ready.'], + [ERROR_7, 'splitio-producer:offline => There was an issue loading the mock Splits data, no changes will be applied to the current cache. %s'], + [ERROR_9, 'splitio-sync:sse-handler => Fail to connect to streaming, with error message: %s'], + [ERROR_10, 'splitio-sync:push-manager => Failed to authenticate for streaming. Error: "%s".'], + [ERROR_11, 'splitio-client:impressions-tracker => Could not store impressions bulk with %s impression%s. Error: %s'], + [ERROR_12, 'splitio-client:impressions-tracker => Impression listener logImpression method threw: %s.'], + [ERROR_13, '%s: attributes must be a plain object.'], + [ERROR_14, '%s: you passed "%s", event_type must adhere to the regular expression /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/g. This means an event_type must be alphanumeric, cannot be more than 80 characters long, and can only include a dash, underscore, period, or colon as separators of alphanumeric characters.'], + [ERROR_15, '%s: you passed a null or undefined event_type, event_type must be a non-empty string.'], + [ERROR_16, '%s: you passed an invalid event_type, event_type must be a non-empty string.'], + [ERROR_17, '%s: you passed an empty event_type, event_type must be a non-empty string.'], + [ERROR_18, '%s: properties must be a plain object.'], + [ERROR_19, '%s: The maximum size allowed for the properties is 32768 bytes, which was exceeded. Event not queued.'], + [ERROR_20, '%s: value must be a finite number.'], + [ERROR_21, 'Client has already been destroyed - no calls possible.'], + [ERROR_22, '%s: you passed a null or undefined %s, %s must be a non-empty string.'], + [ERROR_23, '%s: %s too long, %s must be 250 characters or less.'], + [ERROR_24, '%s: you passed an invalid %s type, %s must be a non-empty string.'], + [ERROR_25, '%s: you passed an empty string, %s must be a non-empty string.'], + [ERROR_26, '%s: Key must be an object with bucketingKey and matchingKey with valid string properties.'], + [ERROR_32, '%s: you passed an invalid %s, %s must be a non-empty string.'], + [ERROR_33, '%s: you passed an empty %s, %s must be a non-empty string.'], + [ERROR_34, '%s: %s must be a non-empty array.'], + [ERROR_35, '%s: you passed a null or undefined traffic_type_name, traffic_type_name must be a non-empty string.'], + [ERROR_36, '%s: you passed an invalid traffic_type_name, traffic_type_name must be a non-empty string.'], + [ERROR_37, '%s: you passed an empty traffic_type_name, traffic_type_name must be a non-empty string.'], + [ERROR_38, 'splitio-settings => You passed an invalid impressionsMode, impressionsMode should be one of the following values: "%s" or "%s". Defaulting to "%s" mode.'], + [ERROR_39, 'Response status is not OK. Status: %s. URL: %s. Message: %s'], + [ERROR_API_KEY, 'Factory instantiation: %s, api_key must be a non-empty string'] +]; diff --git a/src/logger/messages/errorNode.ts b/src/logger/messages/errorNode.ts new file mode 100644 index 00000000..8e3adc6d --- /dev/null +++ b/src/logger/messages/errorNode.ts @@ -0,0 +1,7 @@ +import { ERROR_1, ERROR_8, ERROR_6 } from '../constants'; + +export const codesErrorNode: [number, string][] = [ + [ERROR_1, 'splitio-client:cleanup => Error with Split graceful shutdown: %s'], + [ERROR_8, 'splitio-sync:segment-changes => Factory instantiation: you passed a Browser type authorizationKey, please grab an Api Key from the Split web console that is of type SDK.'], + [ERROR_6, 'splitio-offline:splits-fetcher => Ignoring entry on YAML since the format is incorrect.'], +]; diff --git a/src/logger/messages/info.ts b/src/logger/messages/info.ts new file mode 100644 index 00000000..e2fed1a3 --- /dev/null +++ b/src/logger/messages/info.ts @@ -0,0 +1,26 @@ +import { INFO_0, INFO_1, INFO_2, INFO_3, INFO_4, INFO_5, INFO_6, INFO_7, INFO_8, INFO_9, INFO_10, INFO_11, INFO_12, INFO_13, INFO_14, INFO_15, INFO_16, INFO_17, INFO_18, INFO_19, INFO_20, INFO_21 } from '../constants'; + +export const codesInfo: [number, string][] = [ + [INFO_0, 'Split SDK is ready from cache.'], + [INFO_1, 'Split SDK is ready.'], + [INFO_2, 'splitio-client => Split: %s. Key: %s. Evaluation: %s. Label: %s'], + [INFO_3, 'splitio-client => Queueing corresponding impression.'], + [INFO_4, 'splitio => New shared client instance created.'], + [INFO_5, 'splitio => New Split SDK instance created.'], + [INFO_6, 'splitio => Manager instance retrieved.'], + [INFO_7, 'splitio-sync:polling-manager => Turning segments data polling %s.'], + [INFO_8, 'splitio-sync:polling-manager => Starting polling'], + [INFO_9, 'splitio-sync:polling-manager => Stopping polling'], + [INFO_10, 'splitio-sync:split-changes => Retrying download of splits #%s. Reason: %s'], + [INFO_11, 'splitio-sync:push-manager => Refreshing streaming token in %s seconds.'], + [INFO_12, 'splitio-sync:push-manager => Attempting to reconnect in %s seconds.'], + [INFO_13, 'splitio-sync:push-manager => Connecting to push streaming.'], + [INFO_14, 'splitio-sync:push-manager => Streaming is not available. Switching to polling mode.'], + [INFO_15, 'splitio-sync:push-manager => Disconnecting from push streaming.'], + [INFO_16, 'splitio-sync:submitters => Flushing full events queue and reseting timer.'], + [INFO_17, 'splitio-sync:submitters => Pushing %s %s.'], + [INFO_18, 'splitio-sync:sync-manager => Streaming not available. Starting periodic fetch of data.'], + [INFO_19, 'splitio-sync:sync-manager => Streaming couldn\'t connect. Continue periodic fetch of data.'], + [INFO_20, 'splitio-sync:sync-manager => PUSH (re)connected. Syncing and stopping periodic fetch of data.'], + [INFO_21, 'splitio-client:event-tracker => Successfully qeued %s'] +]; diff --git a/src/logger/messages/warn.ts b/src/logger/messages/warn.ts new file mode 100644 index 00000000..8e4bca72 --- /dev/null +++ b/src/logger/messages/warn.ts @@ -0,0 +1,29 @@ +import { WARN_0, WARN_1, WARN_2, WARN_4, WARN_5, WARN_6, WARN_7, WARN_8, WARN_9, WARN_10, WARN_11, WARN_12, WARN_13, WARN_14, WARN_15, WARN_17, WARN_18, WARN_19, WARN_20, WARN_21, WARN_22, WARN_23, WARN_24, WARN_25, WARN_API_KEY } from '../constants'; + +export const codesWarn: [number, string][] = [ + [WARN_0, 'splitio-engine:value => Value %s %sdoesn\'t match with expected type.'], + [WARN_1, 'splitio-engine:value => Defined attribute [%s], no attributes received.'], + [WARN_2, 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'], + [WARN_4, 'splitio-sync:my-segments => Retrying download of segments #%s. Reason: %s'], + [WARN_5, 'splitio-sync:split-changes => Error while doing fetch of Splits. %s'], + [WARN_6, 'splitio-sync:sse-handler => Error parsing SSE error notification: %s'], + [WARN_7, 'splitio-sync:sse-handler => Error parsing new SSE message notification: %s'], + [WARN_8, 'splitio-sync:push-manager => %sFalling back to polling mode.'], + [WARN_9, 'splitio-sync:submitters => Droping %s %s after retry. Reason %s.'], + [WARN_10, 'splitio-sync:submitters => Failed to push %s %s, keeping data to retry on next iteration. Reason %s.'], + [WARN_11, 'splitio-client:event-tracker => Failed to queue %s'], + [WARN_12, '%s: Property %s is of invalid type. Setting value to null.'], + [WARN_13, '%s: Event has more than 300 properties. Some of them will be trimmed when processed.'], + [WARN_14, '%s: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method.'], + [WARN_15, '%s: %s "%s" is not of type string, converting.'], + [WARN_17, '%s: %s "%s" has extra whitespace, trimming.'], + [WARN_18, '%s: you passed "%s" that does not exist in this environment, please double check what Splits exist in the web console.'], + [WARN_19, '%s: traffic_type_name should be all lowercase - converting string to lowercase.'], + [WARN_20, '%s: Traffic Type %s does not have any corresponding Splits in this environment, make sure you\'re tracking your events to a valid traffic type defined in the Split console.'], + [WARN_21, 'splitio-settings => %s integration %s at settings %s invalid. %s'], + [WARN_22, 'Factory instantiation: split filters have been configured but will have no effect if mode is not "%s", since synchronization is being deferred to an external tool.'], + [WARN_23, 'Factory instantiation: split filter at position %s is invalid. It must be an object with a valid filter type ("byName" or "byPrefix") and a list of "values".'], + [WARN_24, 'Factory instantiation: splitFilters configuration must be a non-empty array of filter objects.'], + [WARN_25, 'splitio-settings => The provided storage is invalid. Fallbacking into default MEMORY storage'], + [WARN_API_KEY, 'Factory instantiation: %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'] +]; diff --git a/src/logger/messages/warnNode.ts b/src/logger/messages/warnNode.ts new file mode 100644 index 00000000..12d1724f --- /dev/null +++ b/src/logger/messages/warnNode.ts @@ -0,0 +1,5 @@ +import { WARN_3 } from '../constants'; + +export const codesWarnNode: [number, string][] = [ + [WARN_3, 'splitio-offline:splits-fetcher => .split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.'], +]; diff --git a/src/logger/types.ts b/src/logger/types.ts index 5fa1d2c4..d691d255 100644 --- a/src/logger/types.ts +++ b/src/logger/types.ts @@ -8,11 +8,11 @@ export interface ILoggerOptions { export interface ILogger { setLogLevel(logLevel: LogLevel): void - debug(msg: string, args?: any[]): void + debug(msg: string | number, args?: any[]): void - info(msg: string, args?: any[]): void + info(msg: string | number, args?: any[]): void - warn(msg: string, args?: any[]): void + warn(msg: string | number, args?: any[]): void - error(msg: string, args?: any[]): void + error(msg: string | number, args?: any[]): void } diff --git a/src/utils/inputValidation/__tests__/attributes.spec.ts b/src/utils/inputValidation/__tests__/attributes.spec.ts index c91310b4..e7ae5e0d 100644 --- a/src/utils/inputValidation/__tests__/attributes.spec.ts +++ b/src/utils/inputValidation/__tests__/attributes.spec.ts @@ -1,3 +1,4 @@ +import { ERROR_13 } from '../../../logger/constants'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; import { validateAttributes } from '../attributes'; @@ -40,7 +41,7 @@ describe('INPUT VALIDATION for Attributes', () => { const invalidAttribute = invalidAttributes[i]; expect(validateAttributes(loggerMock, invalidAttribute, 'test_method')).toBe(false); // Invalid attribute objects should return false. - expect(loggerMock.error.mock.calls[0][0]).toEqual('test_method: attributes must be a plain object.'); // The error should be logged for the invalid attributes map. + expect(loggerMock.error).lastCalledWith(ERROR_13, ['test_method']); // The error should be logged for the invalid attributes map. loggerMock.error.mockClear(); } diff --git a/src/utils/settingsValidation/logger/builtinLogger.ts b/src/utils/settingsValidation/logger/builtinLogger.ts index 51a993e3..b5f108cf 100644 --- a/src/utils/settingsValidation/logger/builtinLogger.ts +++ b/src/utils/settingsValidation/logger/builtinLogger.ts @@ -3,6 +3,7 @@ import { ILogger } from '../../../logger/types'; import { LogLevel } from '../../../types'; import { isLocalStorageAvailable } from '../../env/isLocalStorageAvailable'; import { isNode } from '../../env/isNode'; +import { IMap } from '../../lang/maps'; // @TODO when integrating with other packages, find the best way to handle initial state per environment const LS_KEY = 'splitio_debug'; @@ -47,21 +48,25 @@ export function getLogLevel(debugValue: unknown): LogLevel | undefined { } /** - * Validates the `debug` property at config and use it to set the log level. - * - * @param settings user config object - * @returns a logger instance with the log level at `settings.debug`. If `settings.debug` is invalid or not provided, `initialLogLevel` is used. + * Factory of logger validator, which validates the `debug` property at config and creates a logger instance with the provided `debug` log level. */ -export function validateLogger(settings: { debug: unknown} ): ILogger { +export function validateLoggerFactory(msgCodes?: IMap) { - const settingLogLevel = settings.debug ? getLogLevel(settings.debug) : initialLogLevel; + /** + * Validates the `debug` property at config and use it to set the log level. + * + * @param settings user config object + * @returns a logger instance with the log level at `settings.debug`. If `settings.debug` is invalid or not provided, `initialLogLevel` is used. + */ + return function validateLogger(settings: { debug: unknown }): ILogger { - const log = new Logger('splitio', { logLevel: settingLogLevel || initialLogLevel }); + const settingLogLevel = settings.debug ? getLogLevel(settings.debug) : initialLogLevel; - // logs error if the provided settings debug value is invalid - if (!settingLogLevel) log.error('Invalid Log Level - No changes to the logs will be applied.'); - - return log; -} + const log = new Logger('splitio', { logLevel: settingLogLevel || initialLogLevel }, msgCodes); + // logs error if the provided settings debug value is invalid + if (!settingLogLevel) log.error('Invalid Log Level - No changes to the logs will be applied.'); + return log; + }; +} diff --git a/src/utils/settingsValidation/logger/pluggableLogger.ts b/src/utils/settingsValidation/logger/pluggableLogger.ts index 8e01d90c..4d36e3a3 100644 --- a/src/utils/settingsValidation/logger/pluggableLogger.ts +++ b/src/utils/settingsValidation/logger/pluggableLogger.ts @@ -1,31 +1,27 @@ +import { Logger } from '../../../logger'; import { ILogger } from '../../../logger/types'; -const noopLogger: ILogger = { - setLogLevel() { }, - debug() { }, - info() { }, - warn() { }, - error() { } -}; - function isLogger(log: any): log is ILogger { return log && typeof log.debug === 'function' && typeof log.info === 'function' && typeof log.warn === 'function' && typeof log.error === 'function' && typeof log.setLogLevel === 'function'; } /** - * Validates the `log` (logger) property at config. + * Validates the `debug` (logger) property at config. * * @param settings user config object - * @returns the provided logger or a no-op logger if no one is provided - * @throws throws an error if a logger was provided but is invalid + * @returns the provided logger at `settings.debug` or a new one with NONE log level if invalid or not provided */ export function validateLogger(settings: { debug: unknown }): ILogger { const { debug } = settings; + const log = new Logger('splitio', { logLevel: 'NONE' }); - if (!debug) return noopLogger; + // @TODO consider debug of boolean or string types + if (!debug) return log; if (isLogger(debug)) return debug; - // @TODO log error instead of throwing one - throw new Error('The provided `debug` value at config is not valid'); + // logs error, for consistency with builtin logger validator + log.error('The provided `debug` value at config is invalid.'); + + return log; } From 940a9c7df59dc2464e3c71dd5002455c9337514c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 16 Mar 2021 19:02:47 -0300 Subject: [PATCH 2/3] some comment updates --- .../logger/builtinLogger.ts | 27 +++++++------------ .../logger/pluggableLogger.ts | 4 +-- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/utils/settingsValidation/logger/builtinLogger.ts b/src/utils/settingsValidation/logger/builtinLogger.ts index b5f108cf..358cb7f0 100644 --- a/src/utils/settingsValidation/logger/builtinLogger.ts +++ b/src/utils/settingsValidation/logger/builtinLogger.ts @@ -3,7 +3,6 @@ import { ILogger } from '../../../logger/types'; import { LogLevel } from '../../../types'; import { isLocalStorageAvailable } from '../../env/isLocalStorageAvailable'; import { isNode } from '../../env/isNode'; -import { IMap } from '../../lang/maps'; // @TODO when integrating with other packages, find the best way to handle initial state per environment const LS_KEY = 'splitio_debug'; @@ -48,25 +47,19 @@ export function getLogLevel(debugValue: unknown): LogLevel | undefined { } /** - * Factory of logger validator, which validates the `debug` property at config and creates a logger instance with the provided `debug` log level. + * Validates the `debug` property at config and use it to set the log level. + * + * @param settings user config object + * @returns a logger instance with the log level at `settings.debug`. If `settings.debug` is invalid or not provided, `initialLogLevel` is used. */ -export function validateLoggerFactory(msgCodes?: IMap) { +export function validateLogger(settings: { debug: unknown} ): ILogger { - /** - * Validates the `debug` property at config and use it to set the log level. - * - * @param settings user config object - * @returns a logger instance with the log level at `settings.debug`. If `settings.debug` is invalid or not provided, `initialLogLevel` is used. - */ - return function validateLogger(settings: { debug: unknown }): ILogger { + const settingLogLevel = settings.debug ? getLogLevel(settings.debug) : initialLogLevel; - const settingLogLevel = settings.debug ? getLogLevel(settings.debug) : initialLogLevel; + const log = new Logger('splitio', { logLevel: settingLogLevel || initialLogLevel }); - const log = new Logger('splitio', { logLevel: settingLogLevel || initialLogLevel }, msgCodes); + // logs error if the provided settings debug value is invalid + if (!settingLogLevel) log.error('Invalid Log Level - No changes to the logs will be applied.'); - // logs error if the provided settings debug value is invalid - if (!settingLogLevel) log.error('Invalid Log Level - No changes to the logs will be applied.'); - - return log; - }; + return log; } diff --git a/src/utils/settingsValidation/logger/pluggableLogger.ts b/src/utils/settingsValidation/logger/pluggableLogger.ts index 4d36e3a3..2a644618 100644 --- a/src/utils/settingsValidation/logger/pluggableLogger.ts +++ b/src/utils/settingsValidation/logger/pluggableLogger.ts @@ -9,13 +9,13 @@ function isLogger(log: any): log is ILogger { * Validates the `debug` (logger) property at config. * * @param settings user config object - * @returns the provided logger at `settings.debug` or a new one with NONE log level if invalid or not provided + * @returns the provided logger at `settings.debug` or a new one with NONE log level if the provided one is invalid */ export function validateLogger(settings: { debug: unknown }): ILogger { const { debug } = settings; const log = new Logger('splitio', { logLevel: 'NONE' }); - // @TODO consider debug of boolean or string types + // @TODO support boolean and string values? if (!debug) return log; if (isLogger(debug)) return debug; From 832c0eb6bc2683f4c0f19507d89226d41bc0b371 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 16 Mar 2021 19:12:38 -0300 Subject: [PATCH 3/3] optimized concat call --- src/logger/browser/debugLogger.ts | 5 ++++- src/logger/browser/errorLogger.ts | 5 ++++- src/logger/browser/infoLogger.ts | 5 ++++- src/logger/browser/warnLogger.ts | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/logger/browser/debugLogger.ts b/src/logger/browser/debugLogger.ts index 84962c0d..f0163454 100644 --- a/src/logger/browser/debugLogger.ts +++ b/src/logger/browser/debugLogger.ts @@ -6,4 +6,7 @@ import { codesDebug } from '../messages/debug'; import { codesDebugBrowser } from '../messages/debugBrowser'; import { _Map } from '../../utils/lang/maps'; -export const debugLogger = new Logger('splitio', { logLevel: 'DEBUG' }, new _Map(codesError.concat(codesWarn).concat(codesInfo).concat(codesDebug).concat(codesDebugBrowser))); +export const debugLogger = new Logger( + 'splitio', { logLevel: 'DEBUG' }, + new _Map(codesError.concat(codesWarn, codesInfo, codesDebug, codesDebugBrowser)) +); diff --git a/src/logger/browser/errorLogger.ts b/src/logger/browser/errorLogger.ts index e9f84c2e..7423d7fc 100644 --- a/src/logger/browser/errorLogger.ts +++ b/src/logger/browser/errorLogger.ts @@ -2,4 +2,7 @@ import { Logger } from '../index'; import { codesError } from '../messages/error'; import { _Map } from '../../utils/lang/maps'; -export const errorLogger = new Logger('splitio', { logLevel: 'ERROR' }, new _Map(codesError)); +export const errorLogger = new Logger( + 'splitio', { logLevel: 'ERROR' }, + new _Map(codesError) +); diff --git a/src/logger/browser/infoLogger.ts b/src/logger/browser/infoLogger.ts index 196d2874..c88c7c8d 100644 --- a/src/logger/browser/infoLogger.ts +++ b/src/logger/browser/infoLogger.ts @@ -4,4 +4,7 @@ import { codesWarn } from '../messages/warn'; import { codesInfo } from '../messages/info'; import { _Map } from '../../utils/lang/maps'; -export const infoLogger = new Logger('splitio', { logLevel: 'INFO' }, new _Map(codesError.concat(codesWarn).concat(codesInfo))); +export const infoLogger = new Logger( + 'splitio', { logLevel: 'INFO' }, + new _Map(codesError.concat(codesWarn, codesInfo)) +); diff --git a/src/logger/browser/warnLogger.ts b/src/logger/browser/warnLogger.ts index 21fce48d..348d4284 100644 --- a/src/logger/browser/warnLogger.ts +++ b/src/logger/browser/warnLogger.ts @@ -3,4 +3,7 @@ import { codesError } from '../messages/error'; import { codesWarn } from '../messages/warn'; import { _Map } from '../../utils/lang/maps'; -export const warnLogger = new Logger('splitio', { logLevel: 'WARN' }, new _Map(codesError.concat(codesWarn))); +export const warnLogger = new Logger( + 'splitio', { logLevel: 'WARN' }, + new _Map(codesError.concat(codesWarn)) +);