서버에서 로그를 확인할 경우 grep으로 로그를 캐치할 시 라인단위로 인식하기 때문에 모든 trace를 볼 수 없다. MDC와 log4j2를 사용하면 각 접속한 IP별로 로그를 확인 할 수 있다.
ThreadLocal
ThreadLocal 변수를 선언하면 멀티 스레드 환경에서 각 스레드마다 독립적인 변수를 가지고, get(), set() 메소드를 통해 값에 대해 접근할 수 있다.
public class TestThread implements Runnable { private ThreadLocal threadLocal = new ThreadLocal<DataObj>() { @Override protected DataObj initialValue() { DataObj dataObj = new DataObj(); return dataObj; } }; @Override public void run() { DataObj dataObj = (DataObj) threadLocal.get(); dataObj.setTrxNo(Math.random() + ""); threadLocal.set(dataObj); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(((DataObj) threadLocal.get()).getTrxNo()); }
> 두 개의 쓰레드 런
0.5002465179334552
0.3244909506839274
MDC (Mapped Diagnostic Context)
멀티 클라이언트 환경에서 다른 클라이언트와 값을 구별하여 로그를 추적할 수 있도록 제공되는 map이다.
ThreadLocal에 구별할 수 있는 키 값을 저장하여 Thread가 존재하는 동안 계속해서 사용할 수 있도록 하는 방법으로
현재 log4j 및 logback만 MDC기능을 제공하고 있다.
MDC는 static으로 올라간 맵에 저장된다
public class MDCManager { private String clientIp; public String getClientIp() { return clientIp; } public void setClientIp(String clientIp) { MDC.put("clientIp" , clientIp); this.clientIp = clientIp; } }
Log4j2
pom.xml 로깅
<!-- Logging --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.5</version> </dependency> <!-- Log4j2 SLF4J Bridge --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.5</version> </dependency> <!-- SLF4J JCL Bridge --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.18</version> </dependency> <!-- SLF4J Log4j 1.x Bridge --> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.18</version> </dependency> <!-- Logging -->
log4j2.xml 설정
쓰레드로컬에 저장된 아이피별로 라우팅 시킨다.
패턴에 클라이언트 아이피가 있다면 라우팅 시킨다. 그러나 그 값이 DEFAULT라면 DEFAULT로 라우트한다.
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <!-- Appenders --> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p [$${ctx:clientIp}][%t] %C{2} (%F:%L) - %m%n" /> </Console> <Routing name="ROUTING"> <Routes pattern="$${ctx:clientIp}"> <Route> <RollingFile name="Rolling-${ctx:clientIp}" fileName="C:/logs/myapp/${ctx:clientIp}_myapp.out" filePattern="C:/logs/myapp/${ctx:clientIp}_myapp-%d{yyyy-MM-dd}.out"> <PatternLayout> <pattern>%d{yyyy-MM-dd:hh:mm:ss} [%p][%C{1}][%M (%L)}][$${ctx:clientIp}] | %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="50MB"/> </Policies> <DefaultRolloverStrategy max="1"/> </RollingFile> </Route> <Route key="DEFAULT"> <RollingFile name="Rolling-default" fileName="C:/logs/myapp/default_myapp.out" filePattern="C:/logs/myapp/default_myapp-%d{yyyy-MM-dd}.out"> <PatternLayout> <pattern>%d{yyyy-MM-dd:hh:mm:ss} [%p][%C{1}][%M (%L)}][$${ctx:clientIp}] | %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="50MB"/> </Policies> <DefaultRolloverStrategy max="1"/> </RollingFile> </Route> </Routes> </Routing> </Appenders> <Loggers> <!-- Application Loggers --> <Logger name="com.woo.test" level="debug"> <AppenderRef ref="STDOUT" /> <AppenderRef ref="ROUTING" /> </Logger> <Root level="debug"> </Root> </Loggers> </Configuration>
스프링부트
Spring에서는 기본적으로 Logback을 이용해서 로깅을 하기 때문에 다른 로깅 라이브러리인 Log4j2를 그냥 추가하게 되면, 로깅 라이브러리끼리 충돌이 발생한다.
때문에 Log4j2를 적용하기 위해서는 Logback 라이브러리를 제거해야 한다.
@WebFilter("/*") public class ClientIpFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 클라이언트 IP를 MDC에 설정 String clientIp = request.getRemoteAddr(); MDC.put("clientIp", clientIp); try { chain.doFilter(request, response); } finally { // 요청 처리 후 MDC에서 제거 MDC.remove("clientIp"); } } @Override public void destroy() {} }
1. @ServletComponentScan 추가
@WebFilter로 정의된 필터를 등록하려면 @ServletComponentScan을 추가해야 합니다.
@SpringBootApplication @ServletComponentScan // @WebFilter, @WebServlet 등을 스캔 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation("org.springframework.boot:spring-boot-starter-log4j2") } configurations { all { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } }
request.getRemoteAddr(); 에서 IPv6값이 나옴 -D옵션 추가필요


https://055055.tistory.com/96
'WEB개발 > WEB, WAS' 카테고리의 다른 글
Tomcat - Jasper (JSP Engine) (0) | 2025.03.12 |
---|---|
Class Loader & Hot Deploy (0) | 2021.09.23 |
Jenkins & SVN or Git & Docker (0) | 2021.07.29 |
WEB.XML Config (context-param, init-param, web-app ... ) (0) | 2021.07.23 |
ClassPath, ClassLoad, JAVA COMPILE(컴파일), Tomcat (0) | 2021.07.20 |