opentelemetry-instrumentation-botocore 0.53b1__py3-none-any.whl → 0.54b1__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.
@@ -99,6 +99,7 @@ from opentelemetry.instrumentation.botocore.extensions.types import (
99
99
  _BotocoreInstrumentorContext,
100
100
  )
101
101
  from opentelemetry.instrumentation.botocore.package import _instruments
102
+ from opentelemetry.instrumentation.botocore.utils import get_server_attributes
102
103
  from opentelemetry.instrumentation.botocore.version import __version__
103
104
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
104
105
  from opentelemetry.instrumentation.utils import (
@@ -277,6 +278,7 @@ class BotocoreInstrumentor(BaseInstrumentor):
277
278
  SpanAttributes.RPC_METHOD: call_context.operation,
278
279
  # TODO: update when semantic conventions exist
279
280
  "aws.region": call_context.region,
281
+ **get_server_attributes(call_context.endpoint_url),
280
282
  }
281
283
 
282
284
  _safe_invoke(extension.extract_attributes, attributes)
@@ -15,6 +15,7 @@
15
15
  # Includes work from:
16
16
  # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
17
17
  # SPDX-License-Identifier: Apache-2.0
18
+ # pylint: disable=too-many-lines
18
19
 
19
20
  from __future__ import annotations
20
21
 
@@ -31,6 +32,7 @@ from opentelemetry.instrumentation.botocore.extensions.bedrock_utils import (
31
32
  ConverseStreamWrapper,
32
33
  InvokeModelWithResponseStreamWrapper,
33
34
  _Choice,
35
+ estimate_token_count,
34
36
  genai_capture_message_content,
35
37
  message_to_event,
36
38
  )
@@ -40,6 +42,7 @@ from opentelemetry.instrumentation.botocore.extensions.types import (
40
42
  _BotoClientErrorT,
41
43
  _BotocoreInstrumentorContext,
42
44
  )
45
+ from opentelemetry.instrumentation.botocore.utils import get_server_attributes
43
46
  from opentelemetry.metrics import Instrument, Meter
44
47
  from opentelemetry.semconv._incubating.attributes.error_attributes import (
45
48
  ERROR_TYPE,
@@ -145,7 +148,10 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
145
148
  )
146
149
 
147
150
  def _extract_metrics_attributes(self) -> _AttributeMapT:
148
- attributes = {GEN_AI_SYSTEM: GenAiSystemValues.AWS_BEDROCK.value}
151
+ attributes = {
152
+ GEN_AI_SYSTEM: GenAiSystemValues.AWS_BEDROCK.value,
153
+ **get_server_attributes(self._call_context.endpoint_url),
154
+ }
149
155
 
150
156
  model_id = self._call_context.params.get(_MODEL_ID_KEY)
151
157
  if not model_id:
@@ -162,6 +168,7 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
162
168
  attributes[GEN_AI_OPERATION_NAME] = (
163
169
  GenAiOperationNameValues.CHAT.value
164
170
  )
171
+
165
172
  return attributes
166
173
 
167
174
  def extract_attributes(self, attributes: _AttributeMapT):
@@ -223,6 +230,23 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
223
230
  self._extract_claude_attributes(
224
231
  attributes, request_body
225
232
  )
233
+ elif "cohere.command-r" in model_id:
234
+ self._extract_command_r_attributes(
235
+ attributes, request_body
236
+ )
237
+ elif "cohere.command" in model_id:
238
+ self._extract_command_attributes(
239
+ attributes, request_body
240
+ )
241
+ elif "meta.llama" in model_id:
242
+ self._extract_llama_attributes(
243
+ attributes, request_body
244
+ )
245
+ elif "mistral" in model_id:
246
+ self._extract_mistral_attributes(
247
+ attributes, request_body
248
+ )
249
+
226
250
  except json.JSONDecodeError:
227
251
  _logger.debug("Error: Unable to parse the body as JSON")
228
252
 
@@ -280,6 +304,95 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
280
304
  request_body.get("stop_sequences"),
281
305
  )
282
306
 
