Spring Boot

[Spring Security] docs: Architecture(5) - ExceptionTranslationFilter, RequestCache, logging

kiritoni 2024. 8. 30. 21:28
๋ฐ˜์‘ํ˜•

๐Ÿ”ป Spring Security docs  ๊ฒŒ์‹œ๊ธ€ ๋ชฉ์ฐจ  

๋”๋ณด๊ธฐ

1. [Spring Security] docs : Getting Started

 

[Spring Security] docs : Getting Started

Spring Security๋Š” ์ธ์ฆ, ๊ถŒํ•œ๋ถ€์—ฌ ๋ฐ ์ผ๋ฐ˜์ ์ธ ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ๋ณดํ˜ธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ณด์•ˆ ์„ค์ •์— ์ถ”๊ฐ€์ ์œผ๋กœ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๋”๋ผ๋„ ์•ˆ์ „ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋น ๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋„

kiritoni.tistory.com

 

 

 

2. [Spring Security] docs : Architecture (1) - Filter

 

[Spring Security] docs : Architecture (1) - Filter

Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a

kiritoni.tistory.com

 

 

 

3. [Spring Security] docs: Architecture (2) - DelegatingFilterProxy

 

[Spring Security] docs: Architecture (2) - DelegatingFilterProxy

Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a

kiritoni.tistory.com

 

 

 

