How to log information in Spring application when request is received and before response is returned - Stack Overflow

时间: 2025-01-06 admin 业界

My current solution provide excessive logging. Does Spring provides something to solve this?

Scenario:

When user request for swagger page (/swagger-ui/index.html)
Then I expect to see only 2 log lines.

Expected result:

2025-01-04T14:48:27.368+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.html 
2025-01-04T14:48:27.401+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.html 

Actual result:

2025-01-04T14:48:27.368+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.html 
2025-01-04T14:48:27.401+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.html 
2025-01-04T14:48:27.415+02:00 trace-id: 964b5360-cb30-4195-9247-c03e0f47077d  INFO 15592 --- [http-nio-8080-exec-5] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui-standalone-preset.js 
2025-01-04T14:48:27.415+02:00 trace-id: 09032b5d-cc8e-4368-bbba-e0be97af0d83  INFO 15592 --- [http-nio-8080-exec-2] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-initializer.js 
2025-01-04T14:48:27.415+02:00 trace-id: 4eee41e4-31d7-4b32-95d9-2ce5b47ae680  INFO 15592 --- [http-nio-8080-exec-4] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui.css 
2025-01-04T14:48:27.415+02:00 trace-id: c8e18ed2-9ec0-4c20-b924-c829da437d78  INFO 15592 --- [http-nio-8080-exec-6] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui-bundle.js 
2025-01-04T14:48:27.415+02:00 trace-id: 5b56c4e4-111a-4859-bfe7-7d8d1e45aa80  INFO 15592 --- [http-nio-8080-exec-3] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.css 
2025-01-04T14:48:27.420+02:00 trace-id: 5b56c4e4-111a-4859-bfe7-7d8d1e45aa80  INFO 15592 --- [http-nio-8080-exec-3] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.css 
2025-01-04T14:48:27.421+02:00 trace-id: 4eee41e4-31d7-4b32-95d9-2ce5b47ae680  INFO 15592 --- [http-nio-8080-exec-4] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui.css 
2025-01-04T14:48:27.421+02:00 trace-id: 964b5360-cb30-4195-9247-c03e0f47077d  INFO 15592 --- [http-nio-8080-exec-5] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui-standalone-preset.js 
2025-01-04T14:48:27.429+02:00 trace-id: c8e18ed2-9ec0-4c20-b924-c829da437d78  INFO 15592 --- [http-nio-8080-exec-6] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui-bundle.js 
2025-01-04T14:48:27.444+02:00 trace-id: 09032b5d-cc8e-4368-bbba-e0be97af0d83  INFO 15592 --- [http-nio-8080-exec-2] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-initializer.js 
2025-01-04T14:48:27.563+02:00 trace-id: 9de96e5d-0bff-405b-8175-d30679138cfb  INFO 15592 --- [http-nio-8080-exec-7] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-config 
2025-01-04T14:48:27.620+02:00 trace-id: 9de96e5d-0bff-405b-8175-d30679138cfb  INFO 15592 --- [http-nio-8080-exec-7] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-config 
2025-01-04T14:48:27.633+02:00 trace-id: a6dc7a18-1b57-4e72-b8c1-02fd9ca62bd8  INFO 15592 --- [http-nio-8080-exec-8] c.e.spring.logging.HTTPInterceptor                 : -> GET /api 
2025-01-04T14:48:27.963+02:00 trace-id: a6dc7a18-1b57-4e72-b8c1-02fd9ca62bd8  INFO 15592 --- [http-nio-8080-exec-8] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /api

Solutions that I tried already:

  1. OncePerRequestFilter:
@Configuration
class HTTPInterceptor : OncePerRequestFilter() {
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val traceId = UUID.randomUUID().toString()
        MDC.put(MDCConstants.TRACE_ID, traceId)
        log.info { "-> ${request.method} ${request.requestURI}" }

        filterChain.doFilter(request, response)

