Skip to content

Commit bb2cfd7

Browse files
authored
Merge branch 'master' into master
2 parents e441b84 + 39303a5 commit bb2cfd7

27 files changed

+415
-94
lines changed

.github/workflows/IntegrationTesting.yaml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
branches:
55
- master
66

7+
permissions:
8+
id-token: write
9+
contents: read
10+
711
jobs:
812
build_SDK:
913
name: Build X-Ray Python SDK
@@ -78,10 +82,9 @@ jobs:
7882
run: cp deploy.zip ./terraform
7983

8084
- name: Configure AWS Credentials
81-
uses: aws-actions/configure-aws-credentials@v1
85+
uses: aws-actions/configure-aws-credentials@v4
8286
with:
83-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
84-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
87+
role-to-assume: ${{ secrets.AWS_INTEG_TEST_ROLE_ARN }}
8588
aws-region: us-west-2
8689

8790
- name: Setup Terraform
@@ -126,10 +129,9 @@ jobs:
126129
java-version: 14
127130

128131
- name: Configure AWS Credentials
129-
uses: aws-actions/configure-aws-credentials@v1
132+
uses: aws-actions/configure-aws-credentials@v4
130133
with:
131-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
132-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
134+
role-to-assume: ${{ secrets.AWS_INTEG_TEST_ROLE_ARN }}
133135
aws-region: us-west-2
134136

135137
- name: Checkout test framework

.github/workflows/UnitTesting.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ jobs:
1616
py39: 3.9
1717
py310: '3.10'
1818
py311: '3.11'
19+
py312: '3.12'
1920
DB_DATABASE: test_db
2021
DB_USER: root
2122
DB_PASSWORD: root
2223
strategy:
2324
fail-fast: false
2425
matrix:
25-
python-version: [py37, py38, py39, py310, py311]
26+
python-version: [py37, py38, py39, py310, py311, py312]
2627
testenv: [core, ext]
2728
steps:
2829
- name: Checkout repo
@@ -33,14 +34,17 @@ jobs:
3334
run: |
3435
sudo /etc/init.d/mysql start
3536
mysql -e 'CREATE DATABASE ${{ env.DB_DATABASE }};' -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }}
36-
37+
mysql -e 'CREATE DATABASE test_dburl;' -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }}
38+
mysql -e "CREATE USER test_dburl_user@localhost IDENTIFIED BY 'test]password';" -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }}
39+
mysql -e "GRANT ALL PRIVILEGES ON test_dburl.* TO test_dburl_user@localhost;" -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }}
40+
mysql -e "FLUSH PRIVILEGES;" -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }}
3741
- name: Setup Python
3842
uses: actions/setup-python@v4
3943
with:
4044
python-version: ${{ env[matrix.python-version] }}
4145

4246
- name: Install tox
43-
run: pip install "tox<=3.27.1" -U tox-factor
47+
run: pip install "tox<=3.27.1" -U tox-factor setuptools
4448

4549
- name: Cache tox environment
4650
# Preserves .tox directory between runs for faster installs

.github/workflows/continuous-monitoring.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
schedule:
55
- cron: '*/10 * * * *'
66

7+
permissions:
8+
id-token: write
9+
contents: read
10+
711
jobs:
812
smoke-tests:
913
name: Run smoke tests
@@ -13,10 +17,9 @@ jobs:
1317
uses: actions/checkout@v3
1418

1519
- name: Configure AWS Credentials
16-
uses: aws-actions/configure-aws-credentials@v1
20+
uses: aws-actions/configure-aws-credentials@v4
1721
with:
18-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
19-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
22+
role-to-assume: ${{ secrets.AWS_INTEG_TEST_ROLE_ARN }}
2023
aws-region: us-east-1
2124

2225
- uses: actions/setup-python@v4

CHANGELOG.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,32 @@ CHANGELOG
55
Unreleased
66
==========
77