4. [Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain

 

[Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain

2024.08.29 - [Spring Boot] - [Spring Security] docs: Architecture (2) - DelegatingFilterProxy [Spring Security] docs: Architecture (2) - DelegatingFilterProxySpring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ .

kiritoni.tistory.com

 

 

 

5. 2024.08.30 - [Spring Boot] - [Spring Security] docs : Architecture(4) : FilterChain์˜ ์—ญํ• ๊ณผ ์ˆœ์„œ, ์ปค์Šคํ…€ ํ•„ํ„ฐ

 

[Spring Security] docs : Architecture(4) : FilterChain์˜ ์—ญํ• ๊ณผ ์ˆœ์„œ, ์ปค์Šคํ…€ ํ•„ํ„ฐ

๐Ÿ”ป Spring Security docs  ๊ฒŒ์‹œ๊ธ€ ๋ชฉ์ฐจ  ๋”๋ณด๊ธฐ1. [Spring Security] docs : Getting Started [Spring Security] docs : Getting StartedSpring Security๋Š” ์ธ์ฆ, ๊ถŒํ•œ๋ถ€์—ฌ ๋ฐ ์ผ๋ฐ˜์ ์ธ ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ๋ณดํ˜ธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ

kiritoni.tistory.com

 

 

 

 

๐ŸŒฑ Spring Security docs ๋ฐ”๋กœ๊ฐ€๊ธฐ

 

Architecture :: Spring Security

The Security Filters are inserted into the FilterChainProxy with the SecurityFilterChain API. Those filters can be used for a number of different purposes, like authentication, authorization, exploit protection, and more. The filters are executed in a spec

docs.spring.io

 

 

ExceptionTranslationFilter

`ExceptionTranslationFilter`๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค ์ค‘ํ•˜๋‚˜๋กœ, FilterChainProxy์— ๋“ค์–ด์žˆ๋‹ค. `ExceptionTranslationFilter`๋Š” `AccessDeniedException` ๊ณผ `AuthenticationException` ์„ HTTP ์‘๋‹ต์œผ๋กœ ๋ณ€ํ™˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. 

 

1. `ExceptionTranslationFilter`๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‚˜๋จธ์ง€๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด `FilterChain.doFilter(request, response)`๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. 

 

2. ๋งŒ์•ฝ ์œ ์ €๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜, `AuthenticationException`์— ํ•ด๋‹นํ•˜๋ฉด ์ธ์ฆ์„ ์‹œ์ž‘ํ•œ๋‹ค. 

  • `SecurityContextHolder`๊ฐ€ ์‚ญ์ œ๋œ๋‹ค. 
  • `HttpServletRequest`๊ฐ€ ์ €์žฅ๋˜๋Š”๋ฐ, ์ธ์ฆ์ด ์„ฑ๊ณตํ•˜๋ฉด ์›๋ž˜์˜ ์š”์ฒญ์„ ์žฌ์‹คํ–‰ํ•˜๋Š” ๋ฐ์— ์“ฐ์ธ๋‹ค. 
  • `AuthenticationEntryPoint`๋Š” ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ credential์„ ์š”์ฒญํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋‚˜ `WWW-Authenticate` ํ—ค๋”๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. 

3. ๋ฐ˜๋ฉด์— `AccessDeniedException`์ธ ๊ฒฝ์šฐ์—๋Š”, ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋˜๊ณ , ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด `AccessDeniedHandler`๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. 

 

โœ… ๋งŒ์•ฝ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด `AccessDeniedException`์ด๋‚˜ `AuthenticationException`์„ ๋˜์ง€์ง€ ์•Š์œผ๋ฉด `ExceptionTranslationFilter`๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. 

 

`ExceptionTranslationFilter` ์ˆ˜๋„ ์ฝ”๋“œ

try {
	filterChain.doFilter(request, response); // 1
} catch (AccessDeniedException | AuthenticationException ex) {
	if (!authenticated || ex instanceof AuthenticationException) {
		startAuthentication(); // 2
	} else {
		accessDenied(); // 3
	}
}

 

1. `FilterChain.doFilter(request, response)`๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋‚˜๋จธ์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ์—ญํ• ์„ ํ•œ๋‹ค. ์ฆ‰, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„ (`FilterSecurityInterceptor`์ด๋‚˜ method security)์ด `AuthenticationException`์ด๋‚˜ `AccessDeniedException`์„ ๋˜์ง€๋ฉด ์—ฌ๊ธฐ์„œ ์žกํžˆ๊ณ  ์ฒ˜๋ฆฌ๋œ๋‹ค. 

2. ์œ ์ €๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ `AuthenticationException`์— ํ•ด๋‹นํ•˜๋ฉด ์ธ์ฆ์ด ์‹œ์ž‘๋œ๋‹ค. 

3. ์ ‘๊ทผ ๊ฑฐ๋ถ€

 

 

 

 


 

 

์ธ์ฆ ์‚ฌ์ด์— ์š”์ฒญ ์ €์žฅํ•˜๊ธฐ

์š”์ฒญ์— ์ธ์ฆ์ด ์—†๊ณ  ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์š”์ฒญ์ธ ๊ฒฝ์šฐ, ์ธ์ฆ์ด ์„ฑ๊ณตํ•œ ํ›„ ์ธ์ฆ ๋ฆฌ์†Œ์Šค๋ฅผ ์žฌ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ์„ ์ €์žฅํ•ด๋‘์–ด์•ผ ํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด Spring Security์—์„œ๋Š” `RequestCache` ๊ตฌํ˜„์„ ํ†ตํ•ด `HttpServletRequest`๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

RequestCache

`HttpServletRequest`๋Š” `RequestCache`์— ์ €์žฅ๋œ๋‹ค.`RequestCacheAwareFilter`์™€ `ExceptionTranslationFilter`๋Š” ๋ชจ๋‘ `RequestCache`๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ๊ณผ ๋ชฉ์ ์ด ๋‹ค๋ฅด๋‹ค. 

`RequestCacheAwareFilter`: ์œ ์ €๊ฐ€ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ๋’ค์—  RequestCache์— ์ €์žฅ๋œ ์›๋ณธ ์š”์ฒญ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋งŒ์•ฝ ์žˆ๋‹ค๋ฉด ๊ทธ ์š”์ฒญ์„ ์›๋ž˜ ์š”์ฒญ์„ ๋ณต์›ํ•˜์—ฌ ์ธ์ฆ ์„ฑ๊ณต ํ›„์˜ ๊ฒฝ๋กœ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•œ๋‹ค. ์ฆ‰, ์ด๋ฏธ ์ €์žฅ๋œ ์š”์ฒญ์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ์ด๋‹ค. 

`ExceptionTranslationFilter`: ์ธ์ฆ์ด ํ•„์š”ํ•œ ์š”์ฒญ์„ ์ €๋ฆฌํ•˜๋Š” ๊ณผ์ •์—์„œ ์ธ์ฆ ์˜ˆ์™ธ (`AuthenticationException`)๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, ์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธ ์—”๋“œํฌ์ธํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๊ธฐ ์ „์— `HttpServletRequest`์„ `RequestCache`์— ์ €์žฅํ•œ๋‹ค.

 

 

โœ… ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ `HttpSessionRequestCache`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `HttpSession`์— ์š”์ฒญ์„ ์ €์žฅํ•œ๋‹ค. 

 

 



์ปค์Šคํ„ฐ๋งˆ์ด์ง•๋œ RequestCache ๊ตฌํ˜„

์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” `HttpSessionRequestCache`๊ฐ€ `continue` ๋ผ๋Š” ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์š”์ฒญ์„ ์ €์žฅํ•˜๋„๋ก ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•œ ๊ฒƒ์ด๋‹ค.

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
	requestCache.setMatchingRequestParameterName("continue");
	http
		// ...
		.requestCache((cache) -> cache
			.requestCache(requestCache)
		);
	return http.build();
}

 

 

 

 

 

`NullRequestCache` ๊ตฌํ˜„์„ ํ†ตํ•ด ์š”์ฒญ์ด ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ 

์„ธ์…˜์— ์œ ์ €์˜ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์„ ์ €์žฅํ•˜๊ณ ์‹ถ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋กœ ์˜คํ”„๋กœ๋“œํ•˜๊ฑฐ๋‚˜, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” ๋กœ๊ทธ์ธ ์ „์— ๋ฐฉ๋ฌธํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ํŽ˜์ด์ง€ ๋Œ€์‹ , ํ•ญ์ƒ ํŠน์ • ํŽ˜์ด์ง€(ex. ํ™ˆ ํŽ˜์ด์ง€)๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์š”์ฒญ์„ ์ €์žฅํ•ด๋‘์ง€ ์•Š๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿด ๋•Œ์—๋Š” `NullRequestCache`๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค. 

 

@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
    RequestCache nullRequestCache = new NullRequestCache();
    http
        // ...
        .requestCache((cache) -> cache
            .requestCache(nullRequestCache)
        );
    return http.build();
}

 

