250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- dfs
- 지연로딩
- 낙관적락
- eager
- FetchType
- 힙
- shared lock
- fetch
- 연관관계
- 스토어드 프로시저
- 즉시로딩
- 스프링 폼
- 다대다
- 데코레이터
- 연결리스트
- PS
- SQL프로그래밍
- JPQL
- 비관적락
- querydsl
- 동적sql
- execute
- BOJ
- 일대다
- exclusive lock
- CHECK OPTION
- 백트래킹
- 이진탐색
- 유니크제약조건
- 다대일
Archives
- Today
- Total
흰 스타렉스에서 내가 내리지
로그 남기기 1 본문
728x90
package com.general.gen.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.filter.OncePerRequestFilter;
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.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@Component
public class LoggingFilter extends OncePerRequestFilter {
protected static final Logger log = LoggerFactory.getLogger(LoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
MDC.put("traceId", UUID.randomUUID().toString());
if (isAsyncDispatch(request)) {
filterChain.doFilter(request, response);
} else {
doFilterWrapped(new RequestWrapper(request), new ResponseWrapper(response), filterChain);
}
MDC.clear();
}
protected void doFilterWrapped(RequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain) throws ServletException, IOException {
try {
logRequest(request);
filterChain.doFilter(request, response);
} finally {
logResponse(response);
response.copyBodyToResponse();
}
}
private static void logRequest(RequestWrapper request) throws IOException {
String queryString = request.getQueryString();
log.info("Request : {} uri=[{}] content-type=[{}] ip=[{}]",
request.getMethod(),
queryString == null ? request.getRequestURI() : request.getRequestURI() + queryString,
request.getContentType(),
request.getRemoteAddr()
);
logPayload("Request", request.getContentType(), request.getInputStream());
}
private static void logResponse(ContentCachingResponseWrapper response) throws IOException {
logPayload("Response", response.getContentType(), response.getContentInputStream());
}
private static void logPayload(String prefix, String contentType, InputStream inputStream) throws IOException {
boolean visible = isVisible(MediaType.valueOf(contentType == null ? "application/json" : contentType));
if (visible) {
byte[] content = StreamUtils.copyToByteArray(inputStream);
if (content.length > 0) {
String contentString = new String(content);
log.info("{} Payload: {}", prefix, contentString);
}
} else {
log.info("{} Payload: Binary Content", prefix);
}
}
private static boolean isVisible(MediaType mediaType) {
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
);
return VISIBLE_TYPES.stream()
.anyMatch(visibleType -> visibleType.includes(mediaType));
}
}
package com.general.gen.filters;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class RequestWrapper extends HttpServletRequestWrapper {
private byte[] cachedInputStream;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
InputStream requestInputStream = request.getInputStream();
this.cachedInputStream = StreamUtils.copyToByteArray(requestInputStream);
}
@Override
public ServletInputStream getInputStream() {
return new ServletInputStream() {
private InputStream cachedBodyInputStream = new ByteArrayInputStream(cachedInputStream);
@Override
public boolean isFinished() {
try {
return cachedBodyInputStream.available() == 0;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
throw new UnsupportedOperationException();
}
@Override
public int read() throws IOException {
return cachedBodyInputStream.read();
}
};
}
}
package com.general.gen.filters;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.http.HttpServletResponse;
public class ResponseWrapper extends ContentCachingResponseWrapper {
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--로그 파일 저장 위치-->
<property name="LOGS_PATH" value="./logs"/>
<!-- ‘fileAppender’는 RollingFileAppender 클래스를 이용해서 특정 파일에 로그를 출력한다-->
<appender name="DAILY_ROLLING_FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_PATH}/logback.log</file>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.S} [%thread] [traceId=%X{traceId}] %-5level %logger{36}.%M - %msg%n
</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOGS_PATH}/logback.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
<!-- kb, mb, gb -->
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- ‘consoleAppender’는 ConsoleAppender 클래스를 이용해서 콘솔에 로그를 출력한다.-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<appender name="SAMPLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.S} [%thread] [traceId=%X{traceId}] %-5level %logger{36}.%M - %msg%n</pattern>
</encoder>
</appender>
<springProfile name="!(dev | prod)">
<root level="info">
<appender-ref ref="DAILY_ROLLING_FILE_APPENDER"/>
</root>
</springProfile>
<!-- <logger name="com.general.gen" level="DEBUG">-->
<!-- <appender-ref ref="SAMPLE" />-->
<!-- </logger>-->
<!-- <logger name="com.general.gen" level="INFO">-->
<!-- <appender-ref ref="DAILY_ROLLING_FILE_APPENDER" />-->
<!-- </logger>-->
<!-- <root level="INFO">-->
<!-- <appender-ref ref="STDOUT" />-->
<!-- <appender-ref ref="DAILY_ROLLING_FILE_APPENDER" />-->
<!-- </root>-->
</configuration>
<!-- 로그 파일 생성 위치(리눅스): /var/log/tomcat9/-->
<!-- 로그 파일 생성 위치(개발환경): 프로젝트 루트/logs-->
'Spring' 카테고리의 다른 글
스프링부트 Logback, 로그, @Slf4j (0) | 2023.02.05 |
---|---|
Spring Boot profile 환경별 설정하기 (0) | 2023.01.26 |
Custom Annotation 어노테이션 만들기 (@LoginUser) (0) | 2023.01.18 |
@Transactional(readOnly = true) (0) | 2023.01.18 |
스프링에서 Bean을 주입받는 방식 (0) | 2023.01.17 |