Skip to content

Commit 7c4f239

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat-free-threaded-python
2 parents acd9a47 + 81d01e1 commit 7c4f239

File tree

11 files changed

+446
-30
lines changed

11 files changed

+446
-30
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
platforms: arm64
9090

9191
- name: Build Wheels
92-
uses: pypa/cibuildwheel@faf86a6ed7efa889faf6996aa23820831055001a # 2.23.3
92+
uses: pypa/cibuildwheel@9c00cb4f6b517705a3794b22395aedc36257242c # 3.2.1
9393
env:
9494
CIBW_PLATFORM: auto
9595
CIBW_BUILD: "${{ matrix.wheel }}*"

.github/workflows/tests.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,12 @@ jobs:
374374

375375
- name: Install Python
376376
run: |
377-
uv python install -f 3.13 3.14 3.14t
378-
uv python install -f --default 3.13
377+
uv python install -f \
378+
cpython-3.13-windows-aarch64-none \
379+
cpython-3.14-windows-aarch64-none \
380+
cpython-3.14t-windows-aarch64-none
381+
uv python install -f --default \
382+
cpython-3.13-windows-aarch64-none
379383
380384
- name: Install Dependencies
381385
run: |

.github/workflows/trivy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ jobs:
6161

6262
- name: Upload Trivy scan results to GitHub Security tab
6363
if: ${{ github.event_name == 'schedule' }}
64-
uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # 4.31.0
64+
uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # 4.31.2
6565
with:
6666
sarif_file: "trivy-results.sarif"

newrelic/core/config.py

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -803,9 +803,9 @@ def default_otlp_host(host):
803803
_settings.compressed_content_encoding = "gzip"
804804
_settings.max_payload_size_in_bytes = 1000000
805805

806-
_settings.attributes.enabled = True
807-
_settings.attributes.exclude = []
808-
_settings.attributes.include = []
806+
_settings.attributes.enabled = _environ_as_bool("NEW_RELIC_ATTRIBUTES_ENABLED", default=True)
807+
_settings.attributes.exclude = _environ_as_set(os.environ.get("NEW_RELIC_ATTRIBUTES_EXCLUDE", ""))
808+
_settings.attributes.include = _environ_as_set(os.environ.get("NEW_RELIC_ATTRIBUTES_INCLUDE", ""))
809809

810810
_settings.thread_profiler.enabled = True
811811
_settings.cross_application_tracer.enabled = False
@@ -821,9 +821,15 @@ def default_otlp_host(host):
821821
_settings.event_harvest_config.harvest_limits.analytic_event_data = _environ_as_int(
822822
"NEW_RELIC_ANALYTICS_EVENTS_MAX_SAMPLES_STORED", default=DEFAULT_RESERVOIR_SIZE
823823
)
824-
_settings.transaction_events.attributes.enabled = True
825-
_settings.transaction_events.attributes.exclude = []
826-
_settings.transaction_events.attributes.include = []
824+
_settings.transaction_events.attributes.enabled = _environ_as_bool(
825+
"NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_ENABLED", default=True
826+
)
827+
_settings.transaction_events.attributes.exclude = _environ_as_set(
828+
os.environ.get("NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_EXCLUDE", "")
829+
)
830+
_settings.transaction_events.attributes.include = _environ_as_set(
831+
os.environ.get("NEW_RELIC_TRANSACTION_EVENTS_ATTRIBUTES_INCLUDE", "")
832+
)
827833

