Skip to content

Commit 61f5757

Browse files
committed
add new base and xray provider
1 parent da8effc commit 61f5757

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import abc
2+
import numbers
3+
from contextlib import contextmanager
4+
from typing import Generator, Sequence, Union
5+
6+
7+
## TO-Discuss how to refactor this one. Segment seems X-ray exclusive concept
8+
class BaseSpan(abc.ABC):
9+
"""Holds common properties and methods on segment and subsegment."""
10+
11+
@abc.abstractmethod
12+
def set_attribute(self, key: str, value: Union[str, numbers.Number, bool], **kwargs) -> None:
13+
"""Annotate segment or subsegment with a key-value pair.
14+
15+
Note: Annotations will be indexed for later search query.
16+
17+
Parameters
18+
----------
19+
key: str
20+
Metadata key
21+
value: Union[str, numbers.Number, bool]
22+
Annotation value
23+
"""
24+
25+
@abc.abstractmethod
26+
def record_exception(self, exception: BaseException, **kwargs):
27+
"""Add an exception to trace entities.
28+
29+
Parameters
30+
----------
31+
exception: Exception
32+
Caught exception
33+
Output from `traceback.extract_stack()`.
34+
"""
35+
36+
37+
class BaseProvider(abc.ABC):
38+
@abc.abstractmethod
39+
@contextmanager
40+
def trace(self, name=None, **kwargs) -> Generator[BaseSpan, None, None]:
41+
"""Return a span context manger.
42+
43+
Parameters
44+
----------
45+
name: str
46+
Span name
47+
kwargs: Optional[dict]
48+
Optional parameters to be propagated to span
49+
"""
50+
51+
@abc.abstractmethod
52+
@contextmanager
53+
def trace_async(self, name=None, **kwargs) -> Generator[BaseSpan, None, None]:
54+
"""Return a async span context manger.
55+
56+
Parameters
57+
----------
58+
name: str
59+
Span name
60+
kwargs: Optional[dict]
61+
Optional parameters to be propagated to span
62+
"""
63+
64+
@abc.abstractmethod
65+
def set_attribute(self, key: str, value: Union[str, numbers.Number, bool], **kwargs) -> None:
66+
"""Annotate current active trace entity with a key-value pair.
67+
68+
Note: Annotations will be indexed for later search query.
69+
70+
Parameters
71+
----------
72+
key: str
73+
Metadata key
74+
value: Union[str, numbers.Number, bool]
75+
Annotation value
76+
"""
77+
78+
@abc.abstractmethod
79+
def patch(self, modules: Sequence[str]) -> None:
80+
"""Instrument a set of supported libraries
81+
82+
Parameters
83+
----------
84+
modules: Set[str]
85+
Set of modules to be patched
86+
"""
87+
88+
@abc.abstractmethod
89+
def patch_all(self) -> None:
90+
"""Instrument all supported libraries"""

aws_lambda_powertools/tracing/provider/otel_tracer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
logger = logging.getLogger(__name__)
1414

1515

16+
# optl terminology first
17+
# 1. Provider based on OTel terminology
18+
# 2. X-Ray provider on top of the new BaseProvider
19+
# 3. Datadog provider on top of the new BaseProvider
20+
# access xray sdk
1621
class OtelSpan(BaseSegment):
1722
def __init__(self, otel_span=otel_trace.Span):
1823
self.otel_span = otel_span
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from __future__ import annotations
2+
3+
from contextlib import contextmanager
4+
from numbers import Number
5+
from typing import Generator
6+
7+
from ...shared import constants
8+
from ...shared.lazy_import import LazyLoader
9+
from .base import BaseProvider, BaseSpan
10+
11+
aws_xray_sdk = LazyLoader(constants.XRAY_SDK_MODULE, globals(), constants.XRAY_SDK_MODULE)
12+
13+
14+
class XraySpan(BaseSpan):
15+
def __init__(self, subsegment):
16+
self.subsegment = subsegment
17+
self.add_subsegment = self.subsegment.add_subsegment
18+
self.remove_subsegment = self.subsegment.remove_subsegment
19+
self.put_annotation = self.subsegment.put_annotation
20+
self.put_metadata = self.subsegment.put_metadata
21+
self.add_exception = self.subsegment.add_exception
22+
self.close = self.subsegment.close
23+
24+
def set_attribute(self, key: str, value: str | Number | bool, **kwargs) -> None:
25+
if kwargs.get("namespace", "") != "":
26+
self.put_metadata(key=key, value=value, namespace=kwargs["namespace"])
27+
else:
28+
self.put_annotation(key=key, value=value)
29+
30+
def record_exception(self, exception: BaseException, **kwargs):
31+
stack = aws_xray_sdk.core.utils.stacktrace.get_stacktrace(limit=self._max_trace_back)
32+
self.add_exception(exception=exception, stack=stack)
33+
34+
35+
class XrayProvider(BaseProvider):
36+
def __init__(self, xray_recorder=None):
37+
if not xray_recorder:
38+
from aws_xray_sdk.core import xray_recorder
39+
self.recorder = xray_recorder
40+
self.patch = aws_xray_sdk.core.patch
41+
self.patch_all = aws_xray_sdk.core.patch_all
42+
self.in_subsegment = self.recorder.in_subsegment
43+
self.in_subsegment_async = self.recorder.in_subsegment_async
44+
self.put_annotation = self.recorder.put_annotation
45+
self.put_metadata = self.recorder.put_metadata
46+
47+
@contextmanager
48+
def trace(self, name: str) -> Generator[XraySpan, None, None]:
49+
with self.in_subsegment(name=name) as sub_segment:
50+
yield XraySpan(subsegment=sub_segment)
51+
52+
@contextmanager
53+
def trace_async(self, name: str) -> Generator[XraySpan, None, None]:
54+
with self.in_subsegment_async(name=name) as sub_segment:
55+
yield XraySpan(subsegment=sub_segment)
56+
57+
def set_attribute(self, key: str, value: str | Number | bool, **kwargs) -> None:
58+
if kwargs.get("namespace", "") != "":
59+
self.put_metadata(key=key, value=value, namespace=kwargs["namespace"])
60+
else:
61+
self.put_annotation(key=key, value=value)

0 commit comments

Comments
 (0)