From 9af43585a70efc4a6988fd34fb9492198bfb03d1 Mon Sep 17 00:00:00 2001 From: brock-statsig <146870406+brock-statsig@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:12:54 -0800 Subject: [PATCH] other tweaks (#2437) --- docs/client/concepts/initialize.mdx | 49 ++++++++++++++- docs/client/concepts/parameter-stores.mdx | 2 +- docs/faq.mdx | 3 +- docs/guides/private-attributes.mdx | 2 +- docs/guides/uptime.mdx | 2 +- .../monitoring.mdx | 29 ++------- docs/sdks/debugging.mdx | 21 ++++++- docs/sdks/getting-started.md | 4 +- docs/server/concepts/all_assignments.mdx | 2 +- sidebars.ts | 62 ++++++++++--------- 10 files changed, 114 insertions(+), 62 deletions(-) rename docs/{server/concepts => infrastructure}/monitoring.mdx (65%) diff --git a/docs/client/concepts/initialize.mdx b/docs/client/concepts/initialize.mdx index f2b457de3..9ab753b1d 100644 --- a/docs/client/concepts/initialize.mdx +++ b/docs/client/concepts/initialize.mdx @@ -1,6 +1,6 @@ --- -title: Initializing a Client SDK -sidebar_label: Initializing your SDK +title: Initializing SDKs +sidebar_label: Initializing --- One of the first steps in using a Statsig client SDK is to call the asynchronous `initialize()` method in the SDK language of your choice. @@ -104,3 +104,48 @@ evaluated_keys: { /** The hashing algorithm used */ hash_used: string; ``` + + +## Bootstrapping Overview + +Bootstrapping the Client SDKs is a pattern used to provide the precomputed user assignments directly to the SDK for initialization, rather than relying on the default SDK behavior of downloading the configurations over the network from Statsig servers. This approach is beneficial if you're looking to remove the network dependency on Statsig and consolidate the download of the payload into the initial load to reduce latency. + +### Technical details + +With this approach, your server will be responsible for serving the configuration payload to your client app on page load (for web implementations) or during app launch (for mobile implementations). + +This architecture requires running a server SDK that supports the `getClientInitializeResponse` method. +Your server SDK will maintain a fresh configuration in memory and when a request hits your route handler, you should call `getClientInitializeResponse()`, passing in a StatsigUser Object to generate the configuration object that gets passed to the client SDK for synchronous initialization. + +#### Additional Considerations + +* You should pass the same user object on both the server and client side. +* The `initializeValues` option should be an Object. +* This approach allows the client SDK to initialize synchronously. + +## NodeJS example + +_Server-side Node express.js route_ +```js +app.get('/', async (req, res) => { + const userObj = { + userID: user.id + } + const initializeValues = Statsig.getClientInitializeResponse(userObj, null, {hash: "djb2"}); + // render page.hbs using two variables + res.render('page.hbs', { + initializeValues: JSON.stringify(initializeValues), + userObj: JSON.stringify(userObj), + }); +}); +``` + +_Client-side JS within page.hbs_ +```js +// pass both the userObject and initializeValues payloads as Object. +// The triple curly-brace in handlebars will unescape the JSON string +const client = new StatsigClient('' userObj); +client.dataAdapter.setData(bootstrapObject, user); +client.initializeSync(); +``` + diff --git a/docs/client/concepts/parameter-stores.mdx b/docs/client/concepts/parameter-stores.mdx index 700a2f804..432f61b96 100644 --- a/docs/client/concepts/parameter-stores.mdx +++ b/docs/client/concepts/parameter-stores.mdx @@ -1,6 +1,6 @@ --- title: Parameter Stores -sidebar_label: Parameter Stores +sidebar_label: Using Parameter Stores slug: /client/concepts/parameter-stores --- diff --git a/docs/faq.mdx b/docs/faq.mdx index 0cb2c51b0..91ac1a681 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -65,6 +65,7 @@ For details on flushing, check the [Node.js Server SDK documentation](/server/no --- ### I don't see my client or server language listed. Can I still use Statsig? + If none of our current SDKs meet your needs, please let us know via our [Slack community](https://statsig.com/slack)! --- @@ -77,7 +78,7 @@ If you need all hypothetical assignments, you can consider using the `getClientI #### Example of capturing all assignments in Node -Note, this method is designed to [bootstrap](/client/concepts/bootstrapping) client SDKs, and as such, will hash the experiment and feature keys returned in the payload, obfuscating their names for security. You can provide an optional `hash` parameter, allowing you to disable hashing and capture all values in plain text: [Node](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Python](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Java](https://github.com/statsig-io/java-server-sdk/blob/7443c357c78616142de9257af9e4c55c877ca700/src/main/kotlin/com/statsig/sdk/StatsigServer.kt#L83), [Go](https://github.com/statsig-io/go-sdk/blob/3d7edcbe468efb0fc7a04b0d10202243403dce5f/client.go#L282). +Note, this method is designed to [bootstrap](/client/concepts/initialize#bootstrapping-overview) client SDKs, and as such, will hash the experiment and feature keys returned in the payload, obfuscating their names for security. You can provide an optional `hash` parameter, allowing you to disable hashing and capture all values in plain text: [Node](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Python](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Java](https://github.com/statsig-io/java-server-sdk/blob/7443c357c78616142de9257af9e4c55c877ca700/src/main/kotlin/com/statsig/sdk/StatsigServer.kt#L83), [Go](https://github.com/statsig-io/go-sdk/blob/3d7edcbe468efb0fc7a04b0d10202243403dce5f/client.go#L282). ```node const assignments = statsig.getClientInitializeResponse(userObj, "client-key", {hash: "none"}); diff --git a/docs/guides/private-attributes.mdx b/docs/guides/private-attributes.mdx index 0d3f1938c..79dbe92c8 100644 --- a/docs/guides/private-attributes.mdx +++ b/docs/guides/private-attributes.mdx @@ -43,7 +43,7 @@ Evaluation happening locally to the server on `privateAttributes` in the `statsi Don't just take our word for it - all of our SDKs are open source and [available on github](https://github.com/statsig-io). Feel free to dive in to the implementation of `privateAttributes` in the SDK you are using, or reach out to us on [slack](https://www.statsig.com/slack) and we can point you in the right direction. :::info -To ensure that user PII is never transmitted over the network back to Statsig during Client SDK initialization, you should use [Client Boostrapping](/client/concepts/bootstrapping) and provide the `privateAttributes` as part of the user object on the server to the `getClientInitializeResponse()` call. This will generate all of the assignments locally on your server, and these assignments can then be passed as `initializeValues` to the client SDK, negating the need to send any user attributes from the client device to Statsig. +To ensure that user PII is never transmitted over the network back to Statsig during Client SDK initialization, you should use [Client Boostrapping](/client/concepts/initialize#bootstrapping-overview) and provide the `privateAttributes` as part of the user object on the server to the `getClientInitializeResponse()` call. This will generate all of the assignments locally on your server, and these assignments can then be passed as `initializeValues` to the client SDK, negating the need to send any user attributes from the client device to Statsig. ::: ## Event Logging diff --git a/docs/guides/uptime.mdx b/docs/guides/uptime.mdx index dbda5bdb3..d76645a3a 100644 --- a/docs/guides/uptime.mdx +++ b/docs/guides/uptime.mdx @@ -19,7 +19,7 @@ Collected here are a set of best practices that help maximize your uptime - acro 6. Use **change management** on Statsig in production. Changes should be approved by a reviewer. For critical areas, you can enforce an Allowed Reviewer group that has enough context to decide. Statsig Feature Gates allow you to easily audit and roll back changes. -7. **Caching on client SDKs**: Initializing Statsig client SDKs requires them to connect to Statsig and download config. Client SDKs can cache and reuse config (for the same user) if they are offline. You can also choose to bootstrap your client from your own server (and remove the round trip to Statsig) by using [client SDK bootstrapping](/client/concepts/bootstrapping). +7. **Caching on client SDKs**: Initializing Statsig client SDKs requires them to connect to Statsig and download config. Client SDKs can cache and reuse config (for the same user) if they are offline. You can also choose to bootstrap your client from your own server (and remove the round trip to Statsig) by using [client SDK bootstrapping](/client/concepts/initialize#bootstrapping-overview). 8. **Caching on server SDKs**: Initializing Statsig server SDKs requires them to connect to Statsig and download config. If connectivity to Statsig fails, initialization fails (falling back to default values). Remove this dependency when connectivity fails by providing this config locally. Read more about [dataAdapter](/server/concepts/data_store#dataadapter-or-datastore) diff --git a/docs/server/concepts/monitoring.mdx b/docs/infrastructure/monitoring.mdx similarity index 65% rename from docs/server/concepts/monitoring.mdx rename to docs/infrastructure/monitoring.mdx index a14fe018e..e96c8f744 100644 --- a/docs/server/concepts/monitoring.mdx +++ b/docs/infrastructure/monitoring.mdx @@ -1,29 +1,12 @@ --- title: Monitoring the SDK -sidebar_label: SDK Monitoring -slug: /server/concepts/sdk_monitoring +sidebar_label: SDK Monitoring Integrations +slug: /sdk_monitoring --- -Statsig SDKs provide two main ways of monitoring the SDK's behavior and performance: -1. **Logs**: The SDK logs important events and errors to help you understand event-by-event how Statsig is behaving in your application. -2. **Metrics**: The SDK emits metrics to help you understand the aggregate performance of the SDK its impact on your application. - -**Supported SDKs**: Most SDKs have some level of logging, but our latest release of structured logging and metrics, is currently only [available by the Python SDK](/server/pythonSDK/#sdk-monitoring-). - -## Logging Levels and Expected Information -The Statsig SDK uses multiple logging levels to communicate various information types. Here’s what each logging level represents and what kind of details you can expect: - -- Debug: Detailed logs useful for new users onboarding with the SDK and for diagnosing potential issues, such as: - - Messages when a feature gate does not exist - - Tracking process flows within the SDK -- Info: General information about the SDK’s operation, typically relevant to regular usage, such as: - - Messages regarding SDK initialization, including source and version information - - Notifications when the configuration store is populated -- Warning: Logs about unusual events that may impact functionality but are automatically managed and recovered, such as: - - Messages on non critical errors caught by the SDK - - Notifications about reconnection attempts to gRPC services -- Error: Critical logs about issues that severely impact the SDK’s functionality, such as: - - Messages about initialization failures or timeouts - - Notifications indicating gRPC fallback, suggesting gRPC is unavailable or incorrect configuration + +:::note +This latest release of structured logging and metrics, is currently only [available by the Python SDK](/server/pythonSDK/#sdk-monitoring-). Want it in another? Reach out in our [Support Slack](https://statsig.com/slack). +::: ## SDK Metrics Some Statsig SDKs provide built-in metrics to help you monitor its performance and impact on your application. The specific implementation may vary by programming language, refer to the documentation for the language-specific SDK interface. diff --git a/docs/sdks/debugging.mdx b/docs/sdks/debugging.mdx index 59999cea9..8ded8e781 100644 --- a/docs/sdks/debugging.mdx +++ b/docs/sdks/debugging.mdx @@ -1,6 +1,6 @@ --- title: Debugging -sidebar_label: Debugging your SDK +sidebar_label: Debugging slug: /sdk/debugging --- @@ -23,6 +23,23 @@ When debugging why a certain user got a certain value, there are a number of too ![Screen Shot 2023-04-27 at 11 20 14 AM](https://user-images.githubusercontent.com/74584483/234956317-e65f7fd3-d87d-4616-b905-ee4df097863e.png) +### Logging Levels and Expected Information +Log-line feedback is one of the simplest tools you have to understand how your SDK is behaving. Our SDKs have multiple log levels to decide what information you'd like to receive: + +- Debug: Detailed logs useful for new users onboarding with the SDK and for diagnosing potential issues, such as: + - Messages when a feature gate does not exist + - Tracking process flows within the SDK +- Info: General information about the SDK’s operation, typically relevant to regular usage, such as: + - Messages regarding SDK initialization, including source and version information + - Notifications when the configuration store is populated +- Warning: Logs about unusual events that may impact functionality but are automatically managed and recovered, such as: + - Messages on non critical errors caught by the SDK + - Notifications about reconnection attempts to gRPC services +- Error: Critical logs about issues that severely impact the SDK’s functionality, such as: + - Messages about initialization failures or timeouts + - Notifications indicating gRPC fallback, suggesting gRPC is unavailable or incorrect configuration + + ## Evaluation Details @@ -70,7 +87,7 @@ When debugging why a certain user got a certain value, there are a number of too For example: `Network:Recognized` means the sdk had up to date values from a successful initialization network request, and the gate/config/experiment you were checking was defined in the payload. - If you are not sure why a config was not included (resulting in an "Unrecognized" source), it could be excluded due to [Target Apps](/sdk-keys/target-apps), or [Client Bootstrapping](/client/concepts/bootstrapping). + If you are not sure why a config was not included (resulting in an "Unrecognized" source), it could be excluded due to [Target Apps](/sdk-keys/target-apps), or [Client Bootstrapping](/client/concepts/initialize#bootstrapping-overview). diff --git a/docs/sdks/getting-started.md b/docs/sdks/getting-started.md index 6b46900e7..d4d0f2f97 100644 --- a/docs/sdks/getting-started.md +++ b/docs/sdks/getting-started.md @@ -1,6 +1,6 @@ --- -title: Getting Started with Statsig's SDKs -sidebar_label: Getting Started +title: SDK Overview +sidebar_label: SDK Overview slug: /sdks/getting-started --- diff --git a/docs/server/concepts/all_assignments.mdx b/docs/server/concepts/all_assignments.mdx index e83b1f84a..93ac075d9 100644 --- a/docs/server/concepts/all_assignments.mdx +++ b/docs/server/concepts/all_assignments.mdx @@ -15,7 +15,7 @@ For this use-case, we recommend using the `getClientInitializeResponse` server s #### Example of capturing all assignments in Node -Note that this method is designed to [bootstrap](/client/concepts/bootstrapping) the client SDKs, and as such, will hash the experiment and feature keys returned in the payload, obfuscating their names to mitigate the possibility of end-users spoofing into features & gates. You can now provide an optional `hash` parameter, allowing you to disable hashing and capture all group names and values in plain text — [Node](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Python](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Java](https://github.com/statsig-io/java-server-sdk/blob/7443c357c78616142de9257af9e4c55c877ca700/src/main/kotlin/com/statsig/sdk/StatsigServer.kt#L83), [Go](https://github.com/statsig-io/go-sdk/blob/3d7edcbe468efb0fc7a04b0d10202243403dce5f/client.go#L282). +Note that this method is designed to [bootstrap](/client/concepts/initialize#bootstrapping-overview) the client SDKs, and as such, will hash the experiment and feature keys returned in the payload, obfuscating their names to mitigate the possibility of end-users spoofing into features & gates. You can now provide an optional `hash` parameter, allowing you to disable hashing and capture all group names and values in plain text — [Node](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Python](https://github.com/statsig-io/node-js-server-sdk/blob/ea116142221c1aa83b46eff8b5f2292c8f8e2d54/src/StatsigServer.ts#L597), [Java](https://github.com/statsig-io/java-server-sdk/blob/7443c357c78616142de9257af9e4c55c877ca700/src/main/kotlin/com/statsig/sdk/StatsigServer.kt#L83), [Go](https://github.com/statsig-io/go-sdk/blob/3d7edcbe468efb0fc7a04b0d10202243403dce5f/client.go#L282). ```node const assignments = statsig.getClientInitializeResponse(userObj, "client-key", {hash: "none"}); diff --git a/sidebars.ts b/sidebars.ts index b66288c31..f72e8ba0e 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -35,6 +35,7 @@ const sidebars: SidebarsConfig = { className: "lightbulb-icon sidebar-icon", items: [ "understanding-platform", + "client/concepts/parameter-stores", "guides/first-device-level-experiment", "guides/experiment-on-custom-id-types", "guides/using-environments", @@ -55,23 +56,10 @@ const sidebars: SidebarsConfig = { className: "doc-icon sidebar-icon", items: [ "sdks/getting-started", - { - Concepts: [ - "sdks/client-vs-server", - "server/concepts/user", - "client/concepts/initialize", - "sdks/debugging", - "server/concepts/monitoring", - "client/concepts/bootstrapping", - "client/concepts/persistent_assignment", - "client/concepts/parameter-stores", - "server/concepts/data_store", - "server/concepts/persistent_assignment", - "sdk-keys/api-keys", - "sdk-keys/target-apps", - "server/deprecation-notices", - ], - }, + "sdks/client-vs-server", + "server/concepts/user", + "client/concepts/initialize", + "sdks/debugging", { className: "html-icon sidebar-icon sdk-sidebar-icon", type: "doc", @@ -239,16 +227,7 @@ const sidebars: SidebarsConfig = { ] }, - { - type: "category", - label: "Other Frameworks", - items: [ - "guides/node-express-feature-flags", - "guides/node-express-abtests", - "guides/python-flask-feature-flags", - "guides/python-flask-abtests", - ], - }, + { type: "category", label: "Azure AI", @@ -265,6 +244,28 @@ const sidebars: SidebarsConfig = { "azureai/running-experiments", ], }, + { + type: "category", + label: "Advanced SDK Methods", + items: [ + { + type: "category", + label: "Other Frameworks", + items: [ + "guides/node-express-feature-flags", + "guides/node-express-abtests", + "guides/python-flask-feature-flags", + "guides/python-flask-abtests", + ], + }, + "client/concepts/persistent_assignment", + "server/concepts/persistent_assignment", + "server/concepts/data_store", + "sdk-keys/target-apps", + + ] + }, + "server/deprecation-notices", ], }, { @@ -936,6 +937,7 @@ const sidebars: SidebarsConfig = { label: "Workspace Management", items: [ "access-management/introduction", + "sdk-keys/api-keys", { Workspace: [ "access-management/organizations", @@ -1049,7 +1051,11 @@ const sidebars: SidebarsConfig = { ], }, { - Reliability: ["infrastructure/reliability-faq", "guides/uptime"], + Reliability: [ + "infrastructure/reliability-faq", + "guides/uptime", + "infrastructure/monitoring", + ], }, ], },