828834
_settings.custom_insights_events.enabled = True
829835
_settings.event_harvest_config.harvest_limits.custom_event_data = _environ_as_int(
@@ -847,13 +853,23 @@ def default_otlp_host(host):
847853
_settings.event_harvest_config.harvest_limits.span_event_data = _environ_as_int(
848854
"NEW_RELIC_SPAN_EVENTS_MAX_SAMPLES_STORED", default=SPAN_EVENT_RESERVOIR_SIZE
849855
)
850-
_settings.span_events.attributes.enabled = True
851-
_settings.span_events.attributes.exclude = []
852-
_settings.span_events.attributes.include = []
856+
_settings.span_events.attributes.enabled = _environ_as_bool("NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_ENABLED", default=True)
857+
_settings.span_events.attributes.exclude = _environ_as_set(
858+
os.environ.get("NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_EXCLUDE", "")
859+
)
860+
_settings.span_events.attributes.include = _environ_as_set(
861+
os.environ.get("NEW_RELIC_SPAN_EVENTS_ATTRIBUTES_INCLUDE", "")
862+
)
853863

854-
_settings.transaction_segments.attributes.enabled = True
855-
_settings.transaction_segments.attributes.exclude = []
856-
_settings.transaction_segments.attributes.include = []
864+
_settings.transaction_segments.attributes.enabled = _environ_as_bool(
865+
"NEW_RELIC_TRANSACTION_SEGMENTS_ATTRIBUTES_ENABLED", default=True
866+
)
867+
_settings.transaction_segments.attributes.exclude = _environ_as_set(
868+
os.environ.get("NEW_RELIC_TRANSACTION_SEGMENTS_ATTRIBUTES_EXCLUDE", "")
869+
)
870+
_settings.transaction_segments.attributes.include = _environ_as_set(
871+
os.environ.get("NEW_RELIC_TRANSACTION_SEGMENTS_ATTRIBUTES_INCLUDE", "")
872+
)
857873

858874
_settings.transaction_tracer.enabled = True
859875
_settings.transaction_tracer.transaction_threshold = None
@@ -864,9 +880,15 @@ def default_otlp_host(host):
864880
_settings.transaction_tracer.function_trace = []
865881
_settings.transaction_tracer.generator_trace = []
866882
_settings.transaction_tracer.top_n = 20
867-
_settings.transaction_tracer.attributes.enabled = True
868-
_settings.transaction_tracer.attributes.exclude = []
869-
_settings.transaction_tracer.attributes.include = []
883+
_settings.transaction_tracer.attributes.enabled = _environ_as_bool(
884+
"NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_ENABLED", default=True
885+
)
886+
_settings.transaction_tracer.attributes.exclude = _environ_as_set(
887+
os.environ.get("NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_EXCLUDE", "")
888+
)
889+
_settings.transaction_tracer.attributes.include = _environ_as_set(
890+
os.environ.get("NEW_RELIC_TRANSACTION_TRACER_ATTRIBUTES_INCLUDE", "")
891+
)
870892

871893
_settings.error_collector.enabled = True
872894
_settings.error_collector.capture_events = True
@@ -879,9 +901,15 @@ def default_otlp_host(host):
879901
)
880902
_settings.error_collector.expected_status_codes = set()
881903
_settings.error_collector._error_group_callback = None
882-
_settings.error_collector.attributes.enabled = True
883-
_settings.error_collector.attributes.exclude = []
884-
_settings.error_collector.attributes.include = []
904+
_settings.error_collector.attributes.enabled = _environ_as_bool(
905+
"NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_ENABLED", default=True
906+
)
907+
_settings.error_collector.attributes.exclude = _environ_as_set(
908+
os.environ.get("NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_EXCLUDE", "")
909+
)
910+
_settings.error_collector.attributes.include = _environ_as_set(
911+
os.environ.get("NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_INCLUDE", "")
912+
)
885913

886914
_settings.browser_monitoring.enabled = True
887915
_settings.browser_monitoring.auto_instrument = True
@@ -890,9 +918,15 @@ def default_otlp_host(host):
890918
_settings.browser_monitoring.debug = False
891919
_settings.browser_monitoring.ssl_for_http = None
892920
_settings.browser_monitoring.content_type = ["text/html"]
893-
_settings.browser_monitoring.attributes.enabled = False
894-
_settings.browser_monitoring.attributes.exclude = []
895-
_settings.browser_monitoring.attributes.include = []
921+
_settings.browser_monitoring.attributes.enabled = _environ_as_bool(
922+
"NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_ENABLED", default=False
923+
)
924+
_settings.browser_monitoring.attributes.exclude = _environ_as_set(
925+
os.environ.get("NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_EXCLUDE", "")
926+
)
927+
_settings.browser_monitoring.attributes.include = _environ_as_set(
928+
os.environ.get("NEW_RELIC_BROWSER_MONITORING_ATTRIBUTES_INCLUDE", "")
929+
)
896930

897931
_settings.transaction_name.limit = None
898932
_settings.transaction_name.naming_scheme = os.environ.get("NEW_RELIC_TRANSACTION_NAMING_SCHEME")

newrelic/hooks/external_botocore.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ def extract_bedrock_claude_model_request(request_body, bedrock_attrs):
394394
]
395395
else:
396396
input_message_list = [{"role": "user", "content": request_body.get("prompt")}]
397-
bedrock_attrs["request.max_tokens"] = request_body.get("max_tokens_to_sample")
397+
bedrock_attrs["request.max_tokens"] = request_body.get("max_tokens_to_sample") or request_body.get("max_tokens")
398398
bedrock_attrs["request.temperature"] = request_body.get("temperature")
399399
bedrock_attrs["input_message_list"] = input_message_list
400400

@@ -406,7 +406,13 @@ def extract_bedrock_claude_model_response(response_body, bedrock_attrs):
406406
response_body = json.loads(response_body)
407407
role = response_body.get("role", "assistant")
408408
content = response_body.get("content") or response_body.get("completion")
409-
output_message_list = [{"role": role, "content": content}]
409+
410+
# For Claude Sonnet 3+ models, the content key holds a list with the type and text of the output
411+
if isinstance(content, list):
412+
output_message_list = [{"role": "assistant", "content": result.get("text")} for result in content]
413+
else:
414+
output_message_list = [{"role": role, "content": content}]
415+
410416
bedrock_attrs["response.choices.finish_reason"] = response_body.get("stop_reason")
411417
bedrock_attrs["output_message_list"] = output_message_list
412418