307
+ def _extract_command_r_attributes(self, attributes, request_body):
308
+ prompt = request_body.get("message")
309
+ self._set_if_not_none(
310
+ attributes, GEN_AI_USAGE_INPUT_TOKENS, estimate_token_count(prompt)
311
+ )
312
+ self._set_if_not_none(
313
+ attributes,
314
+ GEN_AI_REQUEST_MAX_TOKENS,
315
+ request_body.get("max_tokens"),
316
+ )
317
+ self._set_if_not_none(
318
+ attributes,
319
+ GEN_AI_REQUEST_TEMPERATURE,
320
+ request_body.get("temperature"),
321
+ )
322
+ self._set_if_not_none(
323
+ attributes, GEN_AI_REQUEST_TOP_P, request_body.get("p")
324
+ )
325
+ self._set_if_not_none(
326
+ attributes,
327
+ GEN_AI_REQUEST_STOP_SEQUENCES,
328
+ request_body.get("stop_sequences"),
329
+ )
330
+
331
+ def _extract_command_attributes(self, attributes, request_body):
332
+ prompt = request_body.get("prompt")
333
+ self._set_if_not_none(
334
+ attributes, GEN_AI_USAGE_INPUT_TOKENS, estimate_token_count(prompt)
335
+ )
336
+ self._set_if_not_none(
337
+ attributes,
338
+ GEN_AI_REQUEST_MAX_TOKENS,
339
+ request_body.get("max_tokens"),
340
+ )
341
+ self._set_if_not_none(
342
+ attributes,
343
+ GEN_AI_REQUEST_TEMPERATURE,
344
+ request_body.get("temperature"),
345
+ )
346
+ self._set_if_not_none(
347
+ attributes, GEN_AI_REQUEST_TOP_P, request_body.get("p")
348
+ )
349
+ self._set_if_not_none(
350
+ attributes,
351
+ GEN_AI_REQUEST_STOP_SEQUENCES,
352
+ request_body.get("stop_sequences"),
353
+ )
354
+
355
+ def _extract_llama_attributes(self, attributes, request_body):
356
+ self._set_if_not_none(
357
+ attributes,
358
+ GEN_AI_REQUEST_MAX_TOKENS,
359
+ request_body.get("max_gen_len"),
360
+ )
361
+ self._set_if_not_none(
362
+ attributes,
363
+ GEN_AI_REQUEST_TEMPERATURE,
364
+ request_body.get("temperature"),
365
+ )
366
+ self._set_if_not_none(
367
+ attributes, GEN_AI_REQUEST_TOP_P, request_body.get("top_p")
368
+ )
369
+ # request for meta llama models does not contain stop_sequences field
370
+
371
+ def _extract_mistral_attributes(self, attributes, request_body):
372
+ prompt = request_body.get("prompt")
373
+ if prompt:
374
+ self._set_if_not_none(
375
+ attributes,
376
+ GEN_AI_USAGE_INPUT_TOKENS,
377
+ estimate_token_count(prompt),
378
+ )
379
+ self._set_if_not_none(
380
+ attributes,
381
+ GEN_AI_REQUEST_MAX_TOKENS,
382
+ request_body.get("max_tokens"),
383
+ )
384
+ self._set_if_not_none(
385
+ attributes,
386
+ GEN_AI_REQUEST_TEMPERATURE,
387
+ request_body.get("temperature"),
388
+ )
389
+ self._set_if_not_none(
390
+ attributes, GEN_AI_REQUEST_TOP_P, request_body.get("top_p")
391
+ )
392
+ self._set_if_not_none(
393
+ attributes, GEN_AI_REQUEST_STOP_SEQUENCES, request_body.get("stop")
394
+ )
395
+
283
396
  @staticmethod
284
397
  def _set_if_not_none(attributes, key, value):
285
398
  if value is not None:
@@ -287,7 +400,6 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
287
400
 
288
401
  def _get_request_messages(self):
289
402
  """Extracts and normalize system and user / assistant messages"""
290
- input_text = None
291
403
  if system := self._call_context.params.get("system", []):
292
404
  system_messages = [{"role": "system", "content": system}]
