spring-trace
์คํ๋ง Trace ์๊ฐ
์คํ๋ง Trace๋ฅผ ์ฌ์ฉํ๋ฉด ์์ฝ๊ฒ ์ ํ๋ฆฌ์ผ์ด์ ํธ์ถ ํํฉ์ ์ถ์ ํ ์ ์์ต๋๋ค.
์ ์ฉ ์์
[REQ] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, body={username:"hello"}
|-->[Controller] HelloController.test()
| |-->[Service] HelloService.hello(holyeye)
| | |-->[Repository] HelloRepository.helloQuery()
| | |<--[Repository] HelloRepository.helloQuery() [size=2] 1ms.
| |<--[Service] HelloService.hello(holyeye) [<Member>] 1ms.
|<--[Controller] HelloController.test() [hello holyeye] 1ms.
[RES] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, status=200, time=3ms, ex=null
๋น๋ TODO
ํ ์คํธ TODO
๊ธฐ๋ฅ
๋ก๊ทธ ์ถ๋ ฅ ๊ธฐ๋ฅ
- ์ค์๊ฐ ๋ก๊ทธ ์ถ๋ ฅ(
TRACE
) - ๋์ ๋ ๋ก๊ทธ ์ถ๋ ฅ
- ๋๋ฌด ๋๋ฆฐ ๋ก์ง ๋ก๊ทธ(
SLOW_LOGIC
) : ํน์ ์๊ฐ ์ด์ ๊ฑธ๋ฆฐ ๋์ ๋ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํฉ๋๋ค. - ์์ธ ๋ฐ์ ๋ก์ง ๋ก๊ทธ(
APP_ERROR
) : ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๋์ ๋ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- ๋๋ฌด ๋๋ฆฐ ๋ก์ง ๋ก๊ทธ(
๋ก๊ทธ ๊ธฐ๋ฅ
-
๋ฉ์๋ ํธ์ถ ์๊ฐ์ ์ ์ ์์ต๋๋ค.
- ex)
hello.finds() took 2ms. [size=2]
- ex)
-
๋ฉ์๋ ํธ์ถ ํ๋ผ๋ฏธํฐ์ ๋ฐํ๊ฐ์ ์ถ์ ํ ์ ์์ต๋๋ค.
- ๋ฐํ ๊ฐ์ด
null
์ด๋ฉดnull
์ ์ถ๋ ฅํฉ๋๋ค. ex)[null]
- ๋ฐํ ๊ฐ์ด ๊ฐ์ฒด๋ฉด ๊ฐ์ฒด ํ์
์ ์ถ๋ ฅํฉ๋๋ค. ex)
[<Member>]
- ๋ฐํ ๊ฐ์ด ์ปฌ๋ ์
์ด๋ ๋ฐฐ์ด์ด๋ฉด ์ฌ์ด์ฆ ๋ฐํํฉ๋๋ค. ex)
[size=10]
- ๋ฐํ ๊ฐ์ด
-
HTTP ์์ฒญ
- ๋ค์ํ HTTP ์์ฒญ ์ ๋ณด๋ฅผ ์ถ์ ํ ์ ์์ต๋๋ค. ํน๋ณํ HTTP Body ์ ๋ณด๋ ์ถ๋ ฅํฉ๋๋ค.
ํ์ ์ค๋น๋ฌผ๊ณผ ์ฃผ์์ฌํญ
- ์คํ๋ง ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- ํ์ฌ๋ ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์ค์ ๋ง ์ง์ํฉ๋๋ค.
- ์์ง์ ์คํ์ ์ธ ๋จ๊ณ์ ๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ
์คํ๋ง ํ๋ ์์ํฌ์ @EnableTrace
๋ฅผ ์ค์ ํฉ๋๋ค.
@EnableTrace(basePackages = "spring.trace.testweb")
์)
@Configuration
@EnableTrace(basePackages = "spring.trace.testweb")
public class TargetWebConfig extends WebMvcConfigurerAdapter {
}
๋ง์ฝ ์น ์ ํ๋ฆฌ์ผ์ด์
์ด๋ฉด spring.trace.web.TraceLogFilter
ํํฐ๋ ์ถ๊ฐํด์ค๋๋ค.
public class TestWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//...
@Override
protected Filter[] getServletFilters() {
return new Filter[]{new TraceLogFilter()};
}
}
๋ค์์ผ๋ก logback.xml
์ ์ค์ ํฉ๋๋ค.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{MM-dd HH:mm:ss} [%thread] %.-1level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<!-- ์ค์๊ฐ TRACE -->
<logger name="TRACE" level="trace" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<!-- ์ ํ๋ฆฌ์ผ์ด์
์์ธ -->
<logger name="APP_ERROR" level="info" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<!-- ๋๋ฆฐ ๋ก์ง -->
<logger name="SLOW_LOGIC" level="info" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
</configuration>
์ฐธ๊ณ : ์ด์์์ ๋๋ฌด ๋ง์ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ๊ฒ์ ์ฑ๋ฅ์ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค. ์ด์์์๋ ์ค์๊ฐ ๋ก๊ทธ๋ ๋๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์์ธ ๋ก๊ทธ์ ๋๋ฆฐ ๋ก์ง๋ง ์ถ๋ ฅํ๋๋ก ์ค์ ํ๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ
์ค์๊ฐ ๋ก๊ทธ
06-09 23:14:44 TRACE - [REQ] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, body=null
06-09 23:14:44 TRACE - |-->[Controller] HelloController.test()
06-09 23:14:44 TRACE - | |-->[Service] HelloService.hello(holyeye)
06-09 23:14:44 TRACE - | | |-->[Repository] HelloRepository.helloQuery()
06-09 23:14:44 TRACE - | | |<--[Repository] HelloRepository.helloQuery() [void] 1ms.
06-09 23:14:44 TRACE - | |<--[Service] HelloService.hello(holyeye) [hello holyeye] 1ms.
06-09 23:14:44 TRACE - |<--[Controller] HelloController.test() [hello holyeye] 1ms.
06-09 23:14:44 TRACE - [RES] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, status=200, time=3ms, ex=null
๋๋ฆฐ ๋ก์ง ๋ก๊ทธ
06-09 23:14:44 [http-nio-8080-exec-6] E SLOW_LOGIC - TRACE LOG
[REQ] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, body=null
|-->[Controller] HelloController.test()
| |-->[Service] HelloService.hello(holyeye)
| | |-->[Repository] HelloRepository.helloQuery()
| | |<--[Repository] HelloRepository.helloQuery() [void] 1ms.
| |<--[Service] HelloService.hello(holyeye) [hello holyeye] 1ms.
|<--[Controller] HelloController.test() [hello holyeye] 1ms.
[RES] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/test, status=200, time=3ms, ex=null
์์ธ ๋ฐ์ ๋ก์ง ๋ก๊ทธ
06-09 23:28:28 [http-nio-8080-exec-9] E APP_ERROR - TRACE LOG
[REQ] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/exception, body=null
|-->[Controller] HelloController.exception()
| |-->[Service] HelloService.helloException()
| |<X-[Service] HelloService.helloException() Exception! java.lang.Exception: ๊ฐ์ ์์ธ 1ms.
|<X-[Controller] HelloController.exception() Exception! java.lang.Exception: ๊ฐ์ ์์ธ 1ms.
[RES] host=0:0:0:0:0:0:0:1, method=GET, url=http://localhost:8080/exception, status=200, time=6ms, ex=org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.Exception: ๊ฐ์ ์์ธ
[EXCEPTION] Request processing failed; nested exception is java.lang.Exception: ๊ฐ์ ์์ธ; trace=org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.Exception: ๊ฐ์ ์์ธ
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at spring.trace.web.TraceLogFilter.doFilterInternal(TraceLogFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
...
์ค์
TODO
- ์ฌ๋ก์ฐ ๋ก์ง ์๊ฐ ์ค์
๋์ ์๋ฆฌ
์ง์ ํ ํจํค์ง ํ์ ์คํ๋ง ๋น์ ๋ก๊ทธ ์์ง์ฉ AOP(spring.trace.SpringTraceAopInterceptor
)๋ฅผ ์ ์ฉํ๊ณ ,
HTTP ์์ฒญ์ ๋ํด์๋ spring.trace.web.TraceLogFilter
๋ฅผ ์ฌ์ฉํด์ ์ถ์ ์ฉ ๋ก๊ทธ๋ฅผ ์์ฑํฉ๋๋ค.
์ด ๋ก๊ทธ๋ค์ ์ค์๊ฐ์ผ๋ก ์ถ๋ ฅ๋๊ธฐ๋ ํ์ง๋ง ์์ธ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ๋๋ฌด ๋๋ฆฐ ๋ก์ง์ด๋ผ๊ณ ํ๋จ๋๋ฉด ๋ก๊ทธ ์ด๋ ฅ ์ ์ฒด๋ฅผ ์ถ๋ ฅํด์ผ ํฉ๋๋ค.
๋ก๊ทธ ์ด๋ ฅ ์ ์ฒด๋ฅผ ๋ณด๊ดํ๊ธฐ ์ํด ๋ด๋ถ์ ์ผ๋ก ThreadLocal
์ ๋ก๊ทธ ์ ๋ณด๋ฅผ ๋ณด๊ดํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ThreadLocal
์ ๋ณด๊ด๋ ๋ก๊ทธ๋ ์ ์ ํ ์์ ์ ์ ๊ฑฐ ๋ฉ๋๋ค.
์ฐธ๊ณ ํ ๊ธฐ๋ฅ
์คํ๋ง ํ๋ ์์ํฌ์ org.springframework.aop.interceptor.CustomizableTraceInterceptor
์์ ๋ง์ ์๊ฐ์ ๋ฐ์์ต๋๋ค.
์ด ํด๋์ค๋ฅผ ํ์ฅํ๋ฉด์ ์คํ๋ง Trace ํ๋ก์ ํธ๊ฐ ์์๋์์ต๋๋ค.
TODO
- ๋ก๊น ํธ๋์ญ์ ID ๋ถ์ฌํ๊ธฐ
- ์คํ๋ง ์ค์ ์ฝ์ด์ ๋์ํ๊ธฐ(์คํ ์๊ฐ ์ต์ ์ฒ๋ฆฌ)
- ํธ๋์ญ์ ์ํ ์ฌ๋ถ ์ ์ ํ ๋ก๊ทธ ๋จ๊ธฐ๊ธฐ
- @Async์์ ์ ์ ํ ๋ก๊ทธ ๋จ๊ธฐ๊ธฐ
- XML ์ค์ ๊ธฐ๋ฅ
- Interceptor ์ ๊ณตํ๊ธฐ
License
Spring Trace is released under version 2.0 of the Apache License.