Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public record AnonymousLogResponse(
String clientIp,
@NotBlank
Integer statusCode,
@NotNull
String customStatusCode,
int failedAttempts
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public record MemberLogResponse(
Long logId,
LogStatus logStatus,
@NotBlank
LocalDateTime responseAt,
LocalDateTime requestAt,
String nickName,
String clientIp,
@NotBlank
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public record FilterAllTasksResponse(
String categoryName,
String title,
String processorName,
String processorUrl,
Copy link
Contributor

Choose a reason for hiding this comment

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

dto에 url 필드를 추가하신 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

작업 목록 조회시 프로필 이미지가 필요할 것 같습니다. 피그마 상에도 존재하고 장호님께서 요청을 주셨습니다.

String requesterName,
String requesterUrl,
TaskStatus taskStatus,
LocalDateTime finishedAt
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record FilterAssignedTaskListResponse(
String categoryName,
String title,
String requesterName,
String requesterUrl,
TaskStatus taskStatus,
LocalDateTime finishedAt
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public record FilterPendingApprovalResponse(
String mainCategoryName,
String categoryName,
String title,
String requesterName
String requesterName,
String requesterUrl
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record FilterRequestedTasksResponse(
String categoryName,
String title,
String processorName,
String processorUrl,
TaskStatus taskStatus,
LocalDateTime finishedAt
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ public void saveAnonymousLog(AnonymousLog anonymousLog) {
apiLogRepository.save(apiLogPersistenceMapper.mapAnonymousLogToEntity(anonymousLog, anonymousLog.getLoginNickname()));
}

@Override
public List<ApiLog> findAllLogs() {
return apiLogRepository.findAll().stream()
.map(apiLogPersistenceMapper::mapLogEntityToDomain)
.toList();
}

@Override
public Page<MemberLog> filterMemberLogs(FilterLogRequest memberLogRequest, Pageable pageable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,4 @@ public MemberLog mapMemberLogEntityToDomain(MemberLogEntity memberLogEntity) {
: null)
.build();
}

public ApiLog mapLogEntityToDomain(ApiLogEntity logEntity) {
return ApiLog.builder()
.logId(logEntity.getLogId())
.clientIp(logEntity.getClientIp())
.requestUrl(logEntity.getRequestUrl())
.requestMethod(logEntity.getRequestMethod().name())
.statusCode(logEntity.getStatusCode())
.customStatusCode(logEntity.getCustomStatusCode())
.requestBody(logEntity.getRequestBody())
.responseBody(logEntity.getResponseBody())
.requestAt(logEntity.getRequestAt())
.logStatus(logEntity.getLogStatus())
.build();
}
}
9 changes: 7 additions & 2 deletions src/main/java/clap/server/application/mapper/TaskMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static FilterRequestedTasksResponse toFilterRequestedTasksResponse(Task t
task.getCategory().getName(),
task.getTitle(),
task.getProcessor() != null ? task.getProcessor().getMemberInfo().getNickname() : "",
task.getProcessor() != null ? task.getProcessor().getImageUrl() : "",
task.getTaskStatus(),
task.getFinishedAt() != null ? task.getFinishedAt() : null
);
Expand All @@ -51,6 +52,7 @@ public static FilterAssignedTaskListResponse toFilterAssignedTaskListResponse(Ta
task.getCategory().getName(),
task.getTitle(),
task.getRequester() != null ? task.getRequester().getMemberInfo().getNickname() : "",
task.getRequester() != null ? task.getRequester().getImageUrl() : "",
task.getTaskStatus(),
task.getFinishedAt() != null ? task.getFinishedAt() : null
);
Expand All @@ -63,7 +65,8 @@ public static FilterPendingApprovalResponse toFilterPendingApprovalTasksResponse
task.getCategory().getMainCategory().getName(),
task.getCategory().getName(),
task.getTitle(),
task.getRequester().getMemberInfo().getNickname()
task.getRequester() != null ? task.getRequester().getMemberInfo().getNickname() : "",
task.getRequester() != null ? task.getRequester().getImageUrl() : ""
);
}

Expand Down Expand Up @@ -106,8 +109,10 @@ public static FilterAllTasksResponse toFilterAllTasksResponse(Task task) {
task.getCategory().getMainCategory().getName(),
task.getCategory().getName(),
task.getTitle(),
task.getRequester().getMemberInfo().getNickname(),
task.getProcessor() != null ? task.getProcessor().getMemberInfo().getNickname() : "",
task.getProcessor() != null ? task.getProcessor().getImageUrl() : "",
task.getRequester() != null ? task.getRequester().getMemberInfo().getNickname() : "",
task.getRequester() != null ? task.getRequester().getImageUrl() : "",
task.getTaskStatus(),
task.getFinishedAt() != null ? task.getFinishedAt() : null
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public static AnonymousLogResponse toAnonymousLogResponse(AnonymousLog anonymous
anonymousLog.getLoginNickname(),
anonymousLog.getClientIp(),
anonymousLog.getStatusCode(),
anonymousLog.getCustomStatusCode(),
failedAttempts
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
import java.time.LocalDateTime;

public interface CreateAnonymousLogsUsecase {
void createAnonymousLog(HttpServletRequest request, HttpServletResponse response, Object result, LogStatus logType, String customCode, String requestBody, String nicknameFromRequestBody);
void createAnonymousLog(HttpServletRequest request, int statusCode, String customCode, LogStatus logStatus, Object responseBody, String requestBody, String nickName);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@

public interface CreateMemberLogsUsecase {

void createMemberLog(HttpServletRequest request, HttpServletResponse response, Object result, LogStatus logType, String customCode, String body, Long userId);
void createMemberLog(HttpServletRequest request, int statusCode,String customCode, LogStatus logStatus, Object responseBody, String requestBody, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@
public interface FindApiLogsUsecase {
PageResponse<AnonymousLogResponse> filterAnonymousLogs(FilterLogRequest anonymousLogsRequest, Pageable pageable);
PageResponse<MemberLogResponse> filterMemberLogs(FilterLogRequest memberLogRequest, Pageable pageable);
List<ApiLog> getApiLogs();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.List;

public interface LoadLogPort {
List<ApiLog> findAllLogs();
Page<AnonymousLog> filterAnonymousLogs(FilterLogRequest anonymousLogRequest, Pageable pageable);

Page<MemberLog> filterMemberLogs(FilterLogRequest memberLogRequest, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class CreateAnonymousLogsService implements CreateAnonymousLogsUsecase {
private final ApiLogPersistenceAdapter apiLogPersistenceAdapter;

@Override
public void createAnonymousLog(HttpServletRequest request, HttpServletResponse response, Object result, LogStatus logType, String customCode, String body, String nickName) {
AnonymousLog anonymousLog = AnonymousLog.createAnonymousLog(request, response, result, logType, customCode, body, nickName);
public void createAnonymousLog(HttpServletRequest request, int statusCode, String customCode, LogStatus logStatus, Object responseBody, String requestBody, String nickName) {
AnonymousLog anonymousLog = AnonymousLog.createAnonymousLog(request, statusCode,customCode, logStatus, responseBody, requestBody, nickName);
apiLogPersistenceAdapter.saveAnonymousLog(anonymousLog);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public class CreateMemberLogsService implements CreateMemberLogsUsecase {

@Override
@Transactional
public void createMemberLog(HttpServletRequest request, HttpServletResponse response, Object result, LogStatus logType, String customCode, String body, Long userId) {
public void createMemberLog(HttpServletRequest request, int statusCode, String customCode,LogStatus logStatus, Object responseBody, String requestBody, Long userId) {
Member member = memberService.findById(userId);
MemberLog memberLog = MemberLog.createMemberLog(request, response, result, logType, customCode, body, member);
MemberLog memberLog = MemberLog.createMemberLog(request, statusCode, customCode, logStatus, responseBody, requestBody, member);
apiLogPersistenceAdapter.saveMemberLog(memberLog);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
@Transactional(readOnly = true)
public class FindApiLogsService implements FindApiLogsUsecase {

private final ApiLogPersistenceAdapter apiLogPersistenceAdapter;
private final LoginDomainService loginDomainService;
private final LoadLogPort loadLogPort;

Expand All @@ -45,10 +44,4 @@ public PageResponse<MemberLogResponse> filterMemberLogs(FilterLogRequest memberL
Page<MemberLogResponse> memberLogResponses = memberLogs.map(LogMapper::toMemberLogResponse);
return PageResponse.from(memberLogResponses);
}

//테스트용
@Override
public List<ApiLog> getApiLogs() {
return apiLogPersistenceAdapter.findAllLogs();
}
}
21 changes: 21 additions & 0 deletions src/main/java/clap/server/config/aop/ContentCachingFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package clap.server.config.aop;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import java.io.IOException;

@Component
public class ContentCachingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingRequestWrapper contentCachingRequestWrapper = new ContentCachingRequestWrapper(request);
filterChain.doFilter(contentCachingRequestWrapper, response);
}
}
55 changes: 28 additions & 27 deletions src/main/java/clap/server/config/aop/LoggingAspect.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import clap.server.application.port.inbound.log.CreateAnonymousLogsUsecase;
import clap.server.application.port.inbound.log.CreateMemberLogsUsecase;
import clap.server.config.annotation.LogType;
import clap.server.exception.BaseException;
import clap.server.exception.ErrorContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -18,15 +19,18 @@
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

@Slf4j
@Aspect
Expand All @@ -36,6 +40,7 @@ public class LoggingAspect {
private final ObjectMapper objectMapper;
private final CreateAnonymousLogsUsecase createAnonymousLogsUsecase;
private final CreateMemberLogsUsecase createMemberLogsUsecase;
private final HandlerExceptionResolver handlerExceptionResolver;

@Pointcut("execution(* clap.server.adapter.inbound.web..*Controller.*(..))")
public void controllerMethods() {
Expand All @@ -45,37 +50,41 @@ public void controllerMethods() {
public Object logApiRequests(ProceedingJoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
if (!(request instanceof ContentCachingRequestWrapper)) {
request = new ContentCachingRequestWrapper(request);
}
HttpServletResponse response = attributes.getResponse();

Object result = null;
Exception capturedException = null;
try {
result = joinPoint.proceed();
} catch (Exception ex) {
log.error("Exception occurred: {}", ex.getMessage());
log.info("response.getStatus()={}",response.getStatus());
log.info("getRequestBody()={}", getRequestBody(request));
capturedException = ex;
throw ex;
} finally {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
LogStatus logType = getLogType(methodSignature);
String customCode = getCustomCode(response);
if (logType != null) {
if (LogStatus.LOGIN.equals(logType)) {
log.info("result={}",result);
log.info("response.getStatus()={}",response.getStatus());
log.info("getRequestBody()={}", getRequestBody(request));
log.info("getNicknameFromRequestBody()={}", getNicknameFromRequestBody(request));
createAnonymousLogsUsecase.createAnonymousLog(request, response, result, logType, customCode, getRequestBody(request), getNicknameFromRequestBody(request));
LogStatus logStatus = getLogType((MethodSignature) joinPoint.getSignature());
int statusCode;
String customCode = null;
if (capturedException != null) {
if (capturedException instanceof BaseException e) {
statusCode = e.getCode().getHttpStatus().value();
customCode = e.getCode().getCustomCode();
} else {
ModelAndView modelAndView = handlerExceptionResolver.resolveException(request, response, null, capturedException);
statusCode = modelAndView.getStatus().value();
}
} else {
statusCode = response.getStatus();
}

if (logStatus != null) {
if (LogStatus.LOGIN.equals(logStatus)) {
createAnonymousLogsUsecase.createAnonymousLog(request, statusCode, customCode, logStatus, result, getRequestBody(request), getNicknameFromRequestBody(request));
} else {
if (!isUserAuthenticated()) {
log.error("로그인 시도 로그를 기록할 수 없음");
} else {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof SecurityUserDetails userDetails) {
createMemberLogsUsecase.createMemberLog(request, response, result, logType, customCode, getRequestBody(request), userDetails.getUserId());
createMemberLogsUsecase.createMemberLog(request, statusCode, customCode, logStatus, result, getRequestBody(request), userDetails.getUserId());
}
}
}
Expand All @@ -92,13 +101,6 @@ private LogStatus getLogType(MethodSignature methodSignature) {
}
}

//TODO: 로그인 시도에 대한 에러 잡도록 수정
private String getCustomCode(HttpServletResponse response) {
String customCode = ErrorContext.getCustomCode();
return customCode != null ? customCode : "CUSTOM" + (response != null ? response.getStatus() : 500);
}

//TODO: 로그인 시도 시 닉네임 파싱하도록 수정
private String getNicknameFromRequestBody(HttpServletRequest request) {
try {
String requestBody = getRequestBody(request);
Expand All @@ -109,14 +111,13 @@ private String getNicknameFromRequestBody(HttpServletRequest request) {
}
}

//TODO: 제거
private String getRequestBody(HttpServletRequest request) {
try {
ContentCachingRequestWrapper cachingRequest = (ContentCachingRequestWrapper) request;
byte[] content = cachingRequest.getContentAsByteArray();
return new String(content, StandardCharsets.UTF_8);
} catch (Exception e) {
return "ERROR: Unable to read request body";
return "요청 바디의 내용을 읽을 수 없음";
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/clap/server/domain/model/log/AnonymousLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
public class AnonymousLog extends ApiLog {
private String loginNickname;

public static AnonymousLog createAnonymousLog(HttpServletRequest request, HttpServletResponse response, Object responseResult, LogStatus logStatus, String customCode, String requestBody, String nickName) {
public static AnonymousLog createAnonymousLog(HttpServletRequest request, int statusCode, String customCode, LogStatus logStatus, Object responseBody, String requestBody, String nickName) {
return AnonymousLog.builder()
.clientIp(ClientIpParseUtil.getClientIp(request))
.requestUrl(request.getRequestURI())
.requestMethod(request.getMethod())
.statusCode(response.getStatus())
.customStatusCode(customCode)
.statusCode(statusCode)
.customStatusCode(customCode != null ? customCode : "")
.requestBody(requestBody)
.responseBody(responseResult != null ? responseResult.toString() : "로그인 실패")
.responseBody(responseBody != null ? responseBody.toString() : "로그인 실패")
.requestAt(LocalDateTime.now())
.logStatus(logStatus)
.loginNickname(nickName)
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/clap/server/domain/model/log/MemberLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
public class MemberLog extends ApiLog {
private Member member;

public static MemberLog createMemberLog(HttpServletRequest request, HttpServletResponse response, Object responseResult, LogStatus logStatus, String customCode, String requestBody, Member member) {
public static MemberLog createMemberLog(HttpServletRequest request, int statusCode, String customCode, LogStatus logStatus, Object responseBody, String requestBody, Member member) {
return MemberLog.builder()
.clientIp(ClientIpParseUtil.getClientIp(request))
.requestUrl(request.getRequestURI())
.requestMethod(request.getMethod())
.statusCode(response.getStatus())
.customStatusCode(customCode)
.statusCode(statusCode)
.customStatusCode(customCode != null ? customCode : "")
.requestBody(requestBody)
.responseBody(responseResult != null ? responseResult.toString() : "UNKNOWN")
.responseBody(responseBody != null ? responseBody.toString() : logStatus.getDescription() + " 실패")
.requestAt(LocalDateTime.now())
.logStatus(logStatus)
.member(member)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE api_log
MODIFY COLUMN custom_status_code VARCHAR(255) NULL,
MODIFY COLUMN log_status ENUM('LOGIN', 'REQUEST_CREATED', 'REQUEST_UPDATED', 'REQUEST_CANCELLED',
'REQUEST_APPROVED', 'ASSIGNER_CHANGED', 'COMMENT_ADDED',
'COMMENT_UPDATED', 'STATUS_CHANGED', 'TASK_VIEWED') NOT NULL;