@@ -80,6 +80,18 @@ def custom_event_context_extractor(lambda_event):
8080
8181from opentelemetry import context as context_api
8282from opentelemetry .context .context import Context
83+ from opentelemetry .instrumentation ._semconv import (
84+ _get_schema_url ,
85+ _OpenTelemetrySemanticConventionStability ,
86+ _OpenTelemetryStabilitySignalType ,
87+ _set_http_method ,
88+ _set_http_net_host ,
89+ _set_http_scheme ,
90+ _set_http_status_code ,
91+ _set_http_target ,
92+ _set_http_user_agent ,
93+ _StabilityMode ,
94+ )
8395from opentelemetry .instrumentation .aws_lambda .package import _instruments
8496from opentelemetry .instrumentation .aws_lambda .version import __version__
8597from opentelemetry .instrumentation .instrumentor import BaseInstrumentor
@@ -95,15 +107,7 @@ def custom_event_context_extractor(lambda_event):
95107 FAAS_TRIGGER ,
96108)
97109from opentelemetry .semconv ._incubating .attributes .http_attributes import (
98- HTTP_METHOD ,
99110 HTTP_ROUTE ,
100- HTTP_SCHEME ,
101- HTTP_STATUS_CODE ,
102- HTTP_TARGET ,
103- HTTP_USER_AGENT ,
104- )
105- from opentelemetry .semconv ._incubating .attributes .net_attributes import (
106- NET_HOST_NAME ,
107111)
108112from opentelemetry .trace import (
109113 Span ,
@@ -113,6 +117,10 @@ def custom_event_context_extractor(lambda_event):
113117 get_tracer_provider ,
114118)
115119from opentelemetry .trace .status import Status , StatusCode
120+ from opentelemetry .util .http import (
121+ _parse_url_query ,
122+ sanitize_method ,
123+ )
116124
117125logger = logging .getLogger (__name__ )
118126
@@ -181,86 +189,135 @@ def _determine_parent_context(
181189
182190
183191def _set_api_gateway_v1_proxy_attributes (
184- lambda_event : Any , span : Span
192+ lambda_event : Any ,
193+ span : Span ,
194+ sem_conv_opt_in_mode : _StabilityMode = _StabilityMode .DEFAULT ,
185195) -> Span :
186196 """Sets HTTP attributes for REST APIs and v1 HTTP APIs
187197
188198 More info:
189199 https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
190200 """
191- span .set_attribute (HTTP_METHOD , lambda_event .get ("httpMethod" ))
201+ http_method = lambda_event .get ("httpMethod" )
202+ if not http_method :
203+ http_method = (
204+ lambda_event .get ("requestContext" , {})
205+ .get ("http" , {})
206+ .get ("method" )
207+ )
208+ result = {}
209+ _set_http_method (
210+ result , http_method , sanitize_method (http_method ), sem_conv_opt_in_mode
211+ )
192212
193213 if lambda_event .get ("headers" ):
194214 if "User-Agent" in lambda_event ["headers" ]:
195- span . set_attribute (
196- HTTP_USER_AGENT ,
215+ _set_http_user_agent (
216+ result ,
197217 lambda_event ["headers" ]["User-Agent" ],
218+ sem_conv_opt_in_mode ,
198219 )
199220 if "X-Forwarded-Proto" in lambda_event ["headers" ]:
200- span . set_attribute (
201- HTTP_SCHEME ,
221+ _set_http_scheme (
222+ result ,
202223 lambda_event ["headers" ]["X-Forwarded-Proto" ],
224+ sem_conv_opt_in_mode ,
203225 )
204226 if "Host" in lambda_event ["headers" ]:
205- span .set_attribute (
206- NET_HOST_NAME ,
207- lambda_event ["headers" ]["Host" ],
208- )
227+ host = lambda_event ["headers" ]["Host" ]
228+ _set_http_net_host (result , host , sem_conv_opt_in_mode )
209229 if "resource" in lambda_event :
210230 span .set_attribute (HTTP_ROUTE , lambda_event ["resource" ])
211231
212232 if lambda_event .get ("queryStringParameters" ):
213- span .set_attribute (
214- HTTP_TARGET ,
215- f"{ lambda_event ['resource' ]} ?{ urlencode (lambda_event ['queryStringParameters' ])} " ,
233+ http_target = f"{ lambda_event ['resource' ]} ?{ urlencode (lambda_event ['queryStringParameters' ])} "
234+ path , query = _parse_url_query (http_target )
235+ _set_http_target (
236+ result ,
237+ http_target ,
238+ path ,
239+ query ,
240+ sem_conv_opt_in_mode ,
216241 )
217242 else :
218- span .set_attribute (HTTP_TARGET , lambda_event ["resource" ])
243+ res = lambda_event ["resource" ]
244+ path , query = _parse_url_query (res )
245+ _set_http_target (
246+ result ,
247+ res ,
248+ path ,
249+ query ,
250+ sem_conv_opt_in_mode ,
251+ )
252+
253+ for key , value in result .items ():
254+ span .set_attribute (key , value )
219255
220256 return span
221257
222258
223259def _set_api_gateway_v2_proxy_attributes (
224- lambda_event : Any , span : Span
260+ lambda_event : Any ,
261+ span : Span ,
262+ sem_conv_opt_in_mode : _StabilityMode = _StabilityMode .DEFAULT ,
225263) -> Span :
226264 """Sets HTTP attributes for v2 HTTP APIs
227265
228266 More info:
229267 https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
230268 """
269+ result = {}
231270 if "domainName" in lambda_event ["requestContext" ]:
232- span . set_attribute (
233- NET_HOST_NAME ,
271+ _set_http_net_host (
272+ result ,
234273 lambda_event ["requestContext" ]["domainName" ],
274+ sem_conv_opt_in_mode ,
235275 )
236276
237277 if lambda_event ["requestContext" ].get ("http" ):
238278 if "method" in lambda_event ["requestContext" ]["http" ]:
239- span .set_attribute (
240- HTTP_METHOD ,
241- lambda_event ["requestContext" ]["http" ]["method" ],
279+ http_method = lambda_event ["requestContext" ]["http" ]["method" ]
280+ _set_http_method (
281+ result ,
282+ http_method ,
283+ sanitize_method (http_method ),
284+ sem_conv_opt_in_mode ,
242285 )
243286 if "userAgent" in lambda_event ["requestContext" ]["http" ]:
244- span . set_attribute (
245- HTTP_USER_AGENT ,
287+ _set_http_user_agent (
288+ result ,
246289 lambda_event ["requestContext" ]["http" ]["userAgent" ],
290+ sem_conv_opt_in_mode ,
247291 )
248292 if "path" in lambda_event ["requestContext" ]["http" ]:
249293 span .set_attribute (
250294 HTTP_ROUTE ,
251295 lambda_event ["requestContext" ]["http" ]["path" ],
252296 )
253297 if lambda_event .get ("rawQueryString" ):
254- span .set_attribute (
255- HTTP_TARGET ,
256- f"{ lambda_event ['requestContext' ]['http' ]['path' ]} ?{ lambda_event ['rawQueryString' ]} " ,
298+ http_target = f"{ lambda_event ['requestContext' ]['http' ]['path' ]} ?{ lambda_event ['rawQueryString' ]} "
299+ path , query = _parse_url_query (http_target )
300+ _set_http_target (
301+ result ,
302+ http_target ,
303+ path ,
304+ query ,
305+ sem_conv_opt_in_mode ,
257306 )
258307 else :
259- span .set_attribute (
260- HTTP_TARGET ,
261- lambda_event ["requestContext" ]["http" ]["path" ],
308+ http_target = lambda_event ["requestContext" ]["http" ]["path" ]
309+ path , query = _parse_url_query (http_target )
310+ _set_http_target (
311+ result ,
312+ http_target ,
313+ path ,
314+ query ,
315+ sem_conv_opt_in_mode ,
262316 )
263317
318+ for key , value in result .items ():
319+ span .set_attribute (key , value )
320+
264321 return span
265322
266323
@@ -272,6 +329,7 @@ def _instrument(
272329 event_context_extractor : Callable [[Any ], Context ],
273330 tracer_provider : TracerProvider = None ,
274331 meter_provider : MeterProvider = None ,
332+ sem_conv_opt_in_mode : _StabilityMode = _StabilityMode .DEFAULT ,
275333):
276334 # pylint: disable=too-many-locals
277335 # pylint: disable=too-many-statements
@@ -314,7 +372,7 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches
314372 __name__ ,
315373 __version__ ,
316374 tracer_provider ,
317- schema_url = "https://opentelemetry.io/schemas/1.11.0" ,
375+ schema_url = _get_schema_url ( sem_conv_opt_in_mode ) ,
318376 )
319377
320378 token = context_api .attach (parent_context )
@@ -371,18 +429,22 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches
371429
372430 if lambda_event .get ("version" ) == "2.0" :
373431 _set_api_gateway_v2_proxy_attributes (
374- lambda_event , span
432+ lambda_event , span , sem_conv_opt_in_mode
375433 )
376434 else :
377435 _set_api_gateway_v1_proxy_attributes (
378- lambda_event , span
436+ lambda_event , span , sem_conv_opt_in_mode
379437 )
380438
381439 if isinstance (result , dict ) and result .get ("statusCode" ):
382- span .set_attribute (
383- HTTP_STATUS_CODE ,
440+ attribute = {}
441+ _set_http_status_code (
442+ attribute ,
384443 result .get ("statusCode" ),
444+ sem_conv_opt_in_mode ,
385445 )
446+ for key , value in attribute .items ():
447+ span .set_attribute (key , value )
386448 finally :
387449 if token :
388450 context_api .detach (token )
@@ -480,6 +542,10 @@ def _instrument(self, **kwargs):
480542 flush_timeout_env ,
481543 )
482544
545+ sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability ._get_opentelemetry_stability_opt_in_mode (
546+ _OpenTelemetryStabilitySignalType .HTTP ,
547+ )
548+
483549 _instrument (
484550 self ._wrapped_module_name ,
485551 self ._wrapped_function_name ,
@@ -489,6 +555,7 @@ def _instrument(self, **kwargs):
489555 ),
490556 tracer_provider = kwargs .get ("tracer_provider" ),
491557 meter_provider = kwargs .get ("meter_provider" ),
558+ sem_conv_opt_in_mode = sem_conv_opt_in_mode ,
492559 )
493560
494561 def _uninstrument (self , ** kwargs ):
0 commit comments