Skip to content

Commit b3225c0

Browse files
committed
fix: OpenTelemetry bugfixes
1 parent 4ecb08f commit b3225c0

4 files changed

Lines changed: 113 additions & 20 deletions

File tree

openfga_sdk/sync/api_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,12 @@ def __call_api(
311311

312312
self._telemetry.metrics().queryDuration(
313313
attributes=_telemetry_attributes,
314-
configuration=self.configuration,
314+
configuration=self.configuration.telemetry,
315315
)
316316

317317
self._telemetry.metrics().requestDuration(
318318
attributes=_telemetry_attributes,
319-
configuration=self.configuration,
319+
configuration=self.configuration.telemetry,
320320
)
321321

322322
if not _preload_content:

openfga_sdk/telemetry/attributes.py

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,69 @@
1111

1212
class TelemetryAttribute(NamedTuple):
1313
name: str
14+
format: str = None
1415

1516

1617
class TelemetryAttributes:
1718
fga_client_request_client_id: TelemetryAttribute = TelemetryAttribute(
1819
name="fga-client.request.client_id",
20+
format="string",
1921
)
2022
fga_client_request_method: TelemetryAttribute = TelemetryAttribute(
2123
name="fga-client.request.method",
24+
format="string",
2225
)
2326
fga_client_request_model_id: TelemetryAttribute = TelemetryAttribute(
2427
name="fga-client.request.model_id",
28+
format="string",
2529
)
2630
fga_client_request_store_id: TelemetryAttribute = TelemetryAttribute(
2731
name="fga-client.request.store_id",
32+
format="string",
2833
)
2934
fga_client_response_model_id: TelemetryAttribute = TelemetryAttribute(
3035
name="fga-client.response.model_id",
36+
format="string",
3137
)
3238
fga_client_user: TelemetryAttribute = TelemetryAttribute(
3339
name="fga-client.user",
40+
format="string",
3441
)
3542
http_client_request_duration: TelemetryAttribute = TelemetryAttribute(
3643
name="http.client.request.duration",
44+
format="int",
3745
)
3846
http_host: TelemetryAttribute = TelemetryAttribute(
3947
name="http.host",
48+
format="string",
4049
)
4150
http_request_method: TelemetryAttribute = TelemetryAttribute(
4251
name="http.request.method",
52+
format="string",
4353
)
4454
http_request_resend_count: TelemetryAttribute = TelemetryAttribute(
4555
name="http.request.resend_count",
56+
format="int",
4657
)
4758
http_response_status_code: TelemetryAttribute = TelemetryAttribute(
4859
name="http.response.status_code",
60+
format="int",
4961
)
5062
http_server_request_duration: TelemetryAttribute = TelemetryAttribute(
5163
name="http.server.request.duration",
64+
format="int",
5265
)
5366
url_scheme: TelemetryAttribute = TelemetryAttribute(
5467
name="url.scheme",
68+
format="string",
5569
)
5670
url_full: TelemetryAttribute = TelemetryAttribute(
5771
name="url.full",
72+
format="string",
5873
)
5974
user_agent_original: TelemetryAttribute = TelemetryAttribute(
6075
name="user_agent.original",
76+
format="string",
6177
)
6278

6379
def prepare(
@@ -67,23 +83,58 @@ def prepare(
6783
) -> dict[str, str | int]:
6884
response = {}
6985

86+
if filter is None or filter == []:
87+
return response
88+
7089
if attributes is not None:
7190
for attribute, value in attributes.items():
72-
if isinstance(attribute, TelemetryAttribute):
73-
if filter is not None and attribute not in filter:
74-
continue
91+
if value is None:
92+
continue
93+
94+
if isinstance(attribute, str):
95+
attributeTranslated = (
96+
attribute.lower().replace("-", "_").replace(".", "_")
97+
)
98+
attributeInstance = getattr(self, attributeTranslated, None)
99+
100+
if attributeInstance is None:
101+
raise ValueError("Invalid attribute specified: %s" % attribute)
75102

76-
response[attribute.name] = value
103+
attribute = attributeInstance
104+
105+
if not isinstance(attribute, TelemetryAttribute):
106+
raise ValueError(
107+
"Invalid attribute specified: %s" % type(attribute)
108+
)
109+
110+
if (
111+
filter is not None
112+
and attribute.name not in filter
113+
and attribute not in filter
114+
):
77115
continue
78116

79-
if attribute in self.__dict__:
80-
if filter is not None and self.__dict__[attribute] not in filter:
117+
if attribute.format == "string":
118+
if not isinstance(value, str):
119+
try:
120+
value = str(value)
121+
except ValueError:
122+
continue
123+
124+
if value == "":
81125
continue
82126

83-
response[self.__dict__[attribute].name] = value
84-
continue
127+
if attribute.format == "int":
128+
if not isinstance(value, int):
129+
try:
130+
value = int(value)
131+
except ValueError:
132+
continue
133+
134+
response[attribute.name] = value
135+
continue
85136

86-
return dict(sorted(response.items()))
137+
return response
87138

88139
def fromRequest(
89140
self,
@@ -114,8 +165,8 @@ def fromRequest(
114165
attributes[self.url_full.name] = url
115166

116167
if start is not None and start > 0:
117-
attributes[self.http_client_request_duration.name] = float(
118-
time.time() - start
168+
attributes[self.http_client_request_duration.name] = int(
169+
(time.time() - start) * 1000
119170
)
120171

121172
if resend_count is not None:

openfga_sdk/telemetry/metrics.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,28 @@ def requestDuration(
122122
configuration = TelemetryConfiguration()
123123

124124
if (
125-
isinstance(configuration, TelemetryMetricsConfiguration) is False
125+
isinstance(configuration, TelemetryConfiguration) is False
126126
or configuration.metrics.histogram_request_duration.enabled is False
127127
or configuration.metrics.histogram_request_duration.attributes() == {}
128128
):
129129
return self.histogram(TelemetryHistograms.request_duration)
130130

131+
if (
132+
value is None
133+
and TelemetryAttributes.http_client_request_duration.name in attributes
134+
):
135+
value = attributes[TelemetryAttributes.http_client_request_duration.name]
136+
attributes.pop(TelemetryAttributes.http_client_request_duration.name, None)
137+
138+
if value is not None:
139+
try:
140+
value = int(value)
141+
attributes[TelemetryAttributes.http_client_request_duration.name] = (
142+
value
143+
)
144+
except ValueError:
145+
value = None
146+
131147
attributes = TelemetryAttributes().prepare(
132148
attributes,
133149
filter=configuration.metrics.histogram_request_duration.attributes(),
@@ -139,6 +155,9 @@ def requestDuration(
139155
):
140156
value = attributes[TelemetryAttributes.http_client_request_duration.name]
141157

158+
if value is None:
159+
return self.histogram(TelemetryHistograms.request_duration)
160+
142161
return self.histogram(TelemetryHistograms.request_duration, value, attributes)
143162

144163
def queryDuration(
@@ -151,21 +170,34 @@ def queryDuration(
151170
configuration = TelemetryConfiguration()
152171

153172
if (
154-
isinstance(configuration, TelemetryMetricsConfiguration) is False
173+
isinstance(configuration, TelemetryConfiguration) is False
155174
or configuration.metrics.histogram_query_duration.enabled is False
156175
or configuration.metrics.histogram_query_duration.attributes() == {}
157176
):
158177
return self.histogram(TelemetryHistograms.query_duration)
159178

160-
attributes = TelemetryAttributes().prepare(
161-
attributes,
162-
filter=configuration.metrics.histogram_query_duration.attributes(),
163-
)
164-
165179
if (
166180
value is None
167181
and TelemetryAttributes.http_server_request_duration.name in attributes
168182
):
169183
value = attributes[TelemetryAttributes.http_server_request_duration.name]
184+
attributes.pop(TelemetryAttributes.http_server_request_duration.name, None)
185+
186+
if value is not None:
187+
try:
188+
value = int(value)
189+
attributes[TelemetryAttributes.http_server_request_duration.name] = (
190+
value
191+
)
192+
except ValueError:
193+
value = None
194+
195+
attributes = TelemetryAttributes().prepare(
196+
attributes,
197+
filter=configuration.metrics.histogram_query_duration.attributes(),
198+
)
199+
200+
if value is None:
201+
return self.histogram(TelemetryHistograms.query_duration)
170202

171203
return self.histogram(TelemetryHistograms.query_duration, value, attributes)

test/telemetry/attributes_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ def test_prepare_with_none_attributes(telemetry_attributes):
4040
assert prepared == {}
4141

4242

43+
def test_prepare_with_invalid_attributes(telemetry_attributes):
44+
attributes = {
45+
"invalid_attribute": "value",
46+
}
47+
filters = [telemetry_attributes.fga_client_request_client_id]
48+
49+
with pytest.raises(ValueError):
50+
telemetry_attributes.prepare(attributes, filter=filters)
51+
52+
4353
def test_from_request_with_all_params(telemetry_attributes):
4454
credentials = Credentials(
4555
method="client_credentials",

0 commit comments

Comments
 (0)