비즈니스 로그 조회 API 및 처리 추가

This commit is contained in:
2025-03-19 10:58:19 +09:00
parent 2cacd7a656
commit 1e20e5ddf7
13 changed files with 804 additions and 1 deletions

View File

@@ -0,0 +1,25 @@
package com.caliverse.admin.domain.api;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.LogResponse;
import com.caliverse.admin.domain.service.LogService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Tag(name = "로그", description = "로그 api")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/log")
public class LogController {
private final LogService logService;
@PostMapping("/generic/list")
public ResponseEntity<LogResponse> genericlist(
@RequestBody LogGenericRequest logGenericRequest){
return ResponseEntity.ok().body( logService.genericLogList(logGenericRequest));
}
}

View File

@@ -0,0 +1,8 @@
package com.caliverse.admin.domain.entity.common;
public enum SearchUserType {
NONE,
GUID,
NICKNAME,
ACCOUNT
}

View File

@@ -0,0 +1,39 @@
package com.caliverse.admin.domain.request;
import com.caliverse.admin.domain.entity.common.SearchUserType;
import com.caliverse.admin.logs.entity.LogAction;
import com.caliverse.admin.logs.entity.LogDomain;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogGenericRequest {
@JsonProperty("search_type")
private SearchUserType searchType;
@JsonProperty("search_data")
private String searchData;
@JsonProperty("log_action")
private LogAction logAction;
@JsonProperty("log_domain")
private LogDomain logDomain;
@JsonProperty("tran_id")
private String tranId;
@JsonProperty("start_dt")
private LocalDateTime startDt;
@JsonProperty("end_dt")
private LocalDateTime endDt;
@JsonProperty("page_no")
private Integer pageNo;
@JsonProperty("page_size")
private Integer pageSize;
@JsonProperty("order_by")
private String orderBy;
}

View File

@@ -0,0 +1,45 @@
package com.caliverse.admin.domain.response;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogResponse {
private int status;
private String result;
@JsonProperty("data")
private ResultData resultData;
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class ResultData {
private String message;
@JsonProperty("generic_list")
// private List<Map<String, Object>> genericList;
private List<GenericMongoLog> genericList;
private int total;
@JsonProperty("total_all")
private int totalAll;
@JsonProperty("page_no")
private int pageNo;
}
}

View File

@@ -0,0 +1,97 @@
package com.caliverse.admin.domain.service;
import com.caliverse.admin.Indicators.Indicatorsservice.aggregationservice.*;
import com.caliverse.admin.Indicators.entity.*;
import com.caliverse.admin.domain.entity.Currencys;
import com.caliverse.admin.domain.entity.LandInfo;
import com.caliverse.admin.domain.entity.ROUTE;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.IndicatorsResponse;
import com.caliverse.admin.domain.response.LandResponse;
import com.caliverse.admin.domain.response.LogResponse;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.ExcelUtils;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsDauService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsMcuService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsNruService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.MongoCommandException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class LogService {
private final BusinessLogGenericService businessLogGenericService;
public LogResponse genericLogList(LogGenericRequest logGenericRequest){
int page = logGenericRequest.getPageNo();
int size = logGenericRequest.getPageSize();
LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
logGenericRequest.setStartDt(startDt);
logGenericRequest.setEndDt(endDt);
// List<Map<String, Object>> logList = businessLogGenericService.loadBusinessLogData(logGenericRequest);
List<GenericMongoLog> logList = new ArrayList<>();
try{
logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericMongoLog.class);
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
.build();
} else {
log.error("MongoDB Query error", e);
return LogResponse.builder()
.status(CommonCode.ERROR.getHttpStatus())
.result(ErrorCode.ERROR_MONGODB_QUERY.toString())
.build();
}
}catch (Exception e){
log.error("businessLog error", e);
}
int totalItems = logList.size();
int totalPages = (int) Math.ceil((double) totalItems / size);
page = (totalItems > 0 && page > totalPages) ? totalPages : page;
List<GenericMongoLog> pagedList = (totalItems == 0) ?
new ArrayList<>() :
logList.subList((page - 1) * size, Math.min((page - 1) * size + size, totalItems));
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.genericList(pagedList)
.total(pagedList.size())
.totalAll(totalItems)
.pageNo(logGenericRequest.getPageNo() != null ?
page : 1)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
}

View File

