From f38bf22d95972dc8bbf78e5853edca45b212f613 Mon Sep 17 00:00:00 2001 From: Evan Sims Date: Fri, 27 Sep 2024 19:58:20 -0500 Subject: [PATCH] docs: add OpenTelemetry documentation (#851) --- .../getting-started/configure-telemetry.mdx | 293 ++++++++++++++++++ docs/sidebars.js | 21 +- 2 files changed, 306 insertions(+), 8 deletions(-) create mode 100644 docs/content/getting-started/configure-telemetry.mdx diff --git a/docs/content/getting-started/configure-telemetry.mdx b/docs/content/getting-started/configure-telemetry.mdx new file mode 100644 index 000000000..902efa4aa --- /dev/null +++ b/docs/content/getting-started/configure-telemetry.mdx @@ -0,0 +1,293 @@ +--- +title: Configure SDK Client Telemetry +description: How to configure your SDK Client to collect telemetry using OpenTelemetry. +slug: /getting-started/configure-telemetry +--- + +import { + AuthzModelSnippetViewer, + DocumentationNotice, + languageLabelMap, + ProductConcept, + ProductName, + ProductNameFormat, + RelatedSection, + SdkSetupPrerequisite, + SupportedLanguage, + WriteAuthzModelViewer, +} from '@components/Docs'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Configure SDK Client Telemetry + + + +The SDK Client supports telemetry data collection using [OpenTelemetry](https://opentelemetry.io). + +## Enabling Telemetry + +1. [Install the SDK Client](./install-sdk.mdx) +2. [Setup OpenTelemetry](https://opentelemetry.io/docs/getting-started/) +3. Install the OpenTelemetry SDK dependencies for your application +4. Instantiate the OpenTelemetry SDK in your application + +Once you have completed these steps, the SDK Client will automatically collect telemetry data using your application's OpenTelemetry configuration. + +## Customizing Telemetry + +The SDK Client will automatically use [a default configuration](#supported-metrics) for telemetry collection. You can provide your own configuration to include additional metrics or to exclude metrics that are not relevant to your application. + + + + +```typescript +import 'dotenv/config'; +import { OpenFgaClient, TelemetryAttribute, TelemetryConfiguration, TelemetryMetric } from '@openfga/sdk'; + +const telemetryConfig = { + metrics: { + [TelemetryMetric.CounterCredentialsRequest]: { + attributes: new Set([ + TelemetryAttribute.UrlScheme, + TelemetryAttribute.UserAgentOriginal, + TelemetryAttribute.HttpRequestMethod, + TelemetryAttribute.FgaClientRequestClientId, + TelemetryAttribute.FgaClientRequestStoreId, + TelemetryAttribute.FgaClientRequestModelId, + TelemetryAttribute.HttpRequestResendCount, + ]), + }, + [TelemetryMetric.HistogramRequestDuration]: { + attributes: new Set([ + TelemetryAttribute.HttpResponseStatusCode, + TelemetryAttribute.UserAgentOriginal, + TelemetryAttribute.FgaClientRequestMethod, + TelemetryAttribute.FgaClientRequestClientId, + TelemetryAttribute.FgaClientRequestStoreId, + TelemetryAttribute.FgaClientRequestModelId, + TelemetryAttribute.HttpRequestResendCount, + ]), + }, + [TelemetryMetric.HistogramQueryDuration]: { + attributes: new Set([ + TelemetryAttribute.HttpResponseStatusCode, + TelemetryAttribute.UserAgentOriginal, + TelemetryAttribute.FgaClientRequestMethod, + TelemetryAttribute.FgaClientRequestClientId, + TelemetryAttribute.FgaClientRequestStoreId, + TelemetryAttribute.FgaClientRequestModelId, + TelemetryAttribute.HttpRequestResendCount, + ]), + }, + }, +}; + +const fgaClient = new OpenFgaClient({ + telemetry: telemetryConfig, + // ... +}); +``` + + + + + +```go +import ( + "github.com/openfga/go-sdk/client" + "github.com/openfga/go-sdk/telemetry" +) + +otel := telemetry.Configuration{ + Metrics: &telemetry.MetricsConfiguration{ + METRIC_COUNTER_CREDENTIALS_REQUEST: &telemetry.MetricConfiguration{ + ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, + }, + METRIC_HISTOGRAM_REQUEST_DURATION: &telemetry.MetricConfiguration{ + ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, + }, + METRIC_HISTOGRAM_QUERY_DURATION: &telemetry.MetricConfiguration{ + ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, + ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, + }, + }, +} + +fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ + Telemetry: &otel, + // ... +}) +``` + + + + + +```csharp +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; +using OpenFga.Sdk.Telemetry; + +TelemetryConfig telemetryConfig = new TelemetryConfig() { + Metrics = new Dictionary { + [TelemetryMeter.RequestDuration] = new () { + Attributes = new HashSet { + TelemetryAttribute.HttpStatus, + TelemetryAttribute.HttpUserAgent, + TelemetryAttribute.RequestMethod, + TelemetryAttribute.RequestClientId, + TelemetryAttribute.RequestStoreId, + TelemetryAttribute.RequestModelId, + TelemetryAttribute.RequestRetryCount, + }, + }, + }, +}; + +var configuration = new ClientConfiguration { + Telemetry = telemetryConfig, + // ... +}; + +var fgaClient = new OpenFgaClient(configuration); +``` + + + + + +```python +from openfga_sdk import ( + ClientConfiguration, + OpenFgaClient, +) + +telemetry_config: dict[str, dict[str, dict[str, bool]]] = { + "metrics": { + "fga-client.request.duration": { + "fga-client.request.model_id": False, + "fga-client.response.model_id": False, + "fga-client.user": True, + "http.client.request.duration": True, + "http.server.request.duration": True, + }, + }, +} + +configuration = ClientConfiguration( + telemetry=telemetry_config, + // ... +) + +with OpenFgaClient(configuration) as fga_client: + # ... +``` + + + + + +```java +import dev.openfga.sdk.api.client.ApiClient; +import dev.openfga.sdk.api.configuration.ClientConfiguration; +import dev.openfga.sdk.api.configuration.TelemetryConfiguration; + +Map> attributes = new HashMap<>(); +attributes.put(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, Optional.empty()); +attributes.put(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty()); +attributes.put(Attributes.FGA_CLIENT_REQUEST_MODEL_ID, Optional.empty()); +attributes.put(Attributes.FGA_CLIENT_REQUEST_STORE_ID, Optional.empty()); +attributes.put(Attributes.FGA_CLIENT_RESPONSE_MODEL_ID, Optional.empty()); +attributes.put(Attributes.HTTP_HOST, Optional.empty()); +attributes.put(Attributes.HTTP_REQUEST_METHOD, Optional.empty()); +attributes.put(Attributes.HTTP_REQUEST_RESEND_COUNT, Optional.empty()); +attributes.put(Attributes.HTTP_RESPONSE_STATUS_CODE, Optional.empty()); +attributes.put(Attributes.URL_FULL, Optional.empty()); +attributes.put(Attributes.URL_SCHEME, Optional.empty()); +attributes.put(Attributes.USER_AGENT, Optional.empty()); + +Map>> metrics = new HashMap<>(); +metrics.put(Counters.CREDENTIALS_REQUEST, attributes); +metrics.put(Histograms.QUERY_DURATION, attributes); +metrics.put(Histograms.REQUEST_DURATION, attributes); + +ClientConfiguration config = new ClientConfiguration() + // ... + .telemetryConfiguration(new TelemetryConfiguration(metrics); + +OpenFgaClient fgaClient = new OpenFgaClient(config); +``` + + + + +## Examples + +We provide example applications for using telemetry with the SDK Client. + +- [Node.js](https://github.com/openfga/js-sdk/tree/main/example/opentelemetry) +- [Go](https://github.com/openfga/go-sdk/tree/main/example/opentelemetry) +- [.NET](https://github.com/openfga/dotnet-sdk/tree/main/example/OpenTelemetryExample) +- [Python](https://github.com/openfga/python-sdk/tree/main/example/opentelemetry) + +## Supported Metrics + +The SDK Client can collect the following metrics: + +| Metric Name | Type | Enabled by Default | Description | +| -------------------------------- | --------- | ------------------ | --------------------------------------------------------------------------------- | +| `fga-client.request.duration` | Histogram | Yes | Total request time for FGA requests, in milliseconds | +| `fga-client.query.duration` | Histogram | Yes | Time taken by the FGA server to process and evaluate the request, in milliseconds | +| `fga-client.credentials.request` | Counter | Yes | Total number of new token requests initiated using the Client Credentials flow | + +## Supported Attributes + +The SDK Client can collect the following attributes: + +| Attribute Name | Type | Enabled by Default | Description | +| ------------------------------ | ------ | ------------------ | --------------------------------------------------------------------------------- | +| `fga-client.request.client_id` | string | Yes | Client ID associated with the request, if any | +| `fga-client.request.method` | string | Yes | FGA method/action that was performed (e.g., Check, ListObjects) in TitleCase | +| `fga-client.request.model_id` | string | Yes | Authorization model ID that was sent as part of the request, if any | +| `fga-client.request.store_id` | string | Yes | Store ID that was sent as part of the request | +| `fga-client.response.model_id` | string | Yes | Authorization model ID that the FGA server used | +| `fga-client.user` | string | No | User associated with the action of the request for check and list users | +| `http.client.request.duration` | int | No | Duration for the SDK to complete the request, in milliseconds | +| `http.host` | string | Yes | Host identifier of the origin the request was sent to | +| `http.request.method` | string | Yes | HTTP method for the request | +| `http.request.resend_count` | int | Yes | Number of retries attempted, if any | +| `http.response.status_code` | int | Yes | Status code of the response (e.g., `200` for success) | +| `http.server.request.duration` | int | No | Time taken by the FGA server to process and evaluate the request, in milliseconds | +| `url.scheme` | string | Yes | HTTP scheme of the request (`http`/`https`) | +| `url.full` | string | Yes | Full URL of the request | +| `user_agent.original` | string | Yes | User Agent used in the query | diff --git a/docs/sidebars.js b/docs/sidebars.js index 8a6603236..a1db7d36c 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -38,7 +38,7 @@ const sidebars = { label: 'Setup OpenFGA', link: { type: 'doc', - id: 'content/getting-started/setup-openfga/overview' + id: 'content/getting-started/setup-openfga/overview', }, items: [ { @@ -60,8 +60,8 @@ const sidebars = { type: 'doc', label: 'Playground', id: 'content/getting-started/setup-openfga/playground', - } - ] + }, + ], }, { type: 'doc', @@ -127,7 +127,12 @@ const sidebars = { type: 'doc', label: 'Implementation Best Practices', id: 'content/getting-started/tuples-api-best-practices', - } + }, + { + type: 'doc', + label: 'Configure SDK Client Telemetry', + id: 'content/getting-started/configure-telemetry', + }, ], }, { @@ -207,12 +212,12 @@ const sidebars = { }, { type: 'doc', - label: "Testing Models", + label: 'Testing Models', id: 'content/modeling/testing-models', }, { type: 'doc', - label: "Modular Models", + label: 'Modular Models', id: 'content/modeling/modular-models', }, { @@ -292,7 +297,7 @@ const sidebars = { link: { type: 'doc', id: 'content/modeling/migrating/overview', - }, + }, items: [ { type: 'doc', @@ -345,7 +350,7 @@ const sidebars = { }, { type: 'doc', - label: "Relationship Queries", + label: 'Relationship Queries', id: 'content/interacting/relationship-queries', }, {