        log.info { "<- ${request.method} [${response.status}] ${request.requestURI}" }
        MDC.clear()
    }
}
  1. WebMvcConfigurer:
@Configuration
class HTTPInterceptor : WebMvcConfigurer {
        override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(object : HandlerInterceptor {
            override fun preHandle(
                request: HttpServletRequest,
                response: HttpServletResponse,
                handler: Any
            ): Boolean {
                val traceId = UUID.randomUUID().toString()
                MDC.put(TRACE_ID.key, traceId)
                log.info { "-> ${request.method} ${request.requestURI}" }
                return true
            }

            override fun afterCompletion(
                request: HttpServletRequest,
                response: HttpServletResponse,
                handler: Any,
                ex: Exception?
            ) {
                log.info { "<- ${request.method} [${response.status}] ${request.requestURI}" }
                MDC.clear()
            }
        })
    }
}
  1. I also tried to add traceId in response header in preHandle() method and then check if next request contains traceId in request header, but for some reason it is not persistent.

My current solution provide excessive logging. Does Spring provides something to solve this?

Scenario:

When user request for swagger page (/swagger-ui/index.html)
Then I expect to see only 2 log lines.

Expected result:

2025-01-04T14:48:27.368+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.html 
2025-01-04T14:48:27.401+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.html 

Actual result:

2025-01-04T14:48:27.368+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.html 
2025-01-04T14:48:27.401+02:00 trace-id: 6b4125a6-0072-4c0c-b7eb-dd6bf526f989  INFO 15592 --- [http-nio-8080-exec-1] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.html 
2025-01-04T14:48:27.415+02:00 trace-id: 964b5360-cb30-4195-9247-c03e0f47077d  INFO 15592 --- [http-nio-8080-exec-5] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui-standalone-preset.js 
2025-01-04T14:48:27.415+02:00 trace-id: 09032b5d-cc8e-4368-bbba-e0be97af0d83  INFO 15592 --- [http-nio-8080-exec-2] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-initializer.js 
2025-01-04T14:48:27.415+02:00 trace-id: 4eee41e4-31d7-4b32-95d9-2ce5b47ae680  INFO 15592 --- [http-nio-8080-exec-4] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui.css 
2025-01-04T14:48:27.415+02:00 trace-id: c8e18ed2-9ec0-4c20-b924-c829da437d78  INFO 15592 --- [http-nio-8080-exec-6] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/swagger-ui-bundle.js 
2025-01-04T14:48:27.415+02:00 trace-id: 5b56c4e4-111a-4859-bfe7-7d8d1e45aa80  INFO 15592 --- [http-nio-8080-exec-3] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-ui/index.css 
2025-01-04T14:48:27.420+02:00 trace-id: 5b56c4e4-111a-4859-bfe7-7d8d1e45aa80  INFO 15592 --- [http-nio-8080-exec-3] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/index.css 
2025-01-04T14:48:27.421+02:00 trace-id: 4eee41e4-31d7-4b32-95d9-2ce5b47ae680  INFO 15592 --- [http-nio-8080-exec-4] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui.css 
2025-01-04T14:48:27.421+02:00 trace-id: 964b5360-cb30-4195-9247-c03e0f47077d  INFO 15592 --- [http-nio-8080-exec-5] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui-standalone-preset.js 
2025-01-04T14:48:27.429+02:00 trace-id: c8e18ed2-9ec0-4c20-b924-c829da437d78  INFO 15592 --- [http-nio-8080-exec-6] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-ui-bundle.js 
2025-01-04T14:48:27.444+02:00 trace-id: 09032b5d-cc8e-4368-bbba-e0be97af0d83  INFO 15592 --- [http-nio-8080-exec-2] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-ui/swagger-initializer.js 
2025-01-04T14:48:27.563+02:00 trace-id: 9de96e5d-0bff-405b-8175-d30679138cfb  INFO 15592 --- [http-nio-8080-exec-7] c.e.spring.logging.HTTPInterceptor                 : -> GET /swagger-config 
2025-01-04T14:48:27.620+02:00 trace-id: 9de96e5d-0bff-405b-8175-d30679138cfb  INFO 15592 --- [http-nio-8080-exec-7] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /swagger-config 
2025-01-04T14:48:27.633+02:00 trace-id: a6dc7a18-1b57-4e72-b8c1-02fd9ca62bd8  INFO 15592 --- [http-nio-8080-exec-8] c.e.spring.logging.HTTPInterceptor                 : -> GET /api 
2025-01-04T14:48:27.963+02:00 trace-id: a6dc7a18-1b57-4e72-b8c1-02fd9ca62bd8  INFO 15592 --- [http-nio-8080-exec-8] c.e.spring.logging.HTTPInterceptor                 : <- GET [200] /api

