diff --git a/newrelic/agent.py b/newrelic/agent.py index 2c7f0fb858..9665cb9d22 100644 --- a/newrelic/agent.py +++ b/newrelic/agent.py @@ -15,7 +15,7 @@ from newrelic.api.application import application_instance as __application from newrelic.api.application import application_settings as __application_settings from newrelic.api.application import register_application as __register_application -from newrelic.api.log import NewRelicContextFormatter # noqa +from newrelic.api.log import NewRelicContextFormatter as __NewRelicContextFormatter from newrelic.api.time_trace import ( add_custom_span_attribute as __add_custom_span_attribute, ) @@ -177,6 +177,7 @@ 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 CallableObjectProxy as __CallableObjectProxy 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 @@ -276,6 +277,7 @@ def __asgi_application(*args, **kwargs): 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") wrap_transaction_name = __wrap_api_call(__wrap_transaction_name, "wrap_transaction_name") @@ -316,6 +318,7 @@ def __asgi_application(*args, **kwargs): wrap_message_transaction = __wrap_api_call(__wrap_message_transaction, "wrap_message_transaction") callable_name = __wrap_api_call(__callable_name, "callable_name") ObjectProxy = __wrap_api_call(__ObjectProxy, "ObjectProxy") +CallableObjectProxy = __wrap_api_call(__CallableObjectProxy, "CallableObjectProxy") wrap_object = __wrap_api_call(__wrap_object, "wrap_object") wrap_object_attribute = __wrap_api_call(__wrap_object_attribute, "wrap_object_attribute") resolve_path = __wrap_api_call(__resolve_path, "resolve_path") diff --git a/newrelic/api/solr_trace.py b/newrelic/api/solr_trace.py index e482158ee9..6907f20f8b 100644 --- a/newrelic/api/solr_trace.py +++ b/newrelic/api/solr_trace.py @@ -14,6 +14,7 @@ import newrelic.api.object_wrapper import newrelic.api.time_trace +import newrelic.common.object_wrapper import newrelic.core.solr_node @@ -111,4 +112,4 @@ def decorator(wrapped): def wrap_solr_trace(module, object_path, library, command): - newrelic.api.object_wrapper.wrap_object(module, object_path, SolrTraceWrapper, (library, command)) + newrelic.common.object_wrapper.wrap_object(module, object_path, SolrTraceWrapper, (library, command)) diff --git a/newrelic/common/object_wrapper.py b/newrelic/common/object_wrapper.py index c676966108..09c737fd2b 100644 --- a/newrelic/common/object_wrapper.py +++ b/newrelic/common/object_wrapper.py @@ -20,6 +20,7 @@ """ import inspect +import warnings from newrelic.packages.wrapt import BoundFunctionWrapper as _BoundFunctionWrapper from newrelic.packages.wrapt import CallableObjectProxy as _CallableObjectProxy @@ -31,7 +32,6 @@ wrap_object, wrap_object_attribute, ) -from newrelic.packages.wrapt.__wrapt__ import _FunctionWrapperBase # We previously had our own pure Python implementation of the generic # object wrapper but we now defer to using the wrapt module as its C @@ -122,19 +122,13 @@ class CallableObjectProxy(ObjectProxy, _CallableObjectProxy): # own code no longer uses it. It reaches down into what are wrapt internals # at present which shouldn't be doing. - -class ObjectWrapper(ObjectProxy, _FunctionWrapperBase): - __bound_function_wrapper__ = _NRBoundFunctionWrapper - +class ObjectWrapper(FunctionWrapper): def __init__(self, wrapped, instance, wrapper): - if isinstance(wrapped, classmethod): - binding = "classmethod" - elif isinstance(wrapped, staticmethod): - binding = "staticmethod" - else: - binding = "function" - - super(ObjectWrapper, self).__init__(wrapped, instance, wrapper, binding=binding) + warnings.warn( + ("The ObjectWrapper API is deprecated. Please use one of ObjectProxy, FunctionWrapper, or CallableObjectProxy instead."), + DeprecationWarning, + ) + super(ObjectWrapper, self).__init__(wrapped, wrapper) # Function for creating a decorator for applying to functions, as well as diff --git a/newrelic/config.py b/newrelic/config.py index d08d51dff7..d63381e44b 100644 --- a/newrelic/config.py +++ b/newrelic/config.py @@ -34,7 +34,7 @@ import newrelic.api.generator_trace import newrelic.api.import_hook import newrelic.api.memcache_trace -import newrelic.api.object_wrapper +from newrelic.common.object_names import callable_name import newrelic.api.profile_trace import newrelic.api.settings import newrelic.api.transaction_name @@ -1345,7 +1345,7 @@ def _process_background_task_configuration(): group = _config_object.get(section, "group") if name and name.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} name = eval(name, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register background-task %s", ((module, object_path, application, name, group),)) @@ -1395,7 +1395,7 @@ def _process_database_trace_configuration(): sql = _config_object.get(section, "sql") if sql.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} sql = eval(sql, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register database-trace %s", ((module, object_path, sql),)) @@ -1450,11 +1450,11 @@ def _process_external_trace_configuration(): method = _config_object.get(section, "method") if url.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} url = eval(url, callable_vars) # nosec, pylint: disable=W0123 if method and method.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} method = eval(method, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register external-trace %s", ((module, object_path, library, url, method),)) @@ -1522,7 +1522,7 @@ def _process_function_trace_configuration(): rollup = _config_object.get(section, "rollup") if name and name.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} name = eval(name, callable_vars) # nosec, pylint: disable=W0123 _logger.debug( @@ -1580,7 +1580,7 @@ def _process_generator_trace_configuration(): group = _config_object.get(section, "group") if name and name.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} name = eval(name, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register generator-trace %s", ((module, object_path, name, group),)) @@ -1639,7 +1639,7 @@ def _process_profile_trace_configuration(): depth = _config_object.get(section, "depth") if name and name.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} name = eval(name, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register profile-trace %s", ((module, object_path, name, group, depth),)) @@ -1689,7 +1689,7 @@ def _process_memcache_trace_configuration(): command = _config_object.get(section, "command") if command.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} command = eval(command, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register memcache-trace %s", (module, object_path, command)) @@ -1749,7 +1749,7 @@ def _process_transaction_name_configuration(): priority = _config_object.getint(section, "priority") if name and name.startswith("lambda "): - callable_vars = {"callable_name": newrelic.api.object_wrapper.callable_name} + callable_vars = {"callable_name": callable_name} name = eval(name, callable_vars) # nosec, pylint: disable=W0123 _logger.debug("register transaction-name %s", ((module, object_path, name, group, priority),)) diff --git a/newrelic/console.py b/newrelic/console.py index 48cda6e7cc..31b664b55a 100644 --- a/newrelic/console.py +++ b/newrelic/console.py @@ -72,8 +72,7 @@ def doc_signature(func): return formatargspec(args[1:], varargs, keywords, defaults) -from newrelic.api.object_wrapper import ObjectWrapper -from newrelic.api.transaction import Transaction +from newrelic.common.object_wrapper import ObjectProxy from newrelic.core.agent import agent_instance from newrelic.core.config import flatten_settings, global_settings from newrelic.core.trace_cache import trace_cache @@ -161,7 +160,7 @@ def __call__(self, code=None): __builtin__.exit = Quitter("exit") -class OutputWrapper(ObjectWrapper): +class OutputWrapper(ObjectProxy): def flush(self): try: shell = _consoles.active @@ -187,8 +186,8 @@ def writelines(self, data): def intercept_console(): setquit() - sys.stdout = OutputWrapper(sys.stdout, None, None) - sys.stderr = OutputWrapper(sys.stderr, None, None) + sys.stdout = OutputWrapper(sys.stdout) + sys.stderr = OutputWrapper(sys.stderr) class EmbeddedConsole(code.InteractiveConsole): diff --git a/newrelic/core/internal_metrics.py b/newrelic/core/internal_metrics.py index 87452fce4a..090a658c73 100644 --- a/newrelic/core/internal_metrics.py +++ b/newrelic/core/internal_metrics.py @@ -17,6 +17,7 @@ import types import time import threading +import newrelic.common.object_wrapper _context = threading.local() @@ -88,7 +89,7 @@ def decorator(wrapped): return decorator def wrap_internal_trace(module, object_path, name=None): - newrelic.api.object_wrapper.wrap_object(module, object_path, + newrelic.common.object_wrapper.wrap_object(module, object_path, InternalTraceWrapper, (name,)) def internal_metric(name, value): diff --git a/newrelic/hooks/application_celery.py b/newrelic/hooks/application_celery.py index 12f41d8d0d..ab7ca9e95c 100644 --- a/newrelic/hooks/application_celery.py +++ b/newrelic/hooks/application_celery.py @@ -26,7 +26,8 @@ from newrelic.api.background_task import BackgroundTask from newrelic.api.function_trace import FunctionTrace from newrelic.api.pre_function import wrap_pre_function -from newrelic.api.object_wrapper import callable_name, ObjectWrapper +from newrelic.common.object_names import callable_name +from newrelic.common.object_wrapper import FunctionWrapper from newrelic.api.transaction import current_transaction from newrelic.core.agent import shutdown_agent @@ -98,10 +99,6 @@ def _application(): with BackgroundTask(_application(), _name, 'Celery', source=instance): return wrapped(*args, **kwargs) - # Start Hotfix v2.2.1. - # obj = ObjectWrapper(wrapped, None, wrapper) - # End Hotfix v2.2.1. - # Celery tasks that inherit from celery.app.task must implement a run() # method. # ref: (http://docs.celeryproject.org/en/2.5/reference/ @@ -110,11 +107,11 @@ def _application(): # task. But celery does a micro-optimization where if the __call__ method # was not overridden by an inherited task, then it will directly execute # the run() method without going through the __call__ method. Our - # instrumentation via ObjectWrapper() relies on __call__ being called which + # instrumentation via FunctionWrapper() relies on __call__ being called which # in turn executes the wrapper() function defined above. Since the micro # optimization bypasses __call__ method it breaks our instrumentation of # celery. To circumvent this problem, we added a run() attribute to our - # ObjectWrapper which points to our __call__ method. This causes Celery + # FunctionWrapper which points to our __call__ method. This causes Celery # to execute our __call__ method which in turn applies the wrapper # correctly before executing the task. # @@ -122,17 +119,11 @@ def _application(): # versions included a monkey-patching provision which did not perform this # optimization on functions that were monkey-patched. - # Start Hotfix v2.2.1. - # obj.__dict__['run'] = obj.__call__ - - class _ObjectWrapper(ObjectWrapper): + class TaskWrapper(FunctionWrapper): def run(self, *args, **kwargs): return self.__call__(*args, **kwargs) - obj = _ObjectWrapper(wrapped, None, wrapper) - # End Hotfix v2.2.1. - - return obj + return TaskWrapper(wrapped, wrapper) def instrument_celery_app_task(module): diff --git a/newrelic/hooks/component_piston.py b/newrelic/hooks/component_piston.py index 78b975ed53..96204f404c 100644 --- a/newrelic/hooks/component_piston.py +++ b/newrelic/hooks/component_piston.py @@ -16,14 +16,15 @@ import newrelic.api.transaction import newrelic.api.function_trace -import newrelic.api.object_wrapper +import newrelic.common.object_wrapper +from newrelic.common.object_names import callable_name import newrelic.api.in_function class MethodWrapper(object): def __init__(self, wrapped, priority=None): - self._nr_name = newrelic.api.object_wrapper.callable_name(wrapped) + self._nr_name = callable_name(wrapped) self._nr_wrapped = wrapped self._nr_priority = priority @@ -76,7 +77,7 @@ def __call__(self, *args, **kwargs): def instrument_piston_resource(module): - newrelic.api.object_wrapper.wrap_object(module, + newrelic.common.object_wrapper.wrap_object(module, 'Resource.__init__', ResourceInitWrapper) diff --git a/newrelic/hooks/component_tastypie.py b/newrelic/hooks/component_tastypie.py index 8cc251916c..da93efbfb3 100644 --- a/newrelic/hooks/component_tastypie.py +++ b/newrelic/hooks/component_tastypie.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from newrelic.api.function_trace import FunctionTraceWrapper -from newrelic.api.object_wrapper import ObjectWrapper, callable_name +from newrelic.common.object_names import callable_name +from newrelic.common.object_wrapper import wrap_function_wrapper, function_wrapper from newrelic.api.transaction import current_transaction from newrelic.api.time_trace import notice_error -from newrelic.common.object_wrapper import wrap_function_wrapper def _nr_wrap_handle_exception(wrapped, instance, args, kwargs): @@ -56,6 +54,7 @@ def outer_fn_wrapper(outer_fn, instance, args, kwargs): name = callable_name(callback) group = None + @function_wrapper def inner_fn_wrapper(inner_fn, instance, args, kwargs): transaction = current_transaction() @@ -69,18 +68,14 @@ def inner_fn_wrapper(inner_fn, instance, args, kwargs): result = outer_fn(*args, **kwargs) - return ObjectWrapper(result, None, inner_fn_wrapper) + return inner_fn_wrapper(result) def instrument_tastypie_resources(module): - _wrap_view = module.Resource.wrap_view - module.Resource.wrap_view = ObjectWrapper( - _wrap_view, None, outer_fn_wrapper) + wrap_function_wrapper(module, "Resource.wrap_view", outer_fn_wrapper) - wrap_function_wrapper(module, 'Resource._handle_500', - _nr_wrap_handle_exception) + wrap_function_wrapper(module, 'Resource._handle_500', _nr_wrap_handle_exception) def instrument_tastypie_api(module): - _wrap_view = module.Api.wrap_view - module.Api.wrap_view = ObjectWrapper(_wrap_view, None, outer_fn_wrapper) + wrap_function_wrapper(module, "Api.wrap_view", outer_fn_wrapper) diff --git a/newrelic/hooks/external_feedparser.py b/newrelic/hooks/external_feedparser.py index 13f9ebd63e..1d2003eb21 100644 --- a/newrelic/hooks/external_feedparser.py +++ b/newrelic/hooks/external_feedparser.py @@ -19,6 +19,7 @@ import newrelic.api.transaction import newrelic.api.object_wrapper +import newrelic.common.object_wrapper import newrelic.api.external_trace class capture_external_trace(object): @@ -70,5 +71,5 @@ def __getattr__(self, name): return getattr(self._nr_next_object, name) def instrument(module): - newrelic.api.object_wrapper.wrap_object( + newrelic.common.object_wrapper.wrap_object( module, 'parse', capture_external_trace) diff --git a/newrelic/hooks/external_httplib.py b/newrelic/hooks/external_httplib.py index 7d322f7194..ca8decb40c 100644 --- a/newrelic/hooks/external_httplib.py +++ b/newrelic/hooks/external_httplib.py @@ -18,7 +18,7 @@ from newrelic.api.external_trace import ExternalTrace from newrelic.api.transaction import current_transaction -from newrelic.common.object_wrapper import ObjectWrapper +from newrelic.common.object_wrapper import wrap_function_wrapper def httplib_endheaders_wrapper(wrapped, instance, args, kwargs, @@ -125,24 +125,7 @@ def instrument(module): else: library = 'http' - module.HTTPConnection.endheaders = ObjectWrapper( - module.HTTPConnection.endheaders, - None, - functools.partial(httplib_endheaders_wrapper, scheme='http', - library=library)) - - module.HTTPSConnection.endheaders = ObjectWrapper( - module.HTTPConnection.endheaders, - None, - functools.partial(httplib_endheaders_wrapper, scheme='https', - library=library)) - - module.HTTPConnection.getresponse = ObjectWrapper( - module.HTTPConnection.getresponse, - None, - httplib_getresponse_wrapper) - - module.HTTPConnection.putheader = ObjectWrapper( - module.HTTPConnection.putheader, - None, - httplib_putheader_wrapper) + wrap_function_wrapper(module, "HTTPConnection.endheaders", functools.partial(httplib_endheaders_wrapper, scheme='http', library=library)) + wrap_function_wrapper(module, "HTTPSConnection.endheaders", functools.partial(httplib_endheaders_wrapper, scheme='https', library=library)) + wrap_function_wrapper(module, "HTTPConnection.getresponse", httplib_getresponse_wrapper) + wrap_function_wrapper(module, "HTTPConnection.putheader", httplib_putheader_wrapper) diff --git a/newrelic/hooks/framework_pylons.py b/newrelic/hooks/framework_pylons.py index 9c5c457cd7..2832261668 100644 --- a/newrelic/hooks/framework_pylons.py +++ b/newrelic/hooks/framework_pylons.py @@ -16,14 +16,15 @@ import newrelic.api.transaction_name import newrelic.api.function_trace import newrelic.api.error_trace -import newrelic.api.object_wrapper +import newrelic.common.object_wrapper +from newrelic.common.object_names import callable_name import newrelic.api.import_hook from newrelic.api.time_trace import notice_error def name_controller(self, environ, start_response): action = environ['pylons.routes_dict']['action'] - return "%s.%s" % (newrelic.api.object_wrapper.callable_name(self), action) + return "%s.%s" % (callable_name(self), action) class capture_error(object): def __init__(self, wrapped): @@ -69,12 +70,12 @@ def instrument(module): module, 'WSGIController.__call__') def name_WSGIController_perform_call(self, func, args): - return newrelic.api.object_wrapper.callable_name(func) + return callable_name(func) newrelic.api.function_trace.wrap_function_trace( module, 'WSGIController._perform_call', name_WSGIController_perform_call) - newrelic.api.object_wrapper.wrap_object( + newrelic.common.object_wrapper.wrap_object( module, 'WSGIController._perform_call', capture_error) elif module.__name__ == 'pylons.templating': diff --git a/newrelic/hooks/framework_web2py.py b/newrelic/hooks/framework_web2py.py index e9785e02f5..aeb22bd84a 100644 --- a/newrelic/hooks/framework_web2py.py +++ b/newrelic/hooks/framework_web2py.py @@ -22,6 +22,7 @@ import newrelic.api.function_trace import newrelic.api.transaction_name import newrelic.api.object_wrapper +import newrelic.common.object_wrapper import newrelic.api.pre_function from newrelic.api.time_trace import notice_error @@ -132,7 +133,7 @@ def __call__(self, request, response, session): def __getattr__(self, name): return getattr(self._nr_next_object, name) - newrelic.api.object_wrapper.wrap_object( + newrelic.common.object_wrapper.wrap_object( module, 'serve_controller', error_serve_controller) def instrument_gluon_template(module): diff --git a/newrelic/hooks/framework_webpy.py b/newrelic/hooks/framework_webpy.py index c1785a89f3..3c15bd1a7d 100644 --- a/newrelic/hooks/framework_webpy.py +++ b/newrelic/hooks/framework_webpy.py @@ -21,7 +21,7 @@ import newrelic.api.in_function import newrelic.api.out_function import newrelic.api.pre_function -from newrelic.api.object_wrapper import callable_name +from newrelic.common.object_names import callable_name from newrelic.api.wsgi_application import WSGIApplicationWrapper from newrelic.api.time_trace import notice_error diff --git a/newrelic/hooks/template_genshi.py b/newrelic/hooks/template_genshi.py index abea1e485a..db58237fdb 100644 --- a/newrelic/hooks/template_genshi.py +++ b/newrelic/hooks/template_genshi.py @@ -15,7 +15,7 @@ import types import newrelic.api.transaction -import newrelic.api.object_wrapper +import newrelic.common.object_wrapper import newrelic.api.function_trace class stream_wrapper(object): @@ -69,5 +69,5 @@ def instrument(module): if module.__name__ == 'genshi.template.base': - newrelic.api.object_wrapper.wrap_object( + newrelic.common.object_wrapper.wrap_object( module, 'Template.generate', wrap_template) diff --git a/newrelic/hooks/template_mako.py b/newrelic/hooks/template_mako.py index 2e20da7306..1cd5bab16f 100644 --- a/newrelic/hooks/template_mako.py +++ b/newrelic/hooks/template_mako.py @@ -13,7 +13,7 @@ # limitations under the License. import newrelic.api.function_trace -import newrelic.api.object_wrapper +import newrelic.common.object_wrapper class TemplateRenderWrapper(object): @@ -42,7 +42,7 @@ def __call__(self, template, *args, **kwargs): def instrument_mako_runtime(module): - newrelic.api.object_wrapper.wrap_object(module, + newrelic.common.object_wrapper.wrap_object(module, '_render', TemplateRenderWrapper) def instrument_mako_template(module):