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
Copy Markdown
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
Copy Markdown
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;