API 로그저장, ExceptionHandler 저장, 감사,에러로그API 작업 진행중

This commit is contained in:
2025-11-20 14:36:59 +09:00
parent aaabd85c9c
commit 107bd6b20f
23 changed files with 1791 additions and 8 deletions

View File

@@ -0,0 +1,127 @@
package com.kamco.cd.kamcoback.log;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@Tag(name = "감사 로그", description = "감사 로그 관리 API")
@RequiredArgsConstructor
@RestController
@RequestMapping({"/api/log/audit", "/v1/api/log/audit"})
public class AuditLogApiController {
private final AuditLogCoreService auditLogCoreService;
@Operation(summary = "일자별 로그 조회")
@GetMapping("/daily")
public ApiResponseDto<Page<AuditLogDto.AuditList>> getDailyLogs(
@RequestParam(required = false) LocalDate startDate,
@RequestParam(required = false) LocalDate endDate,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.DailySearchReq searchReq = new AuditLogDto.DailySearchReq(startDate, endDate, null, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByDaily(
searchReq,
startDate,
endDate
);
return ApiResponseDto.ok(result);
}
@Operation(summary = "일자별 로그 상세")
@GetMapping("/daily/result")
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getDailyResultLogs(
@RequestParam LocalDate logDate,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.DailySearchReq searchReq = new AuditLogDto.DailySearchReq(null, null, logDate, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByDailyResult(
searchReq,
logDate
);
return ApiResponseDto.ok(result);
}
@Operation(summary = "메뉴별 로그 조회")
@GetMapping("/menu")
public ApiResponseDto<Page<AuditLogDto.AuditList>> getMenuLogs(
@RequestParam(required = false) String searchValue,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(searchValue, null, null, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByMenu(
searchReq, searchValue
);
return ApiResponseDto.ok(result);
}
@Operation(summary = "메뉴별 로그 상세")
@GetMapping("/menu/result")
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getMenuResultLogs(
@RequestParam String menuId,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(null, menuId, null, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByMenuResult(
searchReq,
menuId
);
return ApiResponseDto.ok(result);
}
@Operation(summary = "사용자별 로그 조회")
@GetMapping("/account")
public ApiResponseDto<Page<AuditLogDto.AuditList>> getAccountLogs(
@RequestParam(required = false) String searchValue,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(searchValue, null, null, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditList> result = auditLogCoreService.getLogByAccount(
searchReq, searchValue
);
return ApiResponseDto.ok(result);
}
@Operation(summary = "사용자별 로그 상세")
@GetMapping("/account/result")
public ApiResponseDto<Page<AuditLogDto.AuditDetail>> getAccountResultLogs(
@RequestParam Long userUid,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
AuditLogDto.MenuUserSearchReq searchReq = new AuditLogDto.MenuUserSearchReq(null, null, userUid, page, size, "created_dttm,desc");
Page<AuditLogDto.AuditDetail> result = auditLogCoreService.getLogByAccountResult(
searchReq,
userUid
);
return ApiResponseDto.ok(result);
}
}

View File

@@ -0,0 +1,47 @@
package com.kamco.cd.kamcoback.log;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
import com.kamco.cd.kamcoback.log.dto.EventType;
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
import com.kamco.cd.kamcoback.postgres.core.ErrorLogCoreService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.util.List;
@Tag(name = "에러 로그", description = "에러 로그 관리 API")
@RequiredArgsConstructor
@RestController
@RequestMapping({"/api/log/error", "/v1/api/log/error"})
public class ErrorLogApiController {
private final ErrorLogCoreService errorLogCoreService;
@Operation(summary = "에러로그 조회")
@GetMapping("/error")
public ApiResponseDto<Page<ErrorLogDto.Basic>> getErrorLogs(
@RequestParam(required = false) ErrorLogDto.LogErrorLevel logErrorLevel,
@RequestParam(required = false) EventType eventType,
@RequestParam(required = false) LocalDate startDate,
@RequestParam(required = false) LocalDate endDate,
@RequestParam int page,
@RequestParam(defaultValue = "20") int size
) {
ErrorLogDto.ErrorSearchReq searchReq = new ErrorLogDto.ErrorSearchReq(logErrorLevel, eventType, startDate, endDate, page, size, "created_dttm,desc");
Page<ErrorLogDto.Basic> result = errorLogCoreService.findLogByError(searchReq);
return ApiResponseDto.ok(result);
}
}

View File

@@ -0,0 +1,181 @@
package com.kamco.cd.kamcoback.log.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class AuditLogDto {
@Schema(name = "AuditLogBasic", description = "감사로그 기본 정보")
@Getter
public static class Basic {
@JsonIgnore
private final Long id;
private final Long userUid;
private final EventType eventType;
private final EventStatus eventStatus;
private final String menuUid;
private final String ipAddress;
private final String requestUri;
private final String requestBody;
private final Long errorLogUid;
@JsonFormatDttm
private final ZonedDateTime createdDttm;
public Basic(
Long id,
Long userUid,
EventType eventType,
EventStatus eventStatus,
String menuUid,
String ipAddress,
String requestUri,
String requestBody,
Long errorLogUid,
ZonedDateTime createdDttm) {
this.id = id;
this.userUid = userUid;
this.eventType = eventType;
this.eventStatus = eventStatus;
this.menuUid = menuUid;
this.ipAddress = ipAddress;
this.requestUri = requestUri;
this.requestBody = requestBody;
this.errorLogUid = errorLogUid;
this.createdDttm = createdDttm;
}
}
@Schema(name = "AuditList", description = "감사 로그 목록")
@Getter
@AllArgsConstructor
public static class AuditList {
private int readCount;
private int cudCount;
private int printCount;
private int downloadCount;
private Long totalCount;
private Long accountId;
private String loginId;
private String username;
private LocalDateTime baseDate;
private Long menuId;
private String menuName;
public AuditList(LocalDateTime baseDate, int readCount, int cudCount, int printCount, int downloadCount, Long totalCount){
this.baseDate = baseDate;
this.readCount = readCount;
this.cudCount = cudCount;
this.printCount = printCount;
this.downloadCount = downloadCount;
this.totalCount = totalCount;
}
}
@Schema(name = "AuditDetail", description = "감사 로그 상세")
@Getter
@AllArgsConstructor
public static class AuditDetail {
private Long logId;
private LocalDateTime logDateTime;
private EventType eventType;
private LogDetail detail;
private String userName;
private String loginId;
private String menuName;
}
@Getter
@Setter
@AllArgsConstructor
public static class LogDetail{
String serviceName;
String parentMenuName;
String menuName;
String menuUrl;
String menuDescription;
int sortOrder;
boolean used;
}
@Schema(name = "LogDailySearchReq", description = "일자별 로그 검색 요청")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class DailySearchReq {
private LocalDate startDate;
private LocalDate endDate;
// 일자별 로그 검색 조건
private LocalDate logDate;
// 페이징 파라미터
private int page = 0;
private int size = 20;
private String sort;
public Pageable toPageable() {
if (sort != null && !sort.isEmpty()) {
String[] sortParams = sort.split(",");
String property = sortParams[0];
Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property));
}
return PageRequest.of(page, size);
}
}
@Schema(name = "MenuUserSearchReq", description = "메뉴별,사용자별 로그 검색 요청")
@Getter
@Setter
@NoArgsConstructor
public static class MenuUserSearchReq {
// 메뉴별, 사용자별 로그 검색 조건
private String searchValue;
private String menuUid;
private Long userUid; //menuId, userUid 조회
// 페이징 파라미터
private int page = 0;
private int size = 20;
private String sort;
public MenuUserSearchReq(String searchValue, String menuUid, Long userUid, int page, int size, String sort) {
this.searchValue = searchValue;
this.menuUid = menuUid;
this.page = page;
this.size = size;
this.sort = sort;
}
public Pageable toPageable() {
if (sort != null && !sort.isEmpty()) {
String[] sortParams = sort.split(",");
String property = sortParams[0];
Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property));
}
return PageRequest.of(page, size);
}
}
}

View File

@@ -0,0 +1,121 @@
package com.kamco.cd.kamcoback.log.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class ErrorLogDto {
@Schema(name = "ErrorLogBasic", description = "에러로그 기본 정보")
@Getter
public static class Basic {
@JsonIgnore
private final Long id;
private final String requestId;
private final EventType errorType;
private final LogErrorLevel errorLevel;
private final String errorCode;
private final String errorMessage;
private final String stackTrace;
private final Long handlerUid;
@JsonFormatDttm
private final ZonedDateTime handledDttm;
@JsonFormatDttm
private final ZonedDateTime createdDttm;
public Basic(
Long id,
String requestId,
EventType errorType,
LogErrorLevel errorLevel,
String errorCode,
String errorMessage,
String stackTrace,
Long handlerUid,
ZonedDateTime handledDttm,
ZonedDateTime createdDttm) {
this.id = id;
this.requestId = requestId;
this.errorType = errorType;
this.errorLevel = errorLevel;
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.stackTrace = stackTrace;
this.handlerUid = handlerUid;
this.handledDttm = handledDttm;
this.createdDttm = createdDttm;
}
}
@Schema(name = "ErrorSearchReq", description = "에러로그 검색 요청")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ErrorSearchReq {
LogErrorLevel errorLevel;
EventType eventType;
LocalDate startDate;
LocalDate endDate;
// 페이징 파라미터
private int page = 0;
private int size = 20;
private String sort;
public ErrorSearchReq(LogErrorLevel errorLevel, EventType eventType, LocalDate startDate, LocalDate endDate, int page, int size) {
this.errorLevel = errorLevel;
this.eventType = eventType;
this.startDate = startDate;
this.endDate = endDate;
this.page = page;
this.size = size;
}
public Pageable toPageable() {
if (sort != null && !sort.isEmpty()) {
String[] sortParams = sort.split(",");
String property = sortParams[0];
Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property));
}
return PageRequest.of(page, size);
}
}
public enum LogErrorLevel implements EnumType {
WARNING("Warning"),
ERROR("Error"),
CRITICAL("Critical");
private final String desc;
LogErrorLevel(String desc) {
this.desc = desc;
}
@Override
public String getId() { return name(); }
@Override
public String getText() { return desc; }
}
}

View File

@@ -0,0 +1,20 @@
package com.kamco.cd.kamcoback.log.dto;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum EventStatus implements EnumType {
SUCCESS("이벤트 결과 성공"),
FAILED("이벤트 결과 실패");
private final String desc;
@Override
public String getId() { return name(); }
@Override
public String getText() { return desc; }
}

View File

@@ -0,0 +1,25 @@
package com.kamco.cd.kamcoback.log.dto;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum EventType implements EnumType {
CREATE("생성"),
READ("조회"),
UPDATE("수정"),
DELETE("삭제"),
DOWNLOAD("다운로드"),
PRINT("출력"),
OTHER("기타");
private final String desc;
@Override
public String getId() { return name(); }
@Override
public String getText() { return desc; }
}