@ -16,10 +16,15 @@
@@ -16,10 +16,15 @@
package org.springframework.web.server.adapter ;
import java.util.Arrays ;
import java.util.HashSet ;
import java.util.Set ;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import reactor.core.publisher.Mono ;
import org.springframework.core.NestedCheckedException ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.codec.ServerCodecConfigurer ;
import org.springframework.http.server.reactive.HttpHandler ;
@ -28,6 +33,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -28,6 +33,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert ;
import org.springframework.web.server.ServerWebExchange ;
import org.springframework.web.server.WebHandler ;
import org.springframework.web.server.handler.ExceptionHandlingWebHandler ;
import org.springframework.web.server.handler.WebHandlerDecorator ;
import org.springframework.web.server.session.DefaultWebSessionManager ;
import org.springframework.web.server.session.WebSessionManager ;
@ -44,8 +50,27 @@ import org.springframework.web.server.session.WebSessionManager;
@@ -44,8 +50,27 @@ import org.springframework.web.server.session.WebSessionManager;
* /
public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
/ * *
* Dedicated log category for disconnected client exceptions .
* < p > Servlet containers do not expose a notification when a client disconnects ,
* e . g . < a href = "https://java.net/jira/browse/SERVLET_SPEC-44" > SERVLET_SPEC - 44 < / a > .
* < p > To avoid filling logs with unnecessary stack traces , we make an
* effort to identify such network failures on a per - server basis , and then
* log under a separate log category a simple one - line message at DEBUG level
* or a full stack trace only at TRACE level .
* /
private static final String DISCONNECTED_CLIENT_LOG_CATEGORY =
ExceptionHandlingWebHandler . class . getName ( ) + ".DisconnectedClient" ;
private static final Set < String > DISCONNECTED_CLIENT_EXCEPTIONS =
new HashSet < > ( Arrays . asList ( "ClientAbortException" , "EOFException" , "EofException" ) ) ;
private static final Log logger = LogFactory . getLog ( HttpWebHandlerAdapter . class ) ;
private static final Log disconnectedClientLogger = LogFactory . getLog ( DISCONNECTED_CLIENT_LOG_CATEGORY ) ;
private WebSessionManager sessionManager = new DefaultWebSessionManager ( ) ;
private ServerCodecConfigurer codecConfigurer ;
@ -99,10 +124,8 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
@@ -99,10 +124,8 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
ServerWebExchange exchange = createExchange ( request , response ) ;
return getDelegate ( ) . handle ( exchange )
. onErrorResume ( ex - > {
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( "Could not complete request" , ex ) ;
}
response . setStatusCode ( HttpStatus . INTERNAL_SERVER_ERROR ) ;
logException ( ex ) ;
return Mono . empty ( ) ;
} )
. then ( Mono . defer ( response : : setComplete ) ) ;
@ -112,4 +135,25 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
@@ -112,4 +135,25 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
return new DefaultServerWebExchange ( request , response , this . sessionManager , getCodecConfigurer ( ) ) ;
}
@SuppressWarnings ( "serial" )
private void logException ( Throwable ex ) {
NestedCheckedException nestedEx = new NestedCheckedException ( "" , ex ) { } ;
if ( "Broken pipe" . equalsIgnoreCase ( nestedEx . getMostSpecificCause ( ) . getMessage ( ) ) | |
DISCONNECTED_CLIENT_EXCEPTIONS . contains ( ex . getClass ( ) . getSimpleName ( ) ) ) {
if ( disconnectedClientLogger . isTraceEnabled ( ) ) {
disconnectedClientLogger . trace ( "Looks like the client has gone away" , ex ) ;
}
else if ( disconnectedClientLogger . isDebugEnabled ( ) ) {
disconnectedClientLogger . debug (
"The client has gone away: " + nestedEx . getMessage ( ) +
" (For a full stack trace, set the log category" +
"'" + DISCONNECTED_CLIENT_LOG_CATEGORY + "' to TRACE)" ) ;
}
}
else {
logger . error ( "Could not complete request" , ex ) ;
}
}
}