gabotorresruiz commented on code in PR #44666:
URL: https://github.com/apache/superset/pull/44666#discussion_r4187343280


##########
superset/views/error_handling.py:
##########
@@ -248,7 +248,15 @@ def refresh_csrf_token(ex: CSRFError) -> FlaskResponse:
 
     @app.errorhandler(HTTPException)
     def show_http_exception(ex: HTTPException) -> FlaskResponse:
-        logger.warning("HTTPException", exc_info=True)
+        status = ex.code or 500
+        if status == 404:
+            # Unmatched URLs are a client condition, and scanner traffic makes
+            # them frequent; a traceback here only adds noise.
+            logger.debug("HTTPException: 404 %r", request.path)

Review Comment:
   This block worries me a bit, because the 404 branch is a little wider than 
the case the PR describes.
   
   The rationale is about unmatched URLs, but `show_http_exception` also sees 
every 404 raised from inside a matched view, and some of those are not the 
client asking for a URL that does not exist. The one I care about is 
`superset/views/core.py:604-608`:
   
   ```python
   try:
       dashboard.raise_for_access()
   except SupersetSecurityException:
       if not get_current_user():
           return redirect_to_login()
       abort(404)
   ```
   
   That is an authorization denial deliberately masked as a 404. I verified on 
this branch that it now produces a single DEBUG record, and since `LOG_LEVEL` 
defaults to `INFO` (`superset/config.py:1737`) nothing lands in the application 
log at all. On master the same request logged a WARNING whose traceback named 
`core.py` and that `abort(404)` line, which is how you could tell a masked 
denial apart from a scanner hit.
   
   I also checked that nothing else inside Superset picks it up: 
`raise_for_access` does not log the denial itself (its only `logger.info` is 
the `EXTRA_RAISE_FOR_ACCESS_BYPASS` granted path), and 
`event_logger.log_this_with_extra_payload` writes its row only after the 
wrapped view returns, so an aborted request leaves no event log row either. I 
confirmed that with a spy event logger: a normal request recorded its action, a 
request whose view called `abort(404)` recorded nothing. The WSGI access log 
still shows a `404` for the path, so it is not invisible everywhere, just 
inside Superset's own logs.
   
   `request.url_rule` separates the two cases cleanly, it is `None` for an 
unmatched URL and the matched `Rule` for an in-view `abort(404)` (I verified 
both). So the noisy case can stay at DEBUG without taking the rest with it:
   
   ```python
   if status == 404 and request.url_rule is None:
       logger.debug("HTTPException: 404 %r", request.path)
   elif status < 500:
       logger.warning("HTTPException: %r", str(ex))
   else:
       logger.warning("HTTPException", exc_info=True)
   ```
   
   If you go that way, a `test_in_view_404_logs_a_warning` next to the existing 
`test_view_404_logs_one_debug_line_with_path_and_no_traceback` would lock it 
in. Right now both 404 tests assert DEBUG, which is exactly why nothing in the 
suite notices the difference between the two entry points.
   
   Or am I misreading the intent here, and routing in-view 404s to DEBUG along 
with the scanner traffic is deliberate?



##########
superset/views/error_handling.py:
##########
@@ -248,7 +248,15 @@ def refresh_csrf_token(ex: CSRFError) -> FlaskResponse:
 
     @app.errorhandler(HTTPException)
     def show_http_exception(ex: HTTPException) -> FlaskResponse:
-        logger.warning("HTTPException", exc_info=True)
+        status = ex.code or 500
+        if status == 404:
+            # Unmatched URLs are a client condition, and scanner traffic makes
+            # them frequent; a traceback here only adds noise.
+            logger.debug("HTTPException: 404 %r", request.path)
+        elif status < 500:
+            logger.warning("HTTPException: %r", str(ex))

Review Comment:
   Small symmetry nit, not a blocker: the 404 branch gained `request.path` but 
this one did not, so a 400/401/403/405 record now carries neither the route nor 
a traceback. When the raiser passes no description the message is a werkzeug 
constant, so for example the two different `abort(403)` in 
`superset/embedded/view.py` (referrer allowlist at line 71, `Sec-Fetch-Dest` at 
line 85) now emit byte identical lines. Adding `request.path` here too would 
keep it correlatable for roughly free.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to