function_trace

For general information on how the Python agent API calls relate to each other, see the API guide.

newrelic.agent.function_trace(name=None, group=None, label=None, params=None, terminal=False)
Used to instrument functions, methods, generators, and coroutines that aren't instrumented by default.

Description

function_trace is a decorator for adding to functions, methods, generators, and coroutines. Adding this decorator lets you collect additional transaction information (including transaction trace information). (An alternate way to instrument functions without having to touch your app code is to list them in the config file.)

function_trace does not give you a full profile of all the functions that happen in a decorated function. What it does is add the decorated function as a node in the New Relic UI and capture the time spent in that function. If you need more detail about what is going on in that function, you would need to also apply the function trace to the function's child functions.

The function_trace decorator can be used on generators and coroutines with agent version 2.102.0.85 or higher. Timing of these objects begins when consumption starts, and ends when the object is exhausted or goes out of scope. This is a change from earlier versions where the metric represented the time taken to create the generator or coroutine object itself.

You can use the decorator in conjunction with existing decorators, including those for static and class methods. When nesting multiple decorators, have the function_trace decorator as the outermost decorator.

For any decorators that are being wrapped, use functools.wraps() from the Python standard library in their implementation. (Or, otherwise ensure that the decorator propagates the correct name attributes of the innermost wrapped object required to allow correct name introspection.) If this is not done, then when the metric is reported, the name of the nested decorator function (not the innermost wrapped function) will be used.

Alternate call forms

For setups where you cannot use the decorator, these alternate call forms are available:

The FunctionTrace context manager is used when the parameters to be passed cannot be determined before runtime. (For example, you may not know the name of a function at import time.) When using the context manager to name a metric, you must always supply the name and the metric path prefix.

The FunctionTrace class implements the context manager and is used in conjunction with the with statement. The FunctionTrace class is the lowest level primitive available for tracing time against a transaction.

The with statement defines the bounds of what is timed and not a single function. Thus, the context manager could be applied to an arbitrary block of code. The block of code could therefore contain calls to multiple functions, or it could be a self-contained block of code implementing a time-oriented algorithm that you want to track.

Avoid tracing blocks of code that are called an excessive number of times. For example, do not use it within the context of a loop that executes many times. The data generated will incur a performance overhead. A better solution is to enclose the loop.

If you know in advance where the specific functions you want to trace are, you could use the function_trace decorator. However, if you don't know all the functions that need to be traced (for example, if they're being looked up dynamically as part of a routing system), then you must use the FunctionTraceWrapper to wrap the function at the time of registration or at the time of calling.

wrap_function_trace is used for wrapping functions outside of the code they're declared in. For example: you might use this to instrument library code that you don't want to modify.

For more about the differences between these call formats, see Different call formats.

Parameters

Parameters for decorator

newrelic.agent.function_trace(name=None, group=None, label=None, params=None, terminal=False)

This call includes these parameters:

Parameter Description

name

string

Optional. The function name. If not set, defaults to the captured name of the function.

group

string

Optional. The group represents the naming structure for the name parameter. This is used in the UI for segregating the transaction types.

If not supplied, the group will default to Function in expectation that the name is of the form module:class.function or module:function and represents the name of the function being executed. If you are creating a custom group, it's recommended you prefix it with Python/.

label

string

Optional. Adds a callout-style flag to the segment in a transaction trace. Default is None.

params

dict

Optional. Custom parameters to add to the segment in transaction traces.

terminal

boolean

Optional. If true, no children segments will be recorded. Default is False.

Parameters for context manager

newrelic.agent.FunctionTrace(name, group=None, label=None, params=None, terminal=False)

Parameters for the context manager includes all of the parameters from function_trace. The name parameter is required and not optional.

Parameter Description

name

string

Required. The function name.

Wrapper parameters

newrelic.agent.FunctionTraceWrapper(wrapped, name=None, group=None, label=None, params=None, terminal=False)

Parameters for the wrapper include all parameters for function_trace and a wrapped parameter:

Parameter Description

wrapped

function

Required. The function being wrapped.

Path-based wrapping parameters

newrelic.agent.wrap_function_trace(module, object_path, name=None, group=None, label=None, params=None, terminal=False)

Parameters include all parameters for function_trace and these parameters:

Parameter Description

module

object

Required. The module containing the function to be instrumented.

object_path

string

The path to the location of the function.

Example(s)

function_trace example

An example of using the function_trace decorator:

import newrelic.agent

class _Database(UserDict.DictMixin):

    ...

    @newrelic.agent.function_trace()
    def _commit(self):
        ...

@newrelic.agent.function_trace()
def open(file, flag=None, mode=0666):
...

An example of using the function_trace decorator with native coroutines:

import newrelic.agent

class _Database(UserDict.DictMixin):

    ...

    @newrelic.agent.function_trace()
    async def _commit(self):
        ...

@newrelic.agent.function_trace()
async def open(file, flag=None, mode=0666):
...

Context manager example

An example of using the FunctionTrace context manager:

import newrelic.agent

def dispatch_request(self, request):
    adapter = self.url_map.bind_to_environ(request.environ)
    try:
        endpoint, values = adapter.match()
        function = getattr(self, 'on_' + endpoint)
        with newrelic.agent.FunctionTrace(
                endpoint, 'Python/EndPoint'):
            return function(request, **values)
    except HTTPException as e:
        return e

Wrapper example

An example of using the FunctionTraceWrapper:

URL routing with Werkzeug yields a name that is used first to dynamically look up a method of a class using getattr() and the result then invoked:

def dispatch_request(self, request):
    adapter = self.url_map.bind_to_environ(request.environ)
    try:
        endpoint, values = adapter.match()
        return getattr(self, 'on_' + endpoint)(request, **values)
    except HTTPException as e:
        return e

If you want to trace the endpoint function, you can rewrite this as:

import newrelic.agent

def dispatch_request(self, request):
    adapter = self.url_map.bind_to_environ(request.environ)
    try:
        endpoint, values = adapter.match()
        function = getattr(self, 'on_' + endpoint)
        function = newrelic.agent.FunctionTraceWrapper(function)
        return function(request, **values)
    except HTTPException as e:
        return e

If you want to name the metric after the endpoint name (rather than naming the metric based on the identifier for the function being called), you can supply the name to use plus an alternate metric path prefix when the FunctionTraceWrapper object is created.

import newrelic.agent

def dispatch_request(self, request):
    adapter = self.url_map.bind_to_environ(request.environ)
    try:
        endpoint, values = adapter.match()
        function = getattr(self, 'on_' + endpoint)
        function = newrelic.agent.FunctionTraceWrapper(
                function, name=endpoint, group='Python/EndPoint')
        return function(request, **values)
    except HTTPException as e:
        return e

For this example, if the endpoint were called help, the final metric would be:

Python/EndPoint/help

In the performance breakdown for a transaction, the category would be Python and the segment name EndPoint/help. That segment name would also appear in slow transaction traces as the node name.

For more help

Recommendations for learning more: