Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f20911e
Add baseline instrumentation.
umaannamalai Oct 27, 2025
c382f72
Add tool and agent instrumentation.
umaannamalai Oct 29, 2025
78b57bb
Add tests file.
umaannamalai Oct 29, 2025
6c6b40d
Cleanup instrumentation.
umaannamalai Oct 30, 2025
cdc2295
Cleanup.
umaannamalai Oct 30, 2025
c074175
[MegaLinter] Apply linters fixes
umaannamalai Oct 30, 2025
1d9fc03
Strands Mock Model (#1551)
TimPansino Oct 23, 2025
e1cbba0
Add baseline instrumentation.
umaannamalai Oct 27, 2025
5cf6c37
Add tool and agent instrumentation.
umaannamalai Oct 29, 2025
1dfaf55
Add tests file.
umaannamalai Oct 29, 2025
df369a7
Cleanup instrumentation.
umaannamalai Oct 30, 2025
69e1c88
Cleanup.
umaannamalai Oct 30, 2025
a5a3133
Handle additional args in mock model.
umaannamalai Oct 30, 2025
9503558
Merge branch 'feat-strands-agents' of github.com:newrelic/newrelic-py…
umaannamalai Oct 30, 2025
e2ad09d
Add test to force exception and exercise _handle_tool_streaming_compl…
umaannamalai Nov 4, 2025
4213bd3
Strands Mock Model (#1551)
TimPansino Oct 23, 2025
520bd9a
Add baseline instrumentation.
umaannamalai Oct 27, 2025
0bfe25d
Add tool and agent instrumentation.
umaannamalai Oct 29, 2025
b757886
Add tests file.
umaannamalai Oct 29, 2025
4667155
Cleanup instrumentation.
umaannamalai Oct 30, 2025
cec6515
Cleanup.
umaannamalai Oct 30, 2025
bc841df
Handle additional args in mock model.
umaannamalai Oct 30, 2025
78c7bd6
Strands Mock Model (#1551)
TimPansino Oct 23, 2025
3863fdf
Add baseline instrumentation.
umaannamalai Oct 27, 2025
30ab602
Add tool and agent instrumentation.
umaannamalai Oct 29, 2025
b4a6578
Cleanup.
umaannamalai Oct 30, 2025
2b8107e
[MegaLinter] Apply linters fixes
umaannamalai Oct 30, 2025
5527059
Add test to force exception and exercise _handle_tool_streaming_compl…
umaannamalai Nov 4, 2025
21906b3
Merge branch 'feat-strands-agents' of github.com:newrelic/newrelic-py…
umaannamalai Nov 4, 2025
57757d8
Merge branch 'develop-strands' into feat-strands-agents
umaannamalai Nov 4, 2025
43bc792
Implement strands context passing instrumentation.
TimPansino Nov 7, 2025
79ada63
Address review feedback.
umaannamalai Nov 11, 2025
80e9d3d
[MegaLinter] Apply linters fixes
umaannamalai Nov 11, 2025
36d4af2
Remove test_simple.py file.
umaannamalai Nov 12, 2025
260c2bc
Merge branch 'feat-strands-agents' of github.com:newrelic/newrelic-py…
umaannamalai Nov 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions newrelic/api/error_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import functools

from newrelic.api.time_trace import current_trace, notice_error
from newrelic.common.async_wrapper import async_wrapper as get_async_wrapper
from newrelic.common.object_wrapper import FunctionWrapper, wrap_object


Expand Down Expand Up @@ -43,17 +44,31 @@ 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()
def ErrorTraceWrapper(wrapped, ignore=None, expected=None, status_code=None, async_wrapper=None):
def literal_wrapper(wrapped, instance, args, kwargs):
# Determine if the wrapped function is async or sync
wrapper = async_wrapper if async_wrapper is not None else get_async_wrapper(wrapped)
# Sync function path
if not wrapper:
parent = current_trace()
if not parent:
# No active tracing context so just call the wrapped function directly
return wrapped(*args, **kwargs)
# Async function path
else:
# For async functions, the async wrapper will handle trace context propagation
parent = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of wether there is a wrapper or not shouldn't we still set the parent to the current trace if there is a current trace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here was that the if we had an async wrapper, then the trace context management would happen directly in the wrapper (ex: https://github.com/newrelic/newrelic-python-agent/blob/main/newrelic/common/async_wrapper.py#L25). This has been the same approach we take for other trace types such as ExternalTraces and FunctionTraces


if parent is None:
return wrapped(*args, **kwargs)
trace = ErrorTrace(ignore, expected, status_code, parent=parent)

if wrapper:
# The async wrapper handles the context management for us
return wrapper(wrapped, trace)(*args, **kwargs)

with ErrorTrace(ignore, expected, status_code, parent=parent):
with trace:
return wrapped(*args, **kwargs)

return FunctionWrapper(wrapped, wrapper)
return FunctionWrapper(wrapped, literal_wrapper)


def error_trace(ignore=None, expected=None, status_code=None):
Expand Down
24 changes: 24 additions & 0 deletions newrelic/common/llm_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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.


def _get_llm_metadata(transaction):
# Grab LLM-related custom attributes off of the transaction to store as metadata on LLM events
custom_attrs_dict = transaction._custom_params
llm_metadata_dict = {key: value for key, value in custom_attrs_dict.items() if key.startswith("llm.")}
llm_context_attrs = getattr(transaction, "_llm_context_attrs", None)
if llm_context_attrs:
llm_metadata_dict.update(llm_context_attrs)

return llm_metadata_dict
7 changes: 7 additions & 0 deletions newrelic/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2946,6 +2946,13 @@ def _process_module_builtin_defaults():
"newrelic.hooks.mlmodel_autogen",
"instrument_autogen_agentchat_agents__assistant_agent",
)
_process_module_definition("strands.agent.agent", "newrelic.hooks.mlmodel_strands", "instrument_agent_agent")
_process_module_definition(
"strands.tools.executors._executor", "newrelic.hooks.mlmodel_strands", "instrument_tools_executors__executor"
)
_process_module_definition("strands.tools.registry", "newrelic.hooks.mlmodel_strands", "instrument_tools_registry")
_process_module_definition("strands.models.bedrock", "newrelic.hooks.mlmodel_strands", "instrument_models_bedrock")

_process_module_definition("mcp.client.session", "newrelic.hooks.adapter_mcp", "instrument_mcp_client_session")
_process_module_definition(
"mcp.server.fastmcp.tools.tool_manager",
Expand Down
Loading
Loading