Skip to content

Instantly share code, notes, and snippets.

Revisions

  1. @int128 int128 revised this gist Dec 27, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -26,7 +26,7 @@
    * @see ContentCachingResponseWrapper
    */
    @Slf4j
    public class StubLoggingFilter extends OncePerRequestFilter {
    public class RequestAndResponseLoggingFilter extends OncePerRequestFilter {
    private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
    MediaType.valueOf("text/*"),
    MediaType.APPLICATION_FORM_URLENCODED,
  2. @int128 int128 revised this gist Nov 3, 2017. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,7 @@
    import lombok.extern.slf4j.Slf4j;
    import lombok.val;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.web.util.ContentCachingRequestWrapper;
    import org.springframework.web.util.ContentCachingResponseWrapper;
    @@ -28,7 +26,6 @@
    * @see ContentCachingResponseWrapper
    */
    @Slf4j
    @Component
    public class StubLoggingFilter extends OncePerRequestFilter {
    private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
    MediaType.valueOf("text/*"),
  3. @int128 int128 revised this gist Nov 3, 2017. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,6 @@
    * @see ContentCachingResponseWrapper
    */
    @Slf4j
    @ConditionalOnProperty(value = "no-request-response-log", matchIfMissing = true)
    @Component
    public class StubLoggingFilter extends OncePerRequestFilter {
    private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
  4. @int128 int128 revised this gist Nov 3, 2017. 1 changed file with 17 additions and 13 deletions.
    30 changes: 17 additions & 13 deletions RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -88,7 +88,10 @@ private static void logRequestHeader(ContentCachingRequestWrapper request, Strin
    }

    private static void logRequestBody(ContentCachingRequestWrapper request, String prefix) {
    logContent(request.getContentAsByteArray(), request.getContentType(), request.getCharacterEncoding(), prefix);
    val content = request.getContentAsByteArray();
    if (content.length > 0) {
    logContent(content, request.getContentType(), request.getCharacterEncoding(), prefix);
    }
    }

    private static void logResponse(ContentCachingResponseWrapper response, String prefix) {
    @@ -98,23 +101,24 @@ private static void logResponse(ContentCachingResponseWrapper response, String p
    response.getHeaders(headerName).forEach(headerValue ->
    log.info("{} {}: {}", prefix, headerName, headerValue)));
    log.info("{}", prefix);
    logContent(response.getContentAsByteArray(), response.getContentType(), response.getCharacterEncoding(), prefix);
    val content = response.getContentAsByteArray();
    if (content.length > 0) {
    logContent(content, response.getContentType(), response.getCharacterEncoding(), prefix);
    }
    }

    private static void logContent(byte[] content, String contentType, String contentEncoding, String prefix) {
    if (content.length > 0) {
    val mediaType = MediaType.valueOf(contentType);
    val visible = VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
    if (visible) {
    try {
    val contentString = new String(content, contentEncoding);
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{} {}", prefix, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{} [{} bytes content]", prefix, content.length);
    }
    } else {
    val mediaType = MediaType.valueOf(contentType);
    val visible = VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
    if (visible) {
    try {
    val contentString = new String(content, contentEncoding);
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{} {}", prefix, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{} [{} bytes content]", prefix, content.length);
    }
    } else {
    log.info("{} [{} bytes content]", prefix, content.length);
    }
    }

  5. @int128 int128 revised this gist Nov 3, 2017. 2 changed files with 86 additions and 47 deletions.
    104 changes: 68 additions & 36 deletions RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,7 @@
    import lombok.val;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.web.util.ContentCachingRequestWrapper;
    @@ -13,12 +14,33 @@
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.stream.Stream;

    /**
    * Spring Web filter for logging request and response.
    *
    * @author Hidetake Iwata
    * @see org.springframework.web.filter.AbstractRequestLoggingFilter
    * @see ContentCachingRequestWrapper
    * @see ContentCachingResponseWrapper
    */
    @Slf4j
    @ConditionalOnProperty(value = "no-request-response-log", matchIfMissing = true)
    @Component
    public class RequestAndResponseLoggingFilter extends OncePerRequestFilter {
    public class StubLoggingFilter extends OncePerRequestFilter {
    private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
    MediaType.valueOf("text/*"),
    MediaType.APPLICATION_FORM_URLENCODED,
    MediaType.APPLICATION_JSON,
    MediaType.APPLICATION_XML,
    MediaType.valueOf("application/*+json"),
    MediaType.valueOf("application/*+xml"),
    MediaType.MULTIPART_FORM_DATA
    );

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    if (isAsyncDispatch(request)) {
    @@ -29,8 +51,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
    }

    protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain) throws ServletException, IOException {
    beforeRequest(request, response);
    try {
    beforeRequest(request, response);
    filterChain.doFilter(request, response);
    }
    finally {
    @@ -41,47 +63,57 @@ protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCach

    protected void beforeRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
    if (log.isInfoEnabled()) {
    val address = request.getRemoteAddr();
    val queryString = request.getQueryString();
    if (queryString == null) {
    log.info("{}> {} {}", address, request.getMethod(), request.getRequestURI());
    } else {
    log.info("{}> {} {}?{}", address, request.getMethod(), request.getRequestURI(), queryString);
    }
    Collections.list(request.getHeaderNames()).forEach(headerName ->
    Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
    log.info("{}> {}: {}", address, headerName, headerValue)));
    val content = request.getContentAsByteArray();
    if (content.length > 0) {
    log.info("{}>", address);
    try {
    val contentString = new String(content, request.getCharacterEncoding());
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}> {}", address, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{}> [{} bytes body]", address, content.length);
    }
    }
    log.info("{}>", address);
    logRequestHeader(request, request.getRemoteAddr() + "|>");
    }
    }

    protected void afterRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
    if (log.isInfoEnabled()) {
    val address = request.getRemoteAddr();
    val status = response.getStatus();
    log.info("{}< {} {}", address, status, HttpStatus.valueOf(status).getReasonPhrase());
    response.getHeaderNames().forEach(headerName ->
    response.getHeaders(headerName).forEach(headerValue ->
    log.info("{}< {}: {}", address, headerName, headerValue)));
    val content = response.getContentAsByteArray();
    if (content.length > 0) {
    log.info("{}<", address);
    logRequestBody(request, request.getRemoteAddr() + "|>");
    logResponse(response, request.getRemoteAddr() + "|<");
    }
    }

    private static void logRequestHeader(ContentCachingRequestWrapper request, String prefix) {
    val queryString = request.getQueryString();
    if (queryString == null) {
    log.info("{} {} {}", prefix, request.getMethod(), request.getRequestURI());
    } else {
    log.info("{} {} {}?{}", prefix, request.getMethod(), request.getRequestURI(), queryString);
    }
    Collections.list(request.getHeaderNames()).forEach(headerName ->
    Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
    log.info("{} {}: {}", prefix, headerName, headerValue)));
    log.info("{}", prefix);
    }

    private static void logRequestBody(ContentCachingRequestWrapper request, String prefix) {
    logContent(request.getContentAsByteArray(), request.getContentType(), request.getCharacterEncoding(), prefix);
    }

    private static void logResponse(ContentCachingResponseWrapper response, String prefix) {
    val status = response.getStatus();
    log.info("{} {} {}", prefix, status, HttpStatus.valueOf(status).getReasonPhrase());
    response.getHeaderNames().forEach(headerName ->
    response.getHeaders(headerName).forEach(headerValue ->
    log.info("{} {}: {}", prefix, headerName, headerValue)));
    log.info("{}", prefix);
    logContent(response.getContentAsByteArray(), response.getContentType(), response.getCharacterEncoding(), prefix);
    }

    private static void logContent(byte[] content, String contentType, String contentEncoding, String prefix) {
    if (content.length > 0) {
    val mediaType = MediaType.valueOf(contentType);
    val visible = VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
    if (visible) {
    try {
    val contentString = new String(content, request.getCharacterEncoding());
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}< {}", address, line));
    val contentString = new String(content, contentEncoding);
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{} {}", prefix, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{}< [{} bytes body]", address, content.length);
    log.info("{} [{} bytes content]", prefix, content.length);
    }
    } else {
    log.info("{} [{} bytes content]", prefix, content.length);
    }
    }
    }
    @@ -101,4 +133,4 @@ private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse re
    return new ContentCachingResponseWrapper(response);
    }
    }
    }
    }
    29 changes: 18 additions & 11 deletions spring.log
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,18 @@
    2017-10-31 17:08:18.686 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> GET /numbers?order=asc
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> User-Agent: curl/7.54.0
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> Accept: */*
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> Host: 127.0.0.1:8080
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1>
    2017-10-31 17:08:18.777 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< 200 OK
    2017-10-31 17:08:18.778 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Content-Length: 10
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Date: Tue, 31 Oct 2017 08:08:18 GMT
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Content-Type: application/json
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1<
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< [1, 2, 3]
    2017-11-03 13:33:18.777 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> POST /users?v=1
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> User-Agent: curl/7.54.0
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> Host: localhost:8080
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> Accept: */*
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> Content-Length: 24
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> Content-Type: application/json
    2017-11-03 13:33:18.778 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|>
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|> {"id": 1, "name": "Foo"}
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< 200 OK
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< Content-Length: 49
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< Date: Fri, 03 Nov 2017 04:33:18 GMT
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< Content-Type: application/json
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|<
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< {
    2017-11-03 13:33:18.784 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< "id": 1,
    2017-11-03 13:33:18.785 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< "name": "Foo",
    2017-11-03 13:33:18.785 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< "active": true
    2017-11-03 13:33:18.785 INFO 17287 --- [tp1860754643-33] RequestAndResponseLoggingFilter : 0:0:0:0:0:0:0:1|< }
  6. @int128 int128 created this gist Nov 3, 2017.
    104 changes: 104 additions & 0 deletions RequestAndResponseLoggingFilter.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    import lombok.extern.slf4j.Slf4j;
    import lombok.val;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.web.util.ContentCachingRequestWrapper;
    import org.springframework.web.util.ContentCachingResponseWrapper;

    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Collections;
    import java.util.stream.Stream;

    @Slf4j
    @Component
    public class RequestAndResponseLoggingFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    if (isAsyncDispatch(request)) {
    filterChain.doFilter(request, response);
    } else {
    doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
    }
    }

    protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain) throws ServletException, IOException {
    beforeRequest(request, response);
    try {
    filterChain.doFilter(request, response);
    }
    finally {
    afterRequest(request, response);
    response.copyBodyToResponse();
    }
    }

    protected void beforeRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
    if (log.isInfoEnabled()) {
    val address = request.getRemoteAddr();
    val queryString = request.getQueryString();
    if (queryString == null) {
    log.info("{}> {} {}", address, request.getMethod(), request.getRequestURI());
    } else {
    log.info("{}> {} {}?{}", address, request.getMethod(), request.getRequestURI(), queryString);
    }
    Collections.list(request.getHeaderNames()).forEach(headerName ->
    Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
    log.info("{}> {}: {}", address, headerName, headerValue)));
    val content = request.getContentAsByteArray();
    if (content.length > 0) {
    log.info("{}>", address);
    try {
    val contentString = new String(content, request.getCharacterEncoding());
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}> {}", address, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{}> [{} bytes body]", address, content.length);
    }
    }
    log.info("{}>", address);
    }
    }

    protected void afterRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
    if (log.isInfoEnabled()) {
    val address = request.getRemoteAddr();
    val status = response.getStatus();
    log.info("{}< {} {}", address, status, HttpStatus.valueOf(status).getReasonPhrase());
    response.getHeaderNames().forEach(headerName ->
    response.getHeaders(headerName).forEach(headerValue ->
    log.info("{}< {}: {}", address, headerName, headerValue)));
    val content = response.getContentAsByteArray();
    if (content.length > 0) {
    log.info("{}<", address);
    try {
    val contentString = new String(content, request.getCharacterEncoding());
    Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}< {}", address, line));
    } catch (UnsupportedEncodingException e) {
    log.info("{}< [{} bytes body]", address, content.length);
    }
    }
    }
    }

    private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
    if (request instanceof ContentCachingRequestWrapper) {
    return (ContentCachingRequestWrapper) request;
    } else {
    return new ContentCachingRequestWrapper(request);
    }
    }

    private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
    if (response instanceof ContentCachingResponseWrapper) {
    return (ContentCachingResponseWrapper) response;
    } else {
    return new ContentCachingResponseWrapper(response);
    }
    }
    }
    11 changes: 11 additions & 0 deletions spring.log
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    2017-10-31 17:08:18.686 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> GET /numbers?order=asc
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> User-Agent: curl/7.54.0
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> Accept: */*
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1> Host: 127.0.0.1:8080
    2017-10-31 17:08:18.688 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1>
    2017-10-31 17:08:18.777 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< 200 OK
    2017-10-31 17:08:18.778 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Content-Length: 10
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Date: Tue, 31 Oct 2017 08:08:18 GMT
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< Content-Type: application/json
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1<
    2017-10-31 17:08:18.779 INFO 11380 --- [qtp987950392-32] Example : 127.0.0.1< [1, 2, 3]