@@ -61,12 +61,17 @@ public enum ErrorCode {
ERROR_AUCTION_LAND_OWNER("해당 랜드는 소유자가 존재하여 경매를 진행할 수 없습니다."),
ERROR_LAND_OWNER_CHANGES_RESERVATION("소유권 변경 예약을 취소할 수 없는 상태입니다."),
ERROR_LAND_OWNER_CHANGES_DUPLICATION("등록된 소유권 변경 존재합니다."),
ERROR_LAND_OWNER_DUPLICATION("해당 랜드는 소유자가 존재합니다."),
//Battle
ERROR_BATTLE_EVENT_TIME_OVER("해당 시간에 속하는 이벤트가 존재합니다."),
ERROR_BATTLE_EVENT_STATUS_IMPOSSIBLE("수정할 수 없는 이벤트상태입니다."),
ERROR_BATTLE_EVENT_STATUS_START_IMPOSSIBLE("진행중인 이벤트상태입니다."),
//mongoDB
ERROR_LOG_MEMORY_LIMIT("데이터가 많아 메모리 초과"),
ERROR_MONGODB_QUERY("디비 조회 에러"),
//------------------------------------------------------------------------------------------------------------------------------
// DyanamoDB
//------------------------------------------------------------------------------------------------------------------------------

View File

@@ -23,6 +23,7 @@ public class AdminConstants {
public static final String MONGO_DB_KEY_MESSAGE = "message";
public static final String MONGO_DB_KEY_USER_GUID = "userGuid";
public static final String MONGO_DB_KEY_USER_NICKNAME = "userNickname";
public static final String MONGO_DB_KEY_ACCOUNT_ID = "accountId";
public static final String MONGO_DB_KEY_ACCOUNT_IDS_COUNT = "accountIdListCount";
public static final String MONGO_DB_KEY_LANGUAGE_TYPE = "languageType";
@@ -30,6 +31,7 @@ public class AdminConstants {
public static final String MONGO_DB_KEY_LOGOUT_TIME = "logoutTime";
public static final String MONGO_DB_KEY_TRAN_ID = "tranId";
public static final String MONGO_DB_KEY_ACTION = "action";
public static final String MONGO_DB_KEY_DOMAIN = "domain";
public static final String MONGO_DB_KEY_SERVER_TYPE = "serverType";
public static final String MONGO_DB_KEY_USER_GUID_LIST = "userGuidList";

View File

@@ -0,0 +1,17 @@
package com.caliverse.admin.logs.Indicatordomain;
import com.caliverse.admin.global.common.constants.AdminConstants;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Map;
@Document(collection = AdminConstants.MONGO_DB_COLLECTION_LOG)
@Getter
@Setter
public class GenericMongoLog extends MongoLogSearchBase{
// private Map<String, Object> parseMessage;
private Map<String, Object> header;
private Map<String, Object> body;
}

View File

@@ -14,9 +14,13 @@ public abstract class MongoLogSearchBase {
private String logDay;
private String logHour;
private String logMinute;
private String message;
// private String message;
private String languageType;
private String userGuid;
private String userNickname;
private String accountId;
private String action;
private String domain;
private String tranId;
}

View File

@@ -0,0 +1,225 @@
package com.caliverse.admin.logs.entity;
public enum LogAction {
None(""),
AICHAT_DELETE_CHARACTER("NPC 삭제"),
AICHAT_DELETE_USER("유저 삭제"),
AICHAT_GET_CHARACTER("NPC 조회"),
AICHAT_INCENTIVE_MARKING("인센티브 획득 마킹"),
AICHAT_INCENTIVE_SEARCH("인센티브 조회"),
AICHAT_JWT_ISSUE("Jwt 토큰 발행"),
AICHAT_JWT_VERIFY("Jwt 토큰 확인"),
AICHAT_POINT_CHARGE("포인트 충전"),
AICHAT_POINT_CHARGE_VERIFY("포인트 충전 확인"),
AICHAT_REGISTER_CHARACTER("NPC 등록"),
AICHAT_REGISTER_USER("유저 등록"),
AICHAT_UPDATE_CHARACTER("NPC 정보 업데이트"),
BATTLE_INSTANCE_JOIN("배틀 인스턴스 조인"),
BATTLE_INSTANCE_SNAPSHOT_CREATE("배틀 인스턴스 스냅샷 생성"),
BATTLE_INSTANCE_SNAPSHOT_SAVE("배틀 인스턴스 스냅샷 저장"),
BATTLE_OBJECT_INTERACTION("배틀 오브젝트 상호작용"),
BATTLE_OBJECT_STATE_UPDATE("배틀 오브젝트 상태 변경"),
BATTLE_POD_COMBAT_OCCUPY_REWARD("포드 컴뱃 소유 보상"),
BATTLE_ROUND_STATE_UPDATE("배틀 라운드 스테이트 업데이트"),
BATTLE_USER_DEAD("유저 데드"),
BATTLE_USER_RESPAWN("배틀 리스폰"),
BROKER_API_ADMIN("BrokerApi 어드민 재화 지급"),
BROKER_API_PLANET_AUTH("BrokerApi Planet 인증"),
BROKER_API_USER_EXCHANGE_COMPLETE("BrokerApi 재화 교환 완료"),
BROKER_API_USER_EXCHANGE_ORDER("BrokerApi 재화 교환 주문"),
BROKER_API_USER_LOGIN("BrokerApi 유저 로그인"),
BUFF_ADD("버프 추가"),
BUFF_DELETE("버프 제거"),
CALIUM_CONVERTER_ROLLBACK_FAIL("칼리움 컨버터 롤백 실패"),
CALIUM_CONVERT("칼리움 컨버터 변환"),
CALIUM_CONVERT_EXCHANGE("칼리움 교환소 변환"),
CALIUM_CONVERT_INFO_CHANGE("칼리움 정보 변환"),
CALIUM_CREATE_CONTENT("칼리움 컨텐츠 생성"),
CALIUM_ECHO_SYSTEM_FAIL("칼리움 에코시스템 실패"),
CALIUM_FILLUP("칼리움 총량 누적"),
CALIUM_SYNC_ECHO_SYSTEM("칼리움 동기화 처리"),
CART_ADD("장바구니 추가"),
CART_DELETE("장바구니 삭제"),
CART_PURCHASE("장바구니 구매"),
CHALL_CHANNEL("채널 채팅"),
CHAT_NORMAL("노말 채팅"),
CHAT_NOTICE("전서버 채팅"),
CHAT_PARTY("파티 채팅"),
CHAT_WHISPER("귓속말 채팅"),
CHARACTER_APPEARANCE_CUSTOMIZE("캐리터 외형 커스터마이징"),
CHARACTER_APPEARANCE_UPDATE("캐릭터 외형 갱신"),
CHARACTER_CREATE("캐릭터 생성(자동 생성)"),
CHARACTER_LOADING("캐릭터 로딩"),
CHEAT_ALL_CRAFT_FINISH("치트로 인한 모든 제작 시간 단축"),
CHEAT_COMMAND_CHANGE_NICK_NAME("치트로 인한 캐릭터 명 변경"),
CHEAT_COMMAND_CHARACTER_INIT("치트로 인한 캐릭터 초기화"),
CHEAT_COMMAND_CLAIM_RESET("치트로 인한 클레임 리워드 리셋"),
CHEAT_COMMAND_CLAIM_UPDATE("치트로 인한 클레임 리워드 대기시간 단축"),
CHEAT_COMMAND_CRAFT_HELP_INIT("치트로 인한 제작 헬프 초기화"),
CHEAT_COMMAND_DELETE_QUEST("치트로 인한 퀘스트 삭제"),
CHEAT_COMMAND_GAIN_LAND("치트로 인한 랜드 획득"),
CHEAT_COMMAND_INCREASE_EXP("치트로 인한 시즌 패스 경험치 증가"),
CHEAT_COMMAND_ITEM("치트로 인한 아이템 추가 삭제"),
CHEAT_COMMAND_ITEM_LEVEL_UP("치트로 인한 아이템 레벨 업"),
CHEAT_COMMAND_LAND_AUCTION_BLIND_SET("치트로 인한 랜드 경매 블라이인드 입찰 설정"),
CHEAT_COMMAND_LAND_AUCTION_CANEL("치트로 인한 랜드 경매 취소"),
CHEAT_COMMAND_LAND_AUCTION_RESERVE("치트로 인한 랜드 경매 예약"),
CHEAT_COMMAND_LAND_AUCTION_START("치트로 인한 랜드 경매 시작"),
CHEAT_COMMAND_PACKAGE_SEND("치트로 인한 패키지 메일 전송"),
CHEAT_COMMAND_QUEST_ACCEPT("치트로 인한 퀘스트 할당"),
CHEAT_COMMAND_QUEST_COMPLETE("치트로 인한 퀘스트 완료"),
CHEAT_COMMAND_REGISTER_CRAFT_RECIPE("치트로 인한 레시피 등록"),
CHEAT_COMMAND_RESET_ALL_QUEST("치트로 인한 퀘스트 리셋"),
CHEAT_COMMAND_RESET_ESCAPE_POSITION("치트로 인한 탈출시간 리셋"),
CHEAT_COMMAND_RESET_MAIL_COUNT("치트로 인한 메일 횟수 제한 초기화"),
CHEAT_COMMAND_SEASON_PASS_INIT("치트로 인한 시즌 패스 초기화"),
CHEAT_COMMAND_SEND_MAIL("치트로 인한 메일 발송"),
CHEAT_COMMAND_SHOP_PRODUCT_INIT("치트로 인한 상점 품목 초기화"),
CHEAT_COMMAND_SHOP_PRODUCT_RENEWAL("치트로 인한 상점 갱신 전송"),
CLAIM_REWARD("클레임 리워드 이벤트 보상"),
CRAFT_FINISH("제작 완료"),
CRAFT_HELP("제작 도움"),
CRAFT_RECIPE_REGISTER("제작 레시피 추가"),
CRAFT_START("제작 시작"),
CRAFT_STOP("제작 취소"),
CREATE_PARTY("파티 생성"),
CREATE_PARTY_INSTANCE("파티 던전 생성"),
DAILY_QUEST_CHECK("데일리 퀘스트 체크"),
DANCE_ENTITY_STATE_END("캐릭터 엔티티 스테이트 댄스 종료"),
DANCE_ENTITY_STATE_START("캐릭터 엔티티 스테이트 댄스 시작"),
DESTROY_PARTY("파티 파괴"),
ENTER_MYHOME("마이홈 입장"),
ENTER_MYHOME_EDIT_ROOM("마이홈 에디트 룸 입장"),
FARMING_CANCEL("파밍 취소"),
FARMING_COMPLETE("파밍 완료"),
FARMING_INCOMPLETED_REWARD("파밍 미완료 보상"),
FARMING_START("파밍 시작"),
FRIEND_ADD("친구추가"),
FRIEND_DELETE("친구삭세"),
GAIN_LAND_PROFIT("랜드 수익 획득"),
IGM_API_LOGIN("igmApi 로그인"),
INVITE_PARTY("파티 초대"),
ITEM_BUY("아이템 구매"),
ITEM_DESTROY("아이템 제거"),
ITEM_RANDOM_BOX_USE("아이템 랜덤박스 사용"),
ITEM_TATTOO_CHANGE_ATTRIBUTE("타투 아이템 속성변환"),
ITEM_TATTOO_LEVEL_UP("타투 아이템 강화"),
ITEM_USE("아이템 사용"),
JOIN_INSTANCE("인스턴스 입장"),
JOIN_PARTY("파티 가입"),
JOIN_PARTY_INSTANCE("파티 인스턴스 입장"),
KICK_FRIENDS_FROM_MYHOME("마이홈에서 친구 내쫒기"),
LAND_AUCTION_ACTIVITY("랜드 경매 활성화"),
LAND_AUCTION_BID("랜드 경매 입찰"),
LAND_AUCTION_BID_PRICE_REFUND("랜드 경매 입찰금 환급"),
LAND_AUCTION_CHECK("랜드 경매 체크"),
LEAVE_INSTANCE("인스턴스 퇴장"),
LEAVE_PARTY("파티 탈퇴"),
LEAVE_PARTY_INSTANCE("파티 인스턴스 퇴장"),
LOGIN_TO_GAME("게임 로그인"),
LOGIN_TO_GAME_SNAPSHOT("게임 로그인 스냅샷"),
LOGIN_TO_USER_AUTH("계정 로그인"),
MAIL_AI_CHAT_INCENTIVE_POINT("AI Chat 인센티브 우편 지급"),
MAIL_DESTROY("우편 삭제"),
MAIL_GET_SYSTEM_MAIL("시스템 우편 받기"),
MAIL_INIT_SEND_COUNT("우편 보내기 기회 초기화"),
MAIL_READ("우편 읽기"),
MAIL_SEND("우편 발송"),
MAIL_TAKEN("우편 첨부 수령"),
MODIFY_LAND_INFO("랜드 정보 수정"),
MONEY_CHANGE("재화 변경"),
PRODUCT_GIVE("결제 상품 지급"),
PRODUCT_OPEN_FAILED("결제 상품 오픈 실패"),
PRODUCT_OPEN_SUCCESS("결제 상품 오픈 성공"),
QUEST_MAIL_SEND("퀘스트 우편 발송"),
QUEST_MAIN_ABORT("퀘스트 메인 포기"),
QUEST_MAIN_ASSIGN_BY_DIALOGUE("대화를 통한 퀘스트 메인 수락"),
QUEST_MAIN_ASSIGN_FORCE("퀘스트 메인 강제 수락"),
QUEST_MAIN_REFUSE("퀘스트 메인 수락 거절"),
QUEST_MAIN_REPEAT_TIME_INIT("반복가능 퀘스트 리프레시 타임 초기화"),
QUEST_MAIN_REPEAT_TIME_REFRESH("반복가능 퀘스트 리프레시 타임 갱신"),
QUEST_MAIN_REWARD("퀘스트 메인 보상"),
QUEST_MAIN_TASK("퀘스트 메인 태스크관련"),
QUEST_TASK_UPDATE("퀘스트 태스크 업데이트"),
RENAME_FRIEND_FOLDER("친구 폴더면 수정"),
RENAME_MYHOME("마이홈 이름 변경"),
RENEWAL_SHOP_PRODUCTS("사용자 요청에 의한 상픔 리스트 갱심"),
RENT_FLOOR("빌딩 층 임대"),
REPLY_INVITE_PARTY("파티 초대 응답"),
REPLY_SUMMON_PARTY("파티 맴버 소환 응답"),
RESERVATION_ENTER_TO_SERVER("서버 이동 예약"),
REWARD_PROP("리워드 프랍"),
SAVE_MYHOME("마이홈 저장"),
SEASON_PASS_BUY_CHARGED("시즌 패스 유료 구입"),
SEASON_PASS_START_NEW("새로운 시즌 패스 시작"),
SEASON_PASS_TAKE_REWARD("시즌 패스 보상 획득"),
SHOP_CHANGE_PRODUCT_TRADING_METER("상품 리스트 갱신"),
SHOP_GET_PRODUCT_TRADING_METER("상품 리스트 조회"),
SHOP_GET_REPURCHASE("판매한 상품 리스트 조회"),
SHOP_PURCHASE("상품 구매"),
SHOP_REPURCHASE("판매한 상품 재구매"),
SHOP_SELL("상품 판매"),
STAGE_CONCERT_START("콘서트 시작"),
STAGE_ENTER("스테이지 입장"),
STAGE_EXIT("스테이지 퇴장"),
START_PARTY_VOTE("파티 투표 시작"),
SUMMON_PARTY("파티 맴버 소환"),
SWITCHING_PROP("데일리 퀘스트 체크"),
TASK_RESERVATION_COMPLETE("Task Reservation complete"),
TAXI_MOVE("택시 이동"),
TEST_BUSINESS_LOG("테스트 비지니스 로그 전송"),
TEST_USER_CREATE("테스트 계정으로 생성"),
TEST_USER_INITIAL("테스트 계정으로 초기화"),
TEST_WRITE_NOTICE_CHAT("테스트 공지사항 추가"),
TEST_WRITE_SYSTEM_MAIL("테스트 시스템 메일 추가"),
UGQ_ABORT("Ugq 포기"),
UGQ_API_ADMIN_LOGIN("UgqApi 어드민 로그인"),
UGQ_API_CHANGE_STATE("UgqApi Ugq 상태 변경"),
UGQ_API_CREATOR_POINT("UgqApi CreatorPoint 증감"),
UGQ_API_LOGIN("UgqApi 로그인"),
UGQ_API_LOGOUT("UgqApi 로그아웃"),
UGQ_API_QUEST_CRAETE("UgqApi 퀘스트 생성"),
UGQ_API_ADD_SLOT("UgqApi 슬롯 추가"),
UGQ_ASSIGN("Ugq 수락"),
UGQ_DAILY_REWARD_COUNT_REFRESH("Ugq 데일리 보상 리프레시"),
UGQ_DEREGISTER_BOOKMARK("Ugq 북마크 해제"),
UGQ_DEREGISTER_LIKE("Ugq 좋아요 해제"),
UGQ_REASSIGN("Ugq 재수락"),
UGQ_REGISTER_BOOKMARK("Ugq 북마크 등록"),
UGQ_REGISTER_LIKE("Ugq 좋아요 등록"),
UGQ_TEST_ABORT("Test Ugq 포기"),
UGQ_TEST_ASSIGN("Test Ugq 수락"),
UGQ_TEST_DELETE("Test Ugq 삭제"),
UPDATE_BEACON_APPEARANCE_CUSTOMIZE("비컨 외형 커스터마이징"),
UPDATE_CHARACTER_PROFILE("캐릭터 프로필 업데이트"),
UPDATE_CUSTOM_DEFINE_UI("커스텀 UI 업데이트"),
UPDATE_ESCAPE("유저 탈출"),
UPDATE_GAME_OPTION("게임 옵션 업데이트"),
UPDATE_LANGUAGE("유저 언어 업데이트"),
UPDATE_UGC_NPC_LIKE("NPC Like 업데이트"),
USER_BLOCK("유저 차단"),
USER_BLOCK_CANCEL("유저 차단 취소"),
USER_CREATE("유저 생성"),
USER_LOADING("유저 로딩"),
USER_LOGOUT("유저 로그아웃"),
USER_LOGOUT_SNAPSHOT("게임 로그아웃 스냅샷"),
USER_REPORT("유저 신고"),
WARP("워프");
private final String description;
LogAction(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return name() + "(" + description + ")";
}
}

View File

@@ -0,0 +1,93 @@
package com.caliverse.admin.logs.entity;
public enum LogDomain {
BASE(""),
AuthLogInOut("인증 로그인/인증 로그아웃"),
GameLogInOut("게임 로그인/게임 로그아웃"),
UserCreate("유저 생성"),
User("유저"),
UserInitial("유저 초기화"),
CharacterCreate("캐릭터 생성"),
Character("캐릭터"),
Item("아이템"),
Currency("재화"),
Mail("우편"),
MailStoragePeriodExpired("메일 보관 기간 만료 삭제"),
MailProfile("우편 제한 개요"),
Stage("스테이지"),
ClaimReward("클레임 리워드"),
QuestMain("퀘스트 메인"),
QuestUgq("퀘스트 Ugq"),
QuestMail("퀘스트 메일"),
SocialAction("소셜 액션"),
MyHome("마이홈"),
Taxi("택시"),
RewardProp("리워드 프랍"),
Party("파티"),
PartyMember("파티 맴버"),
PartyVote("파티 투표"),
PartyInstance("파티 인스턴스"),
EscapePosition("고립탈출"),
UserBlock("유저 차단"),
Friend("친구"),
UserReport("유저 신고"),
TaskReservation("처리못한 예약 테스크"),
SeasonPass("시즌 패스"),
PackageLastOrderRecode("패키지 마지막 획득 기록"),
PackageRepeat("패키지 연속 지급"),
PackageState("패키지 상태"),
Craft("제작"),
CraftHelp("제작 도움"),
Cart("카트"),
Buff("버프"),
UgqApi("UgqApi"),
AIChat("AI채팅"),
Chat("채팅"),
Shop("상점"),
Calium("칼리움"),
CaliumEchoSystem("칼리움 에코 시스템"),
CaliumStorageFail("칼리움 저장 실패"),
Position("위치"),
Address("주소"),
BeaconCreate("비컨 생성"),
Beacon("비컨"),
CustomDefineUi("CustomDefineUi"),
Farming("파밍"),
FarmingReward("파밍 보상"),
RenewalShopProducts("상점 리뉴얼"),
CheatRenewalShopProducts("상점 리뉴얼 치트"),
ChangeDanceEntityState("댄스 엔티티 상태 변경"),
Land("랜드"),
Building("빌딩"),
SwitchingProp("스위칭프랍"),
LandAuction("랜드 경매"),
LandAuctionActivity("랜드 경매 활성화"),
LandAuctionBid("랜드 경매 입찰"),
LandAuctionBidPriceRefund("랜드 경매 입찰금 환급"),
BrokerApi("BrokerApi"),
Rental("랜탈"),
BuildingProfit("빌딩 수익"),
BattleObjectInteraction("전투 오브젝트 인터렉션"),
BattleObjectStateUpdate("전투 오브젝트 상태 업데이트"),
BattleReward("전투 보상"),
BattleRespawn("전투 리스폰"),
BattleRoomJoin("전투 입장"),
BattleDead("전투 죽음"),
BattleRound("전투 라운드"),
BattleSnapshot("전투 스냅샷");
private final String description;
LogDomain(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return name() + "(" + description + ")";
}
}

View File

@@ -0,0 +1,209 @@
package com.caliverse.admin.logs.logservice.businesslogservice;
import com.caliverse.admin.domain.entity.common.SearchUserType;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.logs.entity.LogAction;
import com.caliverse.admin.logs.entity.LogDomain;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import java.util.*;
@Slf4j
@Service
public class BusinessLogGenericService extends BusinessLogServiceBase {
public BusinessLogGenericService(@Qualifier("mongoBusinessLogTemplate") MongoTemplate mongoTemplate) {
super(mongoTemplate);
}
// public List<Map<String, Object>> loadBusinessLogData(LogGenericRequest logGenericRequest) {
public <T> List<T> loadBusinessLogData(LogGenericRequest logGenericRequest, Class<T> class1) {
String startTime = logGenericRequest.getStartDt().toString().substring(0, 10);
String endTime = logGenericRequest.getEndDt().toString().substring(0, 10);
LogAction logAction = logGenericRequest.getLogAction();
LogDomain logDomain = logGenericRequest.getLogDomain();
SearchUserType searchUserType = logGenericRequest.getSearchType();
String searchData = logGenericRequest.getSearchData();
String tranId = logGenericRequest.getTranId();
Criteria criteria = makeCriteria(startTime, endTime);
List<AggregationOperation> operations = setDefaultOperation(criteria);
//message json parsing
operations.add(context ->
new Document("$addFields",
new Document("parseMessage",
new Document("$function",
new Document("body", "function(jsonString) { try { return JSON.parse(jsonString); } catch(e) { return {}; } }")
.append("args", Arrays.asList("$message"))
.append("lang", "js")
)
)
)
);
operations.add(context ->
new Document("$addFields",
new Document("header","$parseMessage.Header")
.append("body","$parseMessage.Body")
)
);
if(logAction != null && !logAction.equals(LogAction.None)) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_ACTION, logAction.name())
)
);
}
if(logDomain != null && !logDomain.equals(LogDomain.BASE)) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_DOMAIN, logDomain.name())
)
);
}
if(searchUserType != null && !searchData.isEmpty() && !searchUserType.equals(SearchUserType.NONE)) {
switch(searchUserType){
case ACCOUNT:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID, searchData)
)
);
break;
case GUID:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_USER_GUID, searchData)
)
);
break;
case NICKNAME:
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_USER_NICKNAME, searchData)
)
);
break;
}
}
if(tranId != null && !tranId.isEmpty()) {
operations.add(context ->
new Document("$match",
new Document(AdminConstants.MONGO_DB_KEY_TRAN_ID, tranId)
)
);
}
// 최종 출력 형식
operations.add(context ->
new Document("$sort",
new Document("logTime", logGenericRequest.getOrderBy().equals("ASC") ? 1 : -1)
.append(AdminConstants.MONGO_DB_KEY_TRAN_ID, 1)
)
);
Aggregation aggregation = Aggregation.newAggregation(operations);
log.info("loadBusinessLogData Generic Query: {}", aggregation);
// try {
AggregationResults<T> results = getMongoTemplate()
.aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, class1);
return results.getMappedResults();
// }catch(Exception e){
// log.error("BusinessLog query error", e);
// return null;
// }
// AggregationResults<Document> results = getMongoTemplate().aggregate(aggregation, AdminConstants.MONGO_DB_COLLECTION_LOG, Document.class);
//
// List<Map<String, Object>> logMaps = new ArrayList<>();
// for (Document doc : results.getMappedResults()) {
// logMaps.add(flattenDocument(doc));
// }
//
// return logMaps;
}
protected Criteria makeCriteria(String startTime, String endTime) {
return new Criteria()
.andOperator(
Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).gte(startTime).lt(endTime)
);
}
private Map<String, Object> flattenDocument(Document document) {
Map<String, Object> result = new LinkedHashMap<>();
flattenDocumentRecursive(document, "", result);
return result;
}
private void flattenDocumentRecursive(Object obj, String prefix, Map<String, Object> result) {
if (obj instanceof Document) {
Document doc = (Document) obj;
for (String key : doc.keySet()) {
Object value = doc.get(key);
String newKey = prefix.isEmpty() ? key : prefix + "." + key;
if (value instanceof Document || value instanceof Map) {
flattenDocumentRecursive(value, newKey, result);
} else if (value instanceof List) {
// 리스트의 각 항목에 대해 처리
List<?> list = (List<?>) value;
result.put(newKey, list);
// 리스트 항목이 복잡한 객체인 경우 각각 평탄화
for (int i = 0; i < list.size(); i++) {
Object listItem = list.get(i);
if (listItem instanceof Document || listItem instanceof Map) {
flattenDocumentRecursive(listItem, newKey + "[" + i + "]", result);
}
}
} else {
result.put(newKey, value);
}
}
} else if (obj instanceof Map) {
Map<?, ?> map = (Map<?, ?>) obj;
for (Map.Entry<?, ?> entry : map.entrySet()) {
String key = entry.getKey().toString();
Object value = entry.getValue();
String newKey = prefix.isEmpty() ? key : prefix + "." + key;
if (value instanceof Document || value instanceof Map) {
flattenDocumentRecursive(value, newKey, result);
} else if (value instanceof List) {
// 리스트의 각 항목에 대해 처리
List<?> list = (List<?>) value;
result.put(newKey, list);
// 리스트 항목이 복잡한 객체인 경우 각각 평탄화
for (int i = 0; i < list.size(); i++) {
Object listItem = list.get(i);
if (listItem instanceof Document || listItem instanceof Map) {
flattenDocumentRecursive(listItem, newKey + "[" + i + "]", result);
}
}
} else {
result.put(newKey, value);
}
}
}
}
}