8+
2.14.0
9+
==========
10+
* bugfix: Fix warning message condition for subsegment ending `https://github.com/aws/aws-xray-sdk-python/pull/434`
11+
12+
2.13.1
13+
==========
14+
* improvement: Bump idna from 3.6 to 3.7 in /sample-apps/flask `https://github.com/aws/aws-xray-sdk-python/pull/425`
15+
* bugfix: Fix end_time param type docstring from int to float `https://github.com/aws/aws-xray-sdk-python/pull/426`
16+
* improvement: Bump werkzeug from 3.0.1 to 3.0.3 in /sample-apps/flask `https://github.com/aws/aws-xray-sdk-python/pull/428`
17+
* improvement: [LambdaContext] Create dummy segment when trace header is incomplete `https://github.com/aws/aws-xray-sdk-python/pull/429`
18+
* bugfix: [LambdaContext] Fix logging to only happen inside lambda function `https://github.com/aws/aws-xray-sdk-python/pull/431`
19+
20+
2.13.0
21+
==========
22+
* bugfix: Fix passing multiple values in testenv.passenv in tox.ini `https://github.com/aws/aws-xray-sdk-python/pull/399`
23+
* improvement: Pin flask < 3.x for flask sqlalchemy tests `https://github.com/aws/aws-xray-sdk-python/pull/412`
24+
* improvement: Bump werkzeug from 2.2.3 to 3.0.1 in /sample-apps/flask `https://github.com/aws/aws-xray-sdk-python/pull/413`
25+
* improvement: Fix typo in docs `https://github.com/aws/aws-xray-sdk-python/pull/419`
26+
* bugfix: Fix sqlalchemy_core patch errors for unencoded special characters in db url `https://github.com/aws/aws-xray-sdk-python/pull/418`
27+
* bugfix: Fix EB platform version for integration test `https://github.com/aws/aws-xray-sdk-python/pull/420`
28+
29+
2.12.1
30+
==========
31+
* bugfix: set_trace_entity() in lambda adds segment to thread `PR409 https://github.com/aws/aws-xray-sdk-python/pull/409`
32+
* bugfix: Cleanup after drop of support for Python `PR387 https://github.com/aws/aws-xray-sdk-python/pull/387`
33+
834
2.12.0
935
==========
1036
* improvement: Default Context Missing Strategy set to Log Error `PR372 https://github.com/aws/aws-xray-sdk-python/pull/372`