293
405
  else:
@@ -304,15 +416,37 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
304
416
  system_messages = [{"role": "system", "content": content}]
305
417
 
306
418
  messages = decoded_body.get("messages", [])
419
+ # if no messages interface, convert to messages format from generic API
307
420
  if not messages:
308
- # transform old school amazon titan invokeModel api to messages
309
- if input_text := decoded_body.get("inputText"):
310
- messages = [
311
- {"role": "user", "content": [{"text": input_text}]}
312
- ]
421
+ model_id = self._call_context.params.get(_MODEL_ID_KEY)
422
+ if "amazon.titan" in model_id:
423
+ messages = self._get_messages_from_input_text(
424
+ decoded_body, "inputText"
425
+ )
426
+ elif "cohere.command-r" in model_id:
427
+ # chat_history can be converted to messages; for now, just use message
428
+ messages = self._get_messages_from_input_text(
429
+ decoded_body, "message"
430
+ )
431
+ elif (
432
+ "cohere.command" in model_id
433
+ or "meta.llama" in model_id
434
+ or "mistral.mistral" in model_id
435
+ ):
436
+ messages = self._get_messages_from_input_text(
437
+ decoded_body, "prompt"
438
+ )
313
439
 
314
440
  return system_messages + messages
315
441
 
442
+ # pylint: disable=no-self-use
443
+ def _get_messages_from_input_text(
444
+ self, decoded_body: dict[str, Any], input_name: str
445
+ ):
446
+ if input_text := decoded_body.get(input_name):
447
+ return [{"role": "user", "content": [{"text": input_text}]}]
448
+ return []
449
+
316
450
  def before_service_call(
317
451
  self, span: Span, instrumentor_context: _BotocoreInstrumentorContext
318
452
  ):
@@ -439,6 +573,22 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
439
573
  self._handle_anthropic_claude_response(
440
574
  span, response_body, instrumentor_context, capture_content
441
575
  )
576
+ elif "cohere.command-r" in model_id:
577
+ self._handle_cohere_command_r_response(
578
+ span, response_body, instrumentor_context, capture_content
579
+ )
580
+ elif "cohere.command" in model_id:
581
+ self._handle_cohere_command_response(
582
+ span, response_body, instrumentor_context, capture_content
583
+ )
584
+ elif "meta.llama" in model_id:
585
+ self._handle_meta_llama_response(
586
+ span, response_body, instrumentor_context, capture_content
587
+ )
588
+ elif "mistral" in model_id:
589
+ self._handle_mistral_ai_response(
590
+ span, response_body, instrumentor_context, capture_content
591
+ )
442
592
  except json.JSONDecodeError:
443
593
  _logger.debug("Error: Unable to parse the response body as JSON")
444
594
  except Exception as exc: # pylint: disable=broad-exception-caught
@@ -725,6 +875,106 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
725
875
  output_tokens, output_attributes
726
876
  )
727
877
 
