1515import sys
1616from inspect import isawaitable
1717
18- from newrelic .api .web_transaction import web_transaction
19- from newrelic .api .transaction import current_transaction
20- from newrelic .api .function_trace import function_trace , FunctionTrace
18+ from newrelic .api .function_trace import FunctionTrace , function_trace
2119from newrelic .api .time_trace import notice_error
22- from newrelic .common . object_wrapper import ( wrap_function_wrapper ,
23- function_wrapper )
20+ from newrelic .api . transaction import current_transaction
21+ from newrelic . api . web_transaction import web_transaction
2422from newrelic .common .object_names import callable_name
23+ from newrelic .common .object_wrapper import function_wrapper , wrap_function_wrapper
2524
2625
2726def _bind_add (uri , methods , handler , * args , ** kwargs ):
@@ -36,19 +35,20 @@ def _nr_wrapper_handler_(wrapped, instance, args, kwargs):
3635 return wrapped (* args , ** kwargs )
3736
3837 name = callable_name (wrapped )
39- view_class = getattr (wrapped , ' view_class' , None )
38+ view_class = getattr (wrapped , " view_class" , None )
4039 view = view_class or wrapped
4140 if view_class :
4241 try :
4342 method = args [0 ].method .lower ()
44- name = callable_name (view_class ) + '.' + method
43+ name = callable_name (view_class ) + "." + method
4544 view = getattr (view_class , method )
4645 except :
4746 pass
48-
47+
4948 transaction .set_transaction_name (name , priority = 3 )
5049 import sanic
51- transaction .add_framework_info (name = 'Sanic' , version = sanic .__version__ )
50+
51+ transaction .add_framework_info (name = "Sanic" , version = sanic .__version__ )
5252
5353 with FunctionTrace (name = name , source = view ):
5454 return wrapped (* args , ** kwargs )
@@ -60,7 +60,7 @@ def _nr_sanic_router_add(wrapped, instance, args, kwargs):
6060
6161 # Cache the callable_name on the handler object
6262 callable_name (handler )
63- if hasattr (wrapped , ' view_class' ):
63+ if hasattr (wrapped , " view_class" ):
6464 callable_name (wrapped .view_class )
6565 wrapped_handler = _nr_wrapper_handler_ (handler )
6666
@@ -131,7 +131,7 @@ def error_response(wrapped, instance, args, kwargs):
131131 raise
132132 else :
133133 # response can be a response object or a coroutine
134- if hasattr (response , ' status' ):
134+ if hasattr (response , " status" ):
135135 notice_error (error = exc_info , status_code = response .status )
136136 else :
137137 notice_error (exc_info )
@@ -144,18 +144,16 @@ def error_response(wrapped, instance, args, kwargs):
144144def _sanic_app_init (wrapped , instance , args , kwargs ):
145145 result = wrapped (* args , ** kwargs )
146146
147- error_handler = getattr (instance , 'error_handler' )
148- if hasattr (error_handler , 'response' ):
149- instance .error_handler .response = error_response (
150- error_handler .response )
151- if hasattr (error_handler , 'add' ):
152- error_handler .add = _nr_sanic_error_handlers (
153- error_handler .add )
147+ error_handler = getattr (instance , "error_handler" )
148+ if hasattr (error_handler , "response" ):
149+ instance .error_handler .response = error_response (error_handler .response )
150+ if hasattr (error_handler , "add" ):
151+ error_handler .add = _nr_sanic_error_handlers (error_handler .add )
154152
155- router = getattr (instance , ' router' )
156- if hasattr (router , ' add' ):
153+ router = getattr (instance , " router" )
154+ if hasattr (router , " add" ):
157155 router .add = _nr_sanic_router_add (router .add )
158- if hasattr (router , ' get' ):
156+ if hasattr (router , " get" ):
159157 # Cache the callable_name on the router.get
160158 callable_name (router .get )
161159 router .get = _nr_sanic_router_get (router .get )
@@ -172,8 +170,7 @@ def _nr_sanic_response_get_headers(wrapped, instance, args, kwargs):
172170 return result
173171
174172 # instance is the response object
175- cat_headers = transaction .process_response (str (instance .status ),
176- instance .headers .items ())
173+ cat_headers = transaction .process_response (str (instance .status ), instance .headers .items ())
177174
178175 for header_name , header_value in cat_headers :
179176 if header_name not in instance .headers :
@@ -189,27 +186,26 @@ async def _nr_sanic_response_send(wrapped, instance, args, kwargs):
189186 await result
190187
191188 if transaction is None :
192- return wrapped ( * args , ** kwargs )
189+ return result
193190
194191 # instance is the response object
195- cat_headers = transaction .process_response (str (instance .status ),
196- instance .headers .items ())
192+ cat_headers = transaction .process_response (str (instance .status ), instance .headers .items ())
197193
198194 for header_name , header_value in cat_headers :
199195 if header_name not in instance .headers :
200196 instance .headers [header_name ] = header_value
201197
202198 return result
203199
200+
204201def _nr_sanic_response_parse_headers (wrapped , instance , args , kwargs ):
205202 transaction = current_transaction ()
206203
207204 if transaction is None :
208205 return wrapped (* args , ** kwargs )
209206
210207 # instance is the response object
211- cat_headers = transaction .process_response (str (instance .status ),
212- instance .headers .items ())
208+ cat_headers = transaction .process_response (str (instance .status ), instance .headers .items ())
213209
214210 for header_name , header_value in cat_headers :
215211 if header_name not in instance .headers :
@@ -219,7 +215,7 @@ def _nr_sanic_response_parse_headers(wrapped, instance, args, kwargs):
219215
220216
221217def _nr_wrapper_middleware_ (attach_to ):
222- is_request_middleware = attach_to == ' request'
218+ is_request_middleware = attach_to == " request"
223219
224220 @function_wrapper
225221 def _wrapper (wrapped , instance , args , kwargs ):
@@ -238,7 +234,7 @@ def _wrapper(wrapped, instance, args, kwargs):
238234 return _wrapper
239235
240236
241- def _bind_middleware (middleware , attach_to = ' request' , * args , ** kwargs ):
237+ def _bind_middleware (middleware , attach_to = " request" , * args , ** kwargs ):
242238 return middleware , attach_to
243239
244240
@@ -259,36 +255,55 @@ def _bind_request(request, *args, **kwargs):
259255def _nr_sanic_transaction_wrapper_ (wrapped , instance , args , kwargs ):
260256 request = _bind_request (* args , ** kwargs )
261257 # If the request is a websocket request do not wrap it
262- if request .headers .get (' upgrade' , '' ).lower () == ' websocket' :
258+ if request .headers .get (" upgrade" , "" ).lower () == " websocket" :
263259 return wrapped (* args , ** kwargs )
264260
265261 return web_transaction (
266262 request_method = request .method ,
267263 request_path = request .path ,
268264 query_string = request .query_string ,
269- headers = request .headers )(wrapped )(* args , ** kwargs )
265+ headers = request .headers ,
266+ )(wrapped )(* args , ** kwargs )
267+
268+
269+ def _nr_wrap_touchup_run (wrapped , instance , args , kwargs ):
270+ # TouchUp uses metaprogramming to rewrite methods of classes on startup.
271+ # To properly wrap them we need to catch the call to TouchUp.run and
272+ # reinstrument any methods that were replaced with uninstrumented versions.
273+
274+ result = wrapped (* args , ** kwargs )
275+
276+ if "sanic.app" in sys .modules :
277+ module = sys .modules ["sanic.app" ]
278+ target = args [0 ]
279+
280+ if isinstance (target , module .Sanic ):
281+ # Reinstrument class after metaclass "TouchUp" has finished rewriting methods on the class.
282+ target_cls = module .Sanic
283+ if hasattr (target_cls , "handle_request" ) and not hasattr (target_cls .handle_request , "__wrapped__" ):
284+ wrap_function_wrapper (module , "Sanic.handle_request" , _nr_sanic_transaction_wrapper_ )
285+
286+ return result
270287
271288
272289def instrument_sanic_app (module ):
273- wrap_function_wrapper (module , 'Sanic.handle_request' ,
274- _nr_sanic_transaction_wrapper_ )
275- wrap_function_wrapper (module , 'Sanic.__init__' ,
276- _sanic_app_init )
277- wrap_function_wrapper (module , 'Sanic.register_middleware' ,
278- _nr_sanic_register_middleware_ )
279- if hasattr (module .Sanic , 'register_named_middleware' ):
280- wrap_function_wrapper (module , 'Sanic.register_named_middleware' ,
281- _nr_sanic_register_middleware_ )
290+ wrap_function_wrapper (module , "Sanic.handle_request" , _nr_sanic_transaction_wrapper_ )
291+ wrap_function_wrapper (module , "Sanic.__init__" , _sanic_app_init )
292+ wrap_function_wrapper (module , "Sanic.register_middleware" , _nr_sanic_register_middleware_ )
293+ if hasattr (module .Sanic , "register_named_middleware" ):
294+ wrap_function_wrapper (module , "Sanic.register_named_middleware" , _nr_sanic_register_middleware_ )
282295
283296
284297def instrument_sanic_response (module ):
285- if hasattr (module .BaseHTTPResponse , 'send' ):
286- wrap_function_wrapper (module , 'BaseHTTPResponse.send' ,
287- _nr_sanic_response_send )
298+ if hasattr (module .BaseHTTPResponse , "send" ):
299+ wrap_function_wrapper (module , "BaseHTTPResponse.send" , _nr_sanic_response_send )
288300 else :
289- if hasattr (module .BaseHTTPResponse , 'get_headers' ):
290- wrap_function_wrapper (module , 'BaseHTTPResponse.get_headers' ,
291- _nr_sanic_response_get_headers )
292- if hasattr (module .BaseHTTPResponse , '_parse_headers' ):
293- wrap_function_wrapper (module , 'BaseHTTPResponse._parse_headers' ,
294- _nr_sanic_response_parse_headers )
301+ if hasattr (module .BaseHTTPResponse , "get_headers" ):
302+ wrap_function_wrapper (module , "BaseHTTPResponse.get_headers" , _nr_sanic_response_get_headers )
303+ if hasattr (module .BaseHTTPResponse , "_parse_headers" ):
304+ wrap_function_wrapper (module , "BaseHTTPResponse._parse_headers" , _nr_sanic_response_parse_headers )
305+
306+
307+ def instrument_sanic_touchup_service (module ):
308+ if hasattr (module , "TouchUp" ) and hasattr (module .TouchUp , "run" ):
309+ wrap_function_wrapper (module .TouchUp , "run" , _nr_wrap_touchup_run )
0 commit comments