2929
3030from twisted .internet import defer , protocol
3131from twisted .internet .error import DNSLookupError
32- from twisted .internet .interfaces import IReactorPluggableNameResolver
32+ from twisted .internet .interfaces import IReactorPluggableNameResolver , IReactorTime
3333from twisted .internet .task import _EPSILON , Cooperator
3434from twisted .web ._newclient import ResponseDone
3535from twisted .web .http_headers import Headers
36+ from twisted .web .iweb import IResponse
3637
3738import synapse .metrics
3839import synapse .util .retryutils
7475_next_id = 1
7576
7677
77- @attr .s
78+ @attr .s ( frozen = True )
7879class MatrixFederationRequest (object ):
7980 method = attr .ib ()
8081 """HTTP method
@@ -110,26 +111,52 @@ class MatrixFederationRequest(object):
110111 :type: str|None
111112 """
112113
114+ uri = attr .ib (init = False , type = bytes )
115+ """The URI of this request
116+ """
117+
113118 def __attrs_post_init__ (self ):
114119 global _next_id
115- self . txn_id = "%s-O-%s" % (self .method , _next_id )
120+ txn_id = "%s-O-%s" % (self .method , _next_id )
116121 _next_id = (_next_id + 1 ) % (MAXINT - 1 )
117122
123+ object .__setattr__ (self , "txn_id" , txn_id )
124+
125+ destination_bytes = self .destination .encode ("ascii" )
126+ path_bytes = self .path .encode ("ascii" )
127+ if self .query :
128+ query_bytes = encode_query_args (self .query )
129+ else :
130+ query_bytes = b""
131+
132+ # The object is frozen so we can pre-compute this.
133+ uri = urllib .parse .urlunparse (
134+ (b"matrix" , destination_bytes , path_bytes , None , query_bytes , b"" )
135+ )
136+ object .__setattr__ (self , "uri" , uri )
137+
118138 def get_json (self ):
119139 if self .json_callback :
120140 return self .json_callback ()
121141 return self .json
122142
123143
124- async def _handle_json_response (reactor , timeout_sec , request , response ):
144+ async def _handle_json_response (
145+ reactor : IReactorTime ,
146+ timeout_sec : float ,
147+ request : MatrixFederationRequest ,
148+ response : IResponse ,
149+ start_ms : int ,
150+ ):
125151 """
126152 Reads the JSON body of a response, with a timeout
127153
128154 Args:
129- reactor (IReactor): twisted reactor, for the timeout
130- timeout_sec (float): number of seconds to wait for response to complete
131- request (MatrixFederationRequest): the request that triggered the response
132- response (IResponse): response to the request
155+ reactor: twisted reactor, for the timeout
156+ timeout_sec: number of seconds to wait for response to complete
157+ request: the request that triggered the response
158+ response: response to the request
159+ start_ms: Timestamp when request was made
133160
134161 Returns:
135162 dict: parsed JSON response
@@ -143,23 +170,35 @@ async def _handle_json_response(reactor, timeout_sec, request, response):
143170 body = await make_deferred_yieldable (d )
144171 except TimeoutError as e :
145172 logger .warning (
146- "{%s} [%s] Timed out reading response" , request .txn_id , request .destination ,
173+ "{%s} [%s] Timed out reading response - %s %s" ,
174+ request .txn_id ,
175+ request .destination ,
176+ request .method ,
177+ request .uri .decode ("ascii" ),
147178 )
148179 raise RequestSendFailed (e , can_retry = True ) from e
149180 except Exception as e :
150181 logger .warning (
151- "{%s} [%s] Error reading response: %s" ,
182+ "{%s} [%s] Error reading response %s %s : %s" ,
152183 request .txn_id ,
153184 request .destination ,
185+ request .method ,
186+ request .uri .decode ("ascii" ),
154187 e ,
155188 )
156189 raise
190+
191+ time_taken_secs = reactor .seconds () - start_ms / 1000
192+
157193 logger .info (
158- "{%s} [%s] Completed: %d %s" ,
194+ "{%s} [%s] Completed request : %d %s in %.2f secs - %s %s" ,
159195 request .txn_id ,
160196 request .destination ,
161197 response .code ,
162198 response .phrase .decode ("ascii" , errors = "replace" ),
199+ time_taken_secs ,
200+ request .method ,
201+ request .uri .decode ("ascii" ),
163202 )
164203 return body
165204
@@ -261,7 +300,9 @@ async def _send_request_with_optional_trailing_slash(
261300 # 'M_UNRECOGNIZED' which some endpoints can return when omitting a
262301 # trailing slash on Synapse <= v0.99.3.
263302 logger .info ("Retrying request with trailing slash" )
264- request .path += "/"
303+
304+ # Request is frozen so we create a new instance
305+ request = attr .evolve (request , path = request .path + "/" )
265306
266307 response = await self ._send_request (request , ** send_request_args )
267308
@@ -373,9 +414,7 @@ async def _send_request(
373414 else :
374415 retries_left = MAX_SHORT_RETRIES
375416
376- url_bytes = urllib .parse .urlunparse (
377- (b"matrix" , destination_bytes , path_bytes , None , query_bytes , b"" )
378- )
417+ url_bytes = request .uri
379418 url_str = url_bytes .decode ("ascii" )
380419
381420 url_to_sign_bytes = urllib .parse .urlunparse (
@@ -402,7 +441,7 @@ async def _send_request(
402441
403442 headers_dict [b"Authorization" ] = auth_headers
404443
405- logger .info (
444+ logger .debug (
406445 "{%s} [%s] Sending request: %s %s; timeout %fs" ,
407446 request .txn_id ,
408447 request .destination ,
@@ -436,7 +475,6 @@ async def _send_request(
436475 except DNSLookupError as e :
437476 raise RequestSendFailed (e , can_retry = retry_on_dns_fail ) from e
438477 except Exception as e :
439- logger .info ("Failed to send request: %s" , e )
440478 raise RequestSendFailed (e , can_retry = True ) from e
441479
442480 incoming_responses_counter .labels (
@@ -496,7 +534,7 @@ async def _send_request(
496534
497535 break
498536 except RequestSendFailed as e :
499- logger .warning (
537+ logger .info (
500538 "{%s} [%s] Request failed: %s %s: %s" ,
501539 request .txn_id ,
502540 request .destination ,
@@ -654,6 +692,8 @@ async def put_json(
654692 json = data ,
655693 )
656694
695+ start_ms = self .clock .time_msec ()
696+
657697 response = await self ._send_request_with_optional_trailing_slash (
658698 request ,
659699 try_trailing_slash_on_400 ,
@@ -664,7 +704,7 @@ async def put_json(
664704 )
665705
666706 body = await _handle_json_response (
667- self .reactor , self .default_timeout , request , response
707+ self .reactor , self .default_timeout , request , response , start_ms
668708 )
669709
670710 return body
@@ -720,6 +760,8 @@ async def post_json(
720760 method = "POST" , destination = destination , path = path , query = args , json = data
721761 )
722762
763+ start_ms = self .clock .time_msec ()
764+
723765 response = await self ._send_request (
724766 request ,
725767 long_retries = long_retries ,
@@ -733,7 +775,7 @@ async def post_json(
733775 _sec_timeout = self .default_timeout
734776
735777 body = await _handle_json_response (
736- self .reactor , _sec_timeout , request , response
778+ self .reactor , _sec_timeout , request , response , start_ms ,
737779 )
738780 return body
739781
@@ -786,6 +828,8 @@ async def get_json(
786828 method = "GET" , destination = destination , path = path , query = args
787829 )
788830
831+ start_ms = self .clock .time_msec ()
832+
789833 response = await self ._send_request_with_optional_trailing_slash (
790834 request ,
791835 try_trailing_slash_on_400 ,
@@ -796,7 +840,7 @@ async def get_json(
796840 )
797841
798842 body = await _handle_json_response (
799- self .reactor , self .default_timeout , request , response
843+ self .reactor , self .default_timeout , request , response , start_ms
800844 )
801845
802846 return body
@@ -846,6 +890,8 @@ async def delete_json(
846890 method = "DELETE" , destination = destination , path = path , query = args
847891 )
848892
893+ start_ms = self .clock .time_msec ()
894+
849895 response = await self ._send_request (
850896 request ,
851897 long_retries = long_retries ,
@@ -854,7 +900,7 @@ async def delete_json(
854900 )
855901
856902 body = await _handle_json_response (
857- self .reactor , self .default_timeout , request , response
903+ self .reactor , self .default_timeout , request , response , start_ms
858904 )
859905 return body
860906
@@ -914,12 +960,14 @@ async def get_file(
914960 )
915961 raise
916962 logger .info (
917- "{%s} [%s] Completed: %d %s [%d bytes]" ,
963+ "{%s} [%s] Completed: %d %s [%d bytes] %s %s " ,
918964 request .txn_id ,
919965 request .destination ,
920966 response .code ,
921967 response .phrase .decode ("ascii" , errors = "replace" ),
922968 length ,
969+ request .method ,
970+ request .uri .decode ("ascii" ),
923971 )
924972 return (length , headers )
925973
0 commit comments