878
+ def _handle_cohere_command_r_response(
879
+ self,
880
+ span: Span,
881
+ response_body: dict[str, Any],
882
+ instrumentor_context: _BotocoreInstrumentorContext,
883
+ capture_content: bool,
884
+ ):
885
+ if "text" in response_body:
886
+ span.set_attribute(
887
+ GEN_AI_USAGE_OUTPUT_TOKENS,
888
+ estimate_token_count(response_body["text"]),
889
+ )
890
+ if "finish_reason" in response_body:
891
+ span.set_attribute(
892
+ GEN_AI_RESPONSE_FINISH_REASONS,
893
+ [response_body["finish_reason"]],
894
+ )
895
+
896
+ event_logger = instrumentor_context.event_logger
897
+ choice = _Choice.from_invoke_cohere_command_r(
898
+ response_body, capture_content
899
+ )
900
+ event_logger.emit(choice.to_choice_event())
901
+
902
+ def _handle_cohere_command_response(
903
+ self,
904
+ span: Span,
905
+ response_body: dict[str, Any],
906
+ instrumentor_context: _BotocoreInstrumentorContext,
907
+ capture_content: bool,
908
+ ):
909
+ if "generations" in response_body and response_body["generations"]:
910
+ generations = response_body["generations"][0]
911
+ if "text" in generations:
912
+ span.set_attribute(
913
+ GEN_AI_USAGE_OUTPUT_TOKENS,
914
+ estimate_token_count(generations["text"]),
915
+ )
916
+ if "finish_reason" in generations:
917
+ span.set_attribute(
918
+ GEN_AI_RESPONSE_FINISH_REASONS,
919
+ [generations["finish_reason"]],
920
+ )
921
+
922
+ event_logger = instrumentor_context.event_logger
923
+ choice = _Choice.from_invoke_cohere_command(
924
+ response_body, capture_content
925
+ )
926
+ event_logger.emit(choice.to_choice_event())
927
+
928
+ def _handle_meta_llama_response(
929
+ self,
930
+ span: Span,
931
+ response_body: dict[str, Any],
932
+ instrumentor_context: _BotocoreInstrumentorContext,
933
+ capture_content: bool,
934
+ ):
935
+ if "prompt_token_count" in response_body:
936
+ span.set_attribute(
937
+ GEN_AI_USAGE_INPUT_TOKENS, response_body["prompt_token_count"]
938
+ )
939
+ if "generation_token_count" in response_body:
940
+ span.set_attribute(
941
+ GEN_AI_USAGE_OUTPUT_TOKENS,
942
+ response_body["generation_token_count"],
943
+ )
944
+ if "stop_reason" in response_body:
945
+ span.set_attribute(
946
+ GEN_AI_RESPONSE_FINISH_REASONS, [response_body["stop_reason"]]
947
+ )
948
+
949
+ event_logger = instrumentor_context.event_logger
950
+ choice = _Choice.from_invoke_meta_llama(response_body, capture_content)
951
+ event_logger.emit(choice.to_choice_event())
952
+
953
+ def _handle_mistral_ai_response(
954
+ self,
955
+ span: Span,
956
+ response_body: dict[str, Any],
957
+ instrumentor_context: _BotocoreInstrumentorContext,
958
+ capture_content: bool,
959
+ ):
960
+ if "outputs" in response_body:
961
+ outputs = response_body["outputs"][0]
962
+ if "text" in outputs:
963
+ span.set_attribute(
964
+ GEN_AI_USAGE_OUTPUT_TOKENS,
965
+ estimate_token_count(outputs["text"]),
966
+ )
967
+ if "stop_reason" in outputs:
968
+ span.set_attribute(
969
+ GEN_AI_RESPONSE_FINISH_REASONS, [outputs["stop_reason"]]
970
+ )
971
+
972
+ event_logger = instrumentor_context.event_logger
973
+ choice = _Choice.from_invoke_mistral_mistral(
974
+ response_body, capture_content
975
+ )
976
+ event_logger.emit(choice.to_choice_event())
977
+
728
978
  def on_error(
729
979
  self,
730
980
  span: Span,
@@ -15,6 +15,7 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import json
18
+ import math
18
19
  from os import environ
19
20
  from typing import Any, Callable, Dict, Iterator, Sequence, Union
20
21
 
@@ -358,6 +359,12 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
358
359
  return
359
360
 
360
361
 
362
+ def estimate_token_count(message: str) -> int:
363
+ # https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-prepare.html
364
+ # use 6 chars per token to approximate token count when not provided in response body
365
+ return math.ceil(len(message) / 6)
366
+
367
+
361
368
  def genai_capture_message_content() -> bool:
362
369
  capture_content = environ.get(
363
370
  OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, "false"
@@ -519,6 +526,48 @@ class _Choice:
519
526
  message["content"] = response["content"]
520
527
  return cls(message, response["stop_reason"], index=0)
521
528
 
529
+ @classmethod
530
+ def from_invoke_cohere_command_r(
531
+ cls, response: dict[str, Any], capture_content: bool
532
+ ) -> _Choice:
533
+ if capture_content:
534
+ message = {"content": response["text"]}
535
+ else:
536
+ message = {}
537
+ return cls(message, response["finish_reason"], index=0)
538
+
539
+ @classmethod
540
+ def from_invoke_cohere_command(
541
+ cls, response: dict[str, Any], capture_content: bool
542
+ ) -> _Choice:
543
+ result = response["generations"][0]
544
+ if capture_content:
545
+ message = {"content": result["text"]}
546
+ else:
547
+ message = {}
548
+ return cls(message, result["finish_reason"], index=0)
549
+
550
+ @classmethod
551
+ def from_invoke_meta_llama(
552
+ cls, response: dict[str, Any], capture_content: bool
553
+ ) -> _Choice:
554
+ if capture_content:
555
+ message = {"content": response["generation"]}
556
+ else:
557
+ message = {}
558
+ return cls(message, response["stop_reason"], index=0)
559
+
560
+ @classmethod
561
+ def from_invoke_mistral_mistral(
562
+ cls, response: dict[str, Any], capture_content: bool
563
+ ) -> _Choice:
564
+ result = response["outputs"][0]
565
+ if capture_content:
566
+ message = {"content": result["text"]}
567
+ else:
568
+ message = {}
569
+ return cls(message, result["stop_reason"], index=0)
570
+
522
571
  def _to_body_dict(self) -> dict[str, Any]:
523
572
  return {
524
573
  "finish_reason": self.finish_reason,
@@ -0,0 +1,31 @@
1
+ # Copyright The OpenTelemetry Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from __future__ import annotations
15
+
16
+ from urllib.parse import urlparse
17
+
18
+ from opentelemetry.semconv._incubating.attributes import (
19
+ server_attributes as ServerAttributes,
20
+ )
21
+ from opentelemetry.util.types import AttributeValue
22
+
23
+
24
+ def get_server_attributes(endpoint_url: str) -> dict[str, AttributeValue]:
25
+ """Extract server.* attributes from AWS endpoint URL."""
26
+ parsed = urlparse(endpoint_url)
27
+ attributes = {}
28
+ if parsed.hostname:
29
+ attributes[ServerAttributes.SERVER_ADDRESS] = parsed.hostname
30
+ attributes[ServerAttributes.SERVER_PORT] = parsed.port or 443
31
+ return attributes
@@ -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.53b1"
15
+ __version__ = "0.54b1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opentelemetry-instrumentation-botocore
3
- Version: 0.53b1
3
+ Version: 0.54b1
4
4
  Summary: OpenTelemetry Botocore instrumentation
5
5
  Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-botocore
6
6
  Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib
@@ -20,9 +20,9 @@ Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
21
  Requires-Python: >=3.8
22
22
  Requires-Dist: opentelemetry-api~=1.30
23
- Requires-Dist: opentelemetry-instrumentation==0.53b1
23
+ Requires-Dist: opentelemetry-instrumentation==0.54b1
24
24
  Requires-Dist: opentelemetry-propagator-aws-xray~=1.0
25
- Requires-Dist: opentelemetry-semantic-conventions==0.53b1
25
+ Requires-Dist: opentelemetry-semantic-conventions==0.54b1
26
26
  Provides-Extra: instruments
27
27
  Requires-Dist: botocore~=1.0; extra == 'instruments'
28
28
  Description-Content-Type: text/x-rst
@@ -1,18 +1,19 @@
1
- opentelemetry/instrumentation/botocore/__init__.py,sha256=vqJdCimwcLKwvGfXvsT-UW4PD5R0MLb4xPAB1Xdk_Lo,14565
1
+ opentelemetry/instrumentation/botocore/__init__.py,sha256=O2RNAc7SGEWSaBnniTfedrIsNDER01h4VRPJgxxIG_8,14708
2
2
  opentelemetry/instrumentation/botocore/environment_variables.py,sha256=c1lrIEj5wwxZwLd5ppJsfGADBfQLnb_HuxXDLv7ul6s,114
3
3
  opentelemetry/instrumentation/botocore/package.py,sha256=6xvfRpU_C3wlSO6pto7MhGtkPoCHDEiRO_Fh4DiC_50,622
4
- opentelemetry/instrumentation/botocore/version.py,sha256=uYW9AHe_CTRZoi-ExYtUTquCExW6ZiH18ELKvuFwO1I,608
4
+ opentelemetry/instrumentation/botocore/utils.py,sha256=dM5LW5PjIdErBFESyxh6b8oBvbmQ7dPyYOn1YLOUFaQ,1191
5
+ opentelemetry/instrumentation/botocore/version.py,sha256=LAnaEWDOviU2kJ-Xmrhq1biqtDukCylZDisfX_ER5Ng,608
5
6
  opentelemetry/instrumentation/botocore/extensions/__init__.py,sha256=IqMWsCI0HL8gvL8-0Svn9Rp7dz2HKMcIuhRRM0twmCU,1857
6
7
  opentelemetry/instrumentation/botocore/extensions/_messaging.py,sha256=ca2Uwyb1vxWu5qUkKTlfn9KJFN6k8HOTrrBYvwX4WzA,1636
7
- opentelemetry/instrumentation/botocore/extensions/bedrock.py,sha256=fF_SdRGZzTyGDprlffh84bMVQhq3AZMcMAZAUTj1SDA,27814
8
- opentelemetry/instrumentation/botocore/extensions/bedrock_utils.py,sha256=vR_INPz0UeT_ShajwZdLbXcys6mOmXSHwOxP3gR139I,20555
8
+ opentelemetry/instrumentation/botocore/extensions/bedrock.py,sha256=Z0emYAoeP9RzuddnqWr8I-xzI3LAKp0eGc7-WSMKZmo,37169
9
+ opentelemetry/instrumentation/botocore/extensions/bedrock_utils.py,sha256=KyiL_RpU4c-gyXojJcMgXe2IK5DYVY17cyx3iZrI8UI,22178
9
10
  opentelemetry/instrumentation/botocore/extensions/dynamodb.py,sha256=cmTzHnLCO731v8L5wN-rPRyVgQHmRvH3tuG5wrFhqyA,13745
10
11
  opentelemetry/instrumentation/botocore/extensions/lmbd.py,sha256=mqPbgwDFy3XYg-pLo6A6eNu0iKSGa2-tPLwroJDuavY,4253
11
12
  opentelemetry/instrumentation/botocore/extensions/sns.py,sha256=MfppfL91tAbAjp6CIiqvYIuXQRq-PeIYbB1ZKWO5kW4,5334
12
13
  opentelemetry/instrumentation/botocore/extensions/sqs.py,sha256=9_LjlzQ0Sg92hgaL8P31cbpq_C71qCTucjj0SX1Ct5o,2916
13
14
  opentelemetry/instrumentation/botocore/extensions/types.py,sha256=jCIJXt0Zvdn2qVwX6bLUaCLgBPy6XyJ-nYEwurxAZo8,6681
14
- opentelemetry_instrumentation_botocore-0.53b1.dist-info/METADATA,sha256=_MVAZ_TUsHjY7hcIWfUqvJkXslqgp0Xpq0aDNZUorkg,3101
15
- opentelemetry_instrumentation_botocore-0.53b1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- opentelemetry_instrumentation_botocore-0.53b1.dist-info/entry_points.txt,sha256=v5hzQbZMJ61JuhBNq5jHYAapvv3C_486h9CTqxlkUTM,100
17
- opentelemetry_instrumentation_botocore-0.53b1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
18
- opentelemetry_instrumentation_botocore-0.53b1.dist-info/RECORD,,
15
+ opentelemetry_instrumentation_botocore-0.54b1.dist-info/METADATA,sha256=S5XHFnHRY2tMF3FfFkyY86c_krOw0ewBnDQwQi4rnxw,3101
16
+ opentelemetry_instrumentation_botocore-0.54b1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
+ opentelemetry_instrumentation_botocore-0.54b1.dist-info/entry_points.txt,sha256=v5hzQbZMJ61JuhBNq5jHYAapvv3C_486h9CTqxlkUTM,100
18
+ opentelemetry_instrumentation_botocore-0.54b1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
19
+ opentelemetry_instrumentation_botocore-0.54b1.dist-info/RECORD,,