Skip to content

Commit

Permalink
release(python-sdk): v0.7.1 (#415)
Browse files Browse the repository at this point in the history
  • Loading branch information
evansims authored Sep 18, 2024
2 parents 761a8d6 + 079b6e3 commit 1cc4b1b
Show file tree
Hide file tree
Showing 26 changed files with 1,323 additions and 161 deletions.
28 changes: 28 additions & 0 deletions config/clients/python/CHANGELOG.md.mustache
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Changelog

## v0.7.1

### [0.7.1](https://github.com/openfga/python-sdk/compare/v0.7.0...v0.7.1) (2024-09-16)

This release includes fixes for several bugs identified in the previous release related to OpenTelemetry metrics reporting: (#124)

- fix: attribute values are now correctly exported as their intended types (previously, these were all sent as string values)
- fix: `http_client_request_duration` being reported in seconds rather than the intended milliseconds
- fix: sync client mistakenly passing the entire configuration (rather than just the OpenTelemetry configuration as intended) to `queryDuration()` and `requestDuration()`
- fix: some attributes may not have been exported as expected under some conditions
- fix: `queryDuration()` and `requestDuration()` may not have updated their histograms reliably when `attr_http_client_request_duration` or `attr_http_server_request_duration` (respectively) were not enabled (which is the default)

Please note that if you use third-party OpenTelemetry tooling to visualize the attributes mentioned above, you may need to update your queries to account for these changes.

## v0.7.0

### [0.7.0](https://github.com/openfga/python-sdk/compare/v0.6.1...v0.7.0) (2024-08-30)

- feat: enhancements to OpenTelemetry support (#120)

Note this introduces some breaking changes to our metrics:
1. `fga-client.request.method` is now in TitleCase to match the naming conventions in the Protos, e.g. `Check`, `ListObjects`, etc..
2. Due to possible high costs for attributes with high cardinality, we are no longer including the following attributes by default:
* `fga-client.user`
* `http.client.request.duration`
* `http.server.request.duration`
We added configuration options to allow you to set which specific metrics and attributes you care about in case the defaults don't work for your use-case

## v0.6.1

### [0.6.1](https://github.com/openfga/python-sdk/compare/v0.6.0...v0.6.1) (2024-07-31)
Expand Down
30 changes: 29 additions & 1 deletion config/clients/python/config.overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"sdkId": "python",
"gitRepoId": "python-sdk",
"packageName": "openfga_sdk",
"packageVersion": "0.6.1",
"packageVersion": "0.7.1",
"packageDescription": "Python SDK for OpenFGA",
"packageDetailedDescription": "This is an autogenerated python SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api).",
"fossaComplianceNoticeId": "2f8a8629-b46c-435e-b8cd-1174a674fb4b",
Expand Down Expand Up @@ -168,6 +168,10 @@
"destinationFilename": "openfga_sdk/telemetry/attributes.py",
"templateType": "SupportingFiles"
},
"src/telemetry/configuration.py.mustache": {
"destinationFilename": "openfga_sdk/telemetry/configuration.py",
"templateType": "SupportingFiles"
},
"src/telemetry/counters.py.mustache": {
"destinationFilename": "openfga_sdk/telemetry/counters.py",
"templateType": "SupportingFiles"
Expand Down Expand Up @@ -253,6 +257,30 @@
"destinationFilename": "test/sync/oauth2_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/attributes_test.py.mustache": {
"destinationFilename": "test/telemetry/attributes_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/configuration_test.py.mustache": {
"destinationFilename": "test/telemetry/configuration_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/counters_test.py.mustache": {
"destinationFilename": "test/telemetry/counters_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/histograms_test.py.mustache": {
"destinationFilename": "test/telemetry/histograms_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/metrics_test.py.mustache": {
"destinationFilename": "test/telemetry/metrics_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/telemetry_test.py.mustache": {
"destinationFilename": "test/telemetry/telemetry_test.py",
"templateType": "SupportingFiles"
},
"test/__init__.py.mustache": {
"destinationFilename": "test/__init__.py",
"templateType": "SupportingFiles"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
Expand Down Expand Up @@ -80,7 +80,7 @@ jobs:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: "3.10"
cache: "pip"
Expand All @@ -98,7 +98,7 @@ jobs:
python setup.py sdist bdist_wheel

- name: Publish package
uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0
uses: pypa/gh-action-pypi-publish@8a08d616893759ef8e1aa1f2785787c0b97e20d6 # v1.10.0

create-release:
runs-on: ubuntu-latest
Expand Down
138 changes: 112 additions & 26 deletions config/clients/python/template/docs/opentelemetry.md.mustache
Original file line number Diff line number Diff line change
@@ -1,35 +1,121 @@
# OpenTelemetry

This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) that allow you to view data such as request timings. These metrics also include attributes for the model and store ID, as well as the API called to allow you to build reporting.
- [Overview](#overview)
- [Metrics](#metrics)
- [Supported Metrics](#supported-metrics)
- [Supported Attributes](#supported-attributes)
- [Customizing Reporting](#customizing-reporting)
- [Usage](#usage)
- [Installation](#1-install-dependencies)
- [Configure OpenTelemetry](#2-configure-opentelemetry)
- [Configure OpenFGA](#3-configure-openfga)
- [Example Integration](#example-integration)

When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your applications configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent.
## Overview

In cases when metrics events are sent, they will not be viewable outside of infrastructure configured in your application, and are never available to the OpenFGA team or contributors.
This SDK supports [OpenTelemetry](https://opentelemetry.io/) to export [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) that provide insights into your application's performance, such as request timings. These metrics include attributes like model and store IDs, and the API called, which you can use to build detailed reports and dashboards.

If you configure the OpenTelemetry SDK, these metrics will be exported and sent to a collector as specified in your application's configuration. If OpenTelemetry is not configured, metrics functionality is disabled, and no events are sent.

## Metrics

### Supported Metrics

| Metric Name | Type | Description |
| --------------------------------- | --------- | -------------------------------------------------------------------------------- |
| `fga-client.request.duration` | Histogram | The total request time for FGA requests |
| `fga-client.query.duration` | Histogram | The amount of time the FGA server took to process the request |
| ` fga-client.credentials.request` | Counter | The total number of times a new token was requested when using ClientCredentials |

### Supported attributes

| Attribute Name | Type | Description |
| ------------------------------ | -------- | ----------------------------------------------------------------------------------- |
| `fga-client.response.model_id` | `string` | The authorization model ID that the FGA server used |
| `fga-client.request.method` | `string` | The FGA method/action that was performed |
| `fga-client.request.store_id` | `string` | The store ID that was sent as part of the request |
| `fga-client.request.model_id` | `string` | The authorization model ID that was sent as part of the request, if any |
| `fga-client.request.client_id` | `string` | The client ID associated with the request, if any |
| `fga-client.user` | `string` | The user that is associated with the action of the request for check and list users |
| `http.status_code ` | `int` | The status code of the response |
| `http.method` | `string` | The HTTP method for the request |
| `http.host` | `string` | Host identifier of the origin the request was sent to |

## Example

There is an [example project](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory.
| 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

| 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 | Yes | 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 |

## Customizing Reporting

To control which metrics and attributes are reported by the SDK, you can provide your own `TelemetryConfiguration` instance during initialization, as shown in the example above. The `TelemetryConfiguration` class allows you to configure the metrics and attributes that are reported by the SDK, as outlined in [the tables above](#metrics).

## Usage

### 1. Install Dependencies

Install the OpenFGA SDK and OpenTelemetry SDK in your application using `pip`:

```sh
pip install openfga opentelemetry-sdk
```

You must also install an OpenTelemetry exporter; for example, the OTLP gRPC exporter:

```sh
pip install opentelemetry-exporter-otlp-proto-grpc
```

### 2. Configure OpenTelemetry

Configure your application to use OpenTelemetry, and set up the metrics provider to export metrics using an exporter:

```python
from opentelemetry import metrics
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.metrics import MeterProvider

# Configure OpenTelemetry
metrics.set_meter_provider(
MeterProvider(
resource=Resource(attributes={SERVICE_NAME: "openfga-example"}),
metric_readers=[PeriodicExportingMetricReader(OTLPMetricExporter())],
)
)
```

### 3. Configure OpenFGA

Configure the OpenFGA client, and (optionally) customize what metrics and attributes are reported:

```python
from {{packageName}}.telemetry.configuration import (
TelemetryConfiguration,
TelemetryMetricConfiguration,
TelemetryMetricsConfiguration,
)
from {{packageName}} import ClientConfiguration, OpenFgaClient

configuration = ClientConfiguration(
api_url=os.getenv("FGA_API_URL"),
store_id=os.getenv("FGA_STORE_ID"),
authorization_model_id=os.getenv("FGA_AUTHORIZATION_MODEL_ID"),

# If you are comfortable with the default configuration outlined in the tables above, you can omit providing your own TelemetryConfiguration object.
telemetry=TelemetryConfiguration(
metrics=TelemetryMetricsConfiguration(
histogram_request_duration=TelemetryMetricConfiguration(
attr_fga_client_request_method=True,
attr_http_response_status_code=True,
),
),
),
)

fga = OpenFgaClient(configuration)
```

## Example Integration

An [example integration](../example/opentelemetry) is provided that also demonstrates how to configure an application with OpenFGA and OpenTelemetry. Please refer to [the README](../example/opentelemetry/README.md) for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ from opentelemetry.sdk.metrics.export import (
)
from opentelemetry.sdk.resources import SERVICE_NAME, Resource

from {{packageName}}.telemetry.configuration import (
TelemetryConfiguration,
TelemetryMetricConfiguration,
TelemetryMetricsConfiguration,
)

# For usage convenience of this example, we will import the OpenFGA SDK from the parent directory.
sdk_path = os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "..", ".."))
sys.path.insert(0, sdk_path)
Expand Down Expand Up @@ -42,6 +48,7 @@ class app:
client: OpenFgaClient = None,
credentials: Credentials = None,
configuration: ClientConfiguration = None,
telemetry: TelemetryConfiguration = None,
):
"""
Initialize the example with the provided client, credentials, and configuration.
Expand All @@ -50,6 +57,7 @@ class app:
self._client = client
self._credentials = credentials
self._configuration = configuration
self._telemetry = telemetry

async def fga_client(self, env: dict[str, str] = {}) -> OpenFgaClient:
"""
Expand Down Expand Up @@ -78,6 +86,67 @@ class app:
credentials=self._credentials,
)

if not self._telemetry:
# Configure the telemetry metrics to be collected.
# Note: the following represents the default configuration values, so unless you want to change them, you can omit this step.
self._telemetry = TelemetryConfiguration(
metrics=TelemetryMetricsConfiguration(
counter_credentials_request=TelemetryMetricConfiguration(
attr_fga_client_request_client_id=True,
attr_fga_client_request_method=True,
attr_fga_client_request_model_id=True,
attr_fga_client_request_store_id=True,
attr_fga_client_response_model_id=True,
attr_fga_client_user=False,
attr_http_client_request_duration=False,
attr_http_host=True,
attr_http_request_method=True,
attr_http_request_resend_count=True,
attr_http_response_status_code=True,
attr_http_server_request_duration=False,
attr_http_url_scheme=True,
attr_http_url_full=True,
attr_user_agent_original=True,
),
histogram_request_duration=TelemetryMetricConfiguration(
attr_fga_client_request_client_id=True,
attr_fga_client_request_method=True,
attr_fga_client_request_model_id=True,
attr_fga_client_request_store_id=True,
attr_fga_client_response_model_id=True,
attr_fga_client_user=False,
attr_http_client_request_duration=False,
attr_http_host=True,
attr_http_request_method=True,
attr_http_request_resend_count=True,
attr_http_response_status_code=True,
attr_http_server_request_duration=False,
attr_http_url_scheme=True,
attr_http_url_full=True,
attr_user_agent_original=True,
),
histogram_query_duration=TelemetryMetricConfiguration(
attr_fga_client_request_client_id=True,
attr_fga_client_request_method=True,
attr_fga_client_request_model_id=True,
attr_fga_client_request_store_id=True,
attr_fga_client_response_model_id=True,
attr_fga_client_user=False,
attr_http_client_request_duration=False,
attr_http_host=True,
attr_http_request_method=True,
attr_http_request_resend_count=True,
attr_http_response_status_code=True,
attr_http_server_request_duration=False,
attr_http_url_scheme=True,
attr_http_url_full=True,
attr_user_agent_original=True,
),
),
)

self._configuration.telemetry = self._telemetry

if not self._client:
return OpenFgaClient(self._configuration)

Expand Down
Loading

0 comments on commit 1cc4b1b

Please sign in to comment.