From 300d79365bf230a8f5a52f9537c0186972421728 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Fri, 29 Aug 2025 13:07:00 -0700 Subject: [PATCH 01/14] Remove add_custom_parameter(s) --- newrelic/agent.py | 4 --- newrelic/api/transaction.py | 46 ------------------------ tests/agent_features/test_span_events.py | 6 ++-- 3 files changed, 3 insertions(+), 53 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index 292a76fd2e..0d542b34ce 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -25,8 +25,6 @@ from newrelic.api.transaction import accept_distributed_trace_payload as __accept_distributed_trace_payload from newrelic.api.transaction import add_custom_attribute as __add_custom_attribute from newrelic.api.transaction import add_custom_attributes as __add_custom_attributes -from newrelic.api.transaction import add_custom_parameter as __add_custom_parameter -from newrelic.api.transaction import add_custom_parameters as __add_custom_parameters from newrelic.api.transaction import add_framework_info as __add_framework_info from newrelic.api.transaction import capture_request_params as __capture_request_params from newrelic.api.transaction import create_distributed_trace_payload as __create_distributed_trace_payload @@ -178,8 +176,6 @@ def __asgi_application(*args, **kwargs): ignore_transaction = __wrap_api_call(__ignore_transaction, "ignore_transaction") suppress_apdex_metric = __wrap_api_call(__suppress_apdex_metric, "suppress_apdex_metric") capture_request_params = __wrap_api_call(__capture_request_params, "capture_request_params") -add_custom_parameter = __wrap_api_call(__add_custom_parameter, "add_custom_parameter") -add_custom_parameters = __wrap_api_call(__add_custom_parameters, "add_custom_parameters") add_custom_attribute = __wrap_api_call(__add_custom_attribute, "add_custom_attribute") add_custom_attributes = __wrap_api_call(__add_custom_attributes, "add_custom_attributes") add_framework_info = __wrap_api_call(__add_framework_info, "add_framework_info") diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index 28d3a07638..c58cbbfa43 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -1788,28 +1788,6 @@ def add_custom_attributes(self, items): return result - # This function has been deprecated (and will be removed eventually) - # and therefore does not need to be included in coverage analysis - def add_custom_parameter(self, name, value): # pragma: no cover - # Deprecation warning - warnings.warn( - ("The add_custom_parameter API has been deprecated. Please use the add_custom_attribute API."), - DeprecationWarning, - stacklevel=2, - ) - return self.add_custom_attribute(name, value) - - # This function has been deprecated (and will be removed eventually) - # and therefore does not need to be included in coverage analysis - def add_custom_parameters(self, items): # pragma: no cover - # Deprecation warning - warnings.warn( - ("The add_custom_parameters API has been deprecated. Please use the add_custom_attributes API."), - DeprecationWarning, - stacklevel=2, - ) - return self.add_custom_attributes(items) - def add_framework_info(self, name, version=None): if name: self._frameworks.add((name, version)) @@ -1910,30 +1888,6 @@ def add_custom_attributes(items): return False -# This function has been deprecated (and will be removed eventually) -# and therefore does not need to be included in coverage analysis -def add_custom_parameter(key, value): # pragma: no cover - # Deprecation warning - warnings.warn( - ("The add_custom_parameter API has been deprecated. Please use the add_custom_attribute API."), - DeprecationWarning, - stacklevel=2, - ) - return add_custom_attribute(key, value) - - -# This function has been deprecated (and will be removed eventually) -# and therefore does not need to be included in coverage analysis -def add_custom_parameters(items): # pragma: no cover - # Deprecation warning - warnings.warn( - ("The add_custom_parameters API has been deprecated. Please use the add_custom_attributes API."), - DeprecationWarning, - stacklevel=2, - ) - return add_custom_attributes(items) - - def set_user_id(user_id): transaction = current_transaction() diff --git a/tests/agent_features/test_span_events.py b/tests/agent_features/test_span_events.py index 2d49ae01c6..89ecec0a17 100644 --- a/tests/agent_features/test_span_events.py +++ b/tests/agent_features/test_span_events.py @@ -516,9 +516,9 @@ def _test(): def test_span_user_attribute_overrides_transaction_attribute(): transaction = current_transaction() - transaction.add_custom_parameter("foo", "a") + transaction.add_custom_attribute("foo", "a") add_custom_span_attribute("foo", "b") - transaction.add_custom_parameter("foo", "c") + transaction.add_custom_attribute("foo", "c") @override_application_settings({"attributes.include": "*"}) @@ -563,7 +563,7 @@ def _test(): transaction = current_transaction() for i in range(128): - transaction.add_custom_parameter(f"txn_attr{i}", "txnValue") + transaction.add_custom_attribute(f"txn_attr{i}", "txnValue") if i < 64: add_custom_span_attribute(f"span_attr{i}", "spanValue") From 749f143de414a88ce85130138315530432ec37d3 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Fri, 29 Aug 2025 13:09:34 -0700 Subject: [PATCH 02/14] Remove get_browser_timing_footer --- newrelic/agent.py | 2 -- newrelic/api/transaction.py | 9 --------- 2 files changed, 11 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index 0d542b34ce..31b789d4e9 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -33,7 +33,6 @@ from newrelic.api.transaction import current_transaction as __current_transaction from newrelic.api.transaction import disable_browser_autorum as __disable_browser_autorum from newrelic.api.transaction import end_of_transaction as __end_of_transaction -from newrelic.api.transaction import get_browser_timing_footer as __get_browser_timing_footer from newrelic.api.transaction import get_browser_timing_header as __get_browser_timing_header from newrelic.api.transaction import ignore_transaction as __ignore_transaction from newrelic.api.transaction import insert_distributed_trace_headers as __insert_distributed_trace_headers @@ -182,7 +181,6 @@ def __asgi_application(*args, **kwargs): record_exception = __wrap_api_call(__record_exception, "record_exception") notice_error = __wrap_api_call(__notice_error, "notice_error") get_browser_timing_header = __wrap_api_call(__get_browser_timing_header, "get_browser_timing_header") -get_browser_timing_footer = __wrap_api_call(__get_browser_timing_footer, "get_browser_timing_footer") disable_browser_autorum = __wrap_api_call(__disable_browser_autorum, "disable_browser_autorum") suppress_transaction_trace = __wrap_api_call(__suppress_transaction_trace, "suppress_transaction_trace") record_custom_metric = __wrap_api_call(__record_custom_metric, "record_custom_metric") diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index c58cbbfa43..0da7f14887 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -1916,15 +1916,6 @@ def get_browser_timing_header(nonce=None): return "" -def get_browser_timing_footer(nonce=None): - warnings.warn( - "The get_browser_timing_footer function is deprecated. Please migrate to only using the get_browser_timing_header API instead.", - DeprecationWarning, - stacklevel=2, - ) - return "" - - def disable_browser_autorum(flag=True): transaction = current_transaction() if transaction: From e4bdbf2e735a9e7e2ef9aa623f635e2ca3305719 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Fri, 29 Aug 2025 13:14:03 -0700 Subject: [PATCH 03/14] Remove ignore_errors arg from error_trace --- newrelic/api/error_trace.py | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/newrelic/api/error_trace.py b/newrelic/api/error_trace.py index b67261d90a..bf9ea83d12 100644 --- a/newrelic/api/error_trace.py +++ b/newrelic/api/error_trace.py @@ -13,31 +13,21 @@ # limitations under the License. import functools -import warnings from newrelic.api.time_trace import current_trace, notice_error from newrelic.common.object_wrapper import FunctionWrapper, wrap_object class ErrorTrace: - def __init__(self, ignore_errors=None, ignore=None, expected=None, status_code=None, parent=None): - if ignore_errors is None: - ignore_errors = [] + def __init__(self, ignore=None, expected=None, status_code=None, parent=None): if parent is None: parent = current_trace() self._transaction = parent and parent.transaction - self._ignore = ignore if ignore is not None else ignore_errors + self._ignore = ignore self._expected = expected self._status_code = status_code - if ignore_errors: - warnings.warn( - ("The ignore_errors argument is deprecated. Please use the new ignore argument instead."), - DeprecationWarning, - stacklevel=2, - ) - def __enter__(self): return self @@ -53,9 +43,7 @@ def __exit__(self, exc, value, tb): ) -def ErrorTraceWrapper(wrapped, ignore_errors=None, ignore=None, expected=None, status_code=None): - if ignore_errors is None: - ignore_errors = [] +def ErrorTraceWrapper(wrapped, ignore=None, expected=None, status_code=None): def wrapper(wrapped, instance, args, kwargs): parent = current_trace() @@ -63,23 +51,19 @@ def wrapper(wrapped, instance, args, kwargs): if parent is None: return wrapped(*args, **kwargs) - with ErrorTrace(ignore_errors, ignore, expected, status_code, parent=parent): + with ErrorTrace(ignore, expected, status_code, parent=parent): return wrapped(*args, **kwargs) return FunctionWrapper(wrapped, wrapper) -def error_trace(ignore_errors=None, ignore=None, expected=None, status_code=None): - if ignore_errors is None: - ignore_errors = [] +def error_trace(ignore=None, expected=None, status_code=None): return functools.partial( - ErrorTraceWrapper, ignore_errors=ignore_errors, ignore=ignore, expected=expected, status_code=status_code + ErrorTraceWrapper, ignore=ignore, expected=expected, status_code=status_code ) -def wrap_error_trace(module, object_path, ignore_errors=None, ignore=None, expected=None, status_code=None): - if ignore_errors is None: - ignore_errors = [] +def wrap_error_trace(module, object_path, ignore=None, expected=None, status_code=None): - wrap_object(module, object_path, ErrorTraceWrapper, (ignore_errors, ignore, expected, status_code)) + wrap_object(module, object_path, ErrorTraceWrapper, (ignore, expected, status_code)) From e7c871e51c4fa783d2c6f40a4c235c1a6314601b Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Fri, 29 Aug 2025 13:22:31 -0700 Subject: [PATCH 04/14] Remove record_exception --- newrelic/agent.py | 2 -- newrelic/api/application.py | 10 ---------- newrelic/api/time_trace.py | 23 +---------------------- newrelic/api/transaction.py | 12 ------------ newrelic/core/agent.py | 10 ---------- newrelic/core/application.py | 14 -------------- newrelic/core/stats_engine.py | 10 ---------- 7 files changed, 1 insertion(+), 80 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index 31b789d4e9..366a6eaf42 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -20,7 +20,6 @@ from newrelic.api.time_trace import current_trace as __current_trace from newrelic.api.time_trace import get_linking_metadata as __get_linking_metadata from newrelic.api.time_trace import notice_error as __notice_error -from newrelic.api.time_trace import record_exception as __record_exception from newrelic.api.transaction import accept_distributed_trace_headers as __accept_distributed_trace_headers from newrelic.api.transaction import accept_distributed_trace_payload as __accept_distributed_trace_payload from newrelic.api.transaction import add_custom_attribute as __add_custom_attribute @@ -178,7 +177,6 @@ def __asgi_application(*args, **kwargs): add_custom_attribute = __wrap_api_call(__add_custom_attribute, "add_custom_attribute") add_custom_attributes = __wrap_api_call(__add_custom_attributes, "add_custom_attributes") add_framework_info = __wrap_api_call(__add_framework_info, "add_framework_info") -record_exception = __wrap_api_call(__record_exception, "record_exception") notice_error = __wrap_api_call(__notice_error, "notice_error") get_browser_timing_header = __wrap_api_call(__get_browser_timing_header, "get_browser_timing_header") disable_browser_autorum = __wrap_api_call(__disable_browser_autorum, "disable_browser_autorum") diff --git a/newrelic/api/application.py b/newrelic/api/application.py index 46f38967e7..aa9d871e45 100644 --- a/newrelic/api/application.py +++ b/newrelic/api/application.py @@ -110,16 +110,6 @@ def linked_applications(self): def link_to_application(self, name): self._linked[name] = True - def record_exception(self, exc=None, value=None, tb=None, params=None, ignore_errors=None): - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors) - def notice_error(self, error=None, attributes=None, expected=None, ignore=None, status_code=None): if not self.active: return diff --git a/newrelic/api/time_trace.py b/newrelic/api/time_trace.py index bef6f04561..e853d2e8b1 100644 --- a/newrelic/api/time_trace.py +++ b/newrelic/api/time_trace.py @@ -449,16 +449,6 @@ def notice_error(self, error=None, attributes=None, expected=None, ignore=None, settings, fullname, message, is_expected, error_group_name, custom_params, self.guid, tb, source=source ) - def record_exception(self, exc_info=None, params=None, ignore_errors=None): - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(error=exc_info, attributes=params, ignore=ignore_errors) - def _add_agent_attribute(self, key, value): self.agent_attributes[key] = value @@ -515,7 +505,7 @@ def _complete_trace(self): exc_data = self.exc_data self.exc_data = (None, None, None) - # Observe errors on the span only if record_exception hasn't been + # Observe errors on the span only if notice_error hasn't been # called already if exc_data[0] and "error.class" not in self.agent_attributes: self._observe_exception(exc_data) @@ -696,17 +686,6 @@ def get_linking_metadata(application=None): return metadata -def record_exception(exc=None, value=None, tb=None, params=None, ignore_errors=None, application=None): - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors, application=application) - - def notice_error(error=None, attributes=None, expected=None, ignore=None, status_code=None, application=None): if application is None: trace = current_trace() diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index 0da7f14887..76e3f57436 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -1599,18 +1599,6 @@ def record_log_event(self, message, level=None, timestamp=None, attributes=None, self._log_events.add(event, priority=priority) - # This function has been deprecated (and will be removed eventually) - # and therefore does not need to be included in coverage analysis - def record_exception(self, exc=None, value=None, tb=None, params=None, ignore_errors=None): # pragma: no cover - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors) - def notice_error(self, error=None, attributes=None, expected=None, ignore=None, status_code=None): settings = self._settings diff --git a/newrelic/core/agent.py b/newrelic/core/agent.py index ab5cdc19bd..02a9431301 100644 --- a/newrelic/core/agent.py +++ b/newrelic/core/agent.py @@ -473,16 +473,6 @@ def remove_thread_utilization(self): _utilization_trackers.clear() - def record_exception(self, app_name, exc=None, value=None, tb=None, params=None, ignore_errors=None): - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(app_name, error=(exc, value, tb), attributes=params, ignore=ignore_errors) - def notice_error(self, app_name, error=None, attributes=None, expected=None, ignore=None, status_code=None): application = self._applications.get(app_name, None) if application is None or not application.active: diff --git a/newrelic/core/application.py b/newrelic/core/application.py index 43fdddc0ed..9508fbc854 100644 --- a/newrelic/core/application.py +++ b/newrelic/core/application.py @@ -803,20 +803,6 @@ def remove_data_source(self, name): self._data_samplers.remove(data_sampler) - def record_exception(self, exc=None, value=None, tb=None, params=None, ignore_errors=None): - """Record a global exception against the application independent - of a specific transaction. - - """ - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors) - def notice_error(self, error=None, attributes=None, expected=None, ignore=None, status_code=None): """Record a global exception against the application independent of a specific transaction. diff --git a/newrelic/core/stats_engine.py b/newrelic/core/stats_engine.py index cc1bb42bee..a925e555a7 100644 --- a/newrelic/core/stats_engine.py +++ b/newrelic/core/stats_engine.py @@ -676,16 +676,6 @@ def record_time_metrics(self, metrics): for metric in metrics: self.record_time_metric(metric) - def record_exception(self, exc=None, value=None, tb=None, params=None, ignore_errors=None): - # Deprecation Warning - warnings.warn( - ("The record_exception function is deprecated. Please use the new api named notice_error instead."), - DeprecationWarning, - stacklevel=2, - ) - - self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors) - def notice_error(self, error=None, attributes=None, expected=None, ignore=None, status_code=None): attributes = attributes if attributes is not None else {} settings = self.__settings From c3fd216482acc3d1fc803bb68b2d1923c8dedff4 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 12:43:19 -0700 Subject: [PATCH 05/14] Remove accept_distributed_trace_payload --- newrelic/agent.py | 4 ---- newrelic/api/transaction.py | 24 ++++--------------- .../test_asgi_distributed_tracing.py | 3 ++- .../test_distributed_tracing.py | 11 +++++---- tests/agent_features/test_serverless_mode.py | 4 ++-- tests/cross_agent/test_distributed_tracing.py | 16 +++++++------ tests/datastore_psycopg/test_slow_sql.py | 6 ++--- tests/datastore_psycopg2/test_slow_sql.py | 3 ++- 8 files changed, 28 insertions(+), 43 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index 366a6eaf42..f6a0634589 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -21,7 +21,6 @@ from newrelic.api.time_trace import get_linking_metadata as __get_linking_metadata from newrelic.api.time_trace import notice_error as __notice_error from newrelic.api.transaction import accept_distributed_trace_headers as __accept_distributed_trace_headers -from newrelic.api.transaction import accept_distributed_trace_payload as __accept_distributed_trace_payload from newrelic.api.transaction import add_custom_attribute as __add_custom_attribute from newrelic.api.transaction import add_custom_attributes as __add_custom_attributes from newrelic.api.transaction import add_framework_info as __add_framework_info @@ -187,9 +186,6 @@ def __asgi_application(*args, **kwargs): record_log_event = __wrap_api_call(__record_log_event, "record_log_event") record_ml_event = __wrap_api_call(__record_ml_event, "record_ml_event") WithLlmCustomAttributes = __wrap_api_call(__WithLlmCustomAttributes, "WithLlmCustomAttributes") -accept_distributed_trace_payload = __wrap_api_call( - __accept_distributed_trace_payload, "accept_distributed_trace_payload" -) create_distributed_trace_payload = __wrap_api_call( __create_distributed_trace_payload, "create_distributed_trace_payload" ) diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index 76e3f57436..1d8769cead 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -1242,18 +1242,6 @@ def _accept_distributed_trace_payload(self, payload, transport_type="HTTP"): self._record_supportability("Supportability/DistributedTrace/AcceptPayload/Exception") return False - def accept_distributed_trace_payload(self, *args, **kwargs): - warnings.warn( - ( - "The accept_distributed_trace_payload API has been deprecated. " - "Please use the accept_distributed_trace_headers API." - ), - DeprecationWarning, - stacklevel=2, - ) - if not self._can_accept_distributed_trace_headers(): - return False - return self._accept_distributed_trace_payload(*args, **kwargs) def _accept_distributed_trace_data(self, data, transport_type): if transport_type not in DISTRIBUTED_TRACE_TRANSPORT_TYPES: @@ -1352,8 +1340,11 @@ def accept_distributed_trace_headers(self, headers, transport_type="HTTP"): self._record_supportability("Supportability/TraceContext/Accept/Success") return True elif distributed_header: - distributed_header = ensure_str(distributed_header) return self._accept_distributed_trace_payload(distributed_header, transport_type) + else: + # Do not return anything, but still generate supportability + # metric for the lack of payload/distributed_header + self._accept_distributed_trace_payload(distributed_header, transport_type) def _process_incoming_cat_headers(self, encoded_cross_process_id, encoded_txn_header): settings = self._settings @@ -2077,13 +2068,6 @@ def record_log_event(message, level=None, timestamp=None, attributes=None, appli application.record_log_event(message, level, timestamp, attributes=attributes, priority=priority) -def accept_distributed_trace_payload(payload, transport_type="HTTP"): - transaction = current_transaction() - if transaction: - return transaction.accept_distributed_trace_payload(payload, transport_type) - return False - - def accept_distributed_trace_headers(headers, transport_type="HTTP"): transaction = current_transaction() if transaction: diff --git a/tests/agent_features/test_asgi_distributed_tracing.py b/tests/agent_features/test_asgi_distributed_tracing.py index 35a7448125..ae50d45cf3 100644 --- a/tests/agent_features/test_asgi_distributed_tracing.py +++ b/tests/agent_features/test_asgi_distributed_tracing.py @@ -180,7 +180,8 @@ def _make_test_transaction(): ) def _test(): with _make_test_transaction() as transaction: - transaction.accept_distributed_trace_payload(dt_payload) + dt_headers = {"newrelic": dt_payload} + transaction.accept_distributed_trace_headers(dt_headers) if gen_error: try: diff --git a/tests/agent_features/test_distributed_tracing.py b/tests/agent_features/test_distributed_tracing.py index 502b3828b0..7b0e65cd14 100644 --- a/tests/agent_features/test_distributed_tracing.py +++ b/tests/agent_features/test_distributed_tracing.py @@ -28,7 +28,6 @@ from newrelic.api.time_trace import current_trace from newrelic.api.transaction import ( accept_distributed_trace_headers, - accept_distributed_trace_payload, create_distributed_trace_payload, current_span_id, current_trace_id, @@ -181,7 +180,8 @@ def _test(): payload["d"]["pa"] = "5e5733a911cfbc73" if accept_payload: - result = accept_distributed_trace_payload(payload) + headers = {"newrelic": payload} + result = accept_distributed_trace_headers(headers) assert result else: create_distributed_trace_payload() @@ -261,7 +261,8 @@ def _make_test_transaction(): ) def _test(): with _make_test_transaction() as transaction: - transaction.accept_distributed_trace_payload(dt_payload) + dt_headers = {"newrelic": dt_payload} + transaction.accept_distributed_trace_headers(dt_headers) if gen_error: try: @@ -402,8 +403,8 @@ def _test_inbound_dt_payload_acceptance(): "tx": "8703ff3d88eefe9d", }, } - - result = transaction.accept_distributed_trace_payload(payload) + headers = {"newrelic": payload} + result = transaction.accept_distributed_trace_headers(headers) if trusted_account_key: assert result else: diff --git a/tests/agent_features/test_serverless_mode.py b/tests/agent_features/test_serverless_mode.py index 27ffd314f4..6b665d6f42 100644 --- a/tests/agent_features/test_serverless_mode.py +++ b/tests/agent_features/test_serverless_mode.py @@ -135,8 +135,8 @@ def _test_inbound_dt_payload_acceptance(): "tx": "8703ff3d88eefe9d", }, } - - result = transaction.accept_distributed_trace_payload(payload) + headers = {"newrelic": payload} + result = transaction.accept_distributed_trace_headers(headers) assert result _test_inbound_dt_payload_acceptance() diff --git a/tests/cross_agent/test_distributed_tracing.py b/tests/cross_agent/test_distributed_tracing.py index ae3097db2f..b6596a868e 100644 --- a/tests/cross_agent/test_distributed_tracing.py +++ b/tests/cross_agent/test_distributed_tracing.py @@ -118,7 +118,8 @@ def target_wsgi_application(environ, start_response): extra_inbound_payloads = test_settings["extra_inbound_payloads"] for payload, expected_result in extra_inbound_payloads: - result = txn.accept_distributed_trace_payload(payload, test_settings["transport_type"]) + headers = {"newrelic": payload} + result = txn.accept_distributed_trace_headers(headers, test_settings["transport_type"]) assert result is expected_result outbound_payloads = test_settings["outbound_payloads"] @@ -153,15 +154,16 @@ def test_distributed_tracing( web_transaction, ): extra_inbound_payloads = [] - if transport_type != "HTTP": - # Since wsgi_application calls accept_distributed_trace_payload + if not inbound_payloads: + # If there is no `inbound_payloads`, we do + # not want to break the downstream logic, + # so this is explicitly skipped. + pass + elif transport_type != "HTTP": + # Since wsgi_application calls accept_distributed_trace_headers # automatically with transport_type='HTTP', we must defer this call # until we can specify the transport type. extra_inbound_payloads.append((inbound_payloads.pop(), True)) - elif not inbound_payloads: - # In order to assert that accept_distributed_trace_payload returns - # False in this instance, we defer. - extra_inbound_payloads.append((inbound_payloads, False)) elif len(inbound_payloads) > 1: extra_inbound_payloads.extend((payload, False) for payload in inbound_payloads[1:]) diff --git a/tests/datastore_psycopg/test_slow_sql.py b/tests/datastore_psycopg/test_slow_sql.py index 9fc0f04bdd..9ead81cc38 100644 --- a/tests/datastore_psycopg/test_slow_sql.py +++ b/tests/datastore_psycopg/test_slow_sql.py @@ -122,7 +122,7 @@ def _test(): "tx": "8703ff3d88eefe9d", }, } - - transaction.accept_distributed_trace_payload(payload) - + headers = {"newrelic": payload} + transaction.accept_distributed_trace_headers(headers) + _test() diff --git a/tests/datastore_psycopg2/test_slow_sql.py b/tests/datastore_psycopg2/test_slow_sql.py index b41b0a6759..b85c1d1385 100644 --- a/tests/datastore_psycopg2/test_slow_sql.py +++ b/tests/datastore_psycopg2/test_slow_sql.py @@ -132,6 +132,7 @@ def _test(): }, } - transaction.accept_distributed_trace_payload(payload) + headers = {"newrelic": payload} + transaction.accept_distributed_trace_headers(headers) _test() From 15b55381c07dde95b1685cf4504e807688568553 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 14:04:53 -0700 Subject: [PATCH 06/14] Remove create_distributed_trace_payload --- newrelic/agent.py | 4 --- newrelic/api/transaction.py | 29 ------------------- .../test_distributed_tracing.py | 8 +++-- tests/cross_agent/test_distributed_tracing.py | 9 +++++- 4 files changed, 13 insertions(+), 37 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index f6a0634589..1bcdb9659a 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -25,7 +25,6 @@ from newrelic.api.transaction import add_custom_attributes as __add_custom_attributes from newrelic.api.transaction import add_framework_info as __add_framework_info from newrelic.api.transaction import capture_request_params as __capture_request_params -from newrelic.api.transaction import create_distributed_trace_payload as __create_distributed_trace_payload from newrelic.api.transaction import current_span_id as __current_span_id from newrelic.api.transaction import current_trace_id as __current_trace_id from newrelic.api.transaction import current_transaction as __current_transaction @@ -186,9 +185,6 @@ def __asgi_application(*args, **kwargs): record_log_event = __wrap_api_call(__record_log_event, "record_log_event") record_ml_event = __wrap_api_call(__record_ml_event, "record_ml_event") WithLlmCustomAttributes = __wrap_api_call(__WithLlmCustomAttributes, "WithLlmCustomAttributes") -create_distributed_trace_payload = __wrap_api_call( - __create_distributed_trace_payload, "create_distributed_trace_payload" -) accept_distributed_trace_headers = __wrap_api_call( __accept_distributed_trace_headers, "accept_distributed_trace_headers" ) diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index 1d8769cead..5948f8bae6 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -1104,29 +1104,6 @@ def _create_distributed_trace_data(self): return data - def _create_distributed_trace_payload(self): - try: - data = self._create_distributed_trace_data() - if data is None: - return - payload = DistributedTracePayload(v=DistributedTracePayload.version, d=data) - except: - self._record_supportability("Supportability/DistributedTrace/CreatePayload/Exception") - else: - self._record_supportability("Supportability/DistributedTrace/CreatePayload/Success") - return payload - - def create_distributed_trace_payload(self): - warnings.warn( - ( - "The create_distributed_trace_payload API has been deprecated. " - "Please use the insert_distributed_trace_headers API." - ), - DeprecationWarning, - stacklevel=2, - ) - return self._create_distributed_trace_payload() - def _generate_distributed_trace_headers(self, data=None): try: data = data or self._create_distributed_trace_data() @@ -2074,12 +2051,6 @@ def accept_distributed_trace_headers(headers, transport_type="HTTP"): return transaction.accept_distributed_trace_headers(headers, transport_type) -def create_distributed_trace_payload(): - transaction = current_transaction() - if transaction: - return transaction.create_distributed_trace_payload() - - def insert_distributed_trace_headers(headers): transaction = current_transaction() if transaction: diff --git a/tests/agent_features/test_distributed_tracing.py b/tests/agent_features/test_distributed_tracing.py index 7b0e65cd14..d8b08adfe9 100644 --- a/tests/agent_features/test_distributed_tracing.py +++ b/tests/agent_features/test_distributed_tracing.py @@ -28,7 +28,7 @@ from newrelic.api.time_trace import current_trace from newrelic.api.transaction import ( accept_distributed_trace_headers, - create_distributed_trace_payload, + insert_distributed_trace_headers, current_span_id, current_trace_id, current_transaction, @@ -184,8 +184,10 @@ def _test(): result = accept_distributed_trace_headers(headers) assert result else: - create_distributed_trace_payload() - + headers = [] + insert_distributed_trace_headers(headers) + assert headers + try: raise ValueError("cookies") except ValueError: diff --git a/tests/cross_agent/test_distributed_tracing.py b/tests/cross_agent/test_distributed_tracing.py index b6596a868e..0028b1d460 100644 --- a/tests/cross_agent/test_distributed_tracing.py +++ b/tests/cross_agent/test_distributed_tracing.py @@ -13,6 +13,7 @@ # limitations under the License. import json +import base64 from pathlib import Path import pytest @@ -125,7 +126,13 @@ def target_wsgi_application(environ, start_response): outbound_payloads = test_settings["outbound_payloads"] if outbound_payloads: for payload_assertions in outbound_payloads: - payload = txn._create_distributed_trace_payload() + headers = [] + txn.insert_distributed_trace_headers(headers) + # To revert to the dict format of the payload, use this: + payload = json.loads(base64.b64decode([value for key, value in headers if key=="newrelic"][0]).decode("utf-8")) + payload_version = payload.get("v") + if payload_version and isinstance(payload_version, list): + payload["v"] = tuple(payload_version) assert_payload(payload, payload_assertions, test_settings["major_version"], test_settings["minor_version"]) start_response(status, response_headers) From a83708601f770a863bea12090867dfb29de0c84d Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 14:17:36 -0700 Subject: [PATCH 07/14] Remove lambda handler --- newrelic/agent.py | 4 - newrelic/api/lambda_handler.py | 171 ------------- tests/agent_features/test_lambda_handler.py | 231 ------------------ tests/agent_features/test_serverless_mode.py | 32 --- tests/cross_agent/test_lambda_event_source.py | 75 ------ 5 files changed, 513 deletions(-) delete mode 100644 newrelic/api/lambda_handler.py delete mode 100644 tests/agent_features/test_lambda_handler.py delete mode 100644 tests/cross_agent/test_lambda_event_source.py diff --git a/newrelic/agent.py b/newrelic/agent.py index 1bcdb9659a..1ee7878977 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -95,8 +95,6 @@ def __asgi_application(*args, **kwargs): from newrelic.api.generator_trace import wrap_generator_trace as __wrap_generator_trace from newrelic.api.html_insertion import insert_html_snippet as __insert_html_snippet from newrelic.api.html_insertion import verify_body_exists as __verify_body_exists -from newrelic.api.lambda_handler import LambdaHandlerWrapper as __LambdaHandlerWrapper -from newrelic.api.lambda_handler import lambda_handler as __lambda_handler from newrelic.api.llm_custom_attributes import WithLlmCustomAttributes as __WithLlmCustomAttributes from newrelic.api.message_trace import MessageTrace as __MessageTrace from newrelic.api.message_trace import MessageTraceWrapper as __MessageTraceWrapper @@ -207,8 +205,6 @@ def __asgi_application(*args, **kwargs): BackgroundTask = __wrap_api_call(__BackgroundTask, "BackgroundTask") BackgroundTaskWrapper = __wrap_api_call(__BackgroundTaskWrapper, "BackgroundTaskWrapper") wrap_background_task = __wrap_api_call(__wrap_background_task, "wrap_background_task") -LambdaHandlerWrapper = __wrap_api_call(__LambdaHandlerWrapper, "LambdaHandlerWrapper") -lambda_handler = __wrap_api_call(__lambda_handler, "lambda_handler") NewRelicContextFormatter = __wrap_api_call(__NewRelicContextFormatter, "NewRelicContextFormatter") transaction_name = __wrap_api_call(__transaction_name, "transaction_name") TransactionNameWrapper = __wrap_api_call(__TransactionNameWrapper, "TransactionNameWrapper") diff --git a/newrelic/api/lambda_handler.py b/newrelic/api/lambda_handler.py deleted file mode 100644 index 97897c6ae9..0000000000 --- a/newrelic/api/lambda_handler.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import functools -import warnings - -from newrelic.api.application import application_instance -from newrelic.api.transaction import current_transaction -from newrelic.api.web_transaction import WebTransaction -from newrelic.common.object_wrapper import FunctionWrapper -from newrelic.core.attribute import truncate -from newrelic.core.config import global_settings - -COLD_START_RECORDED = False -MEGABYTE_IN_BYTES = 2**20 - - -def extract_event_source_arn(event): - try: - arn = event.get("streamArn") or event.get("deliveryStreamArn") - - if not arn: - record = event["Records"][0] - arn = record.get("eventSourceARN") or record.get("EventSubscriptionArn") or record["s3"]["bucket"]["arn"] - - return truncate(str(arn)) - except Exception: - pass - - -def _LambdaHandlerWrapper(wrapped, application=None, name=None, group=None): - def _nr_lambda_handler_wrapper_(wrapped, instance, args, kwargs): - # Check to see if any transaction is present, even an inactive - # one which has been marked to be ignored or which has been - # stopped already. - - transaction = current_transaction(active_only=False) - - if transaction: - return wrapped(*args, **kwargs) - - try: - event, context = args[:2] - except Exception: - return wrapped(*args, **kwargs) - - target_application = application - - # If application has an activate() method we assume it is an - # actual application. Do this rather than check type so that - # can easily mock it for testing. - - # FIXME Should this allow for multiple apps if a string. - - if not hasattr(application, "activate"): - target_application = application_instance(application) - - try: - request_method = event["httpMethod"] - request_path = event["path"] - headers = event["headers"] - query_params = event.get("multiValueQueryStringParameters") - background_task = False - except Exception: - request_method = None - request_path = None - headers = None - query_params = None - background_task = True - - transaction_name = name or getattr(context, "function_name", None) - - transaction = WebTransaction( - target_application, - transaction_name, - group=group, - request_method=request_method, - request_path=request_path, - headers=headers, - ) - - transaction.background_task = background_task - - request_id = getattr(context, "aws_request_id", None) - aws_arn = getattr(context, "invoked_function_arn", None) - event_source = extract_event_source_arn(event) - - if request_id: - transaction._add_agent_attribute("aws.requestId", request_id) - if aws_arn: - transaction._add_agent_attribute("aws.lambda.arn", aws_arn) - if event_source: - transaction._add_agent_attribute("aws.lambda.eventSource.arn", event_source) - - # COLD_START_RECORDED is initialized to "False" when the container - # first starts up, and will remain that way until the below lines - # of code are encountered during the first transaction after the cold - # start. We record this occurence on the transaction so that an - # attribute is created, and then set COLD_START_RECORDED to False so - # that the attribute is not created again during future invocations of - # this container. - - global COLD_START_RECORDED - if COLD_START_RECORDED is False: - transaction._add_agent_attribute("aws.lambda.coldStart", True) - COLD_START_RECORDED = True - - settings = global_settings() - if query_params and not settings.high_security: - try: - transaction._request_params.update(query_params) - except: - pass - - if not settings.aws_lambda_metadata and aws_arn: - settings.aws_lambda_metadata["arn"] = aws_arn - - with transaction: - result = wrapped(*args, **kwargs) - - if not background_task: - try: - status_code = result.get("statusCode") - response_headers = result.get("headers") - - try: - response_headers = response_headers.items() - except Exception: - response_headers = None - - transaction.process_response(status_code, response_headers) - except Exception: - pass - - return result - - return FunctionWrapper(wrapped, _nr_lambda_handler_wrapper_) - - -def LambdaHandlerWrapper(*args, **kwargs): - warnings.warn( - ( - "The LambdaHandlerWrapper API has been deprecated. Please use the " - "APIs provided in the newrelic-lambda package." - ), - DeprecationWarning, - stacklevel=2, - ) - - return _LambdaHandlerWrapper(*args, **kwargs) - - -def lambda_handler(application=None, name=None, group=None): - warnings.warn( - ("The lambda_handler API has been deprecated. Please use the APIs provided in the newrelic-lambda package."), - DeprecationWarning, - stacklevel=2, - ) - - return functools.partial(_LambdaHandlerWrapper, application=application, name=name, group=group) diff --git a/tests/agent_features/test_lambda_handler.py b/tests/agent_features/test_lambda_handler.py deleted file mode 100644 index 9378606547..0000000000 --- a/tests/agent_features/test_lambda_handler.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import functools -from copy import deepcopy - -import pytest -from testing_support.fixtures import override_application_settings -from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes -from testing_support.validators.validate_transaction_trace_attributes import validate_transaction_trace_attributes - -from newrelic.api import lambda_handler - - -# NOTE: this fixture will force all tests in this file to assume that a cold -# start has occurred, *except* when a test has a parameter named -# "is_cold" and its value is True -@pytest.fixture(autouse=True) -def force_cold_start_status(request): - try: - is_cold_start = request.getfixturevalue("is_cold") - lambda_handler.COLD_START_RECORDED = not is_cold_start - except Exception: - lambda_handler.COLD_START_RECORDED = True - - -@lambda_handler.lambda_handler() -def handler(event, context): - return {"statusCode": "200", "body": "{}", "headers": {"Content-Type": "application/json", "Content-Length": 2}} - - -_override_settings = {"attributes.include": ["request.parameters.*", "request.headers.*"]} -_expected_attributes = { - "agent": [ - "aws.requestId", - "aws.lambda.arn", - "request.method", - "request.uri", - "response.status", - "response.headers.contentType", - "response.headers.contentLength", - ], - "user": [], - "intrinsic": [], -} - -_exact_attrs = { - "agent": {"request.parameters.foo": "bar", "request.headers.host": "myhost"}, - "user": {}, - "intrinsic": {}, -} - -empty_event = {} -firehose_event = { - "records": [ - { - "recordId": "495469866831355442", - "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0IDEyMy4=", - "approximateArrivalTimestamp": 1495072949453, - } - ], - "region": "us-west-2", - "deliveryStreamArn": "arn:aws:kinesis:EXAMPLE", - "invocationId": "invocationIdExample", -} - - -class Context: - aws_request_id = "cookies" - invoked_function_arn = "arn" - function_name = "cats" - function_version = "$LATEST" - memory_limit_in_mb = 128 - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@pytest.mark.parametrize("is_cold", (False, True)) -def test_lambda_transaction_attributes(is_cold, monkeypatch): - # setup copies of the attribute lists for this test only - _forgone_params = {} - _exact = deepcopy(_exact_attrs) - _expected = deepcopy(_expected_attributes) - - # if we have a cold start, then we should see aws.lambda.coldStart=True - if is_cold: - _exact["agent"]["aws.lambda.coldStart"] = True - _expected["agent"].append("aws.lambda.coldStart") - - # otherwise, then we need to make sure that we don't see it at all - else: - _forgone_params = {"agent": ["aws.lambda.coldStart"], "user": [], "intrinsic": []} - - @validate_transaction_trace_attributes(required_params=_expected, forgone_params=_forgone_params) - @validate_transaction_event_attributes( - required_params=_expected, forgone_params=_forgone_params, exact_attrs=_exact - ) - @override_application_settings(_override_settings) - def _test(): - monkeypatch.setenv("AWS_REGION", "earth") - handler( - { - "httpMethod": "GET", - "path": "/", - "headers": {"HOST": "myhost"}, - "queryStringParameters": {"foo": "bar"}, - "multiValueQueryStringParameters": {"foo": ["bar"]}, - }, - Context, - ) - - _test() - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@validate_transaction_trace_attributes(_expected_attributes) -@validate_transaction_event_attributes(_expected_attributes) -@override_application_settings(_override_settings) -def test_lambda_malformed_api_gateway_payload(monkeypatch): - monkeypatch.setenv("AWS_REGION", "earth") - handler( - { - "httpMethod": "GET", - "path": "/", - "headers": {}, - "queryStringParameters": 42, - "multiValueQueryStringParameters": 42, - }, - Context, - ) - - -_malformed_request_attributes = {"agent": ["aws.requestId", "aws.lambda.arn"], "user": [], "intrinsic": []} - - -@validate_transaction_trace_attributes(_malformed_request_attributes) -@validate_transaction_event_attributes(_malformed_request_attributes) -@override_application_settings(_override_settings) -def test_lambda_malformed_request_headers(): - handler({"httpMethod": "GET", "path": "/", "headers": None}, Context) - - -_malformed_response_attributes = { - "agent": ["aws.requestId", "aws.lambda.arn", "request.method", "request.uri", "response.status"], - "user": [], - "intrinsic": [], -} - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@validate_transaction_trace_attributes(_malformed_response_attributes) -@validate_transaction_event_attributes(_malformed_response_attributes) -@override_application_settings(_override_settings) -def test_lambda_malformed_response_headers(): - @lambda_handler.lambda_handler() - def handler(event, context): - return {"statusCode": 200, "body": "{}", "headers": None} - - handler({"httpMethod": "GET", "path": "/", "headers": {}}, Context) - - -_no_status_code_response = { - "agent": [ - "aws.requestId", - "aws.lambda.arn", - "request.method", - "request.uri", - "response.headers.contentType", - "response.headers.contentLength", - ], - "user": [], - "intrinsic": [], -} - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@validate_transaction_trace_attributes(_no_status_code_response) -@validate_transaction_event_attributes(_no_status_code_response) -@override_application_settings(_override_settings) -def test_lambda_no_status_code_response(): - @lambda_handler.lambda_handler() - def handler(event, context): - return {"body": "{}", "headers": {"Content-Type": "application/json", "Content-Length": 2}} - - handler({"httpMethod": "GET", "path": "/", "headers": {}}, Context) - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@pytest.mark.parametrize("event,arn", ((empty_event, None), (firehose_event, "arn:aws:kinesis:EXAMPLE"))) -def test_lambda_event_source_arn_attribute(event, arn): - if arn is None: - _exact = None - _expected = None - _forgone = {"user": [], "intrinsic": [], "agent": ["aws.lambda.eventSource.arn"]} - else: - _exact = {"user": {}, "intrinsic": {}, "agent": {"aws.lambda.eventSource.arn": arn}} - _expected = {"user": [], "intrinsic": [], "agent": ["aws.lambda.eventSource.arn"]} - _forgone = None - - @validate_transaction_trace_attributes(required_params=_expected, forgone_params=_forgone) - @validate_transaction_event_attributes(required_params=_expected, forgone_params=_forgone, exact_attrs=_exact) - @override_application_settings(_override_settings) - def _test(): - handler(event, Context) - - _test() - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@pytest.mark.parametrize( - "api", (lambda_handler.lambda_handler, functools.partial(lambda_handler.LambdaHandlerWrapper, handler)) -) -def test_deprecation_warnings(api): - with pytest.deprecated_call(): - api() diff --git a/tests/agent_features/test_serverless_mode.py b/tests/agent_features/test_serverless_mode.py index 6b665d6f42..9c705c5c24 100644 --- a/tests/agent_features/test_serverless_mode.py +++ b/tests/agent_features/test_serverless_mode.py @@ -23,7 +23,6 @@ from newrelic.api.application import application_instance from newrelic.api.background_task import background_task from newrelic.api.external_trace import ExternalTrace -from newrelic.api.lambda_handler import lambda_handler from newrelic.api.transaction import current_transaction from newrelic.core.config import global_settings @@ -140,34 +139,3 @@ def _test_inbound_dt_payload_acceptance(): assert result _test_inbound_dt_payload_acceptance() - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@pytest.mark.parametrize("arn_set", (True, False)) -def test_payload_metadata_arn(serverless_application, arn_set): - # If the session object gathers the arn from the settings object before the - # lambda handler records it there, then this test will fail. - - settings = global_settings() - original_metadata = settings.aws_lambda_metadata.copy() - - arn = None - if arn_set: - arn = "arrrrrrrrrrRrrrrrrrn" - - settings.aws_lambda_metadata.update({"arn": arn, "function_version": "$LATEST"}) - - class Context: - invoked_function_arn = arn - - @validate_serverless_metadata(exact_metadata={"arn": arn}) - @lambda_handler(application=serverless_application) - def handler(event, context): - assert settings.aws_lambda_metadata["arn"] == arn - return {} - - try: - handler({}, Context) - finally: - settings.aws_lambda_metadata = original_metadata diff --git a/tests/cross_agent/test_lambda_event_source.py b/tests/cross_agent/test_lambda_event_source.py deleted file mode 100644 index 74ca28e5d7..0000000000 --- a/tests/cross_agent/test_lambda_event_source.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -from pathlib import Path - -import pytest -from testing_support.fixtures import override_application_settings -from testing_support.validators.validate_transaction_event_attributes import validate_transaction_event_attributes - -from newrelic.api.lambda_handler import lambda_handler - -FIXTURE_DIR = Path(__file__).parent / "fixtures" -FIXTURE = FIXTURE_DIR / "lambda_event_source.json" -tests = {} -events = {} - - -def _load_tests(): - with FIXTURE.open() as fh: - for test in json.loads(fh.read()): - test_name = test.pop("name") - - test_file = f"{test_name}.json" - path = FIXTURE_DIR / "lambda_event_source" / test_file - with path.open() as fh: - events[test_name] = json.loads(fh.read()) - - tests[test_name] = test - return tests.keys() - - -class Context: - aws_request_id = "cookies" - invoked_function_arn = "arn" - function_name = "cats" - function_version = "$LATEST" - memory_limit_in_mb = 128 - - -@lambda_handler() -def handler(event, context): - return {"statusCode": "200", "body": "{}", "headers": {"Content-Type": "application/json", "Content-Length": 2}} - - -# The lambda_hander has been deprecated for 3+ years -@pytest.mark.skip(reason="The lambda_handler has been deprecated") -@pytest.mark.parametrize("test_name", _load_tests()) -def test_lambda_event_source(test_name): - _exact = {"user": {}, "intrinsic": {}, "agent": {}} - - expected_arn = tests[test_name].get("aws.lambda.eventSource.arn", None) - if expected_arn: - _exact["agent"]["aws.lambda.eventSource.arn"] = expected_arn - else: - pytest.skip("Nothing to test!") - return - - @override_application_settings({"attributes.include": ["aws.*"]}) - @validate_transaction_event_attributes({}, exact_attrs=_exact) - def _test(): - handler(events[test_name], Context) - - _test() From 4ed5a0813431fae280704060029b2ccddf8e6123 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 14:41:45 -0700 Subject: [PATCH 08/14] Remove ObjectWrapper --- newrelic/agent.py | 2 -- newrelic/api/object_wrapper.py | 6 ------ newrelic/common/object_wrapper.py | 18 ------------------ 3 files changed, 26 deletions(-) diff --git a/newrelic/agent.py b/newrelic/agent.py index 1ee7878977..43f452832c 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -125,7 +125,6 @@ def __asgi_application(*args, **kwargs): from newrelic.common.object_wrapper import FunctionWrapper as __FunctionWrapper from newrelic.common.object_wrapper import InFunctionWrapper as __InFunctionWrapper from newrelic.common.object_wrapper import ObjectProxy as __ObjectProxy -from newrelic.common.object_wrapper import ObjectWrapper as __ObjectWrapper from newrelic.common.object_wrapper import OutFunctionWrapper as __OutFunctionWrapper from newrelic.common.object_wrapper import PostFunctionWrapper as __PostFunctionWrapper from newrelic.common.object_wrapper import PreFunctionWrapper as __PreFunctionWrapper @@ -255,7 +254,6 @@ def __asgi_application(*args, **kwargs): function_wrapper = __wrap_api_call(__function_wrapper, "function_wrapper") wrap_function_wrapper = __wrap_api_call(__wrap_function_wrapper, "wrap_function_wrapper") patch_function_wrapper = __wrap_api_call(__patch_function_wrapper, "patch_function_wrapper") -ObjectWrapper = __wrap_api_call(__ObjectWrapper, "ObjectWrapper") pre_function = __wrap_api_call(__pre_function, "pre_function") PreFunctionWrapper = __wrap_api_call(__PreFunctionWrapper, "PreFunctionWrapper") wrap_pre_function = __wrap_api_call(__wrap_pre_function, "wrap_pre_function") diff --git a/newrelic/api/object_wrapper.py b/newrelic/api/object_wrapper.py index 3f76d00e53..480940f476 100644 --- a/newrelic/api/object_wrapper.py +++ b/newrelic/api/object_wrapper.py @@ -12,12 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# These have been moved. They are retained here until all references to -# them are moved at which point will mark as deprecated to ensure users -# weren't using them directly. -from newrelic.common.object_names import callable_name # noqa: F401 -from newrelic.common.object_wrapper import ObjectWrapper, wrap_object # noqa: F401 - # From Python 3.X. In older Python versions it fails if attributes do # not exist and don't maintain a __wrapped__ attribute. diff --git a/newrelic/common/object_wrapper.py b/newrelic/common/object_wrapper.py index dba775a381..be8c351f4e 100644 --- a/newrelic/common/object_wrapper.py +++ b/newrelic/common/object_wrapper.py @@ -20,7 +20,6 @@ """ import inspect -import warnings from newrelic.packages.wrapt import BoundFunctionWrapper as _BoundFunctionWrapper from newrelic.packages.wrapt import CallableObjectProxy as _CallableObjectProxy @@ -113,23 +112,6 @@ class CallableObjectProxy(ObjectProxy, _CallableObjectProxy): pass -# The ObjectWrapper class needs to be deprecated and removed once all our -# own code no longer uses it. It reaches down into what are wrapt internals -# at present which shouldn't be doing. - - -class ObjectWrapper(FunctionWrapper): - def __init__(self, wrapped, instance, wrapper): - warnings.warn( - ( - "The ObjectWrapper API is deprecated. Please use one of ObjectProxy, FunctionWrapper, or CallableObjectProxy instead." - ), - DeprecationWarning, - stacklevel=2, - ) - super().__init__(wrapped, wrapper) - - # Function for creating a decorator for applying to functions, as well as # short cut functions for applying wrapper functions via monkey patching. From 0cb65e773f258c660a4f9f7627fa8b17d896c4d7 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 14:59:58 -0700 Subject: [PATCH 09/14] Remove in_function API --- newrelic/api/in_function.py | 17 ----------------- newrelic/hooks/adapter_cheroot.py | 5 ++--- newrelic/hooks/adapter_cherrypy.py | 4 ++-- newrelic/hooks/adapter_flup.py | 10 +++++----- newrelic/hooks/adapter_meinheld.py | 4 ++-- newrelic/hooks/adapter_paste.py | 4 ++-- newrelic/hooks/adapter_waitress.py | 2 +- newrelic/hooks/adapter_wsgiref.py | 4 ++-- newrelic/hooks/component_piston.py | 5 ++--- newrelic/hooks/framework_webpy.py | 5 ++--- 10 files changed, 20 insertions(+), 40 deletions(-) delete mode 100644 newrelic/api/in_function.py diff --git a/newrelic/api/in_function.py b/newrelic/api/in_function.py deleted file mode 100644 index 88edb084bd..0000000000 --- a/newrelic/api/in_function.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Use of these from this module will be deprecated. - -from newrelic.common.object_wrapper import InFunctionWrapper, in_function, wrap_in_function # noqa: F401 diff --git a/newrelic/hooks/adapter_cheroot.py b/newrelic/hooks/adapter_cheroot.py index 44497d8f52..556a1a443e 100644 --- a/newrelic/hooks/adapter_cheroot.py +++ b/newrelic/hooks/adapter_cheroot.py @@ -12,9 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application - +from newrelic.common.object_wrapper import wrap_in_function def instrument_cheroot_wsgiserver(module): def wrap_wsgi_application_entry_point(server, bind_addr, wsgi_app, *args, **kwargs): @@ -22,4 +21,4 @@ def wrap_wsgi_application_entry_point(server, bind_addr, wsgi_app, *args, **kwar args = [server, bind_addr, application, *args] return (args, kwargs) - newrelic.api.in_function.wrap_in_function(module, "Server.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "Server.__init__", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/adapter_cherrypy.py b/newrelic/hooks/adapter_cherrypy.py index d30795e8f9..243156a5d1 100644 --- a/newrelic/hooks/adapter_cherrypy.py +++ b/newrelic/hooks/adapter_cherrypy.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application +from newrelic.common.object_wrapper import wrap_in_function def instrument_cherrypy_wsgiserver(module): @@ -22,4 +22,4 @@ def wrap_wsgi_application_entry_point(server, bind_addr, wsgi_app, *args, **kwar args = [server, bind_addr, application, *args] return (args, kwargs) - newrelic.api.in_function.wrap_in_function(module, "CherryPyWSGIServer.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "CherryPyWSGIServer.__init__", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/adapter_flup.py b/newrelic/hooks/adapter_flup.py index 93f30bf72b..b84e9883d9 100644 --- a/newrelic/hooks/adapter_flup.py +++ b/newrelic/hooks/adapter_flup.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application +from newrelic.common.object_wrapper import wrap_in_function def wrap_wsgi_application_entry_point(server, application, *args, **kwargs): @@ -23,16 +23,16 @@ def wrap_wsgi_application_entry_point(server, application, *args, **kwargs): def instrument_flup_server_cgi(module): - newrelic.api.in_function.wrap_in_function(module, "WSGIServer.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "WSGIServer.__init__", wrap_wsgi_application_entry_point) def instrument_flup_server_ajp_base(module): - newrelic.api.in_function.wrap_in_function(module, "BaseAJPServer.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "BaseAJPServer.__init__", wrap_wsgi_application_entry_point) def instrument_flup_server_fcgi_base(module): - newrelic.api.in_function.wrap_in_function(module, "BaseFCGIServer.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "BaseFCGIServer.__init__", wrap_wsgi_application_entry_point) def instrument_flup_server_scgi_base(module): - newrelic.api.in_function.wrap_in_function(module, "BaseSCGIServer.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "BaseSCGIServer.__init__", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/adapter_meinheld.py b/newrelic/hooks/adapter_meinheld.py index 8e69a668e0..5bbf6de1c8 100644 --- a/newrelic/hooks/adapter_meinheld.py +++ b/newrelic/hooks/adapter_meinheld.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application +from newrelic.common.object_wrapper import wrap_in_function def instrument_meinheld_server(module): @@ -22,4 +22,4 @@ def wrap_wsgi_application_entry_point(application, *args, **kwargs): args = [application, *args] return (args, kwargs) - newrelic.api.in_function.wrap_in_function(module, "run", wrap_wsgi_application_entry_point) + wrap_in_function(module, "run", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/adapter_paste.py b/newrelic/hooks/adapter_paste.py index 0f1d38ca39..7a2fa9af58 100644 --- a/newrelic/hooks/adapter_paste.py +++ b/newrelic/hooks/adapter_paste.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application +from newrelic.common.object_wrapper import wrap_in_function def instrument_paste_httpserver(module): @@ -22,4 +22,4 @@ def wrap_wsgi_application_entry_point(server, application, *args, **kwargs): args = [server, application, *args] return (args, kwargs) - newrelic.api.in_function.wrap_in_function(module, "WSGIServerBase.__init__", wrap_wsgi_application_entry_point) + wrap_in_function(module, "WSGIServerBase.__init__", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/adapter_waitress.py b/newrelic/hooks/adapter_waitress.py index e1a5e485f9..499f027955 100644 --- a/newrelic/hooks/adapter_waitress.py +++ b/newrelic/hooks/adapter_waitress.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from newrelic.api.in_function import wrap_in_function from newrelic.api.wsgi_application import WSGIApplicationWrapper from newrelic.common.package_version_utils import get_package_version +from newrelic.common.object_wrapper import wrap_in_function def instrument_waitress_server(module): diff --git a/newrelic/hooks/adapter_wsgiref.py b/newrelic/hooks/adapter_wsgiref.py index c368194adf..d788fdf738 100644 --- a/newrelic/hooks/adapter_wsgiref.py +++ b/newrelic/hooks/adapter_wsgiref.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import newrelic.api.in_function import newrelic.api.wsgi_application +from newrelic.common.object_wrapper import wrap_in_function def instrument_wsgiref_simple_server(module): @@ -22,4 +22,4 @@ def wrap_wsgi_application_entry_point(server, application, *args, **kwargs): args = [server, application, *args] return (args, kwargs) - newrelic.api.in_function.wrap_in_function(module, "WSGIServer.set_app", wrap_wsgi_application_entry_point) + wrap_in_function(module, "WSGIServer.set_app", wrap_wsgi_application_entry_point) diff --git a/newrelic/hooks/component_piston.py b/newrelic/hooks/component_piston.py index f2abb2c760..8ec7ee3686 100644 --- a/newrelic/hooks/component_piston.py +++ b/newrelic/hooks/component_piston.py @@ -14,11 +14,10 @@ import newrelic.api.function_trace -import newrelic.api.in_function import newrelic.api.transaction import newrelic.common.object_wrapper from newrelic.common.object_names import callable_name - +from newrelic.common.object_wrapper import wrap_in_function class MethodWrapper: def __init__(self, wrapped, priority=None): @@ -82,4 +81,4 @@ def in_HandlerMethod_init(self, method, *args, **kwargs): method = method._nr_wrapped return ((self, method, *args), kwargs) - newrelic.api.in_function.wrap_in_function(module, "HandlerMethod.__init__", in_HandlerMethod_init) + wrap_in_function(module, "HandlerMethod.__init__", in_HandlerMethod_init) diff --git a/newrelic/hooks/framework_webpy.py b/newrelic/hooks/framework_webpy.py index b8e28e5829..6bb1b4b48c 100644 --- a/newrelic/hooks/framework_webpy.py +++ b/newrelic/hooks/framework_webpy.py @@ -14,14 +14,13 @@ import newrelic.api.function_trace -import newrelic.api.in_function import newrelic.api.out_function import newrelic.api.pre_function import newrelic.api.transaction from newrelic.api.time_trace import notice_error from newrelic.api.wsgi_application import WSGIApplicationWrapper from newrelic.common.object_names import callable_name - +from newrelic.common.object_wrapper import wrap_in_function def transaction_name_delegate(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() @@ -47,7 +46,7 @@ def template_name(render_obj, name): def instrument(module): if module.__name__ == "web.application": newrelic.api.out_function.wrap_out_function(module, "application.wsgifunc", WSGIApplicationWrapper) - newrelic.api.in_function.wrap_in_function(module, "application._delegate", transaction_name_delegate) + wrap_in_function(module, "application._delegate", transaction_name_delegate) newrelic.api.pre_function.wrap_pre_function(module, "application.internalerror", wrap_handle_exception) elif module.__name__ == "web.template": From d25242ff799f4e062ab51368ca43adbbd750d741 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 15:01:59 -0700 Subject: [PATCH 10/14] Remove out_function API --- newrelic/api/out_function.py | 17 ----------------- newrelic/hooks/framework_webpy.py | 5 ++--- 2 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 newrelic/api/out_function.py diff --git a/newrelic/api/out_function.py b/newrelic/api/out_function.py deleted file mode 100644 index 7672cf93d8..0000000000 --- a/newrelic/api/out_function.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Use of these from this module will be deprecated. - -from newrelic.common.object_wrapper import OutFunctionWrapper, out_function, wrap_out_function # noqa: F401 diff --git a/newrelic/hooks/framework_webpy.py b/newrelic/hooks/framework_webpy.py index 6bb1b4b48c..fd5a8a48a4 100644 --- a/newrelic/hooks/framework_webpy.py +++ b/newrelic/hooks/framework_webpy.py @@ -12,15 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. - import newrelic.api.function_trace -import newrelic.api.out_function import newrelic.api.pre_function import newrelic.api.transaction from newrelic.api.time_trace import notice_error from newrelic.api.wsgi_application import WSGIApplicationWrapper from newrelic.common.object_names import callable_name from newrelic.common.object_wrapper import wrap_in_function +from newrelic.common.object_wrapper import wrap_out_function def transaction_name_delegate(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() @@ -45,7 +44,7 @@ def template_name(render_obj, name): def instrument(module): if module.__name__ == "web.application": - newrelic.api.out_function.wrap_out_function(module, "application.wsgifunc", WSGIApplicationWrapper) + wrap_out_function(module, "application.wsgifunc", WSGIApplicationWrapper) wrap_in_function(module, "application._delegate", transaction_name_delegate) newrelic.api.pre_function.wrap_pre_function(module, "application.internalerror", wrap_handle_exception) From 0d15be39879033357af765e7f156d214008e4560 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 15:04:54 -0700 Subject: [PATCH 11/14] Remove pre_function API --- newrelic/api/pre_function.py | 17 ----------------- newrelic/hooks/application_celery.py | 3 +-- newrelic/hooks/framework_webpy.py | 6 ++---- 3 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 newrelic/api/pre_function.py diff --git a/newrelic/api/pre_function.py b/newrelic/api/pre_function.py deleted file mode 100644 index e5df8e9b64..0000000000 --- a/newrelic/api/pre_function.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Use of these from this module will be deprecated. - -from newrelic.common.object_wrapper import PreFunctionWrapper, pre_function, wrap_pre_function # noqa: F401 diff --git a/newrelic/hooks/application_celery.py b/newrelic/hooks/application_celery.py index aa4e31c133..e5856141f0 100644 --- a/newrelic/hooks/application_celery.py +++ b/newrelic/hooks/application_celery.py @@ -26,9 +26,8 @@ from newrelic.api.background_task import BackgroundTask from newrelic.api.function_trace import FunctionTrace from newrelic.api.message_trace import MessageTrace -from newrelic.api.pre_function import wrap_pre_function from newrelic.api.transaction import current_transaction -from newrelic.common.object_wrapper import FunctionWrapper, wrap_function_wrapper +from newrelic.common.object_wrapper import FunctionWrapper, wrap_function_wrapper, wrap_pre_function from newrelic.common.signature import bind_args from newrelic.core.agent import shutdown_agent diff --git a/newrelic/hooks/framework_webpy.py b/newrelic/hooks/framework_webpy.py index fd5a8a48a4..19aef69ca2 100644 --- a/newrelic/hooks/framework_webpy.py +++ b/newrelic/hooks/framework_webpy.py @@ -13,13 +13,11 @@ # limitations under the License. import newrelic.api.function_trace -import newrelic.api.pre_function import newrelic.api.transaction from newrelic.api.time_trace import notice_error from newrelic.api.wsgi_application import WSGIApplicationWrapper from newrelic.common.object_names import callable_name -from newrelic.common.object_wrapper import wrap_in_function -from newrelic.common.object_wrapper import wrap_out_function +from newrelic.common.object_wrapper import wrap_in_function, wrap_out_function, wrap_pre_function def transaction_name_delegate(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() @@ -46,7 +44,7 @@ def instrument(module): if module.__name__ == "web.application": wrap_out_function(module, "application.wsgifunc", WSGIApplicationWrapper) wrap_in_function(module, "application._delegate", transaction_name_delegate) - newrelic.api.pre_function.wrap_pre_function(module, "application.internalerror", wrap_handle_exception) + wrap_pre_function(module, "application.internalerror", wrap_handle_exception) elif module.__name__ == "web.template": newrelic.api.function_trace.wrap_function_trace(module, "render.__getattr__", template_name, "Template/Render") From 32ff973f5602da15f8ea031902a9c6f7aeecf48c Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 15:16:39 -0700 Subject: [PATCH 12/14] Remove post_function API --- newrelic/api/post_function.py | 17 ----------------- newrelic/hooks/coroutines_gevent.py | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 newrelic/api/post_function.py diff --git a/newrelic/api/post_function.py b/newrelic/api/post_function.py deleted file mode 100644 index 436b15f98e..0000000000 --- a/newrelic/api/post_function.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2010 New Relic, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Use of these from this module will be deprecated. - -from newrelic.common.object_wrapper import PostFunctionWrapper, post_function, wrap_post_function # noqa: F401 diff --git a/newrelic/hooks/coroutines_gevent.py b/newrelic/hooks/coroutines_gevent.py index 618c249aac..45380b48a6 100644 --- a/newrelic/hooks/coroutines_gevent.py +++ b/newrelic/hooks/coroutines_gevent.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from newrelic.api.post_function import wrap_post_function +from newrelic.common.object_wrapper import wrap_post_function def _patch_thread(threading=True, *args, **kwargs): From 0f4ae532a8fad74d626508e473bdc4f7603ee523 Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Tue, 2 Sep 2025 15:17:02 -0700 Subject: [PATCH 13/14] Remove NewRelicLogHandler --- newrelic/api/log.py | 84 --------------------------------------------- 1 file changed, 84 deletions(-) diff --git a/newrelic/api/log.py b/newrelic/api/log.py index eacb270de3..1dab724ad5 100644 --- a/newrelic/api/log.py +++ b/newrelic/api/log.py @@ -14,14 +14,11 @@ import json import logging -import re -import warnings from traceback import format_exception from newrelic.api.application import application_instance from newrelic.api.time_trace import get_linking_metadata from newrelic.api.transaction import current_transaction, record_log_event -from newrelic.common import agent_http from newrelic.common.encoding_utils import json_encode from newrelic.common.object_names import parse_exc_info from newrelic.core.attribute import truncate @@ -187,84 +184,3 @@ def filter_record_attributes(cls, record): record_attrs = vars(record) return {k: record_attrs[k] for k in record_attrs if k not in cls.IGNORED_LOG_RECORD_KEYS} - -class NewRelicLogHandler(logging.Handler): - """ - Deprecated: Please use NewRelicLogForwardingHandler instead. - This is an experimental log handler provided by the community. Use with caution. - """ - - PATH = "/log/v1" - - def __init__( - self, - level=logging.INFO, - license_key=None, - host=None, - port=443, - proxy_scheme=None, - proxy_host=None, - proxy_user=None, - proxy_pass=None, - timeout=None, - ca_bundle_path=None, - disable_certificate_validation=False, - ): - warnings.warn( - "The contributed NewRelicLogHandler has been superseded by automatic instrumentation for " - "logging in the standard lib. If for some reason you need to manually configure a handler, " - "please use newrelic.api.log.NewRelicLogForwardingHandler to take advantage of all the " - "features included in application log forwarding such as proper batching.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(level=level) - self.license_key = license_key or self.settings.license_key - self.host = host or self.settings.host or self.default_host(self.license_key) - - self.client = agent_http.HttpClient( - host=host, - port=port, - proxy_scheme=proxy_scheme, - proxy_host=proxy_host, - proxy_user=proxy_user, - proxy_pass=proxy_pass, - timeout=timeout, - ca_bundle_path=ca_bundle_path, - disable_certificate_validation=disable_certificate_validation, - ) - - self.setFormatter(NewRelicContextFormatter()) - - @property - def settings(self): - transaction = current_transaction() - if transaction: - return transaction.settings - return global_settings() - - def emit(self, record): - try: - headers = {"Api-Key": self.license_key or "", "Content-Type": "application/json"} - payload = self.format(record).encode("utf-8") - with self.client: - status_code, response = self.client.send_request(path=self.PATH, headers=headers, payload=payload) - if status_code < 200 or status_code >= 300: - raise RuntimeError( - f"An unexpected HTTP response of {status_code!r} was received for request made to https://{self.client._host}:{int(self.client._port)}{self.PATH}.The response payload for the request was {truncate(response.decode('utf-8'), 1024)!r}. If this issue persists then please report this problem to New Relic support for further investigation." - ) - - except Exception: - self.handleError(record) - - def default_host(self, license_key): - if not license_key: - return "log-api.newrelic.com" - - region_aware_match = re.match("^(.+?)x", license_key) - if not region_aware_match: - return "log-api.newrelic.com" - - region = region_aware_match.group(1) - host = f"log-api.{region}.newrelic.com" - return host From fa4defda66dc04206f245ddb4979536ce2ffbadf Mon Sep 17 00:00:00 2001 From: Lalleh Rafeei Date: Wed, 3 Sep 2025 11:15:44 -0700 Subject: [PATCH 14/14] Fix Megalinter errors --- newrelic/api/application.py | 1 - newrelic/api/error_trace.py | 7 +------ newrelic/api/log.py | 2 -- newrelic/api/time_trace.py | 1 - newrelic/api/transaction.py | 2 -- newrelic/core/agent.py | 1 - newrelic/core/application.py | 1 - newrelic/core/stats_engine.py | 1 - newrelic/hooks/adapter_cheroot.py | 1 + newrelic/hooks/adapter_waitress.py | 2 +- newrelic/hooks/component_piston.py | 1 + newrelic/hooks/framework_webpy.py | 1 + tests/agent_features/test_distributed_tracing.py | 4 ++-- tests/cross_agent/test_distributed_tracing.py | 6 ++++-- tests/datastore_psycopg/test_slow_sql.py | 2 +- 15 files changed, 12 insertions(+), 21 deletions(-) diff --git a/newrelic/api/application.py b/newrelic/api/application.py index aa9d871e45..9aa6d7b6b8 100644 --- a/newrelic/api/application.py +++ b/newrelic/api/application.py @@ -13,7 +13,6 @@ # limitations under the License. import threading -import warnings import newrelic.api.import_hook import newrelic.core.agent diff --git a/newrelic/api/error_trace.py b/newrelic/api/error_trace.py index bf9ea83d12..db63c54316 100644 --- a/newrelic/api/error_trace.py +++ b/newrelic/api/error_trace.py @@ -44,7 +44,6 @@ def __exit__(self, exc, value, tb): def ErrorTraceWrapper(wrapped, ignore=None, expected=None, status_code=None): - def wrapper(wrapped, instance, args, kwargs): parent = current_trace() @@ -58,12 +57,8 @@ def wrapper(wrapped, instance, args, kwargs): def error_trace(ignore=None, expected=None, status_code=None): - - return functools.partial( - ErrorTraceWrapper, ignore=ignore, expected=expected, status_code=status_code - ) + return functools.partial(ErrorTraceWrapper, ignore=ignore, expected=expected, status_code=status_code) def wrap_error_trace(module, object_path, ignore=None, expected=None, status_code=None): - wrap_object(module, object_path, ErrorTraceWrapper, (ignore, expected, status_code)) diff --git a/newrelic/api/log.py b/newrelic/api/log.py index 1dab724ad5..65c147a265 100644 --- a/newrelic/api/log.py +++ b/newrelic/api/log.py @@ -21,7 +21,6 @@ from newrelic.api.transaction import current_transaction, record_log_event from newrelic.common.encoding_utils import json_encode from newrelic.common.object_names import parse_exc_info -from newrelic.core.attribute import truncate from newrelic.core.config import global_settings, is_expected_error @@ -183,4 +182,3 @@ def emit(self, record): def filter_record_attributes(cls, record): record_attrs = vars(record) return {k: record_attrs[k] for k in record_attrs if k not in cls.IGNORED_LOG_RECORD_KEYS} - diff --git a/newrelic/api/time_trace.py b/newrelic/api/time_trace.py index e853d2e8b1..e9ee73936e 100644 --- a/newrelic/api/time_trace.py +++ b/newrelic/api/time_trace.py @@ -18,7 +18,6 @@ import sys import time import traceback -import warnings from newrelic.api.settings import STRIP_EXCEPTION_MESSAGE from newrelic.common.object_names import parse_exc_info diff --git a/newrelic/api/transaction.py b/newrelic/api/transaction.py index 5948f8bae6..57a15508e8 100644 --- a/newrelic/api/transaction.py +++ b/newrelic/api/transaction.py @@ -19,7 +19,6 @@ import sys import threading import time -import warnings import weakref from collections import OrderedDict @@ -1219,7 +1218,6 @@ def _accept_distributed_trace_payload(self, payload, transport_type="HTTP"): self._record_supportability("Supportability/DistributedTrace/AcceptPayload/Exception") return False - def _accept_distributed_trace_data(self, data, transport_type): if transport_type not in DISTRIBUTED_TRACE_TRANSPORT_TYPES: transport_type = "Unknown" diff --git a/newrelic/core/agent.py b/newrelic/core/agent.py index 02a9431301..fbfc06b260 100644 --- a/newrelic/core/agent.py +++ b/newrelic/core/agent.py @@ -25,7 +25,6 @@ import threading import time import traceback -import warnings import newrelic import newrelic.core.application diff --git a/newrelic/core/application.py b/newrelic/core/application.py index 9508fbc854..3ba8168d60 100644 --- a/newrelic/core/application.py +++ b/newrelic/core/application.py @@ -20,7 +20,6 @@ import threading import time import traceback -import warnings from functools import partial from newrelic.common.object_names import callable_name diff --git a/newrelic/core/stats_engine.py b/newrelic/core/stats_engine.py index a925e555a7..7b65287cda 100644 --- a/newrelic/core/stats_engine.py +++ b/newrelic/core/stats_engine.py @@ -27,7 +27,6 @@ import sys import time import traceback -import warnings import zlib from heapq import heapify, heapreplace diff --git a/newrelic/hooks/adapter_cheroot.py b/newrelic/hooks/adapter_cheroot.py index 556a1a443e..a1dbf6fec7 100644 --- a/newrelic/hooks/adapter_cheroot.py +++ b/newrelic/hooks/adapter_cheroot.py @@ -15,6 +15,7 @@ import newrelic.api.wsgi_application from newrelic.common.object_wrapper import wrap_in_function + def instrument_cheroot_wsgiserver(module): def wrap_wsgi_application_entry_point(server, bind_addr, wsgi_app, *args, **kwargs): application = newrelic.api.wsgi_application.WSGIApplicationWrapper(wsgi_app) diff --git a/newrelic/hooks/adapter_waitress.py b/newrelic/hooks/adapter_waitress.py index 499f027955..df251129ec 100644 --- a/newrelic/hooks/adapter_waitress.py +++ b/newrelic/hooks/adapter_waitress.py @@ -13,8 +13,8 @@ # limitations under the License. from newrelic.api.wsgi_application import WSGIApplicationWrapper -from newrelic.common.package_version_utils import get_package_version from newrelic.common.object_wrapper import wrap_in_function +from newrelic.common.package_version_utils import get_package_version def instrument_waitress_server(module): diff --git a/newrelic/hooks/component_piston.py b/newrelic/hooks/component_piston.py index 8ec7ee3686..4b805fa7ee 100644 --- a/newrelic/hooks/component_piston.py +++ b/newrelic/hooks/component_piston.py @@ -19,6 +19,7 @@ from newrelic.common.object_names import callable_name from newrelic.common.object_wrapper import wrap_in_function + class MethodWrapper: def __init__(self, wrapped, priority=None): self._nr_name = callable_name(wrapped) diff --git a/newrelic/hooks/framework_webpy.py b/newrelic/hooks/framework_webpy.py index 19aef69ca2..67bf7e33c3 100644 --- a/newrelic/hooks/framework_webpy.py +++ b/newrelic/hooks/framework_webpy.py @@ -19,6 +19,7 @@ from newrelic.common.object_names import callable_name from newrelic.common.object_wrapper import wrap_in_function, wrap_out_function, wrap_pre_function + def transaction_name_delegate(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() if transaction: diff --git a/tests/agent_features/test_distributed_tracing.py b/tests/agent_features/test_distributed_tracing.py index d8b08adfe9..7dd1f70c7c 100644 --- a/tests/agent_features/test_distributed_tracing.py +++ b/tests/agent_features/test_distributed_tracing.py @@ -28,10 +28,10 @@ from newrelic.api.time_trace import current_trace from newrelic.api.transaction import ( accept_distributed_trace_headers, - insert_distributed_trace_headers, current_span_id, current_trace_id, current_transaction, + insert_distributed_trace_headers, ) from newrelic.api.web_transaction import WSGIWebTransaction from newrelic.api.wsgi_application import wsgi_application @@ -187,7 +187,7 @@ def _test(): headers = [] insert_distributed_trace_headers(headers) assert headers - + try: raise ValueError("cookies") except ValueError: diff --git a/tests/cross_agent/test_distributed_tracing.py b/tests/cross_agent/test_distributed_tracing.py index 0028b1d460..a3536fcce5 100644 --- a/tests/cross_agent/test_distributed_tracing.py +++ b/tests/cross_agent/test_distributed_tracing.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json import base64 +import json from pathlib import Path import pytest @@ -129,7 +129,9 @@ def target_wsgi_application(environ, start_response): headers = [] txn.insert_distributed_trace_headers(headers) # To revert to the dict format of the payload, use this: - payload = json.loads(base64.b64decode([value for key, value in headers if key=="newrelic"][0]).decode("utf-8")) + payload = json.loads( + base64.b64decode([value for key, value in headers if key == "newrelic"][0]).decode("utf-8") + ) payload_version = payload.get("v") if payload_version and isinstance(payload_version, list): payload["v"] = tuple(payload_version) diff --git a/tests/datastore_psycopg/test_slow_sql.py b/tests/datastore_psycopg/test_slow_sql.py index 9ead81cc38..dbf2383325 100644 --- a/tests/datastore_psycopg/test_slow_sql.py +++ b/tests/datastore_psycopg/test_slow_sql.py @@ -124,5 +124,5 @@ def _test(): } headers = {"newrelic": payload} transaction.accept_distributed_trace_headers(headers) - + _test()