-
Notifications
You must be signed in to change notification settings - Fork 429
feat(tracer): Support for external observability providers - Tracer #2342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
06c9110
refactor to standalone tracer class
roger-zhangg 5eab094
refactor tracer provider, add a xray provider
roger-zhangg cbd75f9
fix static checking error
roger-zhangg a6c6171
Merge branch 'develop' into tracer
roger-zhangg 927710c
add_dd_poc
roger-zhangg e6b3a7c
first working POC for dd
roger-zhangg dde7b7f
fix close
roger-zhangg da8effc
add OPTL POC
roger-zhangg 61f5757
add new base and xray provider
roger-zhangg 0cb8463
add functional xray provider
roger-zhangg 7f8bf6c
Merging from develop
leandrodamascena 64dd749
Merging from develop
leandrodamascena f5fa320
Merging from develop
leandrodamascena 52cab66
Merge branch 'develop' into tracer
leandrodamascena ef7c509
fix to pass test
roger-zhangg f66ad21
Merge branch 'tracer' of github.com:roger-zhangg/aws-lambda-powertool…
roger-zhangg 2c3f42e
Merging from develop
leandrodamascena 78051f6
fix mypy, move into folder
roger-zhangg bf16f6e
Merge branch 'develop' into tracer
roger-zhangg 5bc0158
fix poetry
roger-zhangg fe9c763
add set_attribute in tracer
roger-zhangg d49e1cc
fix context datadog
roger-zhangg 7fc17b3
Merge branch 'develop' into tracer
roger-zhangg 5134c36
Merge remote-tracking branch 'upstream/develop' into tracer
leandrodamascena 1b28653
Merging from develop
leandrodamascena b1a2b34
fix docstring, add conversion in otel
roger-zhangg ed1059b
fix typo
roger-zhangg 4639bd4
add in_subsegment_async in dd
roger-zhangg 012f8a8
remove discuss
roger-zhangg c9592c5
Merge branch 'develop' into tracer
roger-zhangg f0561cc
fix poetry
roger-zhangg 33e0225
Merging from develop
leandrodamascena 0ac3800
Merging from develop
leandrodamascena dede79c
merge from develop
roger-zhangg 844d85b
address ruben comments
roger-zhangg cedb2af
change to new example
roger-zhangg ee869b3
change to new example
roger-zhangg 68ee403
docstring in current base class
roger-zhangg 07714e9
refactor set_attribute, fix test
roger-zhangg 8712a30
Merge branch 'develop' of github.com:roger-zhangg/aws-lambda-powertoo…
roger-zhangg 5fb7990
fix poetry
roger-zhangg aeaf6ff
remote print
roger-zhangg 024db25
Addressing Ruben's feedback
leandrodamascena 80739fd
Reveting possible breaking change
leandrodamascena d502dbf
Merging from develop
leandrodamascena 7efe7e4
Merging from develop
leandrodamascena File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import abc | ||
from contextlib import asynccontextmanager, contextmanager | ||
from typing import Any, AsyncGenerator, Generator, Sequence | ||
|
||
|
||
class BaseSpan(abc.ABC): | ||
"""A span represents a unit of work or operation within a trace. | ||
Spans are the building blocks of Traces.""" | ||
|
||
@abc.abstractmethod | ||
def set_attribute(self, key: str, value: Any, **kwargs) -> None: | ||
"""Set an attribute for a span with a key-value pair. | ||
|
||
Parameters | ||
---------- | ||
key: str | ||
Attribute key | ||
value: Any | ||
Attribute value | ||
kwargs: Optional[dict] | ||
Optional parameters | ||
""" | ||
|
||
@abc.abstractmethod | ||
def record_exception(self, exception: BaseException, **kwargs): | ||
"""Records an exception to this Span. | ||
|
||
Parameters | ||
---------- | ||
exception: Exception | ||
Caught exception during the exectution of this Span | ||
kwargs: Optional[dict] | ||
Optional parameters | ||
""" | ||
|
||
|
||
class BaseProvider(abc.ABC): | ||
"""BaseProvider is an abstract base class that defines the expected behavior for tracing providers | ||
used by Tracer. Inheriting classes must implement this interface to be compatible with Tracer. | ||
""" | ||
|
||
@abc.abstractmethod | ||
@contextmanager | ||
def trace(self, name: str, **kwargs) -> Generator[BaseSpan, None, None]: | ||
"""Context manager for creating a new span and set it | ||
as the current span in this tracer's context. | ||
|
||
Exiting the context manager will call the span's end method, | ||
as well as return the current span to its previous value by | ||
returning to the previous context. | ||
|
||
Parameters | ||
---------- | ||
name: str | ||
Span name | ||
kwargs: Optional[dict] | ||
Optional parameters to be propagated to the span | ||
""" | ||
|
||
@abc.abstractmethod | ||
@asynccontextmanager | ||
def trace_async(self, name: str, **kwargs) -> AsyncGenerator[BaseSpan, None]: | ||
"""Async Context manager for creating a new span and set it | ||
as the current span in this tracer's context. | ||
|
||
Exiting the context manager will call the span's end method, | ||
as well as return the current span to its previous value by | ||
returning to the previous context. | ||
|
||
Parameters | ||
---------- | ||
name: str | ||
Span name | ||
kwargs: Optional[dict] | ||
Optional parameters to be propagated to the span | ||
""" | ||
|
||
@abc.abstractmethod | ||
def set_attribute(self, key: str, value: Any, **kwargs) -> None: | ||
"""set attribute on current active span with a key-value pair. | ||
|
||
Parameters | ||
---------- | ||
key: str | ||
attribute key | ||
value: Any | ||
attribute value | ||
kwargs: Optional[dict] | ||
Optional parameters to be propagated to the span | ||
""" | ||
|
||
@abc.abstractmethod | ||
def patch(self, modules: Sequence[str]) -> None: | ||
"""Instrument a set of given libraries if supported by provider | ||
See specific provider for more detail | ||
|
||
Exmaple | ||
------- | ||
tracer = Tracer(service="payment") | ||
libraries = (['aioboto3',mysql]) | ||
# provider.patch will be called by tracer.patch | ||
tracer.patch(libraries) | ||
|
||
Parameters | ||
---------- | ||
modules: Set[str] | ||
Set of modules to be patched | ||
""" | ||
|
||
@abc.abstractmethod | ||
def patch_all(self) -> None: | ||
"""Instrument all supported libraries""" |
142 changes: 142 additions & 0 deletions
142
aws_lambda_powertools/tracing/provider/xray/xray_tracer.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
from __future__ import annotations | ||
|
||
from contextlib import asynccontextmanager, contextmanager | ||
from numbers import Number | ||
from typing import Any, AsyncGenerator, Generator, Literal, Sequence, Union | ||
|
||
from aws_lambda_powertools.shared import constants | ||
from aws_lambda_powertools.shared.lazy_import import LazyLoader | ||
from aws_lambda_powertools.tracing.provider.base import BaseProvider, BaseSpan | ||
|
||
aws_xray_sdk = LazyLoader(constants.XRAY_SDK_MODULE, globals(), constants.XRAY_SDK_MODULE) | ||
|
||
|
||
class XraySpan(BaseSpan): | ||
def __init__(self, subsegment): | ||
self.subsegment = subsegment | ||
self.add_subsegment = self.subsegment.add_subsegment | ||
self.remove_subsegment = self.subsegment.remove_subsegment | ||
self.put_annotation = self.subsegment.put_annotation | ||
self.put_metadata = self.subsegment.put_metadata | ||
self.add_exception = self.subsegment.add_exception | ||
self.close = self.subsegment.close | ||
|
||
def set_attribute( | ||
self, | ||
key: str, | ||
value: Any, | ||
category: Literal["Annotation", "Metadata", "Auto"] = "Auto", | ||
**kwargs, | ||
) -> None: | ||
""" | ||
Set an attribute on this span with a key-value pair. | ||
|
||
Parameters | ||
---------- | ||
key: str | ||
attribute key | ||
value: Any | ||
Value for attribute | ||
category: Literal["Annotation","Metadata","Auto"] = "Auto" | ||
This parameter specifies the category of attribute to set. | ||
- **"Annotation"**: Sets the attribute as an Annotation. | ||
- **"Metadata"**: Sets the attribute as Metadata. | ||
- **"Auto" (default)**: Automatically determines the attribute | ||
type based on its value. | ||
|
||
kwargs: Optional[dict] | ||
Optional parameters to be passed to provider.set_attributes | ||
""" | ||
if category == "Annotation": | ||
self.put_annotation(key=key, value=value) | ||
return | ||
|
||
if category == "Metadata": | ||
self.put_metadata(key=key, value=value, namespace=kwargs.get("namespace", "dafault")) | ||
return | ||
|
||
# Auto | ||
if isinstance(value, (str, Number, bool)): | ||
self.put_annotation(key=key, value=value) | ||
return | ||
|
||
# Auto & not in (str, Number, bool) | ||
self.put_metadata(key=key, value=value, namespace=kwargs.get("namespace", "dafault")) | ||
|
||
def record_exception(self, exception: BaseException, **kwargs): | ||
stack = aws_xray_sdk.core.utils.stacktrace.get_stacktrace() | ||
self.add_exception(exception=exception, stack=stack) | ||
|
||
|
||
class XrayProvider(BaseProvider): | ||
def __init__(self, xray_recorder=None): | ||
if not xray_recorder: | ||
from aws_xray_sdk.core import xray_recorder | ||
|
||
self.recorder = xray_recorder | ||
self.in_subsegment = self.recorder.in_subsegment | ||
self.in_subsegment_async = self.recorder.in_subsegment_async | ||
|
||
@contextmanager | ||
def trace(self, name: str, **kwargs) -> Generator[XraySpan, None, None]: | ||
with self.in_subsegment(name=name, **kwargs) as sub_segment: | ||
yield XraySpan(subsegment=sub_segment) | ||
|
||
@asynccontextmanager | ||
async def trace_async(self, name: str, **kwargs) -> AsyncGenerator[XraySpan, None]: | ||
async with self.in_subsegment_async(name=name, **kwargs) as subsegment: | ||
yield XraySpan(subsegment=subsegment) | ||
|
||
def set_attribute( | ||
self, | ||
key: str, | ||
value: Any, | ||
category: Literal["Annotation", "Metadata", "Auto"] = "Auto", | ||
**kwargs, | ||
) -> None: | ||
""" | ||
Set an attribute on the current active span with a key-value pair. | ||
|
||
Parameters | ||
---------- | ||
key: str | ||
attribute key | ||
value: Any | ||
Value for attribute | ||
category: Literal["Annotation","Metadata","Auto"] = "Auto" | ||
This parameter specifies the type of attribute to set. | ||
- **"Annotation"**: Sets the attribute as an Annotation. | ||
- **"Metadata"**: Sets the attribute as Metadata. | ||
- **"Auto" (default)**: Automatically determines the attribute | ||
type based on its value. | ||
|
||
kwargs: Optional[dict] | ||
Optional parameters to be passed to provider.set_attributes | ||
""" | ||
if category == "Annotation": | ||
self.put_annotation(key=key, value=value) | ||
return | ||
|
||
if category == "Metadata": | ||
self.put_metadata(key=key, value=value, namespace=kwargs.get("namespace", "dafault")) | ||
return | ||
|
||
# Auto | ||
if isinstance(value, (str, Number, bool)): | ||
self.put_annotation(key=key, value=value) | ||
return | ||
|
||
# Auto & not in (str, Number, bool) | ||
self.put_metadata(key=key, value=value, namespace=kwargs.get("namespace", "dafault")) | ||
|
||
def put_annotation(self, key: str, value: Union[str, Number, bool]) -> None: | ||
return self.recorder.put_annotation(key=key, value=value) | ||
|
||
def put_metadata(self, key: str, value: Any, namespace: str = "default") -> None: | ||
return self.recorder.put_metadata(key=key, value=value, namespace=namespace) | ||
|
||
def patch(self, modules: Sequence[str]) -> None: | ||
return aws_xray_sdk.core.patch(modules) | ||
|
||
def patch_all(self) -> None: | ||
return aws_xray_sdk.core.patch_all() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.