You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Which AWS Lambda Powertools utility does this relate to?
Tracer
Summary
This RFC is one of the three that defines the format when setting up loggers, metrics and traces for better integration with other observability providers.
This RFC is specifically for the Tracer. Currently, we have undocumented BaseProvider for Tracer, but we need to decide more on what minimum features the BaseProvider should support. The RFC discusses on the features that could be a part of custom tracer for users to integrate other Observability providers easily.
Use case
The use case for this utility would be for developers who want to use other observability providers to trace their application, other than AWS X-Ray.
Proposal
Current tracer experience
The Powertools’ tracer utility is essentially a wrapper for the AWS X-Ray SDK. Some key features of this utility include auto capturing cold start as annotation, auto capturing responses or full exceptions as metadata, and auto-disabling when not running in AWS Lambda environment. Tracer also auto patches supported modules by AWS X-Ray.
fromaws_lambda_powertoolsimportTracerfromaws_lambda_powertools.utilities.typingimportLambdaContext# Current experience in using metrics should not changetracer=Tracer(service="ServerlessAirline")
defcollect_payment(charge_id: str) ->str:
returnf"dummy payment collected for charge: {charge_id}"@tracer.capture_lambda_handlerdefhandler(event: dict, context: LambdaContext) ->str:
charge_id=event.get("charge_id", "")
returncollect_payment(charge_id=charge_id)
We propose a new parameter to the existing tracer utility that developers can use to specify which observability provider they would like their traces to be pushed to. The below code snippet is a rudimentary look at how this utility can be used and how it will function. Out of the box, we will support DataDog. Other providers TBD
If you would like to use an observability provider not supported out of the box, or define their own tracer functions, we will define an interface that the customer can implement and pass in to the Tracer class.
fromaws_lambda_powertools.tracing.tracerimportTracerfromaws_lambda_powertools.utilities.typingimportLambdaContextfromaws_lambda_powertools.tracing.baseimportBaseProviderfromcontextlibimportcontextmanagerimportthreadingimportasyncioclassCustomTracerProvider(BaseProvider):
_thread_local=threading.local()
@contextmanagerdeftrace_context(self):
# when we enter this context, we start a new span and store its contextifnothasattr(self._thread_local, "trace_id"):
self._thread_local.trace_id=self.start_span()
try:
yieldfinally:
self.end_span(self._thread_local.trace_id)
@contextmanagerdeftrace(self, span:"Span",parent_context: Optional[context_api.Context] =None) ->None:
# when we enter this we start a child span with the given parent contexttry:
self.start_span(self, span, parent_context=parent_context)
yieldfinally:
self.end_span(self, span)
defstart_span(self, span, parent_context: Optional[context_api.Context] =None) ->span:
"""This method is proposed as a solution as it exists for other providers This method is responsible for starting the trace. This might involve initializing some data structures, connecting to an external service, or performing some other setup work"""returnspan()
defend_span(self, span):
"""This method is proposed as a solution as it exists for other providers. This method is responsible for ending the tracing of a span. This might involve finalizing data structures, sending data to an external service, or performing some other cleanup work"""defput_annotation(self, key: str, value: Union[str, numbers.Number, bool]) ->None:
"""Annotate current active trace entity with a key-value pair."""defput_metadata(self, key: str, value: Any, namespace: str="default") ->None:
"""Add metadata to the current active trace entity."""defadd_exception(self, exception):
"""Add an exception to trace entities."""defignore_endpoint(self, hostname: Optional[str] =None, urls: Optional[List[str]] =None):
"""To ignore the endpoints you don't want requests to be traced, perhaps due to the volume of calls or sensitive URLs. """definject_context(self,context):
"""To inject missing context/information like service name"""defcapture_method_async(self, method:Callable, capture_response: Optional[Union[bool, str]] =None, capture_error: Optional[Union[bool, str]] =None):
"""To capture async method"""tracer=Tracer({serviceName: 'serverlessAirline'},provider=CustomTracerProvider())
@tracer.capture_method_asyncasyncdefcollect_payment_async(charge_id: str) ->str:
tracer.put_annotation(key="PaymentId", value=charge_id)
awaitasyncio.sleep(0.5)
returnf"dummy payment collected for charge: {charge_id}"@tracer.capture_methoddefcollect_payment(charge_id: str) ->str:
returnf"dummy payment collected for charge: {charge_id}"@tracer.capture_lambda_handlerdefhandler(event: dict, context: LambdaContext) ->str:
charge_id=event.get("charge_id", "")
withtracer.provider.trace(span="charge"):
returncollect_payment(charge_id=charge_id)
The five methods defined above are a combination of methods that already exist in the BaseProvider and the ones that are most common in other observability providers.
The current BaseProvider does support most of the features used in the major observability providers. There are couple of differences I noticed while researching through the other Observability providers.
There is difference in nomenclature used to define data that gets received from services, Powertools call them segments whereas other observability providers call them span.
Observability providers like Datadog, Lumigo, NewRelic provides an option to start and end tracing through their start_span and end_span methods, whereas in Powertools we do not have such methods. The possible reason could be that AWS X-Ray anyway keeps track of how the request flows within the application from the start and if it doesn’t support any service, it gives an option to add a subsegment there to keep track of it. Whereas for most of the other providers we need to mention it to start and end tracing. We will add those methods so people can utilize them when using other providers with this capability.
Out of scope
Sending traces from Powertools to the customer's desired observability platform will not be in the scope of this project. The implementation should only support modifying the output of the Tracer so that the customer can push them to their platform of choice.
Potential challenges
We need to determine which platforms we want to support out-of-the-box (apart from Datadog).
Dependencies and Integrations
We will have to integrate with (and thus, have a dependency on) Datadog and any other platforms we decide to support out-of-the-box.
Is this related to an existing feature request or issue?
Issue: #1433
Logger RFC: #2014
Metrics RFC: #2015
Which AWS Lambda Powertools utility does this relate to?
Tracer
Summary
This RFC is one of the three that defines the format when setting up loggers, metrics and traces for better integration with other observability providers.
This RFC is specifically for the Tracer. Currently, we have undocumented BaseProvider for Tracer, but we need to decide more on what minimum features the
BaseProvidershould support. The RFC discusses on the features that could be a part of custom tracer for users to integrate other Observability providers easily.Use case
The use case for this utility would be for developers who want to use other observability providers to trace their application, other than AWS X-Ray.
Proposal
Current tracer experience
The Powertools’ tracer utility is essentially a wrapper for the AWS X-Ray SDK. Some key features of this utility include auto capturing cold start as annotation, auto capturing responses or full exceptions as metadata, and auto-disabling when not running in AWS Lambda environment. Tracer also auto patches supported modules by AWS X-Ray.
JSON output
{ "trace_id": "1-5e367daf-6c7f6d9f6c3a6e5800c7d42d", "id": "e986a861d4590d97", "name": "payment", "start_time": 1580441546.023, "end_time": 1580441552.983, "http": { "request": { "method": "GET", "url": "https://api.example.com/", "client_ip": "192.168.1.1", "user_agent": "Mozilla/5.0", }, "response": { "status": 200, "content_length": 1024, "headers": { "Content-Type": "application/json" } } }, "subsegments": [ { "id": "3b3b3d8ba74fa7fe", "name": "my-subsegment", "start_time": 1580441548.023, "end_time": 1580441551.983, "http": { "request": { "method": "POST", "url": "https://api.example.com/submit", "headers": { "Content-Type": "application/json", "Authorization": "Bearer abc123" }, "body": "{\"data\": \"example\"}" }, "response": { "status": 200, "content_length": 128, "headers": { "Content-Type": "application/json" } } }, "annotations": { "example": "annotation" } } ], "annotations": { "example": "annotation" }, "metadata": { "example": "metadata" } }Tracer proposal
We propose a new parameter to the existing tracer utility that developers can use to specify which observability provider they would like their traces to be pushed to. The below code snippet is a rudimentary look at how this utility can be used and how it will function. Out of the box, we will support DataDog. Other providers TBD
JSON output
{ "trace_id": "3541457326329954564", "span_id": "467508042476235233", "parent_id": "3541457326329954564", "name": "payment", "resource": "GET /api", "start": 1647370203.4475, "duration": 0.0325, "service": "serverlessAirline", "type": "web", "meta": { "http": { "method": "GET", "url": "http://localhost:8000/api", "status_code": 200 } } }Bring your own provider
If you would like to use an observability provider not supported out of the box, or define their own tracer functions, we will define an interface that the customer can implement and pass in to the Tracer class.
classDiagram class BaseProvider { +start_span() -> Span +end_span() -> Span +put_annotation(key: str, value: Union[str, numbers.Number, bool]) -> None +put_metadata(key: str, value: Any, namespace: str = "default") -> None } class CustomTracerProvider { +start_span() -> Span +end_span() -> Span +put_annotation(key: str, value: Union[str, numbers.Number, bool]) -> None +put_metadata(key: str, value: Any, namespace: str = "default") -> None } BaseProvider <|-- CustomTracerProviderExample
The five methods defined above are a combination of methods that already exist in the
BaseProviderand the ones that are most common in other observability providers.The current
BaseProviderdoes support most of the features used in the major observability providers. There are couple of differences I noticed while researching through the other Observability providers.Out of scope
Sending traces from Powertools to the customer's desired observability platform will not be in the scope of this project. The implementation should only support modifying the output of the Tracer so that the customer can push them to their platform of choice.
Potential challenges
We need to determine which platforms we want to support out-of-the-box (apart from Datadog).
Dependencies and Integrations
We will have to integrate with (and thus, have a dependency on) Datadog and any other platforms we decide to support out-of-the-box.
Alternative solutions
No response
Acknowledgment