Skip to content

Commit 79309d7

Browse files
committed
Fix: Support new fields in X-Ray API responses
1 parent 5d769ca commit 79309d7

5 files changed

Lines changed: 123 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ For any change that affects end users of this package, please add an entry under
1111
If your change does not need a CHANGELOG entry, add the "skip changelog" label to your PR.
1212

1313
## Unreleased
14+
15+
- Fix: Support new fields in X-Ray API responses
16+
([#577](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/577))
1417
- Sign Lambda layer by AWS Signer
1518
([#573](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/573))
1619
- Support PyPI Signature

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/sampler/_sampling_rule.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

4+
from logging import getLogger
5+
6+
_logger = getLogger(__name__)
7+
48

59
# Disable snake_case naming style so this class can match the sampling rules response from X-Ray
610
# pylint: disable=invalid-name
@@ -20,6 +24,7 @@ def __init__(
2024
ServiceType: str = None,
2125
URLPath: str = None,
2226
Version: int = None,
27+
**kwargs,
2328
):
2429
self.Attributes = Attributes if Attributes is not None else {}
2530
self.FixedRate = FixedRate if FixedRate is not None else 0.0
@@ -36,6 +41,10 @@ def __init__(
3641
self.URLPath = URLPath if URLPath is not None else ""
3742
self.Version = Version if Version is not None else 0
3843

44+
# Log unknown fields for debugging/monitoring
45+
if kwargs:
46+
_logger.debug("Ignoring unknown fields in _SamplingRule: %s", list(kwargs.keys()))
47+
3948
def __lt__(self, other: "_SamplingRule") -> bool:
4049
if self.Priority == other.Priority:
4150
# String order priority example:

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/sampler/_sampling_target.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
from logging import getLogger
4+
from typing import List
45

56
_logger = getLogger(__name__)
67

@@ -15,47 +16,62 @@ def __init__(
1516
ReservoirQuota: int = None,
1617
ReservoirQuotaTTL: float = None,
1718
RuleName: str = None,
19+
**kwargs,
1820
):
1921
self.FixedRate = FixedRate if FixedRate is not None else 0.0
2022
self.Interval = Interval # can be None
2123
self.ReservoirQuota = ReservoirQuota # can be None
2224
self.ReservoirQuotaTTL = ReservoirQuotaTTL # can be None
2325
self.RuleName = RuleName if RuleName is not None else ""
2426

27+
# Log unknown fields for debugging/monitoring
28+
if kwargs:
29+
_logger.debug("Ignoring unknown fields in _SamplingTarget: %s", list(kwargs.keys()))
30+
2531

2632
class _UnprocessedStatistics:
2733
def __init__(
2834
self,
2935
ErrorCode: str = None,
3036
Message: str = None,
3137
RuleName: str = None,
38+
**kwargs,
3239
):
3340
self.ErrorCode = ErrorCode if ErrorCode is not None else ""
3441
self.Message = Message if ErrorCode is not None else ""
3542
self.RuleName = RuleName if ErrorCode is not None else ""
3643

44+
# Log unknown fields for debugging/monitoring
45+
if kwargs:
46+
_logger.debug("Ignoring unknown fields in _UnprocessedStatistics: %s", list(kwargs.keys()))
47+
3748

3849
class _SamplingTargetResponse:
3950
def __init__(
4051
self,
4152
LastRuleModification: float,
42-
SamplingTargetDocuments: [dict] = None,
43-
UnprocessedStatistics: [dict] = None,
53+
SamplingTargetDocuments: List[dict] = None,
54+
UnprocessedStatistics: List[dict] = None,
55+
**kwargs,
4456
):
4557
self.LastRuleModification: float = LastRuleModification if LastRuleModification is not None else 0.0
4658

47-
self.SamplingTargetDocuments: [_SamplingTarget] = []
59+
self.SamplingTargetDocuments: List[_SamplingTarget] = []
4860
if SamplingTargetDocuments is not None:
4961
for document in SamplingTargetDocuments:
5062
try:
5163
self.SamplingTargetDocuments.append(_SamplingTarget(**document))
5264
except TypeError as e:
5365
_logger.debug("TypeError occurred: %s", e)
5466

55-
self.UnprocessedStatistics: [_UnprocessedStatistics] = []
67+
self.UnprocessedStatistics: List[_UnprocessedStatistics] = []
5668
if UnprocessedStatistics is not None:
5769
for unprocessed in UnprocessedStatistics:
5870
try:
5971
self.UnprocessedStatistics.append(_UnprocessedStatistics(**unprocessed))
6072
except TypeError as e:
6173
_logger.debug("TypeError occurred: %s", e)
74+
75+
# Log unknown fields for debugging/monitoring
76+
if kwargs:
77+
_logger.debug("Ignoring unknown fields in _SamplingTargetResponse: %s", list(kwargs.keys()))

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/sampler/test_sampling_rule.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
from unittest import TestCase
4+
from unittest.mock import patch
45

56
from amazon.opentelemetry.distro.sampler._sampling_rule import _SamplingRule
67

@@ -16,6 +17,36 @@ def test_sampling_rule_ordering(self):
1617

1718
self.assertTrue(rule1 < rule2 < rule3 < rule4 < rule5 < rule6)
1819

20+
def test_sampling_rule_with_extra_fields(self):
21+
inputs = {
22+
"Attributes": {},
23+
"FixedRate": 0.1,
24+
"HTTPMethod": "GET",
25+
"Host": "localhost",
26+
"Priority": 20,
27+
"ReservoirSize": 1,
28+
"ResourceARN": "*",
29+
"RuleARN": "arn:aws:xray:us-east-1:999999999999:sampling-rule/test",
30+
"RuleName": "test",
31+
"ServiceName": "myServiceName",
32+
"ServiceType": "AWS::EKS::Container",
33+
"URLPath": "/helloworld",
34+
"Version": 1,
35+
"ExtraField1": "cat",
36+
"ExtraField2": 123,
37+
}
38+
39+
# Does not throw an error and logs debug message about unknown fields
40+
with patch("amazon.opentelemetry.distro.sampler._sampling_rule._logger") as mock_logger:
41+
rule = _SamplingRule(**inputs)
42+
mock_logger.debug.assert_called_once_with(
43+
"Ignoring unknown fields in _SamplingRule: %s", ["ExtraField1", "ExtraField2"]
44+
)
45+
46+
self.assertEqual(rule.FixedRate, 0.1)
47+
self.assertEqual(rule.RuleName, "test")
48+
self.assertEqual(rule.ServiceName, "myServiceName")
49+
1950
def test_sampling_rule_equality(self):
2051
sampling_rule = _SamplingRule(
2152
Attributes={"abc": "123", "def": "4?6", "ghi": "*89"},

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/sampler/test_sampling_target.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,44 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
from unittest import TestCase
4+
from unittest.mock import patch
45

5-
from amazon.opentelemetry.distro.sampler._sampling_target import _SamplingTargetResponse
6+
from amazon.opentelemetry.distro.sampler._sampling_target import _SamplingTarget, _SamplingTargetResponse
67

78

89
class TestSamplingTarget(TestCase):
10+
def test_sampling_target_with_none_inputs(self):
11+
target = _SamplingTarget()
12+
self.assertEqual(target.FixedRate, 0.0)
13+
self.assertEqual(target.RuleName, "")
14+
self.assertIsNone(target.Interval)
15+
self.assertIsNone(target.ReservoirQuota)
16+
self.assertIsNone(target.ReservoirQuotaTTL)
17+
18+
def test_sampling_target_with_extra_inputs(self):
19+
inputs = {
20+
"FixedRate": 1.0,
21+
"RuleName": "cat",
22+
"Interval": 123,
23+
"ReservoirQuota": 456,
24+
"ReservoirQuotaTTL": 789,
25+
"ExtraField1": "cat",
26+
"ExtraField2": 123,
27+
}
28+
29+
with patch("amazon.opentelemetry.distro.sampler._sampling_target._logger") as mock_logger:
30+
target = _SamplingTarget(**inputs)
31+
mock_logger.debug.assert_called_once_with(
32+
"Ignoring unknown fields in _SamplingTarget: %s", ["ExtraField1", "ExtraField2"]
33+
)
34+
35+
self.assertEqual(target.FixedRate, 1.0)
36+
self.assertEqual(target.RuleName, "cat")
37+
self.assertEqual(target.Interval, 123)
38+
self.assertEqual(target.ReservoirQuota, 456)
39+
self.assertEqual(target.ReservoirQuotaTTL, 789)
40+
self.assertFalse(hasattr(target, "ExtraField2"))
41+
942
def test_sampling_target_response_with_none_inputs(self):
1043
target_response = _SamplingTargetResponse(None, None, None)
1144
self.assertEqual(target_response.LastRuleModification, 0.0)
@@ -28,5 +61,29 @@ def test_sampling_target_response_with_invalid_inputs(self):
2861
self.assertEqual(target_response.UnprocessedStatistics[0].RuleName, "")
2962

3063
target_response = _SamplingTargetResponse(1.0, [{"foo": "bar"}], [{"dog": "cat"}])
31-
self.assertEqual(len(target_response.SamplingTargetDocuments), 0)
32-
self.assertEqual(len(target_response.UnprocessedStatistics), 0)
64+
self.assertEqual(len(target_response.SamplingTargetDocuments), 1)
65+
self.assertEqual(len(target_response.UnprocessedStatistics), 1)
66+
67+
def test_sampling_target_response_with_extra_inputs(self):
68+
inputs = {
69+
"LastRuleModification": 1.0,
70+
"SamplingTargetDocuments": [{}],
71+
"UnprocessedStatistics": [{}],
72+
"ExtraField1": "cat",
73+
"ExtraField2": 123,
74+
}
75+
76+
# Does not throw an error and logs debug message about unknown fields
77+
with patch("amazon.opentelemetry.distro.sampler._sampling_target._logger") as mock_logger:
78+
target_response = _SamplingTargetResponse(**inputs)
79+
mock_logger.debug.assert_called_once_with(
80+
"Ignoring unknown fields in _SamplingTargetResponse: %s", ["ExtraField1", "ExtraField2"]
81+
)
82+
83+
self.assertEqual(target_response.LastRuleModification, 1.0)
84+
self.assertEqual(len(target_response.SamplingTargetDocuments), 1)
85+
self.assertEqual(target_response.SamplingTargetDocuments[0].FixedRate, 0)
86+
self.assertEqual(target_response.SamplingTargetDocuments[0].Interval, None)
87+
self.assertEqual(target_response.SamplingTargetDocuments[0].ReservoirQuota, None)
88+
self.assertEqual(target_response.SamplingTargetDocuments[0].ReservoirQuotaTTL, None)
89+
self.assertEqual(target_response.SamplingTargetDocuments[0].RuleName, "")

0 commit comments

Comments
 (0)