aws_xray_sdk/core/context.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Context:
2222
replace the current stored entities and to clean up the storage.
2323
2424
For any data access or data mutation, if there is no active segment present
25-
if will use user-defined behavior to handle such case. By default it throws
25+
it will use user-defined behavior to handle such case. By default it throws
2626
an runtime error.
2727
2828
This data structure is thread-safe.
@@ -44,7 +44,7 @@ def end_segment(self, end_time=None):
4444
"""
4545
End the current active segment.
4646
47-
:param int end_time: epoch in seconds. If not specified the current
47+
:param float end_time: epoch in seconds. If not specified the current
4848
system time will be used.
4949
"""
5050
entity = self.get_trace_entity()
@@ -75,14 +75,16 @@ def end_subsegment(self, end_time=None):
7575
End the current active segment. Return False if there is no
7676
subsegment to end.
7777
78-
:param int end_time: epoch in seconds. If not specified the current
78+
:param float end_time: epoch in seconds. If not specified the current
7979
system time will be used.
8080
"""
81-
subsegment = self.get_trace_entity()
82-
if self._is_subsegment(subsegment):
83-
subsegment.close(end_time)
81+
entity = self.get_trace_entity()
82+
if self._is_subsegment(entity):
83+
entity.close(end_time)
8484
self._local.entities.pop()
8585
return True
86+
elif isinstance(entity, DummySegment):
87+
return False
8688
else:
8789
log.warning("No subsegment to end.")
8890
return False

aws_xray_sdk/core/lambda_launcher.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import threading
44

55
from aws_xray_sdk import global_sdk_config
6+
from .models.dummy_entities import DummySegment
67
from .models.facade_segment import FacadeSegment
78
from .models.trace_header import TraceHeader
89
from .context import Context
@@ -44,7 +45,7 @@ class LambdaContext(Context):
4445
"""
4546
Lambda service will generate a segment for each function invocation which
4647
cannot be mutated. The context doesn't keep any manually created segment
47-
but instead every time ``get_trace_entity()`` gets called it refresh the facade
48+
but instead every time ``get_trace_entity()`` gets called it refresh the
4849
segment based on environment variables set by Lambda worker.
4950
"""
5051
def __init__(self):
@@ -65,19 +66,31 @@ def end_segment(self, end_time=None):
6566

6667
def put_subsegment(self, subsegment):
6768
"""
68-
Refresh the facade segment every time this function is invoked to prevent
69+
Refresh the segment every time this function is invoked to prevent
6970
a new subsegment from being attached to a leaked segment/subsegment.
7071
"""
7172
current_entity = self.get_trace_entity()
7273

73-
if not self._is_subsegment(current_entity) and current_entity.initializing:
74-
if global_sdk_config.sdk_enabled():
74+
if not self._is_subsegment(current_entity) and (getattr(current_entity, 'initializing', None) or isinstance(current_entity, DummySegment)):
75+
if global_sdk_config.sdk_enabled() and not os.getenv(LAMBDA_TRACE_HEADER_KEY):
7576
log.warning("Subsegment %s discarded due to Lambda worker still initializing" % subsegment.name)
7677
return
7778

7879
current_entity.add_subsegment(subsegment)
7980
self._local.entities.append(subsegment)
8081

82+
def set_trace_entity(self, trace_entity):
83+
"""
84+
For Lambda context, we additionally store the segment in the thread local.
85+
"""
86+
if self._is_subsegment(trace_entity):
87+
segment = trace_entity.parent_segment
88+
else:
89+
segment = trace_entity
90+
91+
setattr(self._local, 'segment', segment)
92+
setattr(self._local, 'entities', [trace_entity])
93+
8194
def get_trace_entity(self):
8295
self._refresh_context()
8396
if getattr(self._local, 'entities', None):
@@ -87,9 +100,9 @@ def get_trace_entity(self):
87100

88101
def _refresh_context(self):
89102
"""
90-
Get current facade segment. To prevent resource leaking in Lambda worker,
103+
Get current segment. To prevent resource leaking in Lambda worker,
91104
every time there is segment present, we compare its trace id to current
92-
environment variables. If it is different we create a new facade segment
105+
environment variables. If it is different we create a new segment
93106
and clean up subsegments stored.
94107
"""
95108
header_str = os.getenv(LAMBDA_TRACE_HEADER_KEY)
@@ -124,8 +137,8 @@ def handle_context_missing(self):
124137

125138
def _initialize_context(self, trace_header):
126139
"""
127-
Create a facade segment based on environment variables
128-
set by AWS Lambda and initialize storage for subsegments.
140+
Create a segment based on environment variables set by
141+
AWS Lambda and initialize storage for subsegments.
129142
"""
130143
sampled = None
131144
if not global_sdk_config.sdk_enabled():
@@ -136,12 +149,17 @@ def _initialize_context(self, trace_header):
136149
elif trace_header.sampled == 1:
137150
sampled = True
138151

139-
segment = FacadeSegment(
140-
name='facade',
141-
traceid=trace_header.root,
142-
entityid=trace_header.parent,
143-
sampled=sampled,
144-
)
152+
segment = None
153+
if not trace_header.root or not trace_header.parent or trace_header.sampled is None:
154+
segment = DummySegment()
155+
log.debug("Creating NoOp/Dummy parent segment")
156+
else:
157+
segment = FacadeSegment(
158+
name='facade',
159+
traceid=trace_header.root,
160+
entityid=trace_header.parent,
161+
sampled=sampled,
162+
)
145163
segment.save_origin_trace_header(trace_header)
146164
setattr(self._local, 'segment', segment)
147165
setattr(self._local, 'entities', [])

aws_xray_sdk/core/models/entity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def close(self, end_time=None):
6464
Close the trace entity by setting `end_time`
6565
and flip the in progress flag to False.
6666
67-
:param int end_time: Epoch in seconds. If not specified
67+
:param float end_time: Epoch in seconds. If not specified
6868
current time will be used.
6969
"""
7070
self._check_ended()