@@ -420,6 +426,7 @@ def extract_bedrock_claude_model_streaming_response(response_body, bedrock_attrs
420426
bedrock_attrs["output_message_list"] = [{"role": "assistant", "content": ""}]
421427
bedrock_attrs["output_message_list"][0]["content"] += content
422428
bedrock_attrs["response.choices.finish_reason"] = response_body.get("stop_reason")
429+
423430
return bedrock_attrs
424431

425432

@@ -639,7 +646,7 @@ def _wrap_bedrock_runtime_invoke_model(wrapped, instance, args, kwargs):
639646

640647
# Determine extractor by model type
641648
for extractor_name, request_extractor, response_extractor, stream_extractor in MODEL_EXTRACTORS: # noqa: B007
642-
if model.startswith(extractor_name):
649+
if extractor_name in model:
643650
break
644651
else:
645652
# Model was not found in extractor list
@@ -1057,6 +1064,13 @@ def handle_chat_completion_event(transaction, bedrock_attrs):
10571064

10581065
input_message_list = bedrock_attrs.get("input_message_list", [])
10591066
output_message_list = bedrock_attrs.get("output_message_list", [])
1067+
1068+
no_output_content = len(output_message_list) == 1 and not output_message_list[0].get("content", "")
1069+
1070+
# This checks handles Sonnet 3+ models which report an additional empty input and empty output in streaming cases after the main content has been generated
1071+
if not input_message_list and no_output_content:
1072+
return
1073+
10601074
number_of_messages = (
10611075
len(input_message_list) + len(output_message_list)
10621076
) or None # If 0, attribute will be set to None and removed
@@ -1374,6 +1388,7 @@ def wrap_serialize_to_request(wrapped, instance, args, kwargs):
13741388
extract_agent_attrs=extract_kinesis_agent_attrs,
13751389
library="Kinesis",
13761390
),
1391+
("kinesis", "describe_account_settings"): aws_function_trace("describe_account_settings", library="Kinesis"),
13771392
("kinesis", "describe_limits"): aws_function_trace("describe_limits", library="Kinesis"),
13781393
("kinesis", "describe_stream"): aws_function_trace(
13791394
"describe_stream", extract_kinesis, extract_agent_attrs=extract_kinesis_agent_attrs, library="Kinesis"
@@ -1451,6 +1466,7 @@ def wrap_serialize_to_request(wrapped, instance, args, kwargs):
14511466
("kinesis", "untag_resource"): aws_function_trace(
14521467
"untag_resource", extract_kinesis, extract_agent_attrs=extract_kinesis_agent_attrs, library="Kinesis"
14531468
),
1469+
("kinesis", "update_account_settings"): aws_function_trace("update_account_settings", library="Kinesis"),
14541470
("kinesis", "update_max_record_size"): aws_function_trace(
14551471
"update_max_record_size", extract_kinesis, extract_agent_attrs=extract_kinesis_agent_attrs, library="Kinesis"
14561472
),
@@ -1460,6 +1476,12 @@ def wrap_serialize_to_request(wrapped, instance, args, kwargs):
14601476
("kinesis", "update_stream_mode"): aws_function_trace(
14611477
"update_stream_mode", extract_kinesis, extract_agent_attrs=extract_kinesis_agent_attrs, library="Kinesis"
14621478
),
1479+
("kinesis", "update_stream_warm_throughput"): aws_function_trace(
1480+
"update_stream_warm_throughput",
1481+
extract_kinesis,
1482+
extract_agent_attrs=extract_kinesis_agent_attrs,
1483+
library="Kinesis",
1484+
),
14631485
("kinesis", "put_record"): aws_message_trace(
14641486
"Produce", "Stream", extract_kinesis, extract_agent_attrs=extract_kinesis_agent_attrs, library="Kinesis"
14651487
),

tests/agent_unittests/test_agent_protocol.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ def test_connect(
466466
# Verify that agent settings sent have converted null, containers, and
467467
# unserializable types to string
468468
assert agent_settings_payload["proxy_host"] == "None"
469-
assert agent_settings_payload["attributes.include"] == "[]"
469+
assert agent_settings_payload["attributes.include"] == str(set())
470470
assert agent_settings_payload["feature_flag"] == str(set())
471471
assert isinstance(agent_settings_payload["attribute_filter"], str)
472472

tests/external_aiobotocore/test_bedrock_chat_completion_invoke_model.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def request_streaming(request):
7373
"amazon.titan-text-express-v1",
7474
"ai21.j2-mid-v1",
7575
"anthropic.claude-instant-v1",
76+
"anthropic.claude-3-sonnet-20240229-v1:0",
7677
"meta.llama2-13b-chat-v1",
7778
"mistral.mistral-7b-instruct-v0:2",
7879
],

0 commit comments

Comments
 (0)