์ •๋ฆฌํ•˜์ž๋ฉด, `NullRequestCache`๋Š” ์š”์ฒญ์„ ์บ์‹ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋œ ํ›„, ์›๋ž˜ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์— ์ ํ•ฉํ•˜๋‹ค.

 


 

๋กœ๊น…

Spring Security๋Š” ๋ณด์•ˆ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ข…ํ•ฉ์ ์ธ ๋กœ๊ทธ๋ฅผ DEBUG์™€ TRACE ๋ ˆ๋ฒจ์—์„œ ์ œ๊ณตํ•œ๋‹ค. 401์ด๋‚˜ 403 ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค๋ฉด, ํ˜„์žฌ ์–ด๋–ค ์ƒํ™ฉ์ด ๋ฒŒ์–ด์กŒ๋Š”์ง€์— ๋Œ€ํ•œ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์„ ํ™•๋ฅ ์ด ๋†’๋‹ค. 

 

csrf ๋ณดํ˜ธ๊ฐ€ ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ csrf ํ† ํฐ์ด ์—†์ด POST ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ๋กœ๊ทธ๊ฐ€ ์—†์ด๋Š” ์œ ์ €๊ฐ€ ์•„๋ฌด ์„ค๋ช…๋„ ์—†์ด 403์—๋Ÿฌ๋ฅผ ๋งˆ์ฃผ์น  ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ, Spring Security์˜ ๋กœ๊น…์„ ํ—ˆ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

 

