We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Resource must be immutable
The boto instrumentation changes a span's resource to set attributes, this goes against the spec.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py`
Content:
```
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 """
15 Instrument `Boto`_ to trace service requests.
16 
17 There are two options for instrumenting code. The first option is to use the
18 ``opentelemetry-instrument`` executable which will automatically
19 instrument your Boto client. The second is to programmatically enable
20 instrumentation via the following code:
21 
22 .. _boto: https://pypi.org/project/boto/
23 
24 Usage
25 -----
26 
27 .. code:: python
28 
29     from opentelemetry.instrumentation.boto import BotoInstrumentor
30     import boto
31 
32 
33     # Instrument Boto
34     BotoInstrumentor().instrument()
35 
36     # This will create a span with Boto-specific attributes
37     ec2 = boto.ec2.connect_to_region("us-west-2")
38     ec2.get_all_instances()
39 
40 API
41 ---
42 """
43 
44 import logging
45 from inspect import currentframe
46 
47 from boto.connection import AWSAuthConnection, AWSQueryConnection
48 from wrapt import wrap_function_wrapper
49 
50 from opentelemetry.instrumentation.boto.version import __version__
51 from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
52 from opentelemetry.instrumentation.utils import unwrap
53 from opentelemetry.sdk.trace import Resource
54 from opentelemetry.trace import SpanKind, get_tracer
55 
56 logger = logging.getLogger(__name__)
57 
58 SERVICE_PARAMS_BLOCK_LIST = {"s3": ["params.Body"]}
59 
60 
61 def _get_instance_region_name(instance):
62     region = getattr(instance, "region", None)
63 
64     if not region:
65         return None
66     if isinstance(region, str):
67         return region.split(":")[1]
68     return region.name
69 
70 
71 class BotoInstrumentor(BaseInstrumentor):
72     """A instrumentor for Boto
73 
74     See `BaseInstrumentor`
75     """
76 
77     def __init__(self):
78         super().__init__()
79         self._original_boto = None
80 
81     def _instrument(self, **kwargs):
82         # AWSQueryConnection and AWSAuthConnection are two different classes
83         # called by different services for connection.
84         # For exemple EC2 uses AWSQueryConnection and S3 uses
85         # AWSAuthConnection
86 
87         # pylint: disable=attribute-defined-outside-init
88         self._tracer = get_tracer(
89             __name__, __version__, kwargs.get("tracer_provider")
90         )
91 
92         wrap_function_wrapper(
93             "boto.connection",
94             "AWSQueryConnection.make_request",
95             self._patched_query_request,
96         )
97         wrap_function_wrapper(
98             "boto.connection",
99             "AWSAuthConnection.make_request",
100             self._patched_auth_request,
101         )
102 
103     def _uninstrument(self, **kwargs):
104         unwrap(AWSQueryConnection, "make_request")
105         unwrap(AWSAuthConnection, "make_request")
106 
107     def _common_request(  # pylint: disable=too-many-locals
108         self,
109         args_name,
110         traced_args,
111         operation_name,
112         original_func,
113         instance,
114         args,
115         kwargs,
116     ):
117 
118         endpoint_name = getattr(instance, "host").split(".")[0]
119 
120         with self._tracer.start_as_current_span(
121             "{}.command".format(endpoint_name), kind=SpanKind.CONSUMER,
122         ) as span:
123             if args:
124                 http_method = args[0]
125                 span.resource = Resource(
126                     attributes={
127                         "endpoint": endpoint_name,
128                         "http_method": http_method.lower(),
129                     }
130                 )
131             else:
132                 span.resource = Resource(
133                     attributes={"endpoint": endpoint_name}
134                 )
135 
136             # Original func returns a boto.connection.HTTPResponse object
137             result = original_func(*args, **kwargs)
138 
139             if span.is_recording():
140                 add_span_arg_tags(
141                     span, endpoint_name, args, args_name, traced_args,
142                 )
143 
144                 # Obtaining region name
145                 region_name = _get_instance_region_name(instance)
146 
147                 meta = {
148                     "aws.agent": "boto",
149                     "aws.operation": operation_name,
150                 }
151                 if region_name:
152                     meta["aws.region"] = region_name
153 
154                 for key, value in meta.items():
155                     span.set_attribute(key, value)
156 
157                 span.set_attribute(
158                     "http.status_code", getattr(result, "status")
159                 )
160                 span.set_attribute("http.method", getattr(result, "_method"))
161 
162             return result
163 
164     def _patched_query_request(self, original_func, instance, args, kwargs):
165 
166         return self._common_request(
167             ("operation_name", "params", "path", "verb"),
168             ["operation_name", "params", "path"],
169             args[0] if args else None,
170             original_func,
171             instance,
172             args,
173             kwargs,
174         )
175 
176     def _patched_auth_request(self, original_func, instance, args, kwargs):
177         operation_name = None
178 
179         frame = currentframe().f_back
180         operation_name = None
181         while frame:
182             if frame.f_code.co_name == "make_request":
183                 operation_name = frame.f_back.f_code.co_name
184                 break
185             frame = frame.f_back
186 
187         return self._common_request(
188             (
189                 "method",
190                 "path",
191                 "headers",
192                 "data",
193                 "host",
194                 "auth_path",
195                 "sender",
196             ),
197             ["path", "data", "host"],
198             operation_name,
199             original_func,
200             instance,
201             args,
202             kwargs,
203         )
204 
205 
206 def flatten_dict(dict_, sep=".", prefix=""):
207     """
208     Returns a normalized dict of depth 1 with keys in order of embedding
209     """
210     # NOTE: This should probably be in `opentelemetry.instrumentation.utils`.
211     # adapted from https://stackoverflow.com/a/19647596
212     return (
213         {
214             prefix + sep + k if prefix else k: v
215             for kk, vv in dict_.items()
216             for k, v in flatten_dict(vv, sep, kk).items()
217         }
218         if isinstance(dict_, dict)
219         else {prefix: dict_}
220     )
221 
222 
223 def add_span_arg_tags(span, aws_service, args, args_names, args_traced):
224     def truncate_arg_value(value, max_len=1024):
225         """Truncate values which are bytes and greater than `max_len`.
226         Useful for parameters like "Body" in `put_object` operations.
227         """
228         if isinstance(value, bytes) and len(value) > max_len:
229             return b"..."
230 
231         return value
232 
233     if not span.is_recording():
234         return
235 
236     # Do not trace `Key Management Service` or `Secure Token Service` API calls
237     # over concerns of security leaks.
238     if aws_service not in {"kms", "sts"}:
239         tags = dict(
240             (name, value)
241             for (name, value) in zip(args_names, args)
242             if name in args_traced
243         )
244         tags = flatten_dict(tags)
245 
246         for param_key, value in tags.items():
247             if param_key in SERVICE_PARAMS_BLOCK_LIST.get(aws_service, {}):
248                 continue
249 
250             span.set_attribute(param_key, truncate_arg_value(value))
251
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py
--- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py
@@ -120,18 +120,10 @@
         with self._tracer.start_as_current_span(
             "{}.command".format(endpoint_name), kind=SpanKind.CONSUMER,
         ) as span:
+            span.set_attribute("endpoint", endpoint_name)
             if args:
                 http_method = args[0]
-                span.resource = Resource(
-                    attributes={
-                        "endpoint": endpoint_name,
-                        "http_method": http_method.lower(),
-                    }
-                )
-            else:
-                span.resource = Resource(
-                    attributes={"endpoint": endpoint_name}
-                )
+                span.set_attribute("http_method", http_method.lower())
 
             # Original func returns a boto.connection.HTTPResponse object
             result = original_func(*args, **kwargs)

{"golden_diff": "diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py\n--- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py\n+++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py\n@@ -120,18 +120,10 @@\n         with self._tracer.start_as_current_span(\n             \"{}.command\".format(endpoint_name), kind=SpanKind.CONSUMER,\n         ) as span:\n+            span.set_attribute(\"endpoint\", endpoint_name)\n             if args:\n                 http_method = args[0]\n-                span.resource = Resource(\n-                    attributes={\n-                        \"endpoint\": endpoint_name,\n-                        \"http_method\": http_method.lower(),\n-                    }\n-                )\n-            else:\n-                span.resource = Resource(\n-                    attributes={\"endpoint\": endpoint_name}\n-                )\n+                span.set_attribute(\"http_method\", http_method.lower())\n \n             # Original func returns a boto.connection.HTTPResponse object\n             result = original_func(*args, **kwargs)\n", "issue": "Resource must be immutable\nThe boto instrumentation changes a span's resource to set attributes, this goes against the spec.\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"\nInstrument `Boto`_ to trace service requests.\n\nThere are two options for instrumenting code. The first option is to use the\n``opentelemetry-instrument`` executable which will automatically\ninstrument your Boto client. The second is to programmatically enable\ninstrumentation via the following code:\n\n.. _boto: https://pypi.org/project/boto/\n\nUsage\n-----\n\n.. code:: python\n\n    from opentelemetry.instrumentation.boto import BotoInstrumentor\n    import boto\n\n\n    # Instrument Boto\n    BotoInstrumentor().instrument()\n\n    # This will create a span with Boto-specific attributes\n    ec2 = boto.ec2.connect_to_region(\"us-west-2\")\n    ec2.get_all_instances()\n\nAPI\n---\n\"\"\"\n\nimport logging\nfrom inspect import currentframe\n\nfrom boto.connection import AWSAuthConnection, AWSQueryConnection\nfrom wrapt import wrap_function_wrapper\n\nfrom opentelemetry.instrumentation.boto.version import __version__\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.utils import unwrap\nfrom opentelemetry.sdk.trace import Resource\nfrom opentelemetry.trace import SpanKind, get_tracer\n\nlogger = logging.getLogger(__name__)\n\nSERVICE_PARAMS_BLOCK_LIST = {\"s3\": [\"params.Body\"]}\n\n\ndef _get_instance_region_name(instance):\n    region = getattr(instance, \"region\", None)\n\n    if not region:\n        return None\n    if isinstance(region, str):\n        return region.split(\":\")[1]\n    return region.name\n\n\nclass BotoInstrumentor(BaseInstrumentor):\n    \"\"\"A instrumentor for Boto\n\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self._original_boto = None\n\n    def _instrument(self, **kwargs):\n        # AWSQueryConnection and AWSAuthConnection are two different classes\n        # called by different services for connection.\n        # For exemple EC2 uses AWSQueryConnection and S3 uses\n        # AWSAuthConnection\n\n        # pylint: disable=attribute-defined-outside-init\n        self._tracer = get_tracer(\n            __name__, __version__, kwargs.get(\"tracer_provider\")\n        )\n\n        wrap_function_wrapper(\n            \"boto.connection\",\n            \"AWSQueryConnection.make_request\",\n            self._patched_query_request,\n        )\n        wrap_function_wrapper(\n            \"boto.connection\",\n            \"AWSAuthConnection.make_request\",\n            self._patched_auth_request,\n        )\n\n    def _uninstrument(self, **kwargs):\n        unwrap(AWSQueryConnection, \"make_request\")\n        unwrap(AWSAuthConnection, \"make_request\")\n\n    def _common_request(  # pylint: disable=too-many-locals\n        self,\n        args_name,\n        traced_args,\n        operation_name,\n        original_func,\n        instance,\n        args,\n        kwargs,\n    ):\n\n        endpoint_name = getattr(instance, \"host\").split(\".\")[0]\n\n        with self._tracer.start_as_current_span(\n            \"{}.command\".format(endpoint_name), kind=SpanKind.CONSUMER,\n        ) as span:\n            if args:\n                http_method = args[0]\n                span.resource = Resource(\n                    attributes={\n                        \"endpoint\": endpoint_name,\n                        \"http_method\": http_method.lower(),\n                    }\n                )\n            else:\n                span.resource = Resource(\n                    attributes={\"endpoint\": endpoint_name}\n                )\n\n            # Original func returns a boto.connection.HTTPResponse object\n            result = original_func(*args, **kwargs)\n\n            if span.is_recording():\n                add_span_arg_tags(\n                    span, endpoint_name, args, args_name, traced_args,\n                )\n\n                # Obtaining region name\n                region_name = _get_instance_region_name(instance)\n\n                meta = {\n                    \"aws.agent\": \"boto\",\n                    \"aws.operation\": operation_name,\n                }\n                if region_name:\n                    meta[\"aws.region\"] = region_name\n\n                for key, value in meta.items():\n                    span.set_attribute(key, value)\n\n                span.set_attribute(\n                    \"http.status_code\", getattr(result, \"status\")\n                )\n                span.set_attribute(\"http.method\", getattr(result, \"_method\"))\n\n            return result\n\n    def _patched_query_request(self, original_func, instance, args, kwargs):\n\n        return self._common_request(\n            (\"operation_name\", \"params\", \"path\", \"verb\"),\n            [\"operation_name\", \"params\", \"path\"],\n            args[0] if args else None,\n            original_func,\n            instance,\n            args,\n            kwargs,\n        )\n\n    def _patched_auth_request(self, original_func, instance, args, kwargs):\n        operation_name = None\n\n        frame = currentframe().f_back\n        operation_name = None\n        while frame:\n            if frame.f_code.co_name == \"make_request\":\n                operation_name = frame.f_back.f_code.co_name\n                break\n            frame = frame.f_back\n\n        return self._common_request(\n            (\n                \"method\",\n                \"path\",\n                \"headers\",\n                \"data\",\n                \"host\",\n                \"auth_path\",\n                \"sender\",\n            ),\n            [\"path\", \"data\", \"host\"],\n            operation_name,\n            original_func,\n            instance,\n            args,\n            kwargs,\n        )\n\n\ndef flatten_dict(dict_, sep=\".\", prefix=\"\"):\n    \"\"\"\n    Returns a normalized dict of depth 1 with keys in order of embedding\n    \"\"\"\n    # NOTE: This should probably be in `opentelemetry.instrumentation.utils`.\n    # adapted from https://stackoverflow.com/a/19647596\n    return (\n        {\n            prefix + sep + k if prefix else k: v\n            for kk, vv in dict_.items()\n            for k, v in flatten_dict(vv, sep, kk).items()\n        }\n        if isinstance(dict_, dict)\n        else {prefix: dict_}\n    )\n\n\ndef add_span_arg_tags(span, aws_service, args, args_names, args_traced):\n    def truncate_arg_value(value, max_len=1024):\n        \"\"\"Truncate values which are bytes and greater than `max_len`.\n        Useful for parameters like \"Body\" in `put_object` operations.\n        \"\"\"\n        if isinstance(value, bytes) and len(value) > max_len:\n            return b\"...\"\n\n        return value\n\n    if not span.is_recording():\n        return\n\n    # Do not trace `Key Management Service` or `Secure Token Service` API calls\n    # over concerns of security leaks.\n    if aws_service not in {\"kms\", \"sts\"}:\n        tags = dict(\n            (name, value)\n            for (name, value) in zip(args_names, args)\n            if name in args_traced\n        )\n        tags = flatten_dict(tags)\n\n        for param_key, value in tags.items():\n            if param_key in SERVICE_PARAMS_BLOCK_LIST.get(aws_service, {}):\n                continue\n\n            span.set_attribute(param_key, truncate_arg_value(value))\n", "path": "instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"\nInstrument `Boto`_ to trace service requests.\n\nThere are two options for instrumenting code. The first option is to use the\n``opentelemetry-instrument`` executable which will automatically\ninstrument your Boto client. The second is to programmatically enable\ninstrumentation via the following code:\n\n.. _boto: https://pypi.org/project/boto/\n\nUsage\n-----\n\n.. code:: python\n\n    from opentelemetry.instrumentation.boto import BotoInstrumentor\n    import boto\n\n\n    # Instrument Boto\n    BotoInstrumentor().instrument()\n\n    # This will create a span with Boto-specific attributes\n    ec2 = boto.ec2.connect_to_region(\"us-west-2\")\n    ec2.get_all_instances()\n\nAPI\n---\n\"\"\"\n\nimport logging\nfrom inspect import currentframe\n\nfrom boto.connection import AWSAuthConnection, AWSQueryConnection\nfrom wrapt import wrap_function_wrapper\n\nfrom opentelemetry.instrumentation.boto.version import __version__\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.utils import unwrap\nfrom opentelemetry.sdk.trace import Resource\nfrom opentelemetry.trace import SpanKind, get_tracer\n\nlogger = logging.getLogger(__name__)\n\nSERVICE_PARAMS_BLOCK_LIST = {\"s3\": [\"params.Body\"]}\n\n\ndef _get_instance_region_name(instance):\n    region = getattr(instance, \"region\", None)\n\n    if not region:\n        return None\n    if isinstance(region, str):\n        return region.split(\":\")[1]\n    return region.name\n\n\nclass BotoInstrumentor(BaseInstrumentor):\n    \"\"\"A instrumentor for Boto\n\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self._original_boto = None\n\n    def _instrument(self, **kwargs):\n        # AWSQueryConnection and AWSAuthConnection are two different classes\n        # called by different services for connection.\n        # For exemple EC2 uses AWSQueryConnection and S3 uses\n        # AWSAuthConnection\n\n        # pylint: disable=attribute-defined-outside-init\n        self._tracer = get_tracer(\n            __name__, __version__, kwargs.get(\"tracer_provider\")\n        )\n\n        wrap_function_wrapper(\n            \"boto.connection\",\n            \"AWSQueryConnection.make_request\",\n            self._patched_query_request,\n        )\n        wrap_function_wrapper(\n            \"boto.connection\",\n            \"AWSAuthConnection.make_request\",\n            self._patched_auth_request,\n        )\n\n    def _uninstrument(self, **kwargs):\n        unwrap(AWSQueryConnection, \"make_request\")\n        unwrap(AWSAuthConnection, \"make_request\")\n\n    def _common_request(  # pylint: disable=too-many-locals\n        self,\n        args_name,\n        traced_args,\n        operation_name,\n        original_func,\n        instance,\n        args,\n        kwargs,\n    ):\n\n        endpoint_name = getattr(instance, \"host\").split(\".\")[0]\n\n        with self._tracer.start_as_current_span(\n            \"{}.command\".format(endpoint_name), kind=SpanKind.CONSUMER,\n        ) as span:\n            span.set_attribute(\"endpoint\", endpoint_name)\n            if args:\n                http_method = args[0]\n                span.set_attribute(\"http_method\", http_method.lower())\n\n            # Original func returns a boto.connection.HTTPResponse object\n            result = original_func(*args, **kwargs)\n\n            if span.is_recording():\n                add_span_arg_tags(\n                    span, endpoint_name, args, args_name, traced_args,\n                )\n\n                # Obtaining region name\n                region_name = _get_instance_region_name(instance)\n\n                meta = {\n                    \"aws.agent\": \"boto\",\n                    \"aws.operation\": operation_name,\n                }\n                if region_name:\n                    meta[\"aws.region\"] = region_name\n\n                for key, value in meta.items():\n                    span.set_attribute(key, value)\n\n                span.set_attribute(\n                    \"http.status_code\", getattr(result, \"status\")\n                )\n                span.set_attribute(\"http.method\", getattr(result, \"_method\"))\n\n            return result\n\n    def _patched_query_request(self, original_func, instance, args, kwargs):\n\n        return self._common_request(\n            (\"operation_name\", \"params\", \"path\", \"verb\"),\n            [\"operation_name\", \"params\", \"path\"],\n            args[0] if args else None,\n            original_func,\n            instance,\n            args,\n            kwargs,\n        )\n\n    def _patched_auth_request(self, original_func, instance, args, kwargs):\n        operation_name = None\n\n        frame = currentframe().f_back\n        operation_name = None\n        while frame:\n            if frame.f_code.co_name == \"make_request\":\n                operation_name = frame.f_back.f_code.co_name\n                break\n            frame = frame.f_back\n\n        return self._common_request(\n            (\n                \"method\",\n                \"path\",\n                \"headers\",\n                \"data\",\n                \"host\",\n                \"auth_path\",\n                \"sender\",\n            ),\n            [\"path\", \"data\", \"host\"],\n            operation_name,\n            original_func,\n            instance,\n            args,\n            kwargs,\n        )\n\n\ndef flatten_dict(dict_, sep=\".\", prefix=\"\"):\n    \"\"\"\n    Returns a normalized dict of depth 1 with keys in order of embedding\n    \"\"\"\n    # NOTE: This should probably be in `opentelemetry.instrumentation.utils`.\n    # adapted from https://stackoverflow.com/a/19647596\n    return (\n        {\n            prefix + sep + k if prefix else k: v\n            for kk, vv in dict_.items()\n            for k, v in flatten_dict(vv, sep, kk).items()\n        }\n        if isinstance(dict_, dict)\n        else {prefix: dict_}\n    )\n\n\ndef add_span_arg_tags(span, aws_service, args, args_names, args_traced):\n    def truncate_arg_value(value, max_len=1024):\n        \"\"\"Truncate values which are bytes and greater than `max_len`.\n        Useful for parameters like \"Body\" in `put_object` operations.\n        \"\"\"\n        if isinstance(value, bytes) and len(value) > max_len:\n            return b\"...\"\n\n        return value\n\n    if not span.is_recording():\n        return\n\n    # Do not trace `Key Management Service` or `Secure Token Service` API calls\n    # over concerns of security leaks.\n    if aws_service not in {\"kms\", \"sts\"}:\n        tags = dict(\n            (name, value)\n            for (name, value) in zip(args_names, args)\n            if name in args_traced\n        )\n        tags = flatten_dict(tags)\n\n        for param_key, value in tags.items():\n            if param_key in SERVICE_PARAMS_BLOCK_LIST.get(aws_service, {}):\n                continue\n\n            span.set_attribute(param_key, truncate_arg_value(value))\n", "path": "instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py"}]}