diff --git a/docs/js-client-sdk.loglevel.md b/docs/js-client-sdk.loglevel.md
new file mode 100644
index 0000000..1c0545a
--- /dev/null
+++ b/docs/js-client-sdk.loglevel.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@eppo/js-client-sdk](./js-client-sdk.md) > [LogLevel](./js-client-sdk.loglevel.md)
+
+## LogLevel type
+
+Valid log levels for the Eppo SDK logger.
+
+**Signature:**
+
+```typescript
+export declare type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
+```
diff --git a/docs/js-client-sdk.md b/docs/js-client-sdk.md
index dabb2c4..660ed7f 100644
--- a/docs/js-client-sdk.md
+++ b/docs/js-client-sdk.md
@@ -164,6 +164,17 @@ This method should be called once on application startup.
Initializes the Eppo precomputed client with configuration parameters. This method should be called once on application startup.
+
+
+
+[setLogLevel(level)](./js-client-sdk.setloglevel.md)
+
+
+ |
+
+Sets the log level for the Eppo SDK logger globally. This affects all logging across the entire SDK, including both EppoJSClient and EppoPrecomputedJSClient instances.
+
+
|
@@ -228,3 +239,29 @@ This interface is used for cases where precomputed assignments are available fro
+## Type Aliases
+
+
+
+Type Alias
+
+
+ |
+
+Description
+
+
+ |
+
+
+[LogLevel](./js-client-sdk.loglevel.md)
+
+
+ |
+
+Valid log levels for the Eppo SDK logger.
+
+
+ |
+
+
diff --git a/docs/js-client-sdk.setloglevel.md b/docs/js-client-sdk.setloglevel.md
new file mode 100644
index 0000000..4478f9f
--- /dev/null
+++ b/docs/js-client-sdk.setloglevel.md
@@ -0,0 +1,54 @@
+
+
+[Home](./index.md) > [@eppo/js-client-sdk](./js-client-sdk.md) > [setLogLevel](./js-client-sdk.setloglevel.md)
+
+## setLogLevel() function
+
+Sets the log level for the Eppo SDK logger globally. This affects all logging across the entire SDK, including both EppoJSClient and EppoPrecomputedJSClient instances.
+
+**Signature:**
+
+```typescript
+export declare function setLogLevel(level: LogLevel): void;
+```
+
+## Parameters
+
+
+
+Parameter
+
+
+ |
+
+Type
+
+
+ |
+
+Description
+
+
+ |
+
+
+level
+
+
+ |
+
+[LogLevel](./js-client-sdk.loglevel.md)
+
+
+ |
+
+The log level to set: - 'trace': Most verbose, logs everything - 'debug': Detailed debugging information - 'info': General informational messages - 'warn': Warning messages (default in production) - 'error': Error messages only - 'silent': Disable all logging
+
+
+ |
+
+
+**Returns:**
+
+void
+
diff --git a/js-client-sdk.api.md b/js-client-sdk.api.md
index 05762c4..4ec328b 100644
--- a/js-client-sdk.api.md
+++ b/js-client-sdk.api.md
@@ -216,6 +216,9 @@ export interface IPrecomputedClientConfigSync {
throwOnFailedInitialization?: boolean;
}
+// @public
+export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
+
// Warning: (ae-internal-missing-underscore) The name "NO_OP_EVENT_DISPATCHER" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal (undocumented)
@@ -232,6 +235,9 @@ export function offlinePrecomputedInit(config: IPrecomputedClientConfigSync): Ep
// @public
export function precomputedInit(config: IPrecomputedClientConfig): Promise;
+// @public
+export function setLogLevel(level: LogLevel): void;
+
// (No @packageDocumentation comment for this package)
```
diff --git a/package.json b/package.json
index b85af90..fa1bdda 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@eppo/js-client-sdk",
- "version": "3.17.0",
+ "version": "3.18.0",
"description": "Eppo SDK for client-side JavaScript applications",
"main": "dist/index.js",
"files": [
@@ -59,7 +59,7 @@
"webpack-cli": "^6.0.1"
},
"dependencies": {
- "@eppo/js-client-sdk-common": "4.15.1",
+ "@eppo/js-client-sdk-common": "4.15.3",
"@types/chrome": "^0.0.313",
"lz-string": "^1.5.0"
},
diff --git a/src/index.spec.ts b/src/index.spec.ts
index b24238f..463de41 100644
--- a/src/index.spec.ts
+++ b/src/index.spec.ts
@@ -1679,9 +1679,15 @@ describe('EppoClient config', () => {
});
expect(client).toBe(EppoPrecomputedJSClient.instance);
- td.verify(applicationLogger.error('[Eppo SDK] Invalid precomputed configuration wire'), {
- times: 1,
- });
+ td.verify(
+ applicationLogger.error(
+ td.matchers.contains({ err: td.matchers.anything() }),
+ '[Eppo SDK] Invalid precomputed configuration wire',
+ ),
+ {
+ times: 1,
+ },
+ );
});
});
diff --git a/src/index.ts b/src/index.ts
index daac6db..cb9eade 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -48,6 +48,12 @@ import LocalStorageBackedNamedEventQueue from './events/local-storage-backed-nam
import { IClientConfig, IPrecomputedClientConfig } from './i-client-config';
import { sdkName, sdkVersion } from './sdk-data';
+/**
+ * Valid log levels for the Eppo SDK logger.
+ * @public
+ */
+export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
+
/**
* Configuration interface for synchronous client initialization.
* @public
@@ -424,12 +430,12 @@ export class EppoJSClient extends EppoClient {
return ConfigLoaderStatus.COMPLETED;
})
- .catch((e) => {
+ .catch((err) => {
applicationLogger.warn(
+ { err },
'Eppo SDK encountered an error initializing from the configuration store',
- e,
);
- initFromConfigStoreError = e;
+ initFromConfigStoreError = err;
return ConfigLoaderStatus.FAILED;
})
.then((status) => {
@@ -457,10 +463,13 @@ export class EppoJSClient extends EppoClient {
return ConfigLoaderStatus.DID_NOT_PRODUCE;
}
})
- .catch((e) => {
- applicationLogger.warn('Eppo SDK encountered an error initializing from fetching', e);
+ .catch((err) => {
+ applicationLogger.warn(
+ { err },
+ 'Eppo SDK encountered an error initializing from fetching',
+ );
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- initFromFetchError = e;
+ initFromFetchError = err;
return ConfigLoaderStatus.FAILED;
})
.then((status) => {
@@ -501,7 +510,7 @@ export class EppoJSClient extends EppoClient {
? initFromConfigStoreError
: new Error('Eppo SDK: No configuration source produced a valid configuration');
}
- applicationLogger.debug('Initialization source', initializationSource);
+ applicationLogger.debug(`Initialization source: ${initializationSource}`);
} catch (error: unknown) {
initializationError = error instanceof Error ? error : new Error(String(error));
}
@@ -544,7 +553,10 @@ export class EppoJSClient extends EppoClient {
memoryOnlyConfigurationStore
.setEntries(config.flagsConfiguration)
.catch((err) =>
- applicationLogger.warn('Error setting flags for memory-only configuration store', err),
+ applicationLogger.warn(
+ { err },
+ 'Error setting flags for memory-only configuration store',
+ ),
);
this.setFlagConfigurationStore(memoryOnlyConfigurationStore);
@@ -591,12 +603,13 @@ export class EppoJSClient extends EppoClient {
forceMemoryOnly: true,
});
this.useCustomAssignmentCache(assignmentCache);
- } catch (error) {
+ } catch (err) {
applicationLogger.warn(
+ { err },
'Eppo SDK encountered an error initializing, assignment calls will return the default value and not be logged',
);
if (throwOnFailedInitialization) {
- throw error;
+ throw err;
}
}
@@ -893,12 +906,12 @@ export function offlinePrecomputedInit(
try {
configurationWire = JSON.parse(config.precomputedConfiguration);
if (!configurationWire.precomputed) throw new Error();
- } catch (error) {
+ } catch (err) {
const errorMessage = 'Invalid precomputed configuration wire';
if (throwOnFailedInitialization) {
throw new Error(errorMessage);
}
- applicationLogger.error(`[Eppo SDK] ${errorMessage}`);
+ applicationLogger.error({ err }, `[Eppo SDK] ${errorMessage}`);
return EppoPrecomputedJSClient.instance;
}
const { subjectKey, subjectAttributes, response } = configurationWire.precomputed;
@@ -909,7 +922,10 @@ export function offlinePrecomputedInit(
memoryOnlyPrecomputedStore
.setEntries(parsedResponse.flags)
.catch((err) =>
- applicationLogger.warn('Error setting precomputed assignments for memory-only store', err),
+ applicationLogger.warn(
+ { err },
+ 'Error setting precomputed assignments for memory-only store',
+ ),
);
memoryOnlyPrecomputedStore.salt = parsedResponse.salt;
@@ -917,7 +933,7 @@ export function offlinePrecomputedInit(
memoryOnlyPrecomputedBanditStore
.setEntries(parsedResponse.bandits)
.catch((err) =>
- applicationLogger.warn('Error setting precomputed bandits for memory-only store', err),
+ applicationLogger.warn({ err }, 'Error setting precomputed bandits for memory-only store'),
);
memoryOnlyPrecomputedBanditStore.salt = parsedResponse.salt;
@@ -963,12 +979,13 @@ export function offlinePrecomputedInit(
EppoPrecomputedJSClient.instance.setBanditLogger(config.banditLogger);
}
EppoPrecomputedJSClient.instance.useCustomAssignmentCache(assignmentCache);
- } catch (error) {
+ } catch (err) {
applicationLogger.warn(
+ { err },
'[Eppo SDK] Encountered an error initializing precomputed client, assignment calls will return the default value and not be logged',
);
if (throwOnFailedInitialization) {
- throw error;
+ throw err;
}
}
@@ -994,6 +1011,25 @@ export function getPrecomputedInstance(): EppoPrecomputedClient {
return EppoPrecomputedJSClient.instance;
}
+/**
+ * Sets the log level for the Eppo SDK logger globally.
+ * This affects all logging across the entire SDK, including both
+ * EppoJSClient and EppoPrecomputedJSClient instances.
+ *
+ * @param level - The log level to set:
+ * - 'trace': Most verbose, logs everything
+ * - 'debug': Detailed debugging information
+ * - 'info': General informational messages
+ * - 'warn': Warning messages (default in production)
+ * - 'error': Error messages only
+ * - 'silent': Disable all logging
+ *
+ * @public
+ */
+export function setLogLevel(level: LogLevel): void {
+ applicationLogger.level = level;
+}
+
function newEventDispatcher(
sdkKey: string,
config: IClientConfig['eventTracking'] = {},
diff --git a/src/isolatable-hybrid.store.ts b/src/isolatable-hybrid.store.ts
index 8ea831b..adea4c3 100644
--- a/src/isolatable-hybrid.store.ts
+++ b/src/isolatable-hybrid.store.ts
@@ -29,8 +29,8 @@ export class IsolatableHybridConfigurationStore extends HybridConfigurationSt
try {
// always update persistent store
await this.persistentStore.setEntries(entries);
- } catch (e) {
- applicationLogger.warn(`Failed to setEntries on persistent store: ${e}`);
+ } catch (err) {
+ applicationLogger.warn({ err }, `Failed to setEntries on persistent store`);
}
}
diff --git a/yarn.lock b/yarn.lock
index 5c7a771..f49467e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -402,10 +402,10 @@
dependencies:
tslib "^2.4.0"
-"@eppo/js-client-sdk-common@4.15.1":
- version "4.15.1"
- resolved "https://registry.yarnpkg.com/@eppo/js-client-sdk-common/-/js-client-sdk-common-4.15.1.tgz#bf2d602b1462eb156224edd73f734a3c99267816"
- integrity sha512-ZVyczDCfAMAnuUlfE293b6h2wfDOcZnfxXHS52r0OU9GktdTYD9EuC3Arpzw4JeTgzV1vW6iTzoz5HDJHwZz6A==
+"@eppo/js-client-sdk-common@4.15.3":
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/@eppo/js-client-sdk-common/-/js-client-sdk-common-4.15.3.tgz#70fa31a240b5b482d3f0d654b16ec946525c26d2"
+ integrity sha512-boO/HetQAN5Qi+MAEzCetNteb+h5J4iC4qUcijaqlxLtWx2hUpAcAgRgUEQ4OpRtXSg3HjIgZWJzmhMj+zyYgg==
dependencies:
buffer "npm:@eppo/buffer@6.2.0"
js-base64 "^3.7.7"
@@ -413,6 +413,7 @@
semver "^7.5.4"
spark-md5 "^3.0.2"
uuid "^11.0.5"
+ yargs "^17.7.2"
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.1"
@@ -1994,6 +1995,15 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2753,11 +2763,6 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
-fast-redact@^3.1.1:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4"
- integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==
-
fast-uri@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241"
@@ -3962,9 +3967,9 @@ jju@~1.4.0:
integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==
js-base64@^3.7.7:
- version "3.7.7"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79"
- integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
+ version "3.7.8"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4"
+ integrity sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==
js-tokens@^4.0.0:
version "4.0.0"
@@ -4573,19 +4578,19 @@ pino-std-serializers@^7.0.0:
integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==
pino@^9.5.0:
- version "9.6.0"
- resolved "https://registry.yarnpkg.com/pino/-/pino-9.6.0.tgz#6bc628159ba0cc81806d286718903b7fc6b13169"
- integrity sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==
+ version "9.13.1"
+ resolved "https://registry.yarnpkg.com/pino/-/pino-9.13.1.tgz#55f0230cf691af42510c6dee08eeaca7319418ea"
+ integrity sha512-Szuj+ViDTjKPQYiKumGmEn3frdl+ZPSdosHyt9SnUevFosOkMY2b7ipxlEctNKPmMD/VibeBI+ZcZCJK+4DPuw==
dependencies:
atomic-sleep "^1.0.0"
- fast-redact "^3.1.1"
on-exit-leak-free "^2.1.0"
pino-abstract-transport "^2.0.0"
pino-std-serializers "^7.0.0"
- process-warning "^4.0.0"
+ process-warning "^5.0.0"
quick-format-unescaped "^4.0.3"
real-require "^0.2.0"
safe-stable-stringify "^2.3.1"
+ slow-redact "^0.3.0"
sonic-boom "^4.0.1"
thread-stream "^3.0.0"
@@ -4637,10 +4642,10 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"
-process-warning@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.1.tgz#5c1db66007c67c756e4e09eb170cdece15da32fb"
- integrity sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==
+process-warning@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7"
+ integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==
prompts@^2.0.1:
version "2.4.2"
@@ -5041,6 +5046,11 @@ slice-ansi@^7.1.0:
ansi-styles "^6.2.1"
is-fullwidth-code-point "^5.0.0"
+slow-redact@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/slow-redact/-/slow-redact-0.3.1.tgz#4cb9ad7011dcba97b8a4b58ce8a5d660243100f6"
+ integrity sha512-NvFvl1GuLZNW4U046Tfi8b26zXo8aBzgCAS2f7yVJR/fArN93mOqSA99cB9uITm92ajSz01bsu1K7SCVVjIMpQ==
+
sonic-boom@^4.0.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d"
@@ -5875,6 +5885,19 @@ yargs@^17.3.1:
y18n "^5.0.5"
yargs-parser "^21.0.0"
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"