opentelemetry-instrumentation-aiohttp-client 0.54b0__py3-none-any.whl → 0.55b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -90,7 +90,9 @@ API
90
90
 
91
91
  import types
92
92
  import typing
93
+ from timeit import default_timer
93
94
  from typing import Collection
95
+ from urllib.parse import urlparse
94
96
 
95
97
  import aiohttp
96
98
  import wrapt
@@ -99,11 +101,20 @@ import yarl
99
101
  from opentelemetry import context as context_api
100
102
  from opentelemetry import trace
101
103
  from opentelemetry.instrumentation._semconv import (
104
+ HTTP_DURATION_HISTOGRAM_BUCKETS_NEW,
105
+ HTTP_DURATION_HISTOGRAM_BUCKETS_OLD,
106
+ _client_duration_attrs_new,
107
+ _client_duration_attrs_old,
108
+ _filter_semconv_duration_attrs,
102
109
  _get_schema_url,
103
110
  _OpenTelemetrySemanticConventionStability,
104
111
  _OpenTelemetryStabilitySignalType,
105
112
  _report_new,
113
+ _report_old,
114
+ _set_http_host_client,
106
115
  _set_http_method,
116
+ _set_http_net_peer_name_client,
117
+ _set_http_peer_port_client,
107
118
  _set_http_url,
108
119
  _set_status,
109
120
  _StabilityMode,
@@ -115,8 +126,13 @@ from opentelemetry.instrumentation.utils import (
115
126
  is_instrumentation_enabled,
116
127
  unwrap,
117
128
  )
129
+ from opentelemetry.metrics import MeterProvider, get_meter
118
130
  from opentelemetry.propagate import inject
119
131
  from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
132
+ from opentelemetry.semconv.metrics import MetricInstruments
133
+ from opentelemetry.semconv.metrics.http_metrics import (
134
+ HTTP_CLIENT_REQUEST_DURATION,
135
+ )
120
136
  from opentelemetry.trace import Span, SpanKind, TracerProvider, get_tracer
121
137
  from opentelemetry.trace.status import Status, StatusCode
122
138
  from opentelemetry.util.http import remove_url_credentials, sanitize_method
@@ -172,11 +188,14 @@ def _set_http_status_code_attribute(
172
188
  )
173
189
 
174
190
 
191
+ # pylint: disable=too-many-locals
192
+ # pylint: disable=too-many-statements
175
193
  def create_trace_config(
176
194
  url_filter: _UrlFilterT = None,
177
195
  request_hook: _RequestHookT = None,
178
196
  response_hook: _ResponseHookT = None,
179
197
  tracer_provider: TracerProvider = None,
198
+ meter_provider: MeterProvider = None,
180
199
  sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
181
200
  ) -> aiohttp.TraceConfig:
182
201
  """Create an aiohttp-compatible trace configuration.
@@ -205,6 +224,7 @@ def create_trace_config(
205
224
  :param Callable request_hook: Optional callback that can modify span name and request params.
206
225
  :param Callable response_hook: Optional callback that can modify span name and response params.
207
226
  :param tracer_provider: optional TracerProvider from which to get a Tracer
227
+ :param meter_provider: optional Meter provider to use
208
228
 
209
229
  :return: An object suitable for use with :py:class:`aiohttp.ClientSession`.
210
230
  :rtype: :py:class:`aiohttp.TraceConfig`
@@ -214,20 +234,70 @@ def create_trace_config(
214
234
  # Explicitly specify the type for the `request_hook` and `response_hook` param and rtype to work
215
235
  # around this issue.
216
236
 
237
+ schema_url = _get_schema_url(sem_conv_opt_in_mode)
238
+
217
239
  tracer = get_tracer(
218
240
  __name__,
219
241
  __version__,
220
242
  tracer_provider,
221
- schema_url=_get_schema_url(sem_conv_opt_in_mode),
243
+ schema_url=schema_url,
244
+ )
245
+
246
+ meter = get_meter(
247
+ __name__,
248
+ __version__,
249
+ meter_provider,
250
+ schema_url,
222
251
  )
223
252
 
224
- # TODO: Use this when we have durations for aiohttp-client
253
+ start_time = 0
254
+
255
+ duration_histogram_old = None
256
+ if _report_old(sem_conv_opt_in_mode):
257
+ duration_histogram_old = meter.create_histogram(
258
+ name=MetricInstruments.HTTP_CLIENT_DURATION,
259
+ unit="ms",
260
+ description="measures the duration of the outbound HTTP request",
261
+ explicit_bucket_boundaries_advisory=HTTP_DURATION_HISTOGRAM_BUCKETS_OLD,
262
+ )
263
+ duration_histogram_new = None
264
+ if _report_new(sem_conv_opt_in_mode):
265
+ duration_histogram_new = meter.create_histogram(
266
+ name=HTTP_CLIENT_REQUEST_DURATION,
267
+ unit="s",
268
+ description="Duration of HTTP client requests.",
269
+ explicit_bucket_boundaries_advisory=HTTP_DURATION_HISTOGRAM_BUCKETS_NEW,
270
+ )
271
+
225
272
  metric_attributes = {}
226
273
 
227
274
  def _end_trace(trace_config_ctx: types.SimpleNamespace):
275
+ elapsed_time = max(default_timer() - trace_config_ctx.start_time, 0)
228
276
  context_api.detach(trace_config_ctx.token)
229
277
  trace_config_ctx.span.end()
230
278
 
279
+ if trace_config_ctx.duration_histogram_old is not None:
280
+ duration_attrs_old = _filter_semconv_duration_attrs(
281
+ metric_attributes,
282
+ _client_duration_attrs_old,
283
+ _client_duration_attrs_new,
284
+ _StabilityMode.DEFAULT,
285
+ )
286
+ trace_config_ctx.duration_histogram_old.record(
287
+ max(round(elapsed_time * 1000), 0),
288
+ attributes=duration_attrs_old,
289
+ )
290
+ if trace_config_ctx.duration_histogram_new is not None:
291
+ duration_attrs_new = _filter_semconv_duration_attrs(
292
+ metric_attributes,
293
+ _client_duration_attrs_old,
294
+ _client_duration_attrs_new,
295
+ _StabilityMode.HTTP,
296
+ )
297
+ trace_config_ctx.duration_histogram_new.record(
298
+ elapsed_time, attributes=duration_attrs_new
299
+ )
300
+
231
301
  async def on_request_start(
232
302
  unused_session: aiohttp.ClientSession,
233
303
  trace_config_ctx: types.SimpleNamespace,
@@ -237,6 +307,7 @@ def create_trace_config(
237
307
  trace_config_ctx.span = None
238
308
  return
239
309
 
310
+ trace_config_ctx.start_time = default_timer()
240
311
  method = params.method
241
312
  request_span_name = _get_span_name(method)
242
313
  request_url = (
@@ -252,8 +323,44 @@ def create_trace_config(
252
323
  sanitize_method(method),
253
324
  sem_conv_opt_in_mode,
254
325
  )
326
+ _set_http_method(
327
+ metric_attributes,
328
+ method,
329
+ sanitize_method(method),
330
+ sem_conv_opt_in_mode,
331
+ )
255
332
  _set_http_url(span_attributes, request_url, sem_conv_opt_in_mode)
256
333
 
334
+ try:
335
+ parsed_url = urlparse(request_url)
336
+ if parsed_url.hostname:
337
+ _set_http_host_client(
338
+ metric_attributes,
339
+ parsed_url.hostname,
340
+ sem_conv_opt_in_mode,
341
+ )
342
+ _set_http_net_peer_name_client(
343
+ metric_attributes,
344
+ parsed_url.hostname,
345
+ sem_conv_opt_in_mode,
346
+ )
347
+ if _report_new(sem_conv_opt_in_mode):
348
+ _set_http_host_client(
349
+ span_attributes,
350
+ parsed_url.hostname,
351
+ sem_conv_opt_in_mode,
352
+ )
353
+ if parsed_url.port:
354
+ _set_http_peer_port_client(
355
+ metric_attributes, parsed_url.port, sem_conv_opt_in_mode
356
+ )
357
+ if _report_new(sem_conv_opt_in_mode):
358
+ _set_http_peer_port_client(
359
+ span_attributes, parsed_url.port, sem_conv_opt_in_mode
360
+ )
361
+ except ValueError:
362
+ pass
363
+
257
364
  trace_config_ctx.span = trace_config_ctx.tracer.start_span(
258
365
  request_span_name, kind=SpanKind.CLIENT, attributes=span_attributes
259
366
  )
@@ -298,6 +405,7 @@ def create_trace_config(
298
405
  exc_type = type(params.exception).__qualname__
299
406
  if _report_new(sem_conv_opt_in_mode):
300
407
  trace_config_ctx.span.set_attribute(ERROR_TYPE, exc_type)
408
+ metric_attributes[ERROR_TYPE] = exc_type
301
409
 
302
410
  trace_config_ctx.span.set_status(
303
411
  Status(StatusCode.ERROR, exc_type)
@@ -312,7 +420,12 @@ def create_trace_config(
312
420
  def _trace_config_ctx_factory(**kwargs):
313
421
  kwargs.setdefault("trace_request_ctx", {})
314
422
  return types.SimpleNamespace(
315
- tracer=tracer, url_filter=url_filter, **kwargs
423
+ tracer=tracer,
424
+ url_filter=url_filter,
425
+ start_time=start_time,
426
+ duration_histogram_old=duration_histogram_old,
427
+ duration_histogram_new=duration_histogram_new,
428
+ **kwargs,
316
429
  )
317
430
 
318
431
  trace_config = aiohttp.TraceConfig(
@@ -328,6 +441,7 @@ def create_trace_config(
328
441
 
329
442
  def _instrument(
330
443
  tracer_provider: TracerProvider = None,
444
+ meter_provider: MeterProvider = None,
331
445
  url_filter: _UrlFilterT = None,
332
446
  request_hook: _RequestHookT = None,
333
447
  response_hook: _ResponseHookT = None,
@@ -357,6 +471,7 @@ def _instrument(
357
471
  request_hook=request_hook,
358
472
  response_hook=response_hook,
359
473
  tracer_provider=tracer_provider,
474
+ meter_provider=meter_provider,
360
475
  sem_conv_opt_in_mode=sem_conv_opt_in_mode,
361
476
  )
362
477
  trace_config._is_instrumented_by_opentelemetry = True
@@ -401,6 +516,7 @@ class AioHttpClientInstrumentor(BaseInstrumentor):
401
516
  Args:
402
517
  **kwargs: Optional arguments
403
518
  ``tracer_provider``: a TracerProvider, defaults to global
519
+ ``meter_provider``: a MeterProvider, defaults to global
404
520
  ``url_filter``: A callback to process the requested URL prior to adding
405
521
  it as a span attribute. This can be useful to remove sensitive data
406
522
  such as API keys or user personal information.
@@ -415,6 +531,7 @@ class AioHttpClientInstrumentor(BaseInstrumentor):
415
531
  )
416
532
  _instrument(
417
533
  tracer_provider=kwargs.get("tracer_provider"),
534
+ meter_provider=kwargs.get("meter_provider"),
418
535
  url_filter=kwargs.get("url_filter"),
419
536
  request_hook=kwargs.get("request_hook"),
420
537
  response_hook=kwargs.get("response_hook"),
@@ -15,6 +15,6 @@
15
15
 
16
16
  _instruments = ("aiohttp ~= 3.0",)
17
17
 
18
- _supports_metrics = False
18
+ _supports_metrics = True
19
19
 
20
20
  _semconv_status = "migration"
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "0.54b0"
15
+ __version__ = "0.55b0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opentelemetry-instrumentation-aiohttp-client
3
- Version: 0.54b0
3
+ Version: 0.55b0
4
4
  Summary: OpenTelemetry aiohttp client instrumentation
5
5
  Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-aiohttp-client
6
6
  Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib
@@ -12,17 +12,16 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.8
16
15
  Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
- Requires-Python: >=3.8
20
+ Requires-Python: >=3.9
22
21
  Requires-Dist: opentelemetry-api~=1.12
23
- Requires-Dist: opentelemetry-instrumentation==0.54b0
24
- Requires-Dist: opentelemetry-semantic-conventions==0.54b0
25
- Requires-Dist: opentelemetry-util-http==0.54b0
22
+ Requires-Dist: opentelemetry-instrumentation==0.55b0
23
+ Requires-Dist: opentelemetry-semantic-conventions==0.55b0
24
+ Requires-Dist: opentelemetry-util-http==0.55b0
26
25
  Requires-Dist: wrapt<2.0.0,>=1.0.0
27
26
  Provides-Extra: instruments
28
27
  Requires-Dist: aiohttp~=3.0; extra == 'instruments'
@@ -0,0 +1,8 @@
1
+ opentelemetry/instrumentation/aiohttp_client/__init__.py,sha256=rLi7n_y4XtF1Lv_GAtAz1b5ku7JWDvm_elAA18MkLAg,18851
2
+ opentelemetry/instrumentation/aiohttp_client/package.py,sha256=__vTycWKYyXjT2fu2vsyQ1YEFDZeYBNrlfrJtzELG6o,680
3
+ opentelemetry/instrumentation/aiohttp_client/version.py,sha256=djB9JEy4l2E_EKsbalCYKBVcG9LlXRJzikntFNyt-0E,610
4
+ opentelemetry_instrumentation_aiohttp_client-0.55b0.dist-info/METADATA,sha256=RRxJH0PILchVvhHxvcN-ZBGg2JlEBUz33poxSFosiE0,2167
5
+ opentelemetry_instrumentation_aiohttp_client-0.55b0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ opentelemetry_instrumentation_aiohttp_client-0.55b0.dist-info/entry_points.txt,sha256=RyZ5eVO-u3V_rwvLrhMM0ABs_WYZDqcagmMKwDPtmwE,117
7
+ opentelemetry_instrumentation_aiohttp_client-0.55b0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
8
+ opentelemetry_instrumentation_aiohttp_client-0.55b0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- opentelemetry/instrumentation/aiohttp_client/__init__.py,sha256=_rzwbYr1V-g3Br3P7-1Qbmx1PspqfvFiZalsryk2TKk,14474
2
- opentelemetry/instrumentation/aiohttp_client/package.py,sha256=sNviXDOZG31-3USpt9VVWNqT8kAiIKaxtq-wi1k8WBM,681
3
- opentelemetry/instrumentation/aiohttp_client/version.py,sha256=2Cd60xvNsK-wqkcpMwSA4a6Q10HlvLAHYh5gWJ57vOA,610
4
- opentelemetry_instrumentation_aiohttp_client-0.54b0.dist-info/METADATA,sha256=XSbV2qff-I3zGt_rKnwHHXrr66GIMGEshDUATjC1UXY,2217
5
- opentelemetry_instrumentation_aiohttp_client-0.54b0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- opentelemetry_instrumentation_aiohttp_client-0.54b0.dist-info/entry_points.txt,sha256=RyZ5eVO-u3V_rwvLrhMM0ABs_WYZDqcagmMKwDPtmwE,117
7
- opentelemetry_instrumentation_aiohttp_client-0.54b0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
8
- opentelemetry_instrumentation_aiohttp_client-0.54b0.dist-info/RECORD,,