aws_xray_sdk/core/models/subsegment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def close(self, end_time=None):
133133
and flip the in progress flag to False. Also decrement
134134
parent segment's ref counter by 1.
135135
136-
:param int end_time: Epoch in seconds. If not specified
136+
:param float end_time: Epoch in seconds. If not specified
137137
current time will be used.
138138
"""
139139
super().close(end_time)

aws_xray_sdk/core/patcher.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@
4949

5050

5151
def patch_all(double_patch=False):
52+
"""
53+
The X-Ray Python SDK supports patching aioboto3, aiobotocore, boto3, botocore, pynamodb, requests,
54+
sqlite3, mysql, httplib, pymongo, pymysql, psycopg2, pg8000, sqlalchemy_core, httpx, and mysql-connector.
55+
56+
To patch all supported libraries::
57+
58+
from aws_xray_sdk.core import patch_all
59+
60+
patch_all()
61+
62+
:param bool double_patch: enable or disable patching of indirect dependencies.
63+
"""
5264
if double_patch:
5365
patch(SUPPORTED_MODULES, raise_errors=False)
5466
else:
@@ -68,6 +80,16 @@ def _is_valid_import(module):
6880

6981

7082
def patch(modules_to_patch, raise_errors=True, ignore_module_patterns=None):
83+
"""
84+
To patch specific modules::
85+
86+
from aws_xray_sdk.core import patch
87+
88+
i_want_to_patch = ('botocore') # a tuple that contains the libs you want to patch
89+
patch(i_want_to_patch)
90+
91+
:param tuple modules_to_patch: a tuple containing the list of libraries to be patched
92+
"""
7193
enabled = global_sdk_config.sdk_enabled()
7294
if not enabled:
7395
log.debug("Skipped patching modules %s because the SDK is currently disabled." % ', '.join(modules_to_patch))

aws_xray_sdk/core/recorder.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def configure(self, sampling=None, plugins=None,
8888
8989
Configure needs to run before patching thrid party libraries
9090
to avoid creating dangling subsegment.
91+
9192
:param bool sampling: If sampling is enabled, every time the recorder
9293
creates a segment it decides whether to send this segment to
9394
the X-Ray daemon. This setting is not used if the recorder

aws_xray_sdk/core/sampling/local/sampling_rule.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class SamplingRule:
77
"""
8-
One SamolingRule represents one rule defined from local rule json file
8+
One SamplingRule represents one rule defined from local rule json file
99
or from a dictionary. It can be either a custom rule or default rule.
1010
"""
1111
FIXED_TARGET = 'fixed_target'

aws_xray_sdk/ext/sqlalchemy_core/patch.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import sys
3-
from urllib.parse import urlparse, uses_netloc
3+
from urllib.parse import urlparse, uses_netloc, quote_plus
44

55
import wrapt
66
from sqlalchemy.sql.expression import ClauseElement
@@ -14,18 +14,21 @@
1414
def _sql_meta(engine_instance, args):
1515
try:
1616
metadata = {}
17-
url = urlparse(str(engine_instance.engine.url))
17+
# Workaround for https://github.com/sqlalchemy/sqlalchemy/issues/10662
18+
# sqlalchemy.engine.url.URL's __repr__ does not url encode username nor password.
19+
# This will continue to work once sqlalchemy fixes the bug.
20+
sa_url = engine_instance.engine.url
21+
username = sa_url.username
22+
sa_url = sa_url._replace(username=None, password=None)
23+
url = urlparse(str(sa_url))
24+
name = url.netloc
25+
if username:
26+
# Restore url encoded username
27+
quoted_username = quote_plus(username)
28+
url = url._replace(netloc='{}@{}'.format(quoted_username, url.netloc))
1829
# Add Scheme to uses_netloc or // will be missing from url.
1930
uses_netloc.append(url.scheme)
20-
if url.password is None:
21-
metadata['url'] = url.geturl()
22-
name = url.netloc
23-
else:
24-
# Strip password from URL
25-
host_info = url.netloc.rpartition('@')[-1]
26-
parts = url._replace(netloc='{}@{}'.format(url.username, host_info))
27-
metadata['url'] = parts.geturl()
28-
name = host_info
31+
metadata['url'] = url.geturl()
2932
metadata['user'] = url.username
3033
metadata['database_type'] = engine_instance.engine.name
3134
try:

aws_xray_sdk/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = '2.12.0'
1+
VERSION = '2.14.0'

0 commit comments

Comments
 (0)