Solutions that I tried already:

  1. OncePerRequestFilter:
@Configuration
class HTTPInterceptor : OncePerRequestFilter() {
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val traceId = UUID.randomUUID().toString()
        MDC.put(MDCConstants.TRACE_ID, traceId)
        log.info { "-> ${request.method} ${request.requestURI}" }

        filterChain.doFilter(request, response)

        log.info { "<- ${request.method} [${response.status}] ${request.requestURI}" }
        MDC.clear()
    }
}
  1. WebMvcConfigurer:
@Configuration
class HTTPInterceptor : WebMvcConfigurer {
        override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(object : HandlerInterceptor {
            override fun preHandle(
                request: HttpServletRequest,
                response: HttpServletResponse,
                handler: Any
            ): Boolean {
                val traceId = UUID.randomUUID().toString()
                MDC.put(TRACE_ID.key, traceId)
                log.info { "-> ${request.method} ${request.requestURI}" }
                return true
            }

            override fun afterCompletion(
                request: HttpServletRequest,
                response: HttpServletResponse,
                handler: Any,
                ex: Exception?
            ) {
                log.info { "<- ${request.method} [${response.status}] ${request.requestURI}" }
                MDC.clear()
            }
        })
    }
}
  1. I also tried to add traceId in response header in preHandle() method and then check if next request contains traceId in request header, but for some reason it is not persistent.
Share Improve this question asked yesterday Ilja TarasovsIlja Tarasovs 2113 silver badges13 bronze badges 4
  • From the paths I'm guessing your user is using a web browser to access the Swagger UI page for your API.  Would you not expect that browser to be automatically sending requests for all the resources needed to display that web page (i.e. the CSS and JavaScript files it refers to)?  It looks like that's what you're seeing.  And since they're all valid requests from the user('s browser), how should your logger know which requests you want to see?  (For example, you could tweak your logger to log only requests for a ‘.html’ path.) – gidds Commented yesterday
  • I'm understanding that client is actually doing 1 request to back-end service from browser, and I should see only 2 log messages. One when request come in and another before response is returned. Also logs are harmless situation but I also have some additional logic related with Spring Security where I perform JWT check similarly in every request, but why should I check JWT 8 times instead of just 1 if it is only 1 request from user? – Ilja Tarasovs Commented 20 hours ago
  • The user may be clicking only once; but if the browser receives the new page and sees that it refers to resources such as CSS stylesheets and/or JavaScript files (or, in other cases, images or iframes), then it will have to download those too before it can display the page.  All that happens automatically in the browser.  Isn't that what you're seeing here? — You can probably prove it either way by showing the ‘Network’ tab in the browser's Developer Tools, or by sniffing the network traffic. – gidds Commented 18 hours ago
  • Thanks for clarification. But are there any options that can be used to somehow combine requests into one or ignore ONLY subsequent/nested resources? – Ilja Tarasovs Commented 7 hours ago
Add a comment  | 

1 Answer 1

Reset to default 0

Spring AOP fits for this use case. You can log before, after or at the method calling. There are plenty of tutorials out there, you can get started with Logging With AOP in Spring