2023-06-14T09:44:25.797-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing POST /hello
2023-06-14T09:44:25.797-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/15)
2023-06-14T09:44:25.798-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/15)
2023-06-14T09:44:25.800-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderFilter (3/15)
2023-06-14T09:44:25.801-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (4/15)
2023-06-14T09:44:25.802-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (5/15)
2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8080/hello
2023-06-14T09:44:25.814-03:00 DEBUG 76975 --- [nio-8080-exec-1] o.s.s.w.access.AccessDeniedHandlerImpl   : Responding with 403 status code
2023-06-14T09:44:25.814-03:00 TRACE 76975 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match request to [Is Secure]

 

CSRF ํ† ํฐ์ด missing ์ƒํƒœ์ด๊ณ , ๊ทธ๋ž˜์„œ ์š”์ฒญ์ด denied๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. 

 

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

application.properties

logging.level.org.springframework.security=TRACE

 

application.yml

logging:
  level:
    org.springframework.security: DEBUG
    org.springframework.security.web: TRACE

 

logback.xml

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- ... -->
    </appender>
    <!-- ... -->
    <logger name="org.springframework.security" level="trace" additivity="false">
        <appender-ref ref="Console" />
    </logger>
</configuration>

 

๐Ÿ”ป ๋กœ๊น… ํ”„๋ ˆ์ž„์›Œํฌ Logback

๋”๋ณด๊ธฐ

`logback.xml`์€ Logback ์ด๋ผ๋Š” ๋กœ๊น… ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์„ค์ • ํŒŒ์ผ์ด๋‹ค. 


1. ๋กœ๊น… ์ถœ๋ ฅ ๋Œ€์ƒ (Appenders) ์„ค์ •

`Appender`๋Š” ๋กœ๊น… ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๋Œ€์ƒ์ด๋‹ค. ์œ„์˜ ์ฝ”๋“œ์—์„œ๋Š” `STDOUT์ด`๋ผ๋Š” ์ด๋ฆ„์˜ ์ฝ˜์†”์ด ์ •์˜๋˜์–ด ์žˆ๋‹ค. ์ด ์ฝ˜์†”์€ `ConsoleAppender`ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์ค€ ์ถœ๋ ฅ์— ๊ธฐ๋กํ•œ๋‹ค. 

 

2. ๋กœ๊น… ๋ ˆ๋ฒจ ๋ฐ ๋กœ๊ฑฐ ์ •์˜
`logger`๋Š” ํŠน์ • ํŒจํ‚ค์ง€๋‚˜ ํด๋ž˜์Šค์˜ ๋กœ๊ทธ ์ถœ๋ ฅ์„ ๊ด€๋ฆฌํ•œ๋‹ค. `name` ์†์„ฑ์€ ๋กœ๊ฑฐ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉฐ, ๋ณดํ†ต ํŠน์ • ํŒจํ‚ค์ง€๋‚˜ ํด๋ž˜์Šค ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค. 
`level` ์†์„ฑ์€ ๋กœ๊น… ๋ ˆ๋ฒจ์„ ์ •์˜ํ•œ๋‹ค. `trace`, `debug`, `info`, `warn`, `error` ๋“ฑ์ด ์žˆ๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ๋Š” `trace` ๋ ˆ๋ฒจ๋กœ ์„ค์ •๋˜์—ˆ๊ณ , `trace`๋Š” ๊ฐ€์žฅ ์ƒ์„ธํ•œ ๋กœ๊ทธ๋ ˆ๋ฒจ์ด๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ `additivity="false"`๋Š” ์ด ๋กœ๊ฑฐ๊ฐ€ ์ƒ์œ„ ๋กœ๊ฑฐ์— ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๋„๋ก ํ•˜์—ฌ, ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ๋กœ๊ทธ๋ฅผ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค. 

 

3. ๋กœ๊น… ๋ฉ”์‹œ์ง€์˜ ํฌ๋งท๊ณผ ํ•„ํ„ฐ๋ง
`logback.xml`์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€์˜ ํฌ๋งท์„ ์ •์˜ํ•˜๊ฑฐ๋‚˜, ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๋ฐ˜์‘ํ˜•