Skip to content

Commit

Permalink
Port Python SDK changes (#437)
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris authored Oct 25, 2024
2 parents 5374fc6 + e09a27b commit 67f328e
Show file tree
Hide file tree
Showing 34 changed files with 2,040 additions and 669 deletions.
14 changes: 14 additions & 0 deletions config/clients/python/CHANGELOG.md.mustache
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## v0.7.2

### [0.7.2](https://github.com/openfga/python-sdk/compare/v0.7.1...v0.7.2) (2024-09-22)

This release includes improvements to the OpenTelemetry configuration API introduced in the previous releases

- refactor: improve OpenTelemetry configuration (#127)

This release also includes fixes for several bugs identified in previous releases:

- fix: ensure max_parallel_requests is an int value in batch_check (#132)
- fix: inconsistency in 429 handling between sync/async client (#131)
- fix: ensure telemetry is reported when API exceptions are raised (#127)

## v0.7.1

### [0.7.1](https://github.com/openfga/python-sdk/compare/v0.7.0...v0.7.1) (2024-09-16)
Expand Down
10 changes: 9 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.7.1",
"packageVersion": "0.7.2",
"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 @@ -188,6 +188,10 @@
"destinationFilename": "openfga_sdk/telemetry/telemetry.py",
"templateType": "SupportingFiles"
},
"src/telemetry/utilities.py.mustache": {
"destinationFilename": "openfga_sdk/telemetry/utilities.py",
"templateType": "SupportingFiles"
},
"src/__init__.py.mustache": {
"destinationFilename": "openfga_sdk/__init__.py",
"templateType": "SupportingFiles"
Expand Down Expand Up @@ -281,6 +285,10 @@
"destinationFilename": "test/telemetry/telemetry_test.py",
"templateType": "SupportingFiles"
},
"test/telemetry/utilities_test.py.mustache": {
"destinationFilename": "test/telemetry/utilities_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 @@ -22,7 +22,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
with:
fetch-depth: 0

Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:

- if: matrix.python-version == '3.10'
name: Upload coverage to Codecov
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
continue-on-error: true
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -75,7 +75,7 @@ jobs:
id-token: write # Required for PyPI trusted publishing

steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
with:
fetch-depth: 0

Expand All @@ -98,15 +98,15 @@ jobs:
python setup.py sdist bdist_wheel

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

create-release:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: [publish]

steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
with:
fetch-depth: 0

Expand Down
21 changes: 11 additions & 10 deletions config/clients/python/template/docs/opentelemetry.md.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ If you configure the OpenTelemetry SDK, these metrics will be exported and sent
| `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 |
| `fga-client.request` | Counter | No | Total number of requests made to the FGA server |

### Supported Attributes

Expand All @@ -42,7 +43,7 @@ If you configure the OpenTelemetry SDK, these metrics will be exported and sent
| `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 |
| `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 |
Expand Down Expand Up @@ -102,15 +103,15 @@ configuration = ClientConfiguration(
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,
),
),
),
# If you are comfortable with the default configuration outlined in the tables above, you can omit providing your own TelemetryConfiguration object, as one will be created for you.
telemetry={
"metrics": {
"fga-client.request.duration": {
"fga-client.request.method": True,
"http.response.status_code": True,
},
},
},
)

fga = OpenFgaClient(configuration)
Expand Down
120 changes: 57 additions & 63 deletions config/clients/python/template/example/opentelemetry/main.py.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ 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 All @@ -36,7 +30,7 @@ from {{packageName}}.credentials import (
Credentials,
)
from {{packageName}}.exceptions import FgaValidationException

from {{packageName}}.telemetry.configuration import TelemetryConfiguration

class app:
"""
Expand Down Expand Up @@ -88,62 +82,62 @@ class app:

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,
),
),
)
# Note: the following represents the default configuration values, so unless you want to customize what's reported, you can omit this.
self._telemetry = {
"metrics": {
"fga-client.credentials.request": {
"fga-client.request.client_id": True,
"fga-client.request.method": True,
"fga-client.request.model_id": True,
"fga-client.request.store_id": True,
"fga-client.response.model_id": True,
"fga-client.user": False,
"http.client.request.duration": False,
"http.host": True,
"http.request.method": True,
"http.request.resend_count": True,
"http.response.status_code": True,
"http.server.request.duration": False,
"url.scheme": True,
"url.full": True,
"user_agent.original": True,
},
"fga-client.request.duration": {
"fga-client.request.client_id": True,
"fga-client.request.method": True,
"fga-client.request.model_id": True,
"fga-client.request.store_id": True,
"fga-client.response.model_id": True,
"fga-client.user": False,
"http.client.request.duration": False,
"http.host": True,
"http.request.method": True,
"http.request.resend_count": True,
"http.response.status_code": True,
"http.server.request.duration": False,
"url.scheme": True,
"url.full": True,
"user_agent.original": True,
},
"fga-client.query.duration": {
"fga-client.request.client_id": True,
"fga-client.request.method": True,
"fga-client.request.model_id": True,
"fga-client.request.store_id": True,
"fga-client.response.model_id": True,
"fga-client.user": False,
"http.client.request.duration": False,
"http.host": True,
"http.request.method": True,
"http.request.resend_count": True,
"http.response.status_code": True,
"http.server.request.duration": False,
"url.scheme": True,
"url.full": True,
"user_agent.original": True,
},
}
}

self._configuration.telemetry = self._telemetry

Expand Down
2 changes: 2 additions & 0 deletions config/clients/python/template/src/__init__.py.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ from {{packageName}}.exceptions import ApiException
{{/model}}{{/models}}
from {{packageName}}.telemetry.configuration import (
TelemetryConfiguration,
TelemetryConfigurations,
TelemetryConfigurationType,
TelemetryMetricConfiguration,
TelemetryMetricsConfiguration,
)
Expand Down
40 changes: 9 additions & 31 deletions config/clients/python/template/src/api.py.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class {{classname}}:
if api_client.configuration is not None:
credentials = api_client.configuration.credentials
if credentials is not None and credentials.method == "client_credentials":
self._oauth2_client = OAuth2Client(credentials)
self._oauth2_client = OAuth2Client(
credentials, api_client.configuration
)

self._telemetry = Telemetry()

Expand Down Expand Up @@ -329,38 +331,14 @@ class {{classname}}:
response_types_map = {}
{{/returnType}}

telemetry_attributes: dict[TelemetryAttribute, str] = {
TelemetryAttributes.fga_client_request_method: "{{operationId}}"
telemetry_attributes: dict[TelemetryAttribute, str | int] = {
TelemetryAttributes.fga_client_request_method: "{{operationId}}",
TelemetryAttributes.fga_client_request_store_id: self.api_client.get_store_id(),
TelemetryAttributes.fga_client_request_model_id: local_var_params.get(
"authorization_model_id", ""
),
}

try:
if store_id:
telemetry_attributes[
TelemetryAttributes.fga_client_request_store_id
] = store_id
except:
pass

try:
if body_params.tuple_key:
telemetry_attributes[TelemetryAttributes.fga_client_user] = (
body_params.tuple_key.user
)
except:
pass

try:
if "authorization_model_id" in local_var_params:
telemetry_attributes[
TelemetryAttributes.fga_client_request_model_id
] = local_var_params["authorization_model_id"]
elif body_params.authorization_model_id:
telemetry_attributes[
TelemetryAttributes.fga_client_request_model_id
] = body_params.authorization_model_id
except:
pass

return {{#asyncio}}await ({{/asyncio}}self.api_client.call_api(
'{{{path}}}'.replace('{store_id}', store_id), '{{httpMethod}}',
path_params,
Expand Down
Loading

0 comments on commit 67f328e

Please sign in to comment.