Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 로깅 프레임워크 적용과 모니터링 대시보드 구성(#204) #232

Merged
merged 9 commits into from
Aug 8, 2024
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@

### macOS ###
.DS_Store

### Log ###

logs/**/*.log
2 changes: 1 addition & 1 deletion backend/buildspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 0.2

env:
variables:
REMOTE_ORIGIN: "${REPOSITORY_URL}"
REMOTE_ORIGIN: "https://github.com/woowacourse-teams/2024-corea.git"
GITHUB_TOKEN: "${GITHUB_TOKEN}" # PAT를 환경 변수로 설정
GITHUB_CREDENTIAL: "${GITHUB_CREDENTIAL}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import corea.member.repository.MemberRepository;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
Expand All @@ -24,6 +26,7 @@
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

private static final String ID = "id";
private static final Logger log = LogManager.getLogger(LoginMemberArgumentResolver.class);

private final RequestHandler requestHandler;
private final MemberRepository memberRepository;
Expand All @@ -42,6 +45,7 @@ public AuthInfo resolveArgument(MethodParameter parameter, ModelAndViewContainer
if (accessToken.equals(ANONYMOUS)) {
throw new CoreaException(ExceptionType.AUTHORIZATION_ERROR);
}
log.info("로그인 시도[토큰={}]",accessToken);
Long memberId = tokenProvider.getPayload(accessToken).get(ID, Long.class);
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new CoreaException(ExceptionType.AUTHORIZATION_ERROR));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,29 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.resource.NoResourceFoundException;

@Slf4j
@ControllerAdvice
public class ExceptionResponseHandler {

@ExceptionHandler(CoreaException.class)
public ResponseEntity<ErrorResponse> handleCoreaException(final CoreaException e) {
log.debug("Corea exception [statusCode = {}, errorMessage = {}, cause = {}]", e.getHttpStatus(), e.getMessage(), e.getCause());
log.debug("Corea Custom exception [statusCode = {}, errorMessage = {}, cause = {}]", e.getHttpStatus(), e.getMessage(), e.getCause());
return ResponseEntity.status(e.getHttpStatus())
.body(new ErrorResponse(e.getMessage()));
}

@ExceptionHandler(NoResourceFoundException.class)
public ResponseEntity<ErrorResponse> handleNoResultException(final NoResourceFoundException e) {
log.warn("No Resource exception [errorMessage = {}, cause = {},error ={}]", e.getMessage(), e.getCause(), e);
return ResponseEntity.notFound()
.build();
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(final Exception e) {
log.debug("Server exception [errorMessage = {}, cause = {}]", e.getMessage(), e.getCause());
log.error("Server exception [errorMessage = {}, cause = {},error ={}]", e.getMessage(), e.getCause(), e);
return ResponseEntity.internalServerError()
.body(new ErrorResponse(e.getMessage()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import corea.matching.domain.MatchResult;
import corea.matching.repository.MatchResultRepository;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -17,19 +19,22 @@
@Transactional(readOnly = true)
public class DevelopFeedbackService {

private static final Logger log = LogManager.getLogger(DevelopFeedbackService.class);
private final MatchResultRepository matchResultRepository;
private final DevelopFeedbackRepository developFeedbackRepository;

@Transactional
public DevelopFeedbackResponse create(long roomId, long deliverId, DevelopFeedbackRequest request) {
validateAlreadyExist(roomId, deliverId, request.receiverId());
log.debug("개발 피드백 작성[작성자({}), 요청값({})",deliverId,request);
DevelopFeedback developFeedback = developFeedbackRepository.save(createEntity(roomId, deliverId, request));
return DevelopFeedbackResponse.of(developFeedback);
}

@Transactional
public DevelopFeedbackResponse update(long feedbackId, long roomId, long deliverId, DevelopFeedbackRequest request) {
validateNotExist(feedbackId);
log.debug("개발 피드백 업데이트[작성자({}), 피드백 ID({}), 요청값({})",deliverId,feedbackId,request);
DevelopFeedback developFeedback = developFeedbackRepository.save(createEntity(feedbackId, roomId, deliverId, request));
return DevelopFeedbackResponse.of(developFeedback);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import corea.matching.domain.MatchResult;
import corea.matching.repository.MatchResultRepository;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -17,19 +19,23 @@
@Transactional(readOnly = true)
public class SocialFeedbackService {

private static final Logger log = LogManager.getLogger(SocialFeedbackService.class);
private final SocialFeedbackRepository socialFeedbackRepository;
private final MatchResultRepository matchResultRepository;

@Transactional
public SocialFeedbackResponse create(long roomId, long deliverId, SocialFeedbackRequest request) {
validateAlreadyExist(roomId, deliverId, request.receiverId());
log.debug("소설 피드백 작성[작성자({}), 요청값({})",deliverId,request);
SocialFeedback socialFeedback = socialFeedbackRepository.save(createEntity(roomId, deliverId, request));
return SocialFeedbackResponse.of(socialFeedback);
}

@Transactional
public SocialFeedbackResponse update(long feedbackId, long roomId, long deliverId, SocialFeedbackRequest request) {
validateNotExist(feedbackId);

log.debug("소설 피드백 업데이트[작성자({}), 피드백 ID({}), 요청값({})",deliverId,feedbackId,request);
SocialFeedback socialFeedback = socialFeedbackRepository.save(createEntity(feedbackId, roomId, deliverId, request));
return SocialFeedbackResponse.of(socialFeedback);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;

@Aspect
@Component
Expand Down Expand Up @@ -58,15 +56,14 @@ private Object loggingReturn(
final var result = joinPoint.proceed();
final var elapsedMillis = System.currentTimeMillis() - startMillis;
final Consumer<HttpServletRequest> httpServletRequestLogger = request -> log.debug(
"return [time={}, url={}, httpMethod={}, ip={}, class={}, method={}, result={}, elapsedMillis={}]",
"return [time={}, url={}, httpMethod={}, class={}, method={}, elapsedMillis={}\nresult={}]",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

LocalDateTime.now(),
request.getRequestURL(),
request.getMethod(),
IpExtractor.extract(request),
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
result,
elapsedMillis
elapsedMillis,
result
);
final Runnable requestNotFoundLogger = () -> log.debug(
"return [time={}, class={}, method={}, result={}, elapsedMillis={}]",
Expand All @@ -83,22 +80,19 @@ private Object loggingReturn(

private void loggingEnter(final ProceedingJoinPoint joinPoint, final Logger log) {
final Consumer<HttpServletRequest> httpServletRequestLogger = request -> log.debug(
"enter [time={}, url={}, httpMethod={}, ip={}, class={}, method={}, hashcode={}, arguments={}]",
"enter [time={}, url={}, httpMethod={}, class={}, method={}, arguments={}]",
LocalDateTime.now(),
request.getRequestURL(),
request.getMethod(),
IpExtractor.extract(request),
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
Thread.currentThread().hashCode(),
Arrays.toString(joinPoint.getArgs())
);
final Runnable requestNotFoundLogger = () -> log.warn(
"enter [time={}, class={}, method={}, hashcode={}, arguments={}]",
"enter [time={}, class={}, method={}, arguments={}]",
LocalDateTime.now(),
joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(),
Thread.currentThread().hashCode(),
Arrays.toString(joinPoint.getArgs())
);
getRequest().ifPresentOrElse(httpServletRequestLogger, requestNotFoundLogger);
Expand All @@ -108,43 +102,4 @@ private Logger getLog(final JoinPoint joinPoint) {
return LoggerFactory.getLogger(joinPoint.getTarget()
.getClass());
}

private enum IpExtractor {

X_FORWARDED_FOR("X-Forwarded-For"),
PROXY_CLIENT_IP("Proxy-Client-IP"),
WL_PROXY_CLIENT_IP("WL-Proxy-Client-IP"),
HTTP_CLIENT_IP("HTTP_CLIENT_IP"),
HTTP_X_FORWARDED_FOR("HTTP_X_FORWARDED_FOR"),
X_REAL_IP("X-Real-IP"),
@SuppressWarnings("SpellCheckingInspection") X_REALIP("X-RealIP"),
REMOTE_ADDR("REMOTE_ADDR"),
REMOTE_ADDR_BUILD_IN(HttpServletRequest::getRemoteAddr),

;

private static final String UNKNOWN = "unknown";

private final Function<HttpServletRequest, String> mapper;

IpExtractor(final String headerName) {
this(request -> request.getHeader(headerName));
}

IpExtractor(final Function<HttpServletRequest, String> mapper) {
this.mapper = mapper;
}

private static String extract(final HttpServletRequest request) {
return Arrays.stream(values())
.map(it -> it.mapper.apply(request))
.filter(IpExtractor::isValidIp)
.findAny()
.orElse(UNKNOWN);
}

private static boolean isValidIp(final String ip) {
return StringUtils.hasText(ip) && !UNKNOWN.equalsIgnoreCase(ip);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package corea.global.filter;

import jakarta.servlet.*;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.UUID;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class MdcRequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
UUID uuid = UUID.randomUUID();
MDC.put("requestId", uuid.toString());
chain.doFilter(request, response);
MDC.clear();
}
}


10 changes: 8 additions & 2 deletions backend/src/main/java/corea/matching/domain/MatchResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;
Expand All @@ -15,6 +17,8 @@
@Getter
public class MatchResult {

private static final Logger log = LoggerFactory.getLogger(MatchResult.class);

@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
Expand All @@ -40,12 +44,14 @@ public class MatchResult {

public MatchResult(long roomId, Member reviewer, Member reviewee, String prLink) {
this(null, roomId, reviewer, reviewee, prLink, ReviewStatus.INCOMPLETE, false, false);
log.info("매칭 결과 [방 번호 ({}) ,리뷰어({}) , 리뷰이({})]", roomId, reviewer.getUsername(), reviewee.getUsername());
}

public void reviewerCompleteFeedback(){
public void reviewerCompleteFeedback() {
isReviewerCompletedFeedback = true;
}
public void revieweeCompleteFeedback(){

public void revieweeCompleteFeedback() {
isRevieweeCompletedFeedback = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import corea.member.repository.MemberRepository;
import corea.participation.domain.Participation;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -20,6 +22,8 @@
@Transactional(readOnly = true)
public class MatchingService {

private static final Logger log = LoggerFactory.getLogger(MatchingService.class);

private final MatchingStrategy matchingStrategy;
private final MemberRepository memberRepository;
private final MatchResultRepository matchResultRepository;
Expand All @@ -32,9 +36,8 @@ public void matchMaking(List<Participation> participations, int matchingSize) {
.toList();

long roomId = participations.get(0).getRoomId();

log.info("매칭 시작 [방 번호 ({}), 매칭하는 인원 ({}), 총 인원({})]", roomId, matchingSize, memberIds.size());
List<Pair> results = matchingStrategy.matchPairs(memberIds, matchingSize);

//TODO: prLink 차후 수정
results.stream()
.map(pair -> new MatchResult(roomId, getMember(pair.getFromMemberId()), getMember(pair.getToMemberId()), null))
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/java/corea/review/service/ReviewService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import corea.matching.domain.MatchResult;
import corea.matching.repository.MatchResultRepository;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -13,11 +15,13 @@
@Transactional(readOnly = true)
public class ReviewService {

private static final Logger log = LogManager.getLogger(ReviewService.class);
private final MatchResultRepository matchResultRepository;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private final MatchResultRepository matchResultRepository;
private final MatchResultRepository matchResultRepository;


@Transactional
public void review(long roomId, long reviewerId, long revieweeId) {
MatchResult matchResult = getMatchResult(roomId, reviewerId, revieweeId);
log.info("리뷰 완료[{매칭 ID({}), 리뷰어 ID({}, 리뷰이 ID({})", matchResult.getId(), reviewerId, revieweeId);
matchResult.reviewComplete();
}

Expand Down
18 changes: 7 additions & 11 deletions backend/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ spring:
on-profile: dev
jpa:
defer-datasource-initialization: true
show-sql: true
properties:
hibernate:
format_sql: true
hibernate:
ddl-auto: create-drop
h2:
Expand All @@ -19,11 +15,6 @@ spring:
datasource:
url: jdbc:h2:mem:database

logging:
level:
root: INFO
corea: DEBUG

springdoc:
swagger-ui:
groups-order: DESC
Expand All @@ -44,7 +35,12 @@ springdoc:
- /**

management:
endpoint:
endpoints:
web:
exposure:
include: health
include: health,info,beans,conditions
exclude: threaddump, heapdump

logging:
level:
corea: DEBUG
Loading
Loading