View File

@@ -43,6 +43,12 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
.append("regex", "\"UserGuid\":\"([^\"]+)\"")
)
)
.append(AdminConstants.MONGO_DB_KEY_USER_NICKNAME,
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"UserNickname\":\"([^\"]+)\"")
)
)
.append(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID,
new Document("$regexFind",
new Document("input", "$message")
@@ -73,6 +79,12 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
.append("regex", "\"Action\":\"([^\"]+)\"")
)
)
.append(AdminConstants.MONGO_DB_KEY_DOMAIN,
new Document("$regexFind",
new Document("input", "$message")
.append("regex", "\"Domain\":\"([^\"]+)\"")
)
)
.append(AdminConstants.MONGO_DB_KEY_SERVER_TYPE,
new Document("$regexFind",
new Document("input", "$message")
@@ -107,6 +119,16 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
)
)
)
.append(AdminConstants.MONGO_DB_KEY_USER_NICKNAME,
new Document()
.append("$ifNull", List.of(
new Document("$toString",
new Document("$arrayElemAt", List.of("$userNickname.captures", 0))
),
"None"
)
)
)
.append(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID,
new Document()
.append("$ifNull", List.of(
@@ -157,6 +179,16 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
)
)
)
.append(AdminConstants.MONGO_DB_KEY_DOMAIN,
new Document()
.append("$ifNull", List.of(
new Document("$toString",
new Document("$arrayElemAt", List.of("$domain.captures", 0))
),
""
)
)
)
.append(AdminConstants.MONGO_DB_KEY_SERVER_TYPE,
new Document()
.append("$ifNull", List.of(
@@ -195,11 +227,13 @@ public abstract class BusinessLogServiceBase implements IBusinessLogService {
.and(AdminConstants.MONGO_DB_KEY_MESSAGE).as(AdminConstants.MONGO_DB_KEY_MESSAGE)
.and(AdminConstants.MONGO_DB_KEY_LANGUAGE_TYPE).as(AdminConstants.MONGO_DB_KEY_LANGUAGE_TYPE)
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as(AdminConstants.MONGO_DB_KEY_USER_GUID)
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as(AdminConstants.MONGO_DB_KEY_USER_NICKNAME)
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID)
.and(AdminConstants.MONGO_DB_KEY_LOGIN_TIME).as(AdminConstants.MONGO_DB_KEY_LOGIN_TIME)
.and(AdminConstants.MONGO_DB_KEY_LOGOUT_TIME).as(AdminConstants.MONGO_DB_KEY_LOGOUT_TIME)
.and(AdminConstants.MONGO_DB_KEY_TRAN_ID).as(AdminConstants.MONGO_DB_KEY_TRAN_ID)
.and(AdminConstants.MONGO_DB_KEY_ACTION).as(AdminConstants.MONGO_DB_KEY_ACTION)
.and(AdminConstants.MONGO_DB_KEY_DOMAIN).as(AdminConstants.MONGO_DB_KEY_DOMAIN)
.and(AdminConstants.MONGO_DB_KEY_SERVER_TYPE).as(AdminConstants.MONGO_DB_KEY_SERVER_TYPE)
.and("message").as("message")
;