@@ -33,30 +33,49 @@ async def metrics_handler(request: web.Request):
33
33
34
34
def middleware_factory (app_name : str ) -> Coroutine :
35
35
@web .middleware
36
- async def middleware_handler (request : web .Request , handler ):
36
+ async def _middleware_handler (request : web .Request , handler ):
37
37
try :
38
38
request [kSTART_TIME ] = time .time ()
39
39
request .app [kREQUEST_IN_PROGRESS ].labels (
40
40
app_name , request .path , request .method
41
41
).inc ()
42
42
43
43
resp = await handler (request )
44
- unhandled_exception = None
44
+ log_exception = None
45
+
46
+ assert isinstance (resp , web .Response ), "Forgot envelope middleware?" # nsec
47
+
48
+ except web .HTTPServerError as exc :
49
+ # Transforms exception into response object and log exception
50
+ resp = exc
51
+ log_exception = exc
45
52
46
53
except web .HTTPException as exc :
47
- # Transforms exception into response object
54
+ # Transforms non-HTTPServerError exceptions into response object
48
55
resp = exc
49
- unhandled_exception = None
56
+ log_exception = None
50
57
51
58
except Exception as exc : # pylint: disable=broad-except
52
59
# Transforms unhandled exceptions into responses with status 500
53
60
# NOTE: Prevents issue #1025
54
61
resp = web .HTTPInternalServerError (reason = str (exc ))
55
- unhandled_exception = exc
62
+ log_exception = exc
56
63
57
64
finally :
65
+ assert isinstance ( # nsec
66
+ resp , web .Response # nsec
67
+ ), "Forgot envelope middleware or transformation?" # nsec
68
+
58
69
resp_time_secs : float = time .time () - request [kSTART_TIME ]
59
70
71
+ exc_name = ""
72
+ if log_exception :
73
+ exc_name : str = log_exception .__class__ .__name__
74
+
75
+ # Probes request latency
76
+ request .app [kLATENCY_PROBE ].observe (resp_time_secs )
77
+
78
+ # prometheus probes
60
79
request .app [kREQUEST_LATENCY ].labels (app_name , request .path ).observe (
61
80
resp_time_secs
62
81
)
@@ -65,36 +84,29 @@ async def middleware_handler(request: web.Request, handler):
65
84
app_name , request .path , request .method
66
85
).dec ()
67
86
68
- exc_name : str = unhandled_exception .__class__ .__name__ if unhandled_exception else ""
69
-
70
87
request .app [kREQUEST_COUNT ].labels (
71
88
app_name , request .method , request .path , resp .status , exc_name
72
89
).inc ()
73
90
74
- if unhandled_exception :
75
- # NOTE: all access to API (i.e. and not other paths as /socket, /x, etc)
76
- # shall return web.HTTPErrors since processed by error_middleware_factory
77
- log .exception (
91
+ if log_exception :
92
+ log .error (
78
93
'Unexpected server error "%s" from access: %s "%s %s" done in %3.2f secs. Responding with status %s' ,
79
- type (unhandled_exception ),
94
+ type (log_exception ),
80
95
request .remote ,
81
96
request .method ,
82
97
request .path ,
83
98
resp_time_secs ,
84
99
resp .status ,
100
+ exc_info = log_exception ,
101
+ stack_info = True ,
85
102
)
86
103
87
- # Probes for on-the-fly stats ---
88
- # NOTE: might implement in the future some kind of statistical accumulator
89
- # to perform incremental calculations on the fly
90
-
91
- # Probes request latency
92
- request .app [kLATENCY_PROBE ].observe (resp_time_secs )
93
-
94
104
return resp
95
105
96
- middleware_handler .__middleware_name__ = f"{ __name__ } .{ app_name } "
97
- return middleware_handler
106
+ # adds identifier
107
+ _middleware_handler .__middleware_name__ = f"{ __name__ } .monitor_{ app_name } "
108
+
109
+ return _middleware_handler
98
110
99
111
100
112
def setup_monitoring (app : web .Application ):
@@ -129,8 +141,20 @@ def setup_monitoring(app: web.Application):
129
141
app [kLATENCY_PROBE ] = DelayWindowProbe ()
130
142
131
143
# WARNING: ensure ERROR middleware is over this one
132
- assert len (app .middlewares ) >= 1 # nosec
133
- app .middlewares .append (middleware_factory ("simcore_service_webserver" ))
144
+ #
145
+ # non-API request/response (e.g /metrics, /x/* ...)
146
+ # |
147
+ # API request/response (/v0/*) |
148
+ # | |
149
+ # | |
150
+ # v |
151
+ # ===== monitoring-middleware =====
152
+ # == rest-error-middlewarer ==== |
153
+ # == ... == |
154
+ # == rest-envelope-middleware == v
155
+ #
156
+ #
157
+ app .middlewares .insert (0 , middleware_factory ("simcore_service_webserver" ))
134
158
135
159
# TODO: in production, it should only be accessible to backend services
136
160
app .router .add_get ("/metrics" , metrics_handler )
0 commit comments