모던 대시보드 패치

- ApexCharts 기반 실시간 모니터링 대시보드
- 어댑터/배치/서버/소켓/트랜잭션 모니터링 컴포넌트
- 처리량 계산 및 데이터 매핑 서비스
This commit is contained in:
youna
2025-11-14 17:59:06 +09:00
parent 38057809cf
commit 972819b492
72 changed files with 49662 additions and 547 deletions
@@ -233,4 +233,16 @@ public class AdapterGroupService extends AbstractDataService<AdapterGroup, Strin
return query.fetch();
}
public List<AdapterGroup> findByAdptrinsticodeNotEmpty() {
QAdapterGroup qAdapterGroup = QAdapterGroup.adapterGroup;
JPAQuery<AdapterGroup> query = getJPAQueryFactory()
.selectFrom(qAdapterGroup)
.where(qAdapterGroup.adptrinsticode.isNotNull()
.and(qAdapterGroup.adptrinsticode.ne("")))
.orderBy(qAdapterGroup.adptrbzwkgroupname.asc());
return query.fetch();
}
}
@@ -1,12 +1,10 @@
package com.eactive.eai.rms.onl.dashboard.controller;
import java.util.HashMap;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.onl.dashboard.service.DashboardErrorService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -15,11 +13,11 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.onl.dashboard.service.DashboardErrorService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Vector;
@Controller
public class DashboardErrorController {
@@ -1,29 +1,5 @@
package com.eactive.eai.rms.onl.dashboard.controller;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.View;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
@@ -34,11 +10,23 @@ import com.eactive.eai.rms.onl.dashboard.dao.DashboardDAO;
import com.eactive.eai.rms.onl.dashboard.service.Dashboard2RepositoryService;
import com.eactive.eai.rms.onl.dashboard.service.DashboardService;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.AdaptersVO;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import com.eactive.eai.rms.onl.vo.RealTimeAdaptersVO;
import com.eactive.eai.rms.onl.vo.SmsVO;
import com.eactive.eai.rms.onl.vo.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.View;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
@Controller
@@ -1,12 +1,11 @@
package com.eactive.eai.rms.onl.dashboard.dao;
import java.util.HashMap;
import java.util.Vector;
import org.springframework.stereotype.Repository;
import com.eactive.eai.rms.common.base.SqlMapClientTemplateDao;
import com.ibatis.sqlmap.client.event.RowHandler;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Vector;
@Repository("dashboardDao")
public class DashboardDaoImpl extends SqlMapClientTemplateDao
@@ -1,14 +1,5 @@
package com.eactive.eai.rms.onl.dashboard.dao;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.eactive.eai.rms.common.base.SqlMapClientTemplateDao;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
@@ -16,6 +7,14 @@ import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.SpecifiedDataSourceExecutor;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.ibatis.sqlmap.client.event.RowHandler;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
@Repository("dashboardError")
@SuppressWarnings("unchecked")
@@ -0,0 +1,78 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.eactive.eai.rms.onl.dashboard.modern.service.ThroughputCalculationService;
import com.eactive.eai.rms.onl.tracking.vo.DbStaticsVo;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.MonitorDataVo;
import com.eactive.eai.rms.onl.vo.SmsVO;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Getter
@Setter
public class BackupContentVO implements Serializable {
private String backupTimestamp;
private RepositoryFields repositoryFields;
private DashboardRepository2Fields dashboardRepository2Fields;
// private ThroughputFields throughputFields; 백업 필요 없는 저장소
public BackupContentVO() {
this.backupTimestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
@Getter
@Setter
@NoArgsConstructor
public static class RepositoryFields implements Serializable {
private Map<String, MonitorDataVo> repository;
private ConcurrentHashMap<String, MonitorDataVo> repositoryNoExpire;
}
@Getter
@Setter
@NoArgsConstructor
public static class DashboardRepository2Fields implements Serializable {
private Map<String, Map<String, String>> repoEAISevrDstcd;
private Map<String, MemStaticsVo> repoMemTransaction;
private Map<String, DbStaticsVo> repository;
private Map<String, List<String>> repoHostNames;
private Map<String, List<String>> repoInstNames;
private Map<String, Map<String, List<String>>> repoDataSourceInstNames;
private Map<String, String> repoHostAlive;
private List<SmsVO> repoSms;
private Map<String, String> repoPeakTps;
private Map<String, String> repoPeakTrade;
private int[] procBatch = new int[6];
private int[] procEaiBatch = new int[6];
private Map<String, Map<String, String>> itsmDashTranInfo;
private Map<String, Map<String, String>> itsmDashPeakdayInfo;
private Map<String, List> itsmDashDayTranList;
private Map<String, List> itsmDashHourTranList;
private Map<String, Map<String, String>> itsmDashBizErrorMap;
private Map<String, Map<String, String>> itsmDashTimeoutErrorMap;
private Map<String, Map<String, String>> itsmDashConnectErrorMap;
private Map<String, Map<String, String>> itsmDashServerInstTotalProcMap;
}
@Getter
@Setter
@NoArgsConstructor
public static class ThroughputFields {
private Map<String, ThroughputCalculationService.TimeSeriesData> timeSeriesMap;
private Map<String, ThroughputCalculationService.ServerResourceData> serverResourceMap;
private Map<String, Map<String, Integer>> lastAccumulatedValuesMap;
}
}
@@ -0,0 +1,28 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Slf4j
@Controller
@RequiredArgsConstructor
public class BackupController implements InterceptorSkipController {
private final RepositoryBackupService repositoryBackupService;
@GetMapping("/removeBackupFile.do")
public ResponseEntity<String> removeBackupFile() {
try {
repositoryBackupService.removeBackupFile();
return ResponseEntity.ok("OK");
} catch (Exception e) {
log.error("FILE REMOVE FAIL", e);
return ResponseEntity.internalServerError().body(e.getMessage());
}
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.fasterxml.jackson.annotation.JsonIgnore;
public abstract class MemStaticsVoMixIn {
@JsonIgnore
public abstract int getProcTotal();
@JsonIgnore
public abstract int getErrorTotal();
@JsonIgnore
public abstract int getSysErrorTotal();
@JsonIgnore
public abstract int getTimeoutTotal();
}
@@ -0,0 +1,13 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "category",
visible = true
)
public abstract class MonitorDataVoMixIn {
}
@@ -0,0 +1,9 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public abstract class MonitorVOMixin {
@JsonCreator
public MonitorVOMixin(@JsonProperty("eaiServiceCode") String eaiServiceCode) {}
}
@@ -0,0 +1,177 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup;
import com.eactive.eai.common.monitor.MonitorVO;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.onl.dashboard.modern.backup.mapper.Dashboard2RepositoryVoMapper;
import com.eactive.eai.rms.onl.dashboard.modern.backup.mapper.RepositoryVoMapper;
import com.eactive.eai.rms.onl.dashboard.modern.backup.mapper.ThroughputVoMapper;
import com.eactive.eai.rms.onl.dashboard.repository.Dashboard2Repository;
import com.eactive.eai.rms.onl.server.repository.Repository;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.MonitorDataVo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@RequiredArgsConstructor
public class RepositoryBackupService implements ApplicationListener<ContextRefreshedEvent> {
@Value("${inst.Type:ems}")
private String instType;
@Value("${inst.Name:ems-0}")
private String instName;
private static final DateTimeFormatter BACKUP_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
private final Repository repository;
private final Dashboard2Repository dashboard2Repository;
// private final ThroughputCalculationService throughputCalculationService;
@Autowired
@Qualifier("monitoringContext")
private final MonitoringContext monitoringContext;
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final ObjectMapper objectMapper =
new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.addMixIn(MonitorDataVo.class, MonitorDataVoMixIn.class)
.addMixIn(MonitorVO.class, MonitorVOMixin.class)
.addMixIn(MemStaticsVo.class, MemStaticsVoMixIn.class);
private final RepositoryVoMapper rMapper = new RepositoryVoMapper();
private final Dashboard2RepositoryVoMapper d2rMapper = new Dashboard2RepositoryVoMapper();
private final ThroughputVoMapper tMapper = new ThroughputVoMapper();
private boolean readFlag = false;
private boolean backupFlag = true;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
String repositoryBackupEnable = monitoringContext.getProperty("repository.backup.enable", "false");
backupFlag = BooleanUtils.toBoolean(repositoryBackupEnable);
if (!backupFlag) {
return;
}
try {
// 백업 디렉토리와 경로 생성
String backupDirectory = monitoringContext.getProperty("repository.backup.path", "/log/elink/");
final Path backupFilePath = Paths.get(backupDirectory, instType, instName, "repository", "backup.json");
// 파일이 존재하고 아직 읽지 않은 경우에 진행
synchronized (this) {
if (Files.exists(backupFilePath) && !readFlag) {
String json = new String(Files.readAllBytes(backupFilePath), StandardCharsets.UTF_8);
if (StringUtils.isNotBlank(json)) {
BackupContentVO backupContentVO = objectMapper.readValue(json, BackupContentVO.class);
LocalDateTime fileTime = LocalDateTime.parse(backupContentVO.getBackupTimestamp(), BACKUP_TIMESTAMP_FORMATTER);
// 백업 파일의 날짜가 오늘보다 이전이면 삭제, 그렇지 않으면 복원 수행
if (fileTime.toLocalDate().isBefore(LocalDate.now())) {
synchronized (this) {
Files.delete(backupFilePath);
}
} else {
rMapper.setVoValuesToObject(backupContentVO.getRepositoryFields(), repository);
d2rMapper.setVoValuesToObject(backupContentVO.getDashboardRepository2Fields(), dashboard2Repository);
// tMapper.setVoValuesToObject(backupContentVO.getThroughputFields(), throughputCalculationService);
readFlag = true;
}
}
}
}
// 10분마다 BackupContentVO 생성해서 저장함
scheduler.scheduleAtFixedRate(() -> {
if (!backupFlag)
return;
log.info("Repository Data Backup");
try {
// VO
BackupContentVO backupContentVO = new BackupContentVO();
backupContentVO.setRepositoryFields(rMapper.toVo(repository));
backupContentVO.setDashboardRepository2Fields(d2rMapper.toVo(dashboard2Repository));
// backupContentVO.setThroughputFields(tMapper.toVo(throughputCalculationService));
synchronized (this) {
// File Write
if (!Files.exists(backupFilePath)) {
Files.createDirectories(backupFilePath.getParent());
Files.createFile(backupFilePath);
}
Files.write(backupFilePath, objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(backupContentVO));
}
} catch (Exception e) {
log.error("Repository Backup 데이터 생성 중 오류가 발생했습니다.", e);
}
}, 3, 10, TimeUnit.MINUTES);
} catch (Exception e) {
log.error("Repository Backup 시작 설정 중 오류가 발생했습니다.", e);
}
}
@PreDestroy
public void destroy() {
this.backupFlag = false;
}
// 매일 0시에 실행
@Scheduled(cron = "0 0 0 * * ?")
private void dailyCleanUp() {
removeBackupFile();
}
public synchronized void removeBackupFile() {
String backupFilePathStr = monitoringContext.getProperty("repository.backup.path", "/log/elink/repository/");
backupFilePathStr = backupFilePathStr.endsWith("/") ? backupFilePathStr : backupFilePathStr + "/";
backupFilePathStr += instType + "/" + instName + "/backup.json";
final Path backupFilePath = Paths.get(backupFilePathStr);
if (Files.exists(backupFilePath)) {
try {
Files.delete(backupFilePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -0,0 +1,31 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup.mapper;
import java.lang.reflect.Field;
public interface BackupMapper<VO, OBJ> {
VO toVo(OBJ object) throws Exception;
void setVoValuesToObject(VO vo, OBJ object) throws Exception;
default <T> T getReflection(Class<?> clazz, String fieldName, Object instance) {
try {
Field declaredField = clazz.getDeclaredField(fieldName);
declaredField.setAccessible(true);
return (T) declaredField.get(instance);
} catch (Exception e) {
throw new RuntimeException("Error occurred during field access", e);
}
}
default void setReflection(Class<?> clazz, String fieldName, Object instance, Object value) {
try {
Field declaredField = clazz.getDeclaredField(fieldName);
declaredField.setAccessible(true);
declaredField.set(instance, value);
} catch (Exception e) {
throw new RuntimeException("Error occurred during field access", e);
}
}
}
@@ -0,0 +1,90 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup.mapper;
import com.eactive.eai.rms.common.util.TypeCastUtils;
import com.eactive.eai.rms.onl.dashboard.modern.backup.BackupContentVO;
import com.eactive.eai.rms.onl.dashboard.repository.Dashboard2Repository;
import org.apache.commons.collections.keyvalue.MultiKey;
import org.apache.commons.collections.map.MultiKeyMap;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class Dashboard2RepositoryVoMapper implements BackupMapper<BackupContentVO.DashboardRepository2Fields, Dashboard2Repository> {
@Override
public BackupContentVO.DashboardRepository2Fields toVo(Dashboard2Repository dashboard2Repository) throws Exception {
BackupContentVO.DashboardRepository2Fields dashboardRepository2Fields = new BackupContentVO.DashboardRepository2Fields();
for (Field field : BackupContentVO.DashboardRepository2Fields.class.getDeclaredFields()) {
Method method = Arrays.stream(BackupContentVO.DashboardRepository2Fields.class.getDeclaredMethods()).filter(m -> m.getName().equalsIgnoreCase("set" + field.getName())).findAny().orElse(null);
if (method != null) {
if ("repoMemTransaction".equalsIgnoreCase(field.getName()) || "repository".equalsIgnoreCase(field.getName())) {
method.invoke(dashboardRepository2Fields, multiKeyMapToNormalMap(getReflection(Dashboard2Repository.class, field.getName(), dashboard2Repository)));
} else {
method.invoke(dashboardRepository2Fields, TypeCastUtils.castOrElse(getReflection(Dashboard2Repository.class, field.getName(), dashboard2Repository), field.getType(), null));
}
}
}
return dashboardRepository2Fields;
}
@Override
public void setVoValuesToObject(BackupContentVO.DashboardRepository2Fields vo, Dashboard2Repository object) throws Exception {
for (Field field : BackupContentVO.DashboardRepository2Fields.class.getDeclaredFields()) {
Method method = Arrays.stream(BackupContentVO.DashboardRepository2Fields.class.getDeclaredMethods()).filter(m -> m.getName().equalsIgnoreCase("get" + field.getName())).findAny().orElse(null);
if (method != null) {
if ("repoMemTransaction".equalsIgnoreCase(field.getName()) || "repository".equalsIgnoreCase(field.getName())) {
setReflection(Dashboard2Repository.class, field.getName(), object, normalMapToMultiKeyMap(TypeCastUtils.castOrElse(method.invoke(vo), Map.class, null)));
} else {
setReflection(Dashboard2Repository.class, field.getName(), object, TypeCastUtils.castOrElse(method.invoke(vo), field.getType(), null));
}
}
}
}
private <V> Map<String, V> multiKeyMapToNormalMap(MultiKeyMap multiKeyMap) {
if (multiKeyMap == null)
return null;
Map<String, V> normalMap = new HashMap<>();
for (Object key : multiKeyMap.keySet()) {
// MultiKey에서 키 배열 가져오기
MultiKey multiKey = (MultiKey) key;
Object[] keys = multiKey.getKeys();
// 키를 "_"로 join하여 하나의 문자열로 합성
String combinedKey = Arrays.stream(keys)
.map(Object::toString)
.collect(Collectors.joining("_"));
// 합성된 키, 값 -> normalMap
normalMap.put(combinedKey, (V) multiKeyMap.get(key));
}
return normalMap;
}
public static <V> MultiKeyMap normalMapToMultiKeyMap(Map<String, V> normalMap) {
if (normalMap == null)
return null;
MultiKeyMap multiKeyMap = new MultiKeyMap();
for (Map.Entry<String, V> entry : normalMap.entrySet()) {
String combinedKey = entry.getKey();
V value = entry.getValue();
// "_"로 분리하여 subKeys 배열을 얻음
String[] subKeys = combinedKey.split("_");
multiKeyMap.put(new MultiKey(subKeys), value);
}
return multiKeyMap;
}
}
@@ -0,0 +1,79 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup.mapper;
import com.eactive.eai.rms.onl.dashboard.modern.backup.BackupContentVO;
import com.eactive.eai.rms.onl.server.repository.ExpiringMap;
import com.eactive.eai.rms.onl.server.repository.Repository;
import com.eactive.eai.rms.onl.vo.MonitorDataVo;
import org.apache.commons.collections.keyvalue.MultiKey;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class RepositoryVoMapper implements BackupMapper<BackupContentVO.RepositoryFields, Repository> {
@Override
public BackupContentVO.RepositoryFields toVo(Repository repository) throws Exception {
BackupContentVO.RepositoryFields result = new BackupContentVO.RepositoryFields();
Field fRepository = Repository.class.getDeclaredField("repository");
fRepository.setAccessible(true);
ExpiringMap<MultiKey, MonitorDataVo> vRepository = (ExpiringMap<MultiKey, MonitorDataVo>) fRepository.get(repository);
Map<String, MonitorDataVo> v2Repository = multiKeyToNormalMap(vRepository);
result.setRepository(v2Repository);
Field fRepositoryNoExpire = Repository.class.getDeclaredField("repositoryNoExpire");
fRepositoryNoExpire.setAccessible(true);
ConcurrentHashMap<MultiKey, MonitorDataVo> vRepositoryNoExpire = (ConcurrentHashMap<MultiKey, MonitorDataVo>) fRepositoryNoExpire.get(repository);
ConcurrentHashMap<String, MonitorDataVo> v2RepositoryNoExpire = multiKeyToNormalMap(vRepositoryNoExpire);
result.setRepositoryNoExpire(v2RepositoryNoExpire);
return result;
}
@Override
public void setVoValuesToObject(BackupContentVO.RepositoryFields vo, Repository object) throws Exception {
ExpiringMap<MultiKey, Object> vRepository = new ExpiringMap<>();
vo.getRepository().entrySet().stream()
.forEach(e -> {
String[] splitted = e.getKey().split("_");
vRepository.put(new MultiKey(splitted), e.getValue());
});
Field fRepository = Repository.class.getDeclaredField("repository");
fRepository.setAccessible(true);
fRepository.set(object, vRepository);
ConcurrentHashMap<MultiKey, Object> vRepositoryNoExpire = new ConcurrentHashMap<>();
vo.getRepositoryNoExpire().entrySet().stream()
.forEach(e -> {
String[] splitted = e.getKey().split("_");
vRepositoryNoExpire.put(new MultiKey(splitted), e.getValue());
});
Field fRepositoryNoExpire = Repository.class.getDeclaredField("repositoryNoExpire");
fRepositoryNoExpire.setAccessible(true);
fRepositoryNoExpire.set(object, vRepositoryNoExpire);
}
private <T> ConcurrentHashMap<String, T> multiKeyToNormalMap(Map<MultiKey, T> vRepository) {
if (vRepository == null)
return null;
return vRepository.entrySet().stream()
.collect(Collectors.toMap(
e -> Arrays.stream(e.getKey().getKeys())
.map(Object::toString)
.collect(Collectors.joining("_")),
Map.Entry::getValue, (oldVal, newVal) -> newVal, ConcurrentHashMap::new
));
}
}
@@ -0,0 +1,33 @@
package com.eactive.eai.rms.onl.dashboard.modern.backup.mapper;
import com.eactive.eai.rms.common.util.TypeCastUtils;
import com.eactive.eai.rms.onl.dashboard.modern.backup.BackupContentVO;
import com.eactive.eai.rms.onl.dashboard.modern.service.ThroughputCalculationService;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ThroughputVoMapper implements BackupMapper<BackupContentVO.ThroughputFields, ThroughputCalculationService> {
@Override
public BackupContentVO.ThroughputFields toVo(ThroughputCalculationService throughputCalculationService) throws Exception {
BackupContentVO.ThroughputFields throughputFields = new BackupContentVO.ThroughputFields();
for (Field field : BackupContentVO.ThroughputFields.class.getDeclaredFields()) {
Method method = Arrays.stream(BackupContentVO.ThroughputFields.class.getDeclaredMethods()).filter(m -> m.getName().equalsIgnoreCase("set" + field.getName())).findAny().orElse(null);
if (method != null)
method.invoke(throughputFields, TypeCastUtils.castOrElse(getReflection(ThroughputCalculationService.class, field.getName(), throughputCalculationService), field.getType(), null));
}
return throughputFields;
}
@Override
public void setVoValuesToObject(BackupContentVO.ThroughputFields vo, ThroughputCalculationService object) throws Exception {
for (Field field : BackupContentVO.ThroughputFields.class.getDeclaredFields()) {
Method method = Arrays.stream(BackupContentVO.ThroughputFields.class.getDeclaredMethods()).filter(m -> m.getName().equalsIgnoreCase("get" + field.getName())).findAny().orElse(null);
if (method != null)
setReflection(ThroughputCalculationService.class, field.getName(), object, TypeCastUtils.castOrElse(method.invoke(vo), field.getType(), null));
}
}
}
@@ -0,0 +1,955 @@
package com.eactive.eai.rms.onl.dashboard.modern.controller;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.data.entity.onl.property.PropertyService;
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
import com.eactive.eai.rms.onl.dashboard.dao.DashboardDAO;
import com.eactive.eai.rms.onl.dashboard.modern.dto.*;
import com.eactive.eai.rms.onl.dashboard.modern.mapper.DashboardDataMapper;
import com.eactive.eai.rms.onl.dashboard.modern.mapper.SmsNotificationMapper;
import com.eactive.eai.rms.onl.dashboard.modern.service.SocketMonitorService;
import com.eactive.eai.rms.onl.dashboard.modern.service.ThroughputCalculationService;
import com.eactive.eai.rms.onl.dashboard.modern.service.TransactionSummaryService;
import com.eactive.eai.rms.onl.dashboard.service.Dashboard2RepositoryService;
import com.eactive.eai.rms.onl.dashboard.service.DashboardService;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.AdaptersVO;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import com.eactive.eai.rms.onl.vo.SmsVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* 모던 대시보드 컨트롤러
* ASIS 대시보드에서 TOBE 대시보드로 마이그레이션된 API를 제공합니다.
*/
@Slf4j
@Controller
public class ModernDashboardController {
@Autowired
@Qualifier("monitoringContext")
private transient MonitoringContext monitoringContext;
@Autowired
@Qualifier("eaiServerInfoService")
private EaiServerInfoService eaiServerInfoService;
@Autowired
@Qualifier("dashboardService")
private DashboardService dashboardService;
@Autowired
@Qualifier("dashboard2RepositoryService")
private Dashboard2RepositoryService dashboard2Repository;
@Autowired
@Qualifier("dashboardDao")
private DashboardDAO dashboardDao;
@Autowired
private DashboardDataMapper dataMapper;
@Autowired
private SmsNotificationMapper smsNotificationMapper;
@Autowired
private ThroughputCalculationService throughputCalculationService;
@Autowired
private SocketMonitorService socketMonitorService;
@Autowired
private TransactionSummaryService transactionSummaryService;
@Autowired
@Qualifier("propertyService")
private PropertyService propertyService;
/**
* 모던 대시보드 메인 페이지
*/
@RequestMapping(path = "/modern-dashboard.do")
public String modernDashboard(HttpServletRequest request) {
return "dashboard-modern/modern-dashboard";
}
/**
* 서버 상태 정보 제공 API
* 전체 서버 및 해당 인스턴스의 상태 정보를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=server-status")
@ResponseBody
public Map<String, Object> getServerStatus(@RequestParam(required = false) String serverName) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 타입 목록 가져오기 (특정 서버 이름이 제공된 경우 해당 서버만 포함)
List<DataSourceType> serverTypes;
if (serverName != null && !serverName.isEmpty() && !serverName.equals("all") && !serverName.equals("ALL")) {
DataSourceType server = DataSourceTypeManager.getDataSourceType(serverName.toUpperCase());
serverTypes = server != null ? Collections.singletonList(server) : new ArrayList<>();
} else {
serverTypes = DataSourceTypeManager.getOnlineDataSourceTypes();
// GW 추가
if( DataSourceTypeManager.getDataSourceType("FGW") != null ){
serverTypes.add(DataSourceTypeManager.getDataSourceType("FGW"));
}
if( DataSourceTypeManager.getDataSourceType("CGW") != null ){
serverTypes.add(DataSourceTypeManager.getDataSourceType("CGW"));
}
}
List<ServerStatusDTO> serverList = new ArrayList<>();
for (DataSourceType serverType : serverTypes) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(serverType);
String agentMode = propertyService.getPrpty2valById("RMIInfo", "agent.mode");
if( agentMode == null || agentMode.isEmpty() ){
agentMode = "";
}
// 호스트명으로 인스턴스 그룹화
Map<String, List<Map<String, String>>> instancesByHost = new HashMap<String, List<Map<String, String>>>();
if( "K8S".equals(agentMode) ){
List<Map<String, String>> hostList = dashboard2Repository.getDatasourceByHost(serverType.getName());
for (Map<String, String> instance : hostList) {
String hostname = instance.get("HOSTNAME");
instancesByHost.computeIfAbsent(hostname, k -> new ArrayList<>()).add(instance);
}
} else {
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> ipList = eaiServerInfoService.getEaiServerIpListDB();
for (Map<String, String> instance : ipList) {
String hostname = instance.get("HOSTNAME");
instancesByHost.computeIfAbsent(hostname, k -> new ArrayList<>()).add(instance);
}
}
// 각 호스트별로 서버 상태 DTO 생성
for (Map.Entry<String, List<Map<String, String>>> entry : instancesByHost.entrySet()) {
String hostname = entry.getKey();
List<Map<String, String>> hostInstances = entry.getValue();
// 서버 상태 DTO 생성
ServerStatusDTO serverDTO = new ServerStatusDTO();
serverDTO.setName(hostname);
serverDTO.setText(hostname + " (" + serverType.getText() + ")");
serverDTO.setHostname(hostname);
// 호스트 상태 조회 및 리소스 사용률 설정
HostStatusVo hostVo = dashboardService.findHostStatus(hostInstances);
if (hostVo != null) {
serverDTO.setCpu(hostVo.getCpu());
serverDTO.setMemory(hostVo.getMemory());
serverDTO.setDisk(hostVo.getDisk());
}
// 서버 상태 설정
if (serverDTO.getCpu() > 90 || serverDTO.getMemory() > 90 || serverDTO.getDisk() > 90) {
serverDTO.setStatus("error");
} else if (serverDTO.getCpu() > 70 || serverDTO.getMemory() > 70 || serverDTO.getDisk() > 70) {
serverDTO.setStatus("warning");
} else {
serverDTO.setStatus("normal");
}
// 인스턴스 목록 조회 및 설정
List<EAIEngineStatusVo> engineStatusList = dashboardService.findEngineStatus(hostInstances, true);
List<InstanceDTO> instances = new ArrayList<>();
for (EAIEngineStatusVo engineStatus : engineStatusList) {
InstanceDTO instance = new InstanceDTO();
instance.setId(engineStatus.getInstanceName());
String serverState = StringUtils.defaultString(engineStatus.getServerState());
// 인스턴스 상태 설정
switch (serverState) {
case "0":
instance.setStatus("error");
break;
case "1":
instance.setStatus("warning");
break;
case "2":
instance.setStatus("normal");
break;
default:
instance.setStatus("inactive");
}
// 처리량 설정 (초당 처리량)
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByHost(
engineStatus.getHostName(), engineStatus.getInstanceName());
if (memStatics != null) {
// 처리량 계산 서비스에서 초당 처리량 가져오기
instance.setThroughput(throughputCalculationService.getThroughput(
engineStatus.getHostName(), engineStatus.getInstanceName()));
} else {
instance.setThroughput("0/s");
}
instances.add(instance);
}
serverDTO.setInstances(instances);
serverList.add(serverDTO);
}
}
response.put("servers", serverList);
return response;
} catch (Exception e) {
log.error("서버 상태 정보 조회 중 오류 발생", e);
response.put("error", "서버 상태 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 어댑터 상태 정보 제공 API
* 서버별 어댑터(Socket, HTTP)의 상태 정보를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=adapter-status")
@ResponseBody
public Map<String, Object> getAdapterStatus(@RequestParam(required = false) String serverName) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 타입 목록 가져오기 (특정 서버 이름이 제공된 경우 해당 서버만 포함)
List<DataSourceType> servers;
if (serverName != null && !serverName.isEmpty() && !serverName.equals("all") && !serverName.equals("ALL")) {
DataSourceType server = DataSourceTypeManager.getDataSourceType(serverName.toUpperCase());
servers = server != null ? Collections.singletonList(server) : new ArrayList<>();
} else {
// 온라인 데이터 소스 타입 가져오기 (BAT 서버 제외)
servers = DataSourceTypeManager.getOnlineDataSourceTypes().stream()
.filter(server -> !DataSourceTypeManager.BAT.equals(server.getName()))
.collect(Collectors.toList());
// GW 추가
if( DataSourceTypeManager.getDataSourceType("FGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("FGW"));
}
if( DataSourceTypeManager.getDataSourceType("CGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("CGW"));
}
}
List<Map<String, Object>> serverAdapters = new ArrayList<>();
for (DataSourceType server : servers) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> ipList = eaiServerInfoService.getEaiServerIpListDB();
// 어댑터 상태 목록 조회 (개별 인스턴스별 상태)
List<AdaptersVO> adaptersList = dashboardService.findAdapterStatusList(ipList);
// 어댑터 상태 집계 정보 생성
AdapterStatusSummaryContainerDTO summaryContainer = dataMapper.fromAdaptersVOList(adaptersList);
// 기존 방식의 어댑터 상태 정보도 함께 제공 (하위 호환성 유지)
AdaptersVO adaptersVO = dashboardService.findAdapterStatusTotalList(ipList);
List<AdapterStatusDTO> adapterDTOs = dataMapper.fromAdaptersVO(adaptersVO);
Map<String, Object> serverAdapter = new HashMap<>();
serverAdapter.put("serverName", server.getName());
serverAdapter.put("serverText", server.getText());
serverAdapter.put("adapters", adapterDTOs);
serverAdapter.put("adapterSummaries", summaryContainer.getAdapterSummaryList());
serverAdapter.put("overallStatus", summaryContainer.getOverallStatus());
serverAdapters.add(serverAdapter);
}
response.put("serverAdapters", serverAdapters);
return response;
} catch (Exception e) {
log.error("어댑터 상태 정보 조회 중 오류 발생", e);
response.put("error", "어댑터 상태 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 트랜잭션 정보 제공 API
* 서버별 트랜잭션 처리 현황(성공, 실패, 타임아웃, 시스템 에러)을 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=transaction")
@ResponseBody
public Map<String, Object> getTransactionInfo(@RequestParam(required = false) String serverName) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 타입 목록 가져오기 (특정 서버 이름이 제공된 경우 해당 서버만 포함)
List<DataSourceType> servers;
if (serverName != null && !serverName.isEmpty() && !serverName.equals("all") && !serverName.equals("ALL")) {
DataSourceType server = DataSourceTypeManager.getDataSourceType(serverName.toUpperCase());
servers = server != null ? Collections.singletonList(server) : new ArrayList<>();
} else {
servers = DataSourceTypeManager.getOnlineDataSourceTypes();
}
List<TransactionDTO> transactions = new ArrayList<>();
TransactionDTO totalTransaction = new TransactionDTO();
totalTransaction.setType("TOTAL");
for (DataSourceType server : servers) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버의 트랜잭션 정보 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByService(server.getName());
TransactionDTO transaction = dataMapper.fromMemStaticsVo(memStatics, server.getName());
transactions.add(transaction);
// 전체 트랜잭션 집계에 추가
totalTransaction.setSuccess(totalTransaction.getSuccess() + transaction.getSuccess());
totalTransaction.setFail(totalTransaction.getFail() + transaction.getFail());
totalTransaction.setTimeout(totalTransaction.getTimeout() + transaction.getTimeout());
totalTransaction.setSyserror(totalTransaction.getSyserror() + transaction.getSyserror());
}
// 전체 트랜잭션 정보 추가
transactions.add(totalTransaction);
response.put("transactions", transactions);
return response;
} catch (Exception e) {
log.error("트랜잭션 정보 조회 중 오류 발생", e);
response.put("error", "트랜잭션 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 피크 성능 정보 제공 API
* 서버별 최대 처리량 및 TPS(초당 트랜잭션 수) 정보를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=peak-performance")
@ResponseBody
public Map<String, Object> getPeakPerformance(@RequestParam(required = false) String type) {
Map<String, Object> response = new HashMap<>();
try {
// 피크 성능 유형 (TPS 또는 거래건수)
String peakType = type != null && "trade".equals(type) ? "trade" : "tps";
List<PeakPerformanceDTO> peakTps = new ArrayList<>();
List<PeakPerformanceDTO> peakTrade = new ArrayList<>();
// 온라인 서비스 피크 정보 조회
for (DataSourceType server : DataSourceTypeManager.getOnlineDataSourceTypes()) {
String peakInfo;
peakInfo = dashboard2Repository.getPeakTps(server.getName());
if (peakInfo != null && !peakInfo.isEmpty()) {
PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
peakTps.add(dto);
}
peakInfo = dashboard2Repository.getPeakTrade(server.getName());
if (peakInfo != null && !peakInfo.isEmpty()) {
PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
peakTrade.add(dto);
}
}
// BAP(일괄전송) 서버 피크 정보 조회
DataSourceType bapServer = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAP);
if (bapServer != null) {
String peakInfo;
// peakInfo = dashboard2Repository.getPeakTps(bapServer.getName());
//
// if (peakInfo != null && !peakInfo.isEmpty()) {
// PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
// peakTps.add(dto);
// }
peakInfo = dashboard2Repository.getPeakTrade(bapServer.getName());
if (peakInfo != null && !peakInfo.isEmpty()) {
PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
peakTrade.add(dto);
}
}
// BAT(배치) 서버 피크 정보 조회
DataSourceType batServer = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT);
if (batServer != null) {
String peakInfo;
// peakInfo = dashboard2Repository.getPeakTps(batServer.getName());
//
// if (peakInfo != null && !peakInfo.isEmpty()) {
// PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
// peakTps.add(dto);
// }
peakInfo = dashboard2Repository.getPeakTrade(batServer.getName());
if (peakInfo != null && !peakInfo.isEmpty()) {
PeakPerformanceDTO dto = dataMapper.fromPeakPerformanceString(peakInfo, peakType);
peakTrade.add(dto);
}
}
response.put("peakTps", peakTps);
response.put("peakTrade", peakTrade);
response.put("peakType", peakType);
return response;
} catch (Exception e) {
log.error("피크 성능 정보 조회 중 오류 발생", e);
response.put("error", "피크 성능 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 배치 처리 상태 제공 API
* 일괄 전송(BAP) 및 배치(BAT) 처리 상태 정보를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=batch-process")
@ResponseBody
public Map<String, Object> getBatchProcess() {
Map<String, Object> response = new HashMap<>();
try {
List<BatchProcessDTO> batchData = new ArrayList<>();
// BAP(일괄전송) 배치 처리 정보 조회
if( DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAP) != null ){
String bapBatchInfo = dashboard2Repository.getProcBatch();
if (bapBatchInfo != null && !bapBatchInfo.isEmpty()) {
BatchProcessDTO bapDTO = dataMapper.fromBatchProcessString(DataSourceTypeManager.BAP, bapBatchInfo);
batchData.add(bapDTO);
}
}
// BAT(배치) 배치 처리 정보 조회
if( DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT) != null ){
String batBatchInfo = dashboard2Repository.getProcEaiBatch();
if (batBatchInfo != null && !batBatchInfo.isEmpty()) {
BatchProcessDTO batDTO = dataMapper.fromBatchProcessString(DataSourceTypeManager.BAT, batBatchInfo);
batchData.add(batDTO);
}
}
response.put("batchData", batchData);
return response;
} catch (Exception e) {
log.error("배치 처리 정보 조회 중 오류 발생", e);
response.put("error", "배치 처리 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 인스턴스 상세 정보 제공 API
* 특정 서버 또는 모든 서버의 인스턴스별 상세 정보를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=instance-detail")
@ResponseBody
public Map<String, Object> getInstanceDetail(@RequestParam(required = false) String serverName) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 타입 목록 가져오기 (특정 서버 이름이 제공된 경우 해당 서버만 포함)
List<DataSourceType> servers;
if (serverName != null && !serverName.isEmpty() && !serverName.equals("all") && !serverName.equals("ALL")) {
DataSourceType server = DataSourceTypeManager.getDataSourceType(serverName.toUpperCase());
servers = server != null ? Collections.singletonList(server) : new ArrayList<>();
} else {
servers = DataSourceTypeManager.getOnlineDataSourceTypes();
}
List<Map<String, Object>> instanceDetails = new ArrayList<>();
for (DataSourceType server : servers) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> ipList = eaiServerInfoService.getEaiServerIpListDB();
// 각 인스턴스별 상세 정보 수집
for (Map<String, String> instanceInfo : ipList) {
String hostName = instanceInfo.get("HOSTNAME");
String instanceName = instanceInfo.get("EAISVRINSTNM");
// 엔진 상태 조회
EAIEngineStatusVo engineStatus = new EAIEngineStatusVo();
engineStatus.setHostName(hostName);
engineStatus.setInstanceName(instanceName);
engineStatus.setService(server.getName());
EAIEngineStatusVo engineStatusResult = dashboardService.findEngineStatus(engineStatus);
// 어댑터 상태 조회
AdaptersVO adaptersVO = new AdaptersVO();
adaptersVO.setHostName(hostName);
adaptersVO.setInstanceName(instanceName);
adaptersVO.setService(server.getName());
AdaptersVO adaptersResult = dashboardService.findAdapterStatus(adaptersVO);
// 트랜잭션 정보 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByHost(hostName, instanceName);
// DTO로 변환
ServerStatusDTO serverDTO = dataMapper.fromEAIEngineStatusVo(engineStatusResult);
List<AdapterStatusDTO> adapterDTOs = dataMapper.fromAdaptersVO(adaptersResult);
TransactionDTO transactionDTO = dataMapper.fromMemStaticsVo(memStatics, server.getName());
// 인스턴스 상세 정보 구성
Map<String, Object> instanceDetail = new HashMap<>();
instanceDetail.put("serverName", server.getName());
instanceDetail.put("serverText", server.getText());
instanceDetail.put("hostName", hostName);
instanceDetail.put("instanceName", instanceName);
instanceDetail.put("server", serverDTO);
instanceDetail.put("adapters", adapterDTOs);
instanceDetail.put("transaction", transactionDTO);
instanceDetails.add(instanceDetail);
}
}
response.put("instanceDetails", instanceDetails);
return response;
} catch (Exception e) {
log.error("인스턴스 상세 정보 조회 중 오류 발생", e);
response.put("error", "인스턴스 상세 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 실시간 성능 데이터 제공 API
* 서버 및 어댑터의 최신 성능 데이터를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=performance-data")
@ResponseBody
public Map<String, Object> getPerformanceData() {
Map<String, Object> response = new HashMap<>();
try {
// 서버별 성능 정보 수집
List<Map<String, Object>> serverPerformance = new ArrayList<>();
for (DataSourceType server : DataSourceTypeManager.getOnlineDataSourceTypes()) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> ipList = eaiServerInfoService.getEaiServerIpListDB();
// 호스트 상태 조회
HostStatusVo hostVo = dashboardService.findHostStatus(ipList);
// 실시간 트랜잭션 정보 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByService(server.getName());
// 서버 성능 정보 구성
Map<String, Object> performance = new HashMap<>();
performance.put("serverName", server.getName());
performance.put("serverText", server.getText());
performance.put("cpu", hostVo != null ? hostVo.getCpu() : 0);
performance.put("memory", hostVo != null ? hostVo.getMemory() : 0);
performance.put("disk", hostVo != null ? hostVo.getDisk() : 0);
performance.put("procTotal", memStatics != null ? memStatics.getProcTotal() : 0);
performance.put("errorTotal", memStatics != null ?
(memStatics.getErrorTotal() + memStatics.getTimeoutTotal() + memStatics.getSysErrorTotal()) : 0);
serverPerformance.add(performance);
}
response.put("serverPerformance", serverPerformance);
response.put("timestamp", System.currentTimeMillis());
return response;
} catch (Exception e) {
log.error("성능 데이터 조회 중 오류 발생", e);
response.put("error", "성능 데이터 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 트랜잭션 시계열 데이터 제공 API
* 서버별 시간에 따른 트랜잭션 처리 현황(성공, 실패, 타임아웃, 시스템 에러)을 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=transaction-timeseries")
@ResponseBody
public Map<String, Object> getTransactionTimeSeries(
@RequestParam(required = false) String serverName,
@RequestParam(required = false, defaultValue = "10") int minutes) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 타입 목록 가져오기 (특정 서버 이름이 제공된 경우 해당 서버만 포함)
List<DataSourceType> servers;
if (serverName != null && !serverName.isEmpty() && !serverName.equals("all") && !serverName.equals("ALL")) {
DataSourceType server = DataSourceTypeManager.getDataSourceType(serverName.toUpperCase());
servers = server != null ? Collections.singletonList(server) : new ArrayList<>();
} else {
servers = DataSourceTypeManager.getOnlineDataSourceTypes();
}
// 시계열 데이터 수집 기간 제한 (기본 10분)
minutes = Math.min(Math.max(minutes, 1), 60); // 1~60분 범위로 제한
// 서버별 시계열 데이터 수집
Map<String, Map<String, Object>> timeSeriesData = new HashMap<>();
// 현재 시간 저장
long currentTimestamp = System.currentTimeMillis();
// 현재 실시간 거래 정보 저장용 맵
Map<String, MemStaticsVo> currentTransactions = new HashMap<>();
// 현재 거래 정보 먼저 조회 (실시간 값 추가용)
for (DataSourceType server : servers) {
String serverType = server.getName();
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버의 트랜잭션 정보 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByService(serverType);
if (memStatics != null) {
currentTransactions.put(serverType, memStatics);
}
}
// ThroughputCalculationService에서 시계열 데이터 가져오기
for (DataSourceType server : servers) {
String serverType = server.getName();
// 시계열 데이터 조회
ThroughputCalculationService.TimeSeriesData seriesData =
throughputCalculationService.getTimeSeriesData(serverType, minutes);
if (seriesData != null) {
// 시계열 데이터 저장할 구조 생성
Map<String, Object> serviceData = new HashMap<>();
// 기존 타임스탬프와 데이터 복사
List<Long> timestamps = new ArrayList<>(seriesData.getTimestamps());
List<Integer> success = new ArrayList<>(seriesData.getSuccess());
List<Integer> fail = new ArrayList<>(seriesData.getFail());
List<Integer> timeout = new ArrayList<>(seriesData.getTimeout());
List<Integer> syserror = new ArrayList<>(seriesData.getSyserror());
// 현재 값을 시계열에 추가 (마지막 데이터가 없거나 10초 이상 지났을 경우)
MemStaticsVo currentStats = currentTransactions.get(serverType);
if (currentStats != null) {
boolean shouldAddCurrentData = true;
// 마지막 데이터와 현재 시간이 2초 이상 차이가 나면 현재 값 추가
if (!timestamps.isEmpty() && (currentTimestamp - timestamps.get(timestamps.size() - 1)) < 2000) {
shouldAddCurrentData = false;
}
if (shouldAddCurrentData) {
// 현재 값을 시계열 마지막에 추가
timestamps.add(currentTimestamp);
// 성공 건수 = 전체 - (실패 + 타임아웃 + 시스템에러)
int successCount = currentStats.getProcTotal() - currentStats.getErrorTotal()
- currentStats.getTimeoutTotal() - currentStats.getSysErrorTotal();
success.add(Math.max(0, successCount));
fail.add(currentStats.getErrorTotal());
timeout.add(currentStats.getTimeoutTotal());
syserror.add(currentStats.getSysErrorTotal());
}
}
// 최종 데이터 저장
serviceData.put("timestamps", timestamps);
serviceData.put("success", success);
serviceData.put("fail", fail);
serviceData.put("timeout", timeout);
serviceData.put("syserror", syserror);
// 이 서버의 데이터 저장
timeSeriesData.put(serverType, serviceData);
} else {
// 데이터가 없는 경우 빈 데이터 생성
Map<String, Object> emptyData = new HashMap<>();
emptyData.put("timestamps", new ArrayList<>());
emptyData.put("success", new ArrayList<>());
emptyData.put("fail", new ArrayList<>());
emptyData.put("timeout", new ArrayList<>());
emptyData.put("syserror", new ArrayList<>());
timeSeriesData.put(serverType, emptyData);
}
}
// 전체 합계 데이터 조회
ThroughputCalculationService.TimeSeriesData totalData =
throughputCalculationService.getTimeSeriesData("TOTAL", minutes);
if (totalData != null) {
Map<String, Object> totalSeriesData = new HashMap<>();
// 기존 타임스탬프와 데이터 복사
List<Long> timestamps = new ArrayList<>(totalData.getTimestamps());
List<Integer> success = new ArrayList<>(totalData.getSuccess());
List<Integer> fail = new ArrayList<>(totalData.getFail());
List<Integer> timeout = new ArrayList<>(totalData.getTimeout());
List<Integer> syserror = new ArrayList<>(totalData.getSyserror());
// 현재 전체 합계 계산
int totalSuccess = 0;
int totalFail = 0;
int totalTimeout = 0;
int totalSyserror = 0;
for (String serviceType : currentTransactions.keySet()) {
MemStaticsVo stats = currentTransactions.get(serviceType);
if (stats != null) {
totalSuccess += stats.getProcTotal() - stats.getErrorTotal()
- stats.getTimeoutTotal() - stats.getSysErrorTotal();
totalFail += stats.getErrorTotal();
totalTimeout += stats.getTimeoutTotal();
totalSyserror += stats.getSysErrorTotal();
}
}
// 마지막 데이터와 현재 시간이 2초 이상 차이가 나면 현재 값 추가
boolean shouldAddCurrentData = true;
if (!timestamps.isEmpty() && (currentTimestamp - timestamps.get(timestamps.size() - 1)) < 2000) {
shouldAddCurrentData = false;
}
if (shouldAddCurrentData) {
timestamps.add(currentTimestamp);
success.add(totalSuccess);
fail.add(totalFail);
timeout.add(totalTimeout);
syserror.add(totalSyserror);
}
totalSeriesData.put("timestamps", timestamps);
totalSeriesData.put("success", success);
totalSeriesData.put("fail", fail);
totalSeriesData.put("timeout", timeout);
totalSeriesData.put("syserror", syserror);
timeSeriesData.put("TOTAL", totalSeriesData);
} else {
// 전체 데이터가 없는 경우, 더미 데이터 생성은 제거
Map<String, Object> emptyData = new HashMap<>();
emptyData.put("timestamps", new ArrayList<>());
emptyData.put("success", new ArrayList<>());
emptyData.put("fail", new ArrayList<>());
emptyData.put("timeout", new ArrayList<>());
emptyData.put("syserror", new ArrayList<>());
timeSeriesData.put("TOTAL", emptyData);
}
response.put("timeSeriesData", timeSeriesData);
response.put("minutes", minutes);
response.put("timestamp", System.currentTimeMillis());
return response;
} catch (Exception e) {
log.error("트랜잭션 시계열 정보 조회 중 오류 발생", e);
response.put("error", "트랜잭션 시계열 정보 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* 서버 리소스 시계열 데이터 제공 API
* 특정 서버의 CPU, 메모리, 디스크 사용량 시계열 데이터를 제공합니다.
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=server-resource")
@ResponseBody
public Map<String, Object> getServerResourceData(
@RequestParam String hostname,
@RequestParam(required = false, defaultValue = "7") int count) {
Map<String, Object> response = new HashMap<>();
try {
// 서버 리소스 시계열 데이터 조회
ThroughputCalculationService.ServerResourceData resourceData =
throughputCalculationService.getServerResourceData(hostname, count);
// 응답 데이터 구성
Map<String, Object> data = new HashMap<>();
data.put("hostname", hostname);
data.put("timestamps", resourceData.getTimestamps());
data.put("cpu", resourceData.getCpu());
data.put("memory", resourceData.getMemory());
data.put("disk", resourceData.getDisk());
response.put("data", data);
return response;
} catch (Exception e) {
log.error("서버 리소스 시계열 데이터 조회 중 오류 발생", e);
response.put("error", "서버 리소스 시계열 데이터 조회 중 오류가 발생했습니다.");
return response;
}
}
/**
* SMS 장애 통보 정보를 조회합니다.
* @return SMS 장애 통보 정보
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=sms-notification")
@ResponseBody
public Map<String, Object> getSmsNotification() {
Map<String, Object> result = new HashMap<>();
List<SmsVO> totalSmsList = new ArrayList<>();
try {
List<DataSourceType> servers = DataSourceTypeManager.getOnlineDataSourceTypes();
// GW 추가
if( DataSourceTypeManager.getDataSourceType("FGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("FGW"));
}
if( DataSourceTypeManager.getDataSourceType("CGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("CGW"));
}
for (DataSourceType d : servers) {
DataSourceContextHolder.setDataSourceType(d);
List ipList = eaiServerInfoService.getEaiServerIpListDB();
List<SmsVO> smsList = dashboardService.findSmsList(ipList, d.getName());
totalSmsList.addAll(smsList);
}
// SmsVO 목록을 SmsNotificationDto 목록으로 변환
List<SmsNotificationDto> smsNotificationDtoList = smsNotificationMapper.mapToSmsNotificationDtoList(totalSmsList);
result.put("success", true);
result.put("data", smsNotificationDtoList);
} catch (Exception e) {
log.error("SMS 장애 통보 정보 조회 중 오류 발생", e);
result.put("success", false);
result.put("message", "SMS 장애 통보 정보 조회 중 오류가 발생했습니다.");
}
return result;
}
/**
* Get socket status data
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return SocketStatusDTO with all socket status data
*/
@RequestMapping(value = "/socket-status")
@ResponseBody
public ResponseEntity<SocketStatusDTO> getSocketStatus(
@RequestParam(value = "serverName", required = false) String serverName,
@RequestParam(value = "adapterGroup", required = false) String adapterGroup) {
SocketStatusDTO result = socketMonitorService.getSocketStatus(serverName, adapterGroup);
return ResponseEntity.ok(result);
}
/**
* Get socket process data
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return SocketProcessDTO with all socket process data
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=socket-process")
@ResponseBody
public ResponseEntity<SocketProcessDTO> getSocketProcess(
@RequestParam(value = "serverName", required = false) String serverName,
@RequestParam(value = "adapterGroup", required = false) String adapterGroup) {
SocketProcessDTO result = socketMonitorService.getSocketProcess(serverName, adapterGroup);
return ResponseEntity.ok(result);
}
/**
* Get combined socket data (both status and process)
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return Map containing both socket status and process data
*/
@RequestMapping(path = "/modern-dashboard-api.do", params = "type=socket-combined")
@ResponseBody
public ResponseEntity<Map<String, Object>> getCombinedSocketData(
@RequestParam(value = "serverName", required = false) String serverName,
@RequestParam(value = "adapterGroup", required = false) String adapterGroup) {
Map<String, Object> result = socketMonitorService.getCombinedSocketData(serverName, adapterGroup);
return ResponseEntity.ok(result);
}
/**
* 거래현황 시계열 데이터 조회
* @param seconds 조회할 초 단위 기간 (기본값 60초, 최대 120초)
* @return 시계열 데이터
*/
@GetMapping(path = "/modern-dashboard-api.do", params = "type=timeseries")
public ResponseEntity<Map<String, Object>> getTimeSeriesData(
@RequestParam(defaultValue = "60") int seconds) {
TransactionSummaryService.TimeSeriesData data = transactionSummaryService.getTimeSeriesData(seconds);
// 전체 기간 동안의 합계 계산
Map<String, Integer> totals = data.calculateTotalCounts();
// 데이터 포인트들을 오류 건수 -> 정상 건수 순으로 정렬
List<Map<String, Object>> sortedDataPoints = IntStream.range(0, data.getTimestamps().size())
.mapToObj(i -> {
Map<String, Object> point = new HashMap<>();
point.put("timestamp", data.getTimestamps().get(i));
point.put("error", data.getError().get(i));
point.put("success", data.getSuccess().get(i));
point.put("avgTime", data.getAvgTime().get(i));
return point;
})
.sorted((a, b) -> {
// 1차: 오류 건수 내림차순
int errorCompare = ((Integer)b.get("error")).compareTo((Integer)a.get("error"));
if (errorCompare != 0) return errorCompare;
// 2차: 정상 건수 내림차순
return ((Integer)b.get("success")).compareTo((Integer)a.get("success"));
})
.collect(Collectors.toList());
Map<String, Object> response = new HashMap<>();
response.put("seconds", seconds);
response.put("totalError", totals.get("error"));
response.put("totalSuccess", totals.get("success"));
response.put("dataPoints", sortedDataPoints);
return ResponseEntity.ok(response);
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 어댑터 상태 정보 DTO
* 시스템 내 어댑터의 상태 정보를 전달하기 위한 데이터 객체입니다.
*/
@Data
public class AdapterStatusDTO {
private String serverName; // 서버 이름
private String instanceId; // 인스턴스 ID
private String adapterType; // 어댑터 유형(Socket, HTTP)
private String status; // 상태(normal, warning, error, inactive)
private int totalCount; // 전체 수
private int runningCount; // 실행 중인 수
private int stopCount; // 정지된 수
}
@@ -0,0 +1,73 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 어댑터 상태 요약 컨테이너 DTO
* 모든 어댑터 유형의 상태 요약 정보를 담는 컨테이너입니다.
*/
@Data
public class AdapterStatusSummaryContainerDTO {
private Map<String, AdapterStatusSummaryDTO> adapterSummaries;
private String overallStatus; // 전체 상태 (normal, warning, error, inactive)
public AdapterStatusSummaryContainerDTO() {
this.adapterSummaries = new HashMap<>();
this.overallStatus = "normal";
// 기본 어댑터 유형 초기화 (Socket, HTTP만 포함, Socket2는 Socket으로 통합)
adapterSummaries.put("Socket", new AdapterStatusSummaryDTO("Socket"));
adapterSummaries.put("HTTP", new AdapterStatusSummaryDTO("HTTP"));
}
/**
* 특정 어댑터 유형의 상태 요약 정보를 반환합니다.
* @param adapterType 어댑터 유형
* @return 해당 어댑터 유형의 상태 요약 정보
*/
public AdapterStatusSummaryDTO getAdapterSummary(String adapterType) {
return adapterSummaries.get(adapterType);
}
/**
* 모든 어댑터 유형의 상태 요약 정보를 리스트로 반환합니다.
* @return 어댑터 상태 요약 정보 리스트
*/
public List<AdapterStatusSummaryDTO> getAdapterSummaryList() {
return new ArrayList<>(adapterSummaries.values());
}
/**
* 전체 상태를 업데이트합니다.
*/
public void updateOverallStatus() {
boolean hasError = false;
boolean hasWarning = false;
boolean hasNormal = false;
for (AdapterStatusSummaryDTO summary : adapterSummaries.values()) {
if ("error".equals(summary.getOverallStatus())) {
hasError = true;
} else if ("warning".equals(summary.getOverallStatus())) {
hasWarning = true;
} else if ("normal".equals(summary.getOverallStatus())) {
hasNormal = true;
}
}
if (hasError) {
overallStatus = "error";
} else if (hasWarning) {
overallStatus = "warning";
} else if (hasNormal) {
overallStatus = "normal";
} else {
overallStatus = "inactive";
}
}
}
@@ -0,0 +1,76 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 어댑터 상태 요약 정보 DTO
* 어댑터 유형별 상태 집계 정보를 제공합니다.
*/
@Data
public class AdapterStatusSummaryDTO {
private String adapterType; // 어댑터 유형(SNA, Socket, Tuxedo, MQ, HTTP, EJB)
// 상태별 카운트
private int errorCount; // 에러 상태 수
private int warningCount; // 부분정상(경고) 상태 수
private int normalCount; // 정상 상태 수
private int inactiveCount; // 정지 상태 수
// 전체 상태 (UI 표시용)
private String overallStatus; // 전체 상태 (normal, warning, error, inactive)
public AdapterStatusSummaryDTO(String adapterType) {
this.adapterType = adapterType;
this.errorCount = 0;
this.warningCount = 0;
this.normalCount = 0;
this.inactiveCount = 0;
this.overallStatus = "normal";
}
/**
* 상태 코드에 따라 카운트를 증가시킵니다.
* @param statusCode 상태 코드 (0: 에러, 1: 부분정상, 2: 정상, 3: 정지)
*/
public void incrementStatusCount(int statusCode) {
switch (statusCode) {
case 0: // 에러
errorCount++;
break;
case 1: // 부분정상
warningCount++;
break;
case 2: // 정상
normalCount++;
break;
case 3: // 정지
inactiveCount++;
break;
}
// 전체 상태 업데이트
updateOverallStatus();
}
/**
* 카운트 정보를 기반으로 전체 상태를 업데이트합니다.
*/
private void updateOverallStatus() {
if (errorCount > 0) {
overallStatus = "error";
} else if (warningCount > 0) {
overallStatus = "warning";
} else if (normalCount > 0) {
overallStatus = "normal";
} else {
overallStatus = "inactive";
}
}
/**
* 전체 어댑터 수를 반환합니다.
*/
public int getTotalCount() {
return errorCount + warningCount + normalCount + inactiveCount;
}
}
@@ -0,0 +1,12 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
@Data
public class AlertMessageDTO {
private String type; // 메시지 유형(개발, 운영 등)
private String instance; // 인스턴스 ID
private String timestamp; // 발생 시간
private String message; // 메시지 내용
private String severity; // 심각도(error, warning, info)
}
@@ -0,0 +1,141 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
/**
* 배치 처리 현황 DTO
*/
public class BatchProcessDTO {
private String serviceType; // BAP 또는 BAT
private String procBatch; // 원본 CSV 데이터
private int sendSuccess; // 송신 성공
private int receiveSuccess; // 수신 성공
private int sendError; // 송신 에러
private int receiveError; // 수신 에러
private int sendWaiting; // 송신 대기
private int receiveWaiting; // 수신 대기
public BatchProcessDTO() {
// 기본 생성자
}
public String getServiceType() {
return serviceType;
}
public void setServiceType(String serviceType) {
this.serviceType = serviceType;
}
public String getProcBatch() {
return procBatch;
}
public void setProcBatch(String procBatch) {
this.procBatch = procBatch;
// CSV 데이터 파싱
if (procBatch != null && !procBatch.isEmpty()) {
String[] fields = procBatch.split(",");
if (fields.length >= 6) {
try {
this.sendSuccess = Integer.parseInt(fields[0].trim());
this.receiveSuccess = Integer.parseInt(fields[1].trim());
this.sendError = Integer.parseInt(fields[2].trim());
this.receiveError = Integer.parseInt(fields[3].trim());
this.sendWaiting = Integer.parseInt(fields[4].trim());
this.receiveWaiting = Integer.parseInt(fields[5].trim());
} catch (NumberFormatException e) {
// 파싱 실패 시 기본값 유지
}
}
}
}
public int getSendSuccess() {
return sendSuccess;
}
public void setSendSuccess(int sendSuccess) {
this.sendSuccess = sendSuccess;
}
public int getReceiveSuccess() {
return receiveSuccess;
}
public void setReceiveSuccess(int receiveSuccess) {
this.receiveSuccess = receiveSuccess;
}
public int getSendError() {
return sendError;
}
public void setSendError(int sendError) {
this.sendError = sendError;
}
public int getReceiveError() {
return receiveError;
}
public void setReceiveError(int receiveError) {
this.receiveError = receiveError;
}
public int getSendWaiting() {
return sendWaiting;
}
public void setSendWaiting(int sendWaiting) {
this.sendWaiting = sendWaiting;
}
public int getReceiveWaiting() {
return receiveWaiting;
}
public void setReceiveWaiting(int receiveWaiting) {
this.receiveWaiting = receiveWaiting;
}
/**
* 총 송신 건수 반환
*/
public int getTotalSend() {
return sendSuccess + sendError + sendWaiting;
}
/**
* 총 수신 건수 반환
*/
public int getTotalReceive() {
return receiveSuccess + receiveError + receiveWaiting;
}
/**
* 총 처리 건수 반환
*/
public int getTotal() {
return getTotalSend() + getTotalReceive();
}
/**
* 송신 오류율 계산 (%)
*/
public double getSendErrorRate() {
if (getTotalSend() == 0) {
return 0.0;
}
return (double) sendError / getTotalSend() * 100;
}
/**
* 수신 오류율 계산 (%)
*/
public double getReceiveErrorRate() {
if (getTotalReceive() == 0) {
return 0.0;
}
return (double) receiveError / getTotalReceive() * 100;
}
}
@@ -0,0 +1,48 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 인스턴스 정보 DTO
* 서버 인스턴스의 상태 정보를 전달하기 위한 데이터 객체입니다.
*/
@Data
public class InstanceDTO {
private String id; // 인스턴스 ID
private String status; // 상태(normal, warning, error, inactive)
private String throughput; // 처리량(초당 처리 건수)
/**
* 처리량 수치만 추출
*/
public int getThroughputValue() {
if (throughput == null || throughput.isEmpty()) {
return 0;
}
try {
// "123/s" 형식에서 숫자만 추출
return Integer.parseInt(throughput.replaceAll("[^0-9]", ""));
} catch (NumberFormatException e) {
return 0;
}
}
/**
* 상태에 따른 표시용 텍스트 반환
*/
public String getStatusText() {
switch (status) {
case "normal":
return "정상";
case "warning":
return "경고";
case "error":
return "에러";
case "inactive":
return "비활성";
default:
return "알 수 없음";
}
}
}
@@ -0,0 +1,45 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 기관 연결 상태 모니터링을 위한 DTO
*/
@Data
public class InstitutionStatusDTO {
/**
* 기관 코드
*/
private String institutionCode;
/**
* 기관명
*/
private String institutionName;
/**
* 담당자명
*/
private String contactPerson;
/**
* 담당자 연락처
*/
private String contactNumber;
/**
* 정상 어댑터 수
*/
private int normalAdapterCount;
/**
* 오류 어댑터 수
*/
private int errorAdapterCount;
/**
* 회선 상태 (NORMAL, WARN, ERROR)
*/
private String lineStatus;
}
@@ -0,0 +1,28 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 피크 성능 정보 DTO
* 시스템의 최대 성능 기록을 전달하기 위한 데이터 객체입니다.
*/
@Data
public class PeakPerformanceDTO {
private String serviceType; // 서비스 유형(EAI, FEP 등)
private String date; // 날짜(YYYYMMDD)
private int transactionCount; // 처리 건수
private int tps; // 초당 트랜잭션 수(Transactions Per Second)
/**
* 날짜를 포맷팅하여 반환 (YYYY-MM-DD 형식)
*/
public String getFormattedDate() {
if (date == null || date.length() < 8) {
return date;
}
return date.substring(0, 4) + "-" +
date.substring(4, 6) + "-" +
date.substring(6, 8);
}
}
@@ -0,0 +1,93 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 서버 상태 정보 DTO
* 서버의 상태 정보와 하위 인스턴스 목록을 포함하는 데이터 객체입니다.
*/
@Data
public class ServerStatusDTO {
private String name; // 서버 이름
private String text; // 서버 표시명
private String hostname; // 서버 표시명
private String status; // 상태(normal, warning, error)
private int cpu; // CPU 사용률(%)
private int memory; // 메모리 사용률(%)
private int disk; // 디스크 사용률(%)
private List<InstanceDTO> instances = new ArrayList<>(); // 인스턴스 목록
/**
* 특정 인스턴스 ID에 해당하는 인스턴스를 찾습니다.
* @param instanceId 찾을 인스턴스 ID
* @return 해당 인스턴스 또는 null
*/
public InstanceDTO findInstance(String instanceId) {
if (instanceId == null || instances == null) {
return null;
}
for (InstanceDTO instance : instances) {
if (instanceId.equals(instance.getId())) {
return instance;
}
}
return null;
}
/**
* 에러 상태의 인스턴스 수를 반환합니다.
*/
public int getErrorInstanceCount() {
int count = 0;
for (InstanceDTO instance : instances) {
if ("error".equals(instance.getStatus())) {
count++;
}
}
return count;
}
/**
* 경고 상태의 인스턴스 수를 반환합니다.
*/
public int getWarningInstanceCount() {
int count = 0;
for (InstanceDTO instance : instances) {
if ("warning".equals(instance.getStatus())) {
count++;
}
}
return count;
}
/**
* 정상 상태의 인스턴스 수를 반환합니다.
*/
public int getNormalInstanceCount() {
int count = 0;
for (InstanceDTO instance : instances) {
if ("normal".equals(instance.getStatus())) {
count++;
}
}
return count;
}
/**
* 비활성 상태의 인스턴스 수를 반환합니다.
*/
public int getInactiveInstanceCount() {
int count = 0;
for (InstanceDTO instance : instances) {
if ("inactive".equals(instance.getStatus())) {
count++;
}
}
return count;
}
}
@@ -0,0 +1,109 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
/**
* SMS 장애 통보 정보를 담는 DTO 클래스
*/
public class SmsNotificationDto {
@JsonFormat(pattern = "MMdd HH:mm:ss.SSS")
private LocalDateTime dateTime; // 발생 일시
private Integer count; // 발생 건수
private String instanceName; // 인스턴스 명
private String errorContent; // 에러 내용
private String adapterDesc; // 어댑터 설명 (어댑터 오류인 경우)
private String adapterId; // 어댑터 ID (어댑터 오류인 경우)
private String interfaceId; // 인터페이스 ID (인터페이스 오류인 경우)
private String errorType; // 오류 유형 (ADAPTER/INTERFACE)
private String serviceType; // 서비스 유형
// Getters and Setters
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime(LocalDateTime dateTime) {
this.dateTime = dateTime;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public String getInstanceName() {
return instanceName;
}
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}
public String getErrorContent() {
return errorContent;
}
public void setErrorContent(String errorContent) {
this.errorContent = errorContent;
}
public String getAdapterDesc() {
return adapterDesc;
}
public void setAdapterDesc(String adapterDesc) {
this.adapterDesc = adapterDesc;
}
public String getAdapterId() {
return adapterId;
}
public void setAdapterId(String adapterId) {
this.adapterId = adapterId;
}
public String getInterfaceId() {
return interfaceId;
}
public void setInterfaceId(String interfaceId) {
this.interfaceId = interfaceId;
}
public String getErrorType() {
return errorType;
}
public void setErrorType(String errorType) {
this.errorType = errorType;
}
public String getServiceType() {
return serviceType;
}
public void setServiceType(String serviceType) {
this.serviceType = serviceType;
}
@Override
public String toString() {
return "SmsNotificationDto{" +
"dateTime=" + dateTime +
", count=" + count +
", instanceName='" + instanceName + '\'' +
", errorContent='" + errorContent + '\'' +
", adapterDesc='" + adapterDesc + '\'' +
", adapterId='" + adapterId + '\'' +
", interfaceId='" + interfaceId + '\'' +
", errorType='" + errorType + '\'' +
", serviceType='" + serviceType + '\'' +
'}';
}
}
@@ -0,0 +1,220 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import java.util.List;
/**
* Socket Process DTO for modern dashboard
*/
public class SocketProcessDTO {
private JsonPageVoDTO jsonPageVo;
private int total;
private int page;
private int records;
private List<SocketProcessItemDTO> rows;
public SocketProcessDTO() {
}
public JsonPageVoDTO getJsonPageVo() {
return jsonPageVo;
}
public void setJsonPageVo(JsonPageVoDTO jsonPageVo) {
this.jsonPageVo = jsonPageVo;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRecords() {
return records;
}
public void setRecords(int records) {
this.records = records;
}
public List<SocketProcessItemDTO> getRows() {
return rows;
}
public void setRows(List<SocketProcessItemDTO> rows) {
this.rows = rows;
}
/**
* JsonPageVo DTO
*/
public static class JsonPageVoDTO {
private int page;
private int totalCount;
private int rows;
private int total;
private int startNum;
private int endNum;
public JsonPageVoDTO() {
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getStartNum() {
return startNum;
}
public void setStartNum(int startNum) {
this.startNum = startNum;
}
public int getEndNum() {
return endNum;
}
public void setEndNum(int endNum) {
this.endNum = endNum;
}
}
/**
* Socket Process Item DTO
*/
public static class SocketProcessItemDTO {
private String maxConnection;
private String status;
private String eaiSevrInstncName;
private String adptrBzwkGroupName;
private String currentConnection;
private String recvCount;
private String adptrBzwkName;
private String adptrBzwkDesc;
private String sendCount;
private String errorCount;
public SocketProcessItemDTO() {
}
public String getMaxConnection() {
return maxConnection;
}
public void setMaxConnection(String maxConnection) {
this.maxConnection = maxConnection;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getEaiSevrInstncName() {
return eaiSevrInstncName;
}
public void setEaiSevrInstncName(String eaiSevrInstncName) {
this.eaiSevrInstncName = eaiSevrInstncName;
}
public String getAdptrBzwkGroupName() {
return adptrBzwkGroupName;
}
public void setAdptrBzwkGroupName(String adptrBzwkGroupName) {
this.adptrBzwkGroupName = adptrBzwkGroupName;
}
public String getCurrentConnection() {
return currentConnection;
}
public void setCurrentConnection(String currentConnection) {
this.currentConnection = currentConnection;
}
public String getRecvCount() {
return recvCount;
}
public void setRecvCount(String recvCount) {
this.recvCount = recvCount;
}
public String getAdptrBzwkName() {
return adptrBzwkName;
}
public void setAdptrBzwkName(String adptrBzwkName) {
this.adptrBzwkName = adptrBzwkName;
}
public String getAdptrBzwkDesc() {
return adptrBzwkDesc;
}
public void setAdptrBzwkDesc(String adptrBzwkDesc) {
this.adptrBzwkDesc = adptrBzwkDesc;
}
public String getSendCount() {
return sendCount;
}
public void setSendCount(String sendCount) {
this.sendCount = sendCount;
}
public String getErrorCount() {
return errorCount;
}
public void setErrorCount(String errorCount) {
this.errorCount = errorCount;
}
}
}
@@ -0,0 +1,148 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import java.util.List;
/**
* Socket Status DTO for modern dashboard
*/
public class SocketStatusDTO {
private int total;
private int page;
private int records;
private List<SocketStatusItemDTO> rows;
public SocketStatusDTO() {
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRecords() {
return records;
}
public void setRecords(int records) {
this.records = records;
}
public List<SocketStatusItemDTO> getRows() {
return rows;
}
public void setRows(List<SocketStatusItemDTO> rows) {
this.rows = rows;
}
/**
* Socket Status Item DTO
*/
public static class SocketStatusItemDTO {
private String status;
private String eaiSevrInstncName;
private String testMasterYn;
private String adptrNickName;
private String startStop;
private String adptrBzwkGroupName;
private String adptrBzwkName;
private String adptrType;
private String starting;
private String adptrBzwkDesc;
public SocketStatusItemDTO() {
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getEaiSevrInstncName() {
return eaiSevrInstncName;
}
public void setEaiSevrInstncName(String eaiSevrInstncName) {
this.eaiSevrInstncName = eaiSevrInstncName;
}
public String getTestMasterYn() {
return testMasterYn;
}
public void setTestMasterYn(String testMasterYn) {
this.testMasterYn = testMasterYn;
}
public String getAdptrNickName() {
return adptrNickName;
}
public void setAdptrNickName(String adptrNickName) {
this.adptrNickName = adptrNickName;
}
public String getStartStop() {
return startStop;
}
public void setStartStop(String startStop) {
this.startStop = startStop;
}
public String getAdptrBzwkGroupName() {
return adptrBzwkGroupName;
}
public void setAdptrBzwkGroupName(String adptrBzwkGroupName) {
this.adptrBzwkGroupName = adptrBzwkGroupName;
}
public String getAdptrBzwkName() {
return adptrBzwkName;
}
public void setAdptrBzwkName(String adptrBzwkName) {
this.adptrBzwkName = adptrBzwkName;
}
public String getAdptrType() {
return adptrType;
}
public void setAdptrType(String adptrType) {
this.adptrType = adptrType;
}
public String getStarting() {
return starting;
}
public void setStarting(String starting) {
this.starting = starting;
}
public String getAdptrBzwkDesc() {
return adptrBzwkDesc;
}
public void setAdptrBzwkDesc(String adptrBzwkDesc) {
this.adptrBzwkDesc = adptrBzwkDesc;
}
}
}
@@ -0,0 +1,30 @@
package com.eactive.eai.rms.onl.dashboard.modern.dto;
import lombok.Data;
/**
* 트랜잭션 정보 DTO
* 시스템 내 처리된 트랜잭션 정보를 전달하기 위한 데이터 객체입니다.
*/
@Data
public class TransactionDTO {
private String type; // 서비스 유형(EAI, FEP 등)
private int success; // 성공 건수
private int fail; // 실패(업무 에러) 건수
private int timeout; // 타임아웃 건수
private int syserror; // 시스템 에러 건수
/**
* 총 처리 건수 반환
*/
public int getTotal() {
return success + fail + timeout + syserror;
}
/**
* 에러 건수 합계 반환 (업무 에러 + 타임아웃 + 시스템 에러)
*/
public int getTotalError() {
return fail + timeout + syserror;
}
}
@@ -0,0 +1,354 @@
package com.eactive.eai.rms.onl.dashboard.modern.mapper;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.onl.dashboard.modern.dto.*;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.AdaptersVO;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 대시보드 데이터 매퍼
* VO 객체를 DTO로 변환하는 역할을 담당합니다.
*/
@Component
public class DashboardDataMapper {
/**
* EAIEngineStatusVo를 ServerStatusDTO로 변환
* 서버 상태 정보를 포함합니다.
*/
public ServerStatusDTO fromEAIEngineStatusVo(EAIEngineStatusVo vo) {
ServerStatusDTO dto = new ServerStatusDTO();
if (vo == null) {
return dto;
}
// 서버 기본 정보 설정
dto.setName(vo.getServerName() != null ? vo.getServerName() : vo.getHostName());
dto.setText(vo.getService());
// 서버 상태 설정 (serverStateImage: 0=중지/에러, 1=경고, 2=정상)
switch (vo.getServerStateImage()) {
case 0:
dto.setStatus("error");
break;
case 1:
dto.setStatus("warning");
break;
case 2:
dto.setStatus("normal");
break;
default:
dto.setStatus("unknown");
}
// 리소스 사용률 설정
if (vo.getHeapSizeCurrent() > 0) {
dto.setCpu((int)(100 - (vo.getHeapFreeCurrent() * 100) / vo.getHeapSizeCurrent()));
} else {
dto.setCpu(0);
}
dto.setMemory(vo.getHeapFreePercent() > 0 ? 100 - vo.getHeapFreePercent() : 0);
dto.setDisk(vo.getJmsFileStoreUseAge());
// 인스턴스 정보 설정
List<InstanceDTO> instances = new ArrayList<>();
InstanceDTO instance = new InstanceDTO();
instance.setId(vo.getInstanceName());
// 인스턴스 상태 설정
switch (vo.getServerStateImage()) {
case 0:
instance.setStatus("error");
break;
case 1:
instance.setStatus("warning");
break;
case 2:
instance.setStatus("normal");
break;
default:
instance.setStatus("inactive");
}
// 처리량 정보 설정
instance.setThroughput(vo.getPendingRequestCurrentCount() + "/s");
instances.add(instance);
dto.setInstances(instances);
return dto;
}
/**
* HostStatusVo를 ServerStatusDTO로 변환
* 호스트 상태 정보를 포함합니다.
*/
public ServerStatusDTO fromHostStatusVo(HostStatusVo vo) {
ServerStatusDTO dto = new ServerStatusDTO();
if (vo == null) {
return dto;
}
dto.setName(vo.getHostName());
dto.setText(vo.getHostName());
dto.setCpu(vo.getCpu());
dto.setMemory(vo.getMemory());
dto.setDisk(vo.getDisk());
dto.setStatus(getStatusFromUsage(vo.getCpu(), vo.getMemory(), vo.getDisk()));
// 인스턴스 리스트는 다른 곳에서 채워질 것임
dto.setInstances(new ArrayList<>());
return dto;
}
/**
* AdaptersVO를 AdapterStatusDTO 목록으로 변환
* Socket, HTTP 어댑터 정보만 포함합니다.
*/
public List<AdapterStatusDTO> fromAdaptersVO(AdaptersVO vo) {
List<AdapterStatusDTO> dtoList = new ArrayList<>();
if (vo == null) {
return dtoList;
}
// Socket 어댑터 상태 (Socket과 Socket2를 하나로 통합)
AdapterStatusDTO socketDTO = new AdapterStatusDTO();
socketDTO.setServerName(vo.getHostName());
socketDTO.setInstanceId(vo.getInstanceName());
socketDTO.setAdapterType("Socket");
// Socket과 Socket2의 상태 중 더 심각한 상태를 선택
int socketStatus = vo.getSocket(3);
int socket2Status = vo.getSocket2(3);
int combinedStatus = Math.min(socketStatus, socket2Status); // 낮은 값이 더 심각한 상태
socketDTO.setStatus(getStatusTextFromCode(combinedStatus));
// Socket과 Socket2의 카운트를 합산
socketDTO.setTotalCount(vo.getSocket(0) + vo.getSocket2(0));
socketDTO.setRunningCount(vo.getSocket(1) + vo.getSocket2(1));
socketDTO.setStopCount(vo.getSocket(2) + vo.getSocket2(2));
dtoList.add(socketDTO);
// HTTP 어댑터 상태
AdapterStatusDTO httpDTO = new AdapterStatusDTO();
httpDTO.setServerName(vo.getHostName());
httpDTO.setInstanceId(vo.getInstanceName());
httpDTO.setAdapterType("HTTP");
httpDTO.setStatus(getStatusTextFromCode(vo.getHttp(3)));
httpDTO.setTotalCount(vo.getHttp(0));
httpDTO.setRunningCount(vo.getHttp(1));
httpDTO.setStopCount(vo.getHttp(2));
dtoList.add(httpDTO);
return dtoList;
}
/**
* 상태 코드를 텍스트로 변환
*/
private String getStatusTextFromCode(int statusCode) {
switch (statusCode) {
case 0:
return "error";
case 1:
return "warning";
case 2:
return "normal";
case 3:
return "inactive";
default:
return "unknown";
}
}
/**
* MemStaticsVo를 TransactionDTO로 변환
* 트랜잭션 통계 정보를 포함합니다.
*/
public TransactionDTO fromMemStaticsVo(MemStaticsVo vo, String serviceType) {
TransactionDTO dto = new TransactionDTO();
if (vo == null) {
return dto;
}
dto.setType(serviceType); // 서비스 타입을 파라미터로 받아서 설정
dto.setSuccess(vo.getProcTotal() - vo.getTimeoutTotal() - vo.getErrorTotal() - vo.getSysErrorTotal());
dto.setTimeout(vo.getTimeoutTotal());
dto.setFail(vo.getErrorTotal());
dto.setSyserror(vo.getSysErrorTotal());
return dto;
}
/**
* DB 저장소에서 가져온 피크 성능 문자열을 PeakPerformanceDTO로 변환
*/
public PeakPerformanceDTO fromPeakPerformanceString(String peakDataStr, String type) {
PeakPerformanceDTO dto = new PeakPerformanceDTO();
if (peakDataStr == null || peakDataStr.isEmpty()) {
return dto;
}
String[] fields = peakDataStr.split(",");
if (fields.length < 4) {
return dto;
}
dto.setServiceType(fields[0]); // 서비스 유형
dto.setDate(fields[1]); // 날짜
try {
dto.setTransactionCount(Integer.parseInt(fields[2])); // 처리 건수
if( "--".equals(fields[3]) ){
dto.setTps(0);
} else {
dto.setTps(Integer.parseInt(fields[3])); // TPS
}
} catch (NumberFormatException e) {
dto.setTransactionCount(0);
dto.setTps(0);
}
return dto;
}
/**
* 일괄 전송 처리 데이터를 BatchProcessDTO로 변환
* @param csvData 형식: 송신성공,수신성공,송신에러,수신에러,송신대기,수신대기
*/
public BatchProcessDTO fromBatchProcessString(String serviceType, String csvData) {
BatchProcessDTO dto = new BatchProcessDTO();
dto.setServiceType(serviceType);
dto.setProcBatch(csvData); // 원본 CSV 데이터 설정
return dto;
}
/**
* 서버 인스턴스 정보를 포함하는 서버 상태 DTO 생성
*/
public ServerStatusDTO createServerStatus(DataSourceType server, Map<String, Object> serverData) {
ServerStatusDTO dto = new ServerStatusDTO();
dto.setName(server.getName());
dto.setText(server.getText());
// CPU, 메모리, 디스크 사용률 설정
if (serverData.containsKey("cpu")) {
dto.setCpu((int) serverData.get("cpu"));
}
if (serverData.containsKey("memory")) {
dto.setMemory((int) serverData.get("memory"));
}
if (serverData.containsKey("disk")) {
dto.setDisk((int) serverData.get("disk"));
}
// 서버 상태 설정
dto.setStatus(getStatusFromUsage(dto.getCpu(), dto.getMemory(), dto.getDisk()));
// 인스턴스 목록 설정
List<InstanceDTO> instances = new ArrayList<>();
if (serverData.containsKey("instances")) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> instanceDataList = (List<Map<String, Object>>) serverData.get("instances");
for (Map<String, Object> instanceData : instanceDataList) {
InstanceDTO instance = new InstanceDTO();
if (instanceData.containsKey("id")) {
instance.setId((String) instanceData.get("id"));
}
if (instanceData.containsKey("status")) {
instance.setStatus((String) instanceData.get("status"));
}
if (instanceData.containsKey("throughput")) {
instance.setThroughput((String) instanceData.get("throughput"));
}
instances.add(instance);
}
}
dto.setInstances(instances);
return dto;
}
/**
* 사용률에 따른 상태 반환
*/
private String getStatusFromUsage(int cpu, int memory, int disk) {
if (cpu > 90 || memory > 90 || disk > 90) {
return "error";
} else if (cpu > 70 || memory > 70 || disk > 70) {
return "warning";
} else {
return "normal";
}
}
/**
* 서버 이름과 인스턴스 목록을 기반으로 인스턴스별 상태를 생성
*/
public List<Map<String, Object>> createInstanceStatusList(String serverName, List<EAIEngineStatusVo> engineStatusList) {
List<Map<String, Object>> instanceStatusList = new ArrayList<>();
for (EAIEngineStatusVo engineStatus : engineStatusList) {
Map<String, Object> instanceStatus = new HashMap<>();
instanceStatus.put("serverName", serverName);
instanceStatus.put("instanceName", engineStatus.getInstanceName());
instanceStatus.put("status", getStatusTextFromCode(engineStatus.getServerStateImage()));
instanceStatus.put("cpu", engineStatus.getHeapFreePercent() > 0 ? 100 - engineStatus.getHeapFreePercent() : 0);
instanceStatus.put("memory", engineStatus.getHeapFreePercent() > 0 ? engineStatus.getHeapFreePercent() : 0);
instanceStatus.put("disk", engineStatus.getJmsFileStoreUseAge());
instanceStatus.put("throughput", engineStatus.getPendingRequestCurrentCount() + "/s");
instanceStatusList.add(instanceStatus);
}
return instanceStatusList;
}
/**
* AdaptersVO 목록을 AdapterStatusSummaryContainerDTO로 변환
* 어댑터 유형별 상태 집계 정보를 제공합니다.
*/
public AdapterStatusSummaryContainerDTO fromAdaptersVOList(List<AdaptersVO> adaptersList) {
AdapterStatusSummaryContainerDTO container = new AdapterStatusSummaryContainerDTO();
if (adaptersList == null || adaptersList.isEmpty()) {
return container;
}
// 각 어댑터의 상태를 집계
for (AdaptersVO vo : adaptersList) {
if (vo == null) continue;
// Socket 어댑터 상태 집계 (Socket과 Socket2를 하나로 통합)
container.getAdapterSummary("Socket").incrementStatusCount(vo.getSocket(3));
container.getAdapterSummary("Socket").incrementStatusCount(vo.getSocket2(3));
// HTTP 어댑터 상태 집계
container.getAdapterSummary("HTTP").incrementStatusCount(vo.getHttp(3));
}
// 전체 상태 업데이트
container.updateOverallStatus();
return container;
}
}
@@ -0,0 +1,169 @@
package com.eactive.eai.rms.onl.dashboard.modern.mapper;
import com.eactive.eai.rms.onl.dashboard.modern.dto.SmsNotificationDto;
import com.eactive.eai.rms.onl.vo.SmsVO;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SMS 장애 통보 정보를 DTO로 변환하는 매퍼 클래스
*/
@Component
public class SmsNotificationMapper {
private static final Pattern DATE_TIME_PATTERN = Pattern.compile("(\\d{4}) (\\d{2}:\\d{2}:\\d{2}\\.\\d{3})");
private static final Pattern COUNT_PATTERN = Pattern.compile("\\[(\\d+)\\]");
/**
* SmsVO 목록을 SmsNotificationDto 목록으로 변환합니다.
*
* @param smsList SmsVO 목록
* @return SmsNotificationDto 목록
*/
public List<SmsNotificationDto> mapToSmsNotificationDtoList(List<SmsVO> smsList) {
List<SmsNotificationDto> dtoList = new ArrayList<>();
if (smsList == null || smsList.isEmpty()) {
return dtoList;
}
for (SmsVO smsVO : smsList) {
List<String> messages = smsVO.getMessage();
if (messages != null && !messages.isEmpty()) {
for (String msg : messages) {
SmsNotificationDto dto = parseMessage(msg);
if (dto != null) {
dto.setServiceType(smsVO.getService()); // SmsVO의 service 값을 serviceType으로 매핑
dtoList.add(dto);
}
}
}
}
return dtoList;
}
/**
* 메시지를 파싱하여 SmsNotificationDto 객체를 생성합니다.
*
* @param message 메시지 문자열
* @return SmsNotificationDto 객체
*/
private SmsNotificationDto parseMessage(String message) {
if (message == null || message.trim().isEmpty()) {
return null;
}
try {
String[] parts = message.split("\\|");
// Determine message type based on number of delimiters
boolean isAdapterError = parts.length == 3;
boolean isInterfaceError = parts.length == 2;
if (!isAdapterError && !isInterfaceError) {
return null;
}
SmsNotificationDto dto = new SmsNotificationDto();
// Parse the first part (common for both types)
String mainPart = parts[0];
// Extract date and time
Matcher dateTimeMatcher = DATE_TIME_PATTERN.matcher(mainPart);
if (dateTimeMatcher.find()) {
String mmdd = dateTimeMatcher.group(1);
String time = dateTimeMatcher.group(2);
String year = String.valueOf(LocalDate.now().getYear());
String dateTimeStr = year + mmdd + " " + time; // Assuming current year
LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr,
DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSS"));
dto.setDateTime(dateTime);
}
// 당일 데이터가 아닌건은 skip
if( !LocalDate.now().equals(dto.getDateTime().toLocalDate()) ){
return null;
}
// Extract count
Matcher countMatcher = COUNT_PATTERN.matcher(mainPart);
if (countMatcher.find()) {
dto.setCount(Integer.parseInt(countMatcher.group(1)));
}
// Extract instance name (between [] and first space after it)
int instanceStart = mainPart.indexOf("]") + 1;
int errorStart = mainPart.indexOf(" ", instanceStart);
if (instanceStart > 0 && errorStart > instanceStart) {
dto.setInstanceName(mainPart.substring(instanceStart, errorStart));
}
// Extract error content
if (errorStart > 0) {
dto.setErrorContent(mainPart.substring(errorStart).trim());
}
if (isAdapterError) {
// Adapter error specific fields
dto.setAdapterDesc(parts[1].trim());
dto.setAdapterId(parts[2].trim());
dto.setErrorType("ADAPTER");
} else {
// Interface error specific fields
dto.setInterfaceId(parts[1].trim());
dto.setErrorType("INTERFACE");
}
return dto;
} catch (Exception e) {
// Log error if needed
return null;
}
}
public static void main(String[] args) {
SmsNotificationMapper mapper = new SmsNotificationMapper();
SmsVO smsVO = new SmsVO();
// 테스트할 메시지들
List<String> messages = Arrays.asList(
"0311 09:59:16.537[1]fep11 가용소켓연결없음|BASICTEST101S1",
"0311 10:05:39.779[49]fep11 Client커넥션오류|싱글어댑터 Prim|_TST_OU_NET_AsC{ALL}",
"0311 10:05:39.780[48]fep11 Client커넥션오류|비동기 표준 아|_TST_OU_NET_AsC{JSON_ALL}",
"0311 17:33:04.182[1]fep11 추적관리필드추출에러|BASICTEST101S1"
);
smsVO.setMessage(messages);
List<SmsNotificationDto> results = mapper.mapToSmsNotificationDtoList(Arrays.asList(smsVO));
System.out.println("=== SMS 메시지 파싱 결과 ===");
for (SmsNotificationDto dto : results) {
System.out.println("\n[메시지 정보]");
System.out.println("시간: " + dto.getDateTime());
System.out.println("건수: " + dto.getCount());
System.out.println("인스턴스: " + dto.getInstanceName());
System.out.println("에러내용: " + dto.getErrorContent());
System.out.println("에러유형: " + dto.getErrorType());
if ("ADAPTER".equals(dto.getErrorType())) {
System.out.println("어댑터설명: " + dto.getAdapterDesc());
System.out.println("어댑터ID: " + dto.getAdapterId());
} else {
System.out.println("인터페이스ID: " + dto.getInterfaceId());
}
System.out.println("------------------------");
}
}
}
@@ -0,0 +1,350 @@
package com.eactive.eai.rms.onl.dashboard.modern.service;
import com.eactive.eai.data.entity.onl.adapter.AdapterGroup;
import com.eactive.eai.data.entity.onl.server.EAIServer;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.data.entity.onl.adapter.AdapterGroupService;
import com.eactive.eai.rms.data.entity.onl.server.EAIServerService;
import com.eactive.eai.rms.onl.common.util.DataSetUtil;
import com.eactive.eai.rms.onl.common.vo.HostInfomationForm;
import com.eactive.eai.rms.onl.dashboard.modern.dto.InstitutionStatusDTO;
import com.eactive.eai.rms.onl.dashboard.modern.dto.SocketProcessDTO;
import com.eactive.eai.rms.onl.dashboard.modern.dto.SocketStatusDTO;
import com.eactive.eai.rms.onl.manage.adapter.adapter.mapper.AdapterGroupUIMapper;
import com.eactive.eai.rms.onl.manage.adapter.adapter.ui.AdapterGroupUI;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* Service for socket monitoring in modern dashboard
*/
@Service
public class SocketMonitorService {
private static final String AGENT_PAGE_STATUS = "adapter_socket2_agent1.jsp";
private static final String AGENT_PAGE_PROCESS = "adapter_socket2_agent2.jsp";
private final EAIServerService eaiServerService;
private final AdapterGroupService adapterGroupService;
private final AdapterGroupUIMapper adapterGroupUIMapper;
@Autowired
public SocketMonitorService(EAIServerService eaiServerService, AdapterGroupService adapterGroupService, AdapterGroupUIMapper adapterGroupUIMapper) {
this.eaiServerService = eaiServerService;
this.adapterGroupService = adapterGroupService;
this.adapterGroupUIMapper = adapterGroupUIMapper;
}
/**
* Get socket status data
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return SocketStatusDTO with all socket status data
*/
public SocketStatusDTO getSocketStatus(String serverName, String adapterGroup) {
try {
// Create a list to store all adapter data from all servers
List<HashMap<String, Object>> allAdapterData = new ArrayList<>();
// Loop through all online data source types
for (DataSourceType server : DataSourceTypeManager.getOnlineDataSourceTypes()) {
// Set server context
DataSourceContextHolder.setDataSourceType(server);
// Get server list for current data source
List<EAIServer> serverList = eaiServerService.selectEaiServerIpList();
if (serverList.isEmpty()) {
continue; // Skip if no servers found for this data source
}
List<String> urls = new ArrayList<>();
for (EAIServer serverMap : serverList) {
String serverUrl = "http://" + serverMap.getEaisevrip() + ":"
+ serverMap.getSevrlsnportname()
+ HostInfomationForm.WEB_AGENT_CONTEXT_PATH
+ AGENT_PAGE_STATUS + "?adapterType=SOC"
+ "&eaiSvrInstNm="
+ serverMap.getEaisevrinstncname();
urls.add(serverUrl);
}
// No filtering - get all data
DataSetUtil gUtil = new DataSetUtil();
List<HashMap<String, Object>> list = gUtil.flushXmlToClient(urls);
// Add to the combined list
allAdapterData.addAll(list);
}
// Reset the data source context
DataSourceContextHolder.clearDataSourceType();
// Convert the result to SocketStatusDTO
SocketStatusDTO result = new SocketStatusDTO();
result.setTotal(1);
result.setPage(1);
result.setRecords(allAdapterData.size());
// Convert HashMap list to SocketStatusItemDTO list
List<SocketStatusDTO.SocketStatusItemDTO> rows = new ArrayList<>();
for (HashMap<String, Object> item : allAdapterData) {
SocketStatusDTO.SocketStatusItemDTO row = new SocketStatusDTO.SocketStatusItemDTO();
// Map the fields from HashMap to DTO
row.setStatus((String) item.get("Status"));
row.setEaiSevrInstncName((String) item.get("EaiSevrInstncName"));
row.setTestMasterYn((String) item.get("TestMasterYn"));
row.setAdptrNickName((String) item.get("AdptrNickName"));
row.setStartStop((String) item.get("StartStop"));
row.setAdptrBzwkGroupName((String) item.get("AdptrBzwkGroupName"));
row.setAdptrBzwkName((String) item.get("AdptrBzwkName"));
row.setAdptrType((String) item.get("AdptrType"));
row.setStarting((String) item.get("Starting"));
row.setAdptrBzwkDesc((String) item.get("AdptrBzwkDesc"));
rows.add(row);
}
// Sort rows by AdptrBzwkGroupName in ascending order
rows.sort(Comparator.comparing(
row -> row.getAdptrBzwkGroupName() != null ? row.getAdptrBzwkGroupName() : ""
));
result.setRows(rows);
return result;
} catch (Exception e) {
throw new RuntimeException("Failed to get socket status data", e);
}
}
/**
* Get socket process data
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return SocketProcessDTO with all socket process data
*/
public SocketProcessDTO getSocketProcess(String serverName, String adapterGroup) {
try {
// Create a list to store all adapter data from all servers
List<HashMap<String, Object>> allAdapterData = new ArrayList<>();
// Loop through all online data source types
for (DataSourceType server : DataSourceTypeManager.getOnlineDataSourceTypes()) {
// Set server context
DataSourceContextHolder.setDataSourceType(server);
// Get server list for current data source
List<EAIServer> serverList = eaiServerService.selectEaiServerIpList();
if (serverList.isEmpty()) {
continue; // Skip if no servers found for this data source
}
List<String> urls = new ArrayList<>();
for (EAIServer serverMap : serverList) {
String serverUrl = "http://" + serverMap.getEaisevrip() + ":"
+ serverMap.getSevrlsnportname()
+ HostInfomationForm.WEB_AGENT_CONTEXT_PATH
+ AGENT_PAGE_PROCESS + "?cmd=get+connection+summary"
+ "&eaiSvrInstNm=" + serverMap.getEaisevrinstncname();
urls.add(serverUrl);
}
// No filtering - get all data
DataSetUtil gUtil = new DataSetUtil();
List<HashMap<String, Object>> list = gUtil.flushXmlToClient(urls);
// Add to the combined list
allAdapterData.addAll(list);
}
// Reset the data source context
DataSourceContextHolder.clearDataSourceType();
// Convert the result to SocketProcessDTO
SocketProcessDTO result = new SocketProcessDTO();
// Create JsonPageVoDTO
SocketProcessDTO.JsonPageVoDTO jsonPageVo = new SocketProcessDTO.JsonPageVoDTO();
jsonPageVo.setPage(1);
jsonPageVo.setTotalCount(allAdapterData.size());
jsonPageVo.setRows(10000);
jsonPageVo.setTotal(1);
jsonPageVo.setStartNum(1);
jsonPageVo.setEndNum(10000);
result.setJsonPageVo(jsonPageVo);
result.setTotal(1);
result.setPage(1);
result.setRecords(allAdapterData.size());
// Convert HashMap list to SocketProcessItemDTO list
List<SocketProcessDTO.SocketProcessItemDTO> rows = new ArrayList<>();
for (HashMap<String, Object> item : allAdapterData) {
SocketProcessDTO.SocketProcessItemDTO row = new SocketProcessDTO.SocketProcessItemDTO();
// Map the fields from HashMap to DTO
row.setMaxConnection((String) item.get("MaxConnection"));
row.setCurrentConnection((String) item.get("CurrentConnection"));
row.setStatus((String) item.get("Status"));
row.setEaiSevrInstncName((String) item.get("EaiSevrInstncName"));
row.setAdptrBzwkGroupName((String) item.get("AdptrBzwkGroupName"));
row.setRecvCount((String) item.get("RecvCount"));
row.setAdptrBzwkName((String) item.get("AdptrBzwkName"));
row.setAdptrBzwkDesc((String) item.get("AdptrBzwkDesc"));
row.setSendCount((String) item.get("SendCount"));
row.setErrorCount((String) item.get("ErrorCount"));
rows.add(row);
}
// Sort rows by AdptrBzwkGroupName in ascending order
rows.sort(Comparator.comparing(
row -> row.getAdptrBzwkGroupName() != null ? row.getAdptrBzwkGroupName() : ""
));
result.setRows(rows);
return result;
} catch (Exception e) {
throw new RuntimeException("Failed to get socket process data", e);
}
}
/**
* Get institution monitoring status data
* @param statusData Socket status data with adapter information
* @return List of institution status information
*/
public List<InstitutionStatusDTO> getInstitutionStatus(SocketStatusDTO statusData) {
try {
// Set context to access AdapterGroup data
DataSourceContextHolder.setDataSourceType(DataSourceTypeManager.getOnlineDataSourceTypes().get(0));
// Get institutions with non-empty adptrinsticode
List<AdapterGroup> adapterGroups = adapterGroupService.findByAdptrinsticodeNotEmpty();
List<AdapterGroupUI> adapterGroupUIs = adapterGroups.stream()
.map(adapterGroupUIMapper::toVoWithoutChildrenMapping)
.collect(Collectors.toList());
// Group adapter groups by institution code
Map<String, List<AdapterGroupUI>> institutionGroups = adapterGroupUIs.stream()
.filter(ag -> StringUtils.isNotBlank(ag.getAdptrinsticode()))
.collect(Collectors.groupingBy(AdapterGroupUI::getAdptrinsticode));
List<InstitutionStatusDTO> result = new ArrayList<>();
// Process each institution
for (Map.Entry<String, List<AdapterGroupUI>> entry : institutionGroups.entrySet()) {
String institutionCode = entry.getKey();
List<AdapterGroupUI> institutionAdapters = entry.getValue();
if (institutionAdapters.isEmpty()) {
continue;
}
// Use the first adapter's information for institution details
AdapterGroupUI firstAdapter = institutionAdapters.get(0);
// Create a new institution status DTO
InstitutionStatusDTO institutionStatus = new InstitutionStatusDTO();
institutionStatus.setInstitutionCode(institutionCode);
institutionStatus.setInstitutionName(firstAdapter.getAdptrinstiName());
institutionStatus.setContactPerson(firstAdapter.getOsidinstibzwkrsempname());
institutionStatus.setContactNumber(firstAdapter.getOsidinstitelno());
// Get adapter group names for this institution
List<String> adapterGroupNames = institutionAdapters.stream()
.map(AdapterGroupUI::getAdptrbzwkgroupname)
.collect(Collectors.toList());
// Count normal and error adapters
int normalCount = 0;
int errorCount = 0;
// Check status in statusData
if (statusData != null && statusData.getRows() != null) {
for (SocketStatusDTO.SocketStatusItemDTO statusItem : statusData.getRows()) {
if (adapterGroupNames.contains(statusItem.getAdptrBzwkGroupName())) {
if ("NORMAL".equals(statusItem.getStatus()) ||
"true".equals(statusItem.getStatus()) ||
"OK".equals(statusItem.getStatus())) {
normalCount++;
} else {
errorCount++;
}
}
}
}
institutionStatus.setNormalAdapterCount(normalCount);
institutionStatus.setErrorAdapterCount(errorCount);
// Determine line status
if (normalCount == 0 && errorCount == 0) {
institutionStatus.setLineStatus("UNDEFINED");
} else if (errorCount == 0 && normalCount > 0) {
institutionStatus.setLineStatus("NORMAL");
} else if (errorCount > 0 && normalCount > 0) {
institutionStatus.setLineStatus("WARN");
} else if (errorCount > 0 && normalCount == 0) {
institutionStatus.setLineStatus("ERROR");
}
result.add(institutionStatus);
}
// Reset data source context
DataSourceContextHolder.clearDataSourceType();
// Sort the result by status priority: ERROR > WARN > NORMAL > UNDEFINED
result.sort((a, b) -> {
// Define status priority (higher number = higher priority)
Map<String, Integer> statusPriority = new HashMap<>();
statusPriority.put("ERROR", 3);
statusPriority.put("WARN", 2);
statusPriority.put("NORMAL", 1);
statusPriority.put("UNDEFINED", 0);
// Get priority values for comparison
int priorityA = statusPriority.getOrDefault(a.getLineStatus(), 0);
int priorityB = statusPriority.getOrDefault(b.getLineStatus(), 0);
// Sort by priority (descending)
return Integer.compare(priorityB, priorityA);
});
return result;
} catch (Exception e) {
DataSourceContextHolder.clearDataSourceType();
throw new RuntimeException("Failed to get institution status data", e);
}
}
/**
* Get combined socket data (both status and process)
* @param serverName Optional server name filter
* @param adapterGroup Optional adapter group filter
* @return Map containing both socket status and process data
*/
public Map<String, Object> getCombinedSocketData(String serverName, String adapterGroup) {
Map<String, Object> result = new HashMap<>();
SocketStatusDTO statusData = getSocketStatus(serverName, adapterGroup);
SocketProcessDTO processData = getSocketProcess(serverName, adapterGroup);
List<InstitutionStatusDTO> institutionStatus = getInstitutionStatus(statusData);
result.put("socketStatus", statusData);
result.put("socketProcess", processData);
result.put("institutionStatus", institutionStatus);
return result;
}
}
@@ -0,0 +1,571 @@
package com.eactive.eai.rms.onl.dashboard.modern.service;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
import com.eactive.eai.rms.onl.dashboard.service.Dashboard2RepositoryService;
import com.eactive.eai.rms.onl.dashboard.service.DashboardService;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 처리량 계산 서비스
* 각 인스턴스별 초당 처리량을 계산하여 저장합니다.
* 시계열 데이터를 유지하여 트렌드 분석에 사용합니다.
*/
@Slf4j
@Service
public class ThroughputCalculationService {
@Autowired
@Qualifier("eaiServerInfoService")
private EaiServerInfoService eaiServerInfoService;
@Autowired
@Qualifier("dashboard2RepositoryService")
private Dashboard2RepositoryService dashboard2Repository;
@Autowired
@Qualifier("dashboardService")
private DashboardService dashboardService;
// 인스턴스별 처리량 정보를 저장하는 작은 캐시
private final ConcurrentHashMap<String, ThroughputCacheInfo> throughputCache = new ConcurrentHashMap<>();
// 서비스 타입별 시계열 데이터를 저장하는 맵
// 키: 서비스타입(EAI, FEP 등), 값: TimeSeriesData 객체
private final ConcurrentHashMap<String, TimeSeriesData> timeSeriesMap = new ConcurrentHashMap<>();
// 서버별 리소스 사용량 시계열 데이터를 저장하는 맵
// 키: 호스트명, 값: ServerResourceData 객체
private final ConcurrentHashMap<String, ServerResourceData> serverResourceMap = new ConcurrentHashMap<>();
// 서비스 타입별 마지막 누적 값을 저장하는 맵
private final ConcurrentHashMap<String, Map<String, Integer>> lastAccumulatedValuesMap = new ConcurrentHashMap<>();
// 스케줄러
private ScheduledExecutorService scheduler;
// 시계열 데이터 저장 기간 (분)
private static final int TIME_SERIES_RETENTION_MINUTES = 60;
// 서버 정보 시계열 데이터 저장 기간 (분)
private static final int SERVER_STATUS_TIME_SERIES_RETENTION_MINUTES = 2;
// 시계열 데이터 샘플링 간격 (초)
private static final int TIME_SERIES_SAMPLING_SECONDS = 1;
// 처리량 정보를 담는 내부 클래스 (캐시용)
private static class ThroughputCacheInfo {
private long timestamp; // 마지막 조회 시간
private int totalCount; // 마지막 누적 건수
public ThroughputCacheInfo(long timestamp, int totalCount) {
this.timestamp = timestamp;
this.totalCount = totalCount;
}
}
// 시계열 데이터를 담는 내부 클래스
public static class TimeSeriesData {
private List<Long> timestamps = new ArrayList<>(); // 타임스탬프 목록
private List<Integer> success = new ArrayList<>(); // 성공 건수
private List<Integer> fail = new ArrayList<>(); // 실패 건수
private List<Integer> timeout = new ArrayList<>(); // 타임아웃 건수
private List<Integer> syserror = new ArrayList<>(); // 시스템 에러 건수
// 시계열 데이터 추가
public void addDataPoint(long timestamp, int successCount, int failCount, int timeoutCount, int syserrorCount) {
timestamps.add(timestamp);
success.add(successCount);
fail.add(failCount);
timeout.add(timeoutCount);
syserror.add(syserrorCount);
// 오래된 데이터 정리 (최대 저장 기간을 초과하는 데이터 제거)
long cutoffTime = System.currentTimeMillis() - (TIME_SERIES_RETENTION_MINUTES * 60 * 1000);
while (!timestamps.isEmpty() && timestamps.get(0) < cutoffTime) {
timestamps.remove(0);
success.remove(0);
fail.remove(0);
timeout.remove(0);
syserror.remove(0);
}
}
// Getter 메서드
public List<Long> getTimestamps() {
return timestamps;
}
public List<Integer> getSuccess() {
return success;
}
public List<Integer> getFail() {
return fail;
}
public List<Integer> getTimeout() {
return timeout;
}
public List<Integer> getSyserror() {
return syserror;
}
}
// 서버 리소스 사용량 시계열 데이터를 담는 내부 클래스
public static class ServerResourceData {
private List<Long> timestamps = new ArrayList<>(); // 타임스탬프 목록
private List<Integer> cpu = new ArrayList<>(); // CPU 사용률
private List<Integer> memory = new ArrayList<>(); // 메모리 사용률
private List<Integer> disk = new ArrayList<>(); // 디스크 사용률
// 시계열 데이터 추가
public void addDataPoint(long timestamp, int cpuUsage, int memoryUsage, int diskUsage) {
timestamps.add(timestamp);
cpu.add(cpuUsage);
memory.add(memoryUsage);
disk.add(diskUsage);
}
public void removeExpiredDataPoint(){
// 오래된 데이터 정리 (최대 저장 기간을 초과하는 데이터 제거)
long cutoffTime = System.currentTimeMillis() - (SERVER_STATUS_TIME_SERIES_RETENTION_MINUTES * 60 * 1000);
while (!timestamps.isEmpty() && timestamps.get(0) < cutoffTime) {
timestamps.remove(0);
cpu.remove(0);
memory.remove(0);
disk.remove(0);
}
}
// Getter 메서드
public List<Long> getTimestamps() {
return timestamps;
}
public List<Integer> getCpu() {
return cpu;
}
public List<Integer> getMemory() {
return memory;
}
public List<Integer> getDisk() {
return disk;
}
// 최근 N개의 데이터 포인트 반환
public ServerResourceData getRecentDataPoints(int count) {
ServerResourceData result = new ServerResourceData();
int size = timestamps.size();
int startIndex = Math.max(0, size - count);
for (int i = startIndex; i < size; i++) {
result.timestamps.add(timestamps.get(i));
result.cpu.add(cpu.get(i));
result.memory.add(memory.get(i));
result.disk.add(disk.get(i));
}
return result;
}
}
/**
* 초기화 메서드
* 서비스 로드 시 스케줄러를 시작합니다.
*/
@PostConstruct
public void init() {
log.info("처리량 계산 서비스 초기화");
// 스케줄러 생성
scheduler = Executors.newScheduledThreadPool(2);
// 시계열 데이터 수집 작업 추가 (지정된 간격마다 실행)
scheduler.scheduleWithFixedDelay(this::collectTimeSeriesData, 5, TIME_SERIES_SAMPLING_SECONDS, TimeUnit.SECONDS);
// 서버 리소스 사용량 데이터 수집 작업 추가 (10초마다 실행)
scheduler.scheduleWithFixedDelay(this::collectServerResourceData, 3, 10, TimeUnit.SECONDS);
log.info("처리량 계산 스케줄러 시작됨");
// 서비스 타입 초기화
for (DataSourceType server : DataSourceTypeManager.getOnlineDataSourceTypes()) {
timeSeriesMap.putIfAbsent(server.getName(), new TimeSeriesData());
}
// BAT(배치) 서버 추가
DataSourceType batServer = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT);
if (batServer != null) {
timeSeriesMap.putIfAbsent(batServer.getName(), new TimeSeriesData());
}
// BAP(일괄전송) 서버 추가
DataSourceType bapServer = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAP);
if (bapServer != null) {
timeSeriesMap.putIfAbsent(bapServer.getName(), new TimeSeriesData());
}
// 전체 데이터용 TOTAL 엔트리 추가
timeSeriesMap.putIfAbsent("TOTAL", new TimeSeriesData());
}
/**
* 종료 메서드
* 서비스 종료 시 스케줄러를 정리합니다.
*/
@PreDestroy
public void destroy() {
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdown();
log.info("처리량 계산 스케줄러 종료됨");
}
}
/**
* 서버 리소스 사용량 데이터 수집
* 10초마다 실행되어 각 서버의 CPU, 메모리, 디스크 사용량을 수집합니다.
*/
public void collectServerResourceData() {
try {
// 수집 시간
long currentTime = System.currentTimeMillis();
// 모든 온라인 데이터소스 타입에 대해 처리
List<DataSourceType> servers = DataSourceTypeManager.getOnlineDataSourceTypes();
// GW 추가
if( DataSourceTypeManager.getDataSourceType("FGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("FGW"));
}
if( DataSourceTypeManager.getDataSourceType("CGW") != null ){
servers.add(DataSourceTypeManager.getDataSourceType("CGW"));
}
for (DataSourceType server : servers) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> ipList = eaiServerInfoService.getEaiServerIpListDB();
// 호스트명으로 인스턴스 그룹화
Map<String, List<Map<String, String>>> instancesByHost = new HashMap<>();
for (Map<String, String> instance : ipList) {
String hostname = instance.get("HOSTNAME");
instancesByHost.computeIfAbsent(hostname, k -> new ArrayList<>()).add(instance);
}
// 각 호스트별로 리소스 사용량 수집
for (Map.Entry<String, List<Map<String, String>>> entry : instancesByHost.entrySet()) {
String hostname = entry.getKey();
List<Map<String, String>> hostInstances = entry.getValue();
// 호스트 상태 조회
HostStatusVo hostVo = dashboardService.findHostStatus(hostInstances);
if (hostVo != null) {
// 서버 리소스 데이터 객체 가져오기 또는 생성
ServerResourceData resourceData = serverResourceMap.computeIfAbsent(hostname, k -> new ServerResourceData());
// 데이터 포인트 추가
resourceData.addDataPoint(currentTime, hostVo.getCpu(), hostVo.getMemory(), hostVo.getDisk());
}
}
}
// 기간 만료 데이터 삭제
serverResourceMap.values().forEach(ServerResourceData::removeExpiredDataPoint);
} catch (Exception e) {
log.error("서버 리소스 사용량 데이터 수집 중 오류 발생", e);
}
}
/**
* 시계열 데이터 수집
* 정해진 간격마다 실행되어 각 서비스 타입별 처리 건수를 수집합니다.
*/
public void collectTimeSeriesData() {
try {
// 수집 시간
long currentTime = System.currentTimeMillis();
// 서비스 타입별 현재 누적 데이터
Map<String, Integer> currentSuccessByService = new HashMap<>();
Map<String, Integer> currentFailByService = new HashMap<>();
Map<String, Integer> currentTimeoutByService = new HashMap<>();
Map<String, Integer> currentSyserrorByService = new HashMap<>();
// 전체 합계
int totalSuccess = 0;
int totalFail = 0;
int totalTimeout = 0;
int totalSyserror = 0;
// 모든 온라인 데이터소스 타입에 대해 처리
List<DataSourceType> servers = DataSourceTypeManager.getOnlineDataSourceTypes();
for (DataSourceType server : servers) {
// 서버 컨텍스트 설정
DataSourceContextHolder.setDataSourceType(server);
// 서버의 트랜잭션 정보 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByService(server.getName());
if (memStatics != null) {
// 현재 누적 값 계산
int currentSuccess = memStatics.getProcTotal() - memStatics.getTimeoutTotal() - memStatics.getErrorTotal() - memStatics.getSysErrorTotal();
int currentFail = memStatics.getErrorTotal();
int currentTimeout = memStatics.getTimeoutTotal();
int currentSyserror = memStatics.getSysErrorTotal();
// 서비스별 데이터 저장
currentSuccessByService.put(server.getName(), currentSuccess);
currentFailByService.put(server.getName(), currentFail);
currentTimeoutByService.put(server.getName(), currentTimeout);
currentSyserrorByService.put(server.getName(), currentSyserror);
// 전체 합계에 추가
totalSuccess += currentSuccess;
totalFail += currentFail;
totalTimeout += currentTimeout;
totalSyserror += currentSyserror;
}
}
// 각 서비스 타입별 시계열 데이터 업데이트
for (String serviceType : timeSeriesMap.keySet()) {
if (serviceType.equals("TOTAL")) {
// TOTAL 데이터는 아래에서 별도로 처리
continue;
}
// 현재 누적 값
int currentSuccess = currentSuccessByService.getOrDefault(serviceType, 0);
int currentFail = currentFailByService.getOrDefault(serviceType, 0);
int currentTimeout = currentTimeoutByService.getOrDefault(serviceType, 0);
int currentSyserror = currentSyserrorByService.getOrDefault(serviceType, 0);
// 마지막 누적 값 가져오기
Map<String, Integer> lastValues = lastAccumulatedValuesMap.getOrDefault(serviceType, new HashMap<>());
// 차이 계산
int deltaSuccess = currentSuccess - lastValues.getOrDefault("success", 0);
int deltaFail = currentFail - lastValues.getOrDefault("fail", 0);
int deltaTimeout = currentTimeout - lastValues.getOrDefault("timeout", 0);
int deltaSyserror = currentSyserror - lastValues.getOrDefault("syserror", 0);
// 인스턴스 재기동 감지 (누적치가 감소한 경우)
boolean isReset = false;
if (deltaSuccess < 0 || deltaFail < 0 || deltaTimeout < 0 || deltaSyserror < 0) {
isReset = true;
}
// 시계열 데이터에 추가할 값 결정
// 재기동된 경우 건수는 0으로 처리
int addSuccess = isReset ? 0 : Math.max(0, deltaSuccess);
int addFail = isReset ? 0 : Math.max(0, deltaFail);
int addTimeout = isReset ? 0 : Math.max(0, deltaTimeout);
int addSyserror = isReset ? 0 : Math.max(0, deltaSyserror);
// 시계열 데이터 추가
TimeSeriesData timeSeriesData = timeSeriesMap.get(serviceType);
if (timeSeriesData != null) {
timeSeriesData.addDataPoint(currentTime, addSuccess, addFail, addTimeout, addSyserror);
}
// 마지막 누적 값 업데이트 (현재 값으로 항상 갱신)
Map<String, Integer> newLastValues = new HashMap<>();
newLastValues.put("success", currentSuccess);
newLastValues.put("fail", currentFail);
newLastValues.put("timeout", currentTimeout);
newLastValues.put("syserror", currentSyserror);
lastAccumulatedValuesMap.put(serviceType, newLastValues);
}
// TOTAL 시계열 데이터 업데이트
TimeSeriesData totalTimeSeriesData = timeSeriesMap.get("TOTAL");
if (totalTimeSeriesData != null) {
// 마지막 누적 값 가져오기
Map<String, Integer> lastTotalValues = lastAccumulatedValuesMap.getOrDefault("TOTAL", new HashMap<>());
// 차이 계산
int deltaSuccess = totalSuccess - lastTotalValues.getOrDefault("success", 0);
int deltaFail = totalFail - lastTotalValues.getOrDefault("fail", 0);
int deltaTimeout = totalTimeout - lastTotalValues.getOrDefault("timeout", 0);
int deltaSyserror = totalSyserror - lastTotalValues.getOrDefault("syserror", 0);
// 인스턴스 재기동 감지
boolean isReset = false;
if (deltaSuccess < 0 || deltaFail < 0 || deltaTimeout < 0 || deltaSyserror < 0) {
isReset = true;
}
// 시계열 데이터에 추가할 값 결정
int addSuccess = isReset ? 0 : Math.max(0, deltaSuccess);
int addFail = isReset ? 0 : Math.max(0, deltaFail);
int addTimeout = isReset ? 0 : Math.max(0, deltaTimeout);
int addSyserror = isReset ? 0 : Math.max(0, deltaSyserror);
totalTimeSeriesData.addDataPoint(currentTime, addSuccess, addFail, addTimeout, addSyserror);
// 마지막 누적 값 업데이트
Map<String, Integer> newLastTotalValues = new HashMap<>();
newLastTotalValues.put("success", totalSuccess);
newLastTotalValues.put("fail", totalFail);
newLastTotalValues.put("timeout", totalTimeout);
newLastTotalValues.put("syserror", totalSyserror);
lastAccumulatedValuesMap.put("TOTAL", newLastTotalValues);
}
} catch (Exception e) {
log.error("시계열 데이터 수집 중 오류 발생", e);
}
}
/**
* 특정 인스턴스의 처리량 조회
* 실시간으로 계산하여 반환합니다.
* @param hostName 호스트명
* @param instanceName 인스턴스명
* @return 초당 처리량 문자열 (예: "10.5/s")
*/
public String getThroughput(String hostName, String instanceName) {
try {
// 현재 처리 건수 조회
MemStaticsVo memStatics = dashboard2Repository.getMemTradeVoByHost(hostName, instanceName);
if (memStatics != null) {
// 현재 시간과 누적 건수
long currentTime = System.currentTimeMillis();
int currentTotal = memStatics.getProcTotal();
String instanceKey = hostName + "_" + instanceName;
// 이전 조회 데이터 가져오기
ThroughputCacheInfo prevInfo = throughputCache.get(instanceKey);
double throughput = 0.0;
boolean isReset = false;
if (prevInfo != null) {
// 경과 시간 계산 (초 단위)
double elapsedSeconds = (currentTime - prevInfo.timestamp) / 1000.0;
// 최소 0.1초 이상 경과했을 때만 계산
if (elapsedSeconds >= 0.1) {
int processedCount = currentTotal - prevInfo.totalCount;
// 처리 건수가 음수이면 인스턴스 재기동으로 간주
if (processedCount < 0) {
processedCount = 0;
isReset = true;
}
throughput = processedCount / elapsedSeconds;
}
}
// 캐시 업데이트
throughputCache.put(instanceKey, new ThroughputCacheInfo(currentTime, currentTotal));
// 처리량 문자열 반환
return String.format("%.1f/s", throughput);
}
} catch (Exception e) {
log.error("처리량 계산 중 오류 발생", e);
}
return "0/s";
}
/**
* 특정 서버의 리소스 사용량 시계열 데이터 조회
* @param hostname 호스트명
* @param count 조회할 데이터 포인트 수 (최대 7개)
* @return 서버 리소스 사용량 시계열 데이터
*/
public ServerResourceData getServerResourceData(String hostname, int count) {
// 데이터 포인트 수 제한 (최대 7개)
count = Math.min(count, 7);
ServerResourceData resourceData = serverResourceMap.get(hostname);
if (resourceData != null) {
return resourceData.getRecentDataPoints(count);
} else {
return new ServerResourceData();
}
}
/**
* 특정 서비스 타입의 시계열 데이터 조회
* @param serviceType 서비스 타입 (EAI, FEP 등)
* @param minutes 조회할 분 단위 기간 (최대 60분)
* @return 시계열 데이터
*/
public TimeSeriesData getTimeSeriesData(String serviceType, int minutes) {
// 기간 제한 (1~60분)
minutes = Math.min(Math.max(minutes, 1), TIME_SERIES_RETENTION_MINUTES);
// 기본적으로 요청된 서비스 타입의 시계열 데이터 사용
TimeSeriesData originalData = timeSeriesMap.get(serviceType);
// 서비스 타입이 없거나 "ALL"인 경우 TOTAL 데이터 사용
if (originalData == null || "ALL".equalsIgnoreCase(serviceType) || "all".equals(serviceType)) {
originalData = timeSeriesMap.get("TOTAL");
}
// 데이터가 없으면 빈 데이터 반환
if (originalData == null) {
return new TimeSeriesData();
}
// 기간에 맞게 데이터 필터링
TimeSeriesData filteredData = new TimeSeriesData();
long cutoffTime = System.currentTimeMillis() - (minutes * 60 * 1000);
List<Long> originalTimestamps = originalData.getTimestamps();
List<Integer> originalSuccess = originalData.getSuccess();
List<Integer> originalFail = originalData.getFail();
List<Integer> originalTimeout = originalData.getTimeout();
List<Integer> originalSyserror = originalData.getSyserror();
// 최근 데이터부터 시작하여 지정된 기간 내의 데이터만 필터링
for (int i = originalTimestamps.size() - 1; i >= 0; i--) {
if (originalTimestamps.get(i) >= cutoffTime) {
filteredData.timestamps.add(0, originalTimestamps.get(i));
filteredData.success.add(0, originalSuccess.get(i));
filteredData.fail.add(0, originalFail.get(i));
filteredData.timeout.add(0, originalTimeout.get(i));
filteredData.syserror.add(0, originalSyserror.get(i));
} else {
// 시간 범위를 벗어나면 종료
break;
}
}
return filteredData;
}
}
@@ -0,0 +1,334 @@
package com.eactive.eai.rms.onl.dashboard.modern.service;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
import com.eactive.eai.rms.onl.dashboard.service.Dashboard2RepositoryService;
import com.eactive.eai.rms.onl.server.repository.TransactionRepositoryService;
import com.eactive.eai.rms.onl.vo.TransactionTrackingVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 거래현황 집계 서비스
* 각 인터페이스별 10초 단위 처리량을 계산하여 저장합니다.
* 시계열 데이터를 유지하여 트렌드 분석에 사용합니다.
*/
@Slf4j
@Service
public class TransactionSummaryService {
@Autowired
@Qualifier("dashboard2RepositoryService")
private Dashboard2RepositoryService dashboard2Repository;
@Autowired
@Qualifier("transactionRepositoryService")
private TransactionRepositoryService transactionRepositoryService;
@Autowired
private EaiServerInfoService eaiServerInfoService;
// 인터페이스별 처리량 정보를 저장하는 맵
// 키: 서비스명, 값: 시계열 데이터
private final ConcurrentHashMap<String, TimeSeriesData> timeSeriesMap = new ConcurrentHashMap<>();
// 서비스별 마지막 누적 값을 저장하는 맵
private final ConcurrentHashMap<String, Map<String, Integer>> lastAccumulatedValuesMap = new ConcurrentHashMap<>();
// 스케줄러
private ScheduledExecutorService scheduler;
// 시계열 데이터 저장 기간 (초)
private static final int TIME_SERIES_RETENTION_SECONDS = 120;
// 시계열 데이터 샘플링 간격 (초)
private static final int TIME_SERIES_SAMPLING_SECONDS = 10;
// 시계열 데이터를 담는 내부 클래스
public static class TimeSeriesData {
private List<Long> timestamps = new ArrayList<>(); // 타임스탬프 목록
private List<Integer> success = new ArrayList<>(); // 성공 건수
private List<Integer> error = new ArrayList<>(); // 오류 건수
private List<Double> avgTime = new ArrayList<>(); // 평균 소요시간
// 시계열 데이터 추가
public void addDataPoint(long timestamp, int successCount, int errorCount, double avgProcessTime) {
timestamps.add(timestamp);
success.add(successCount);
error.add(errorCount);
avgTime.add(avgProcessTime);
// 오래된 데이터 정리 (최대 저장 기간을 초과하는 데이터 제거)
long cutoffTime = System.currentTimeMillis() - (TIME_SERIES_RETENTION_SECONDS * 1000);
while (!timestamps.isEmpty() && timestamps.get(0) < cutoffTime) {
timestamps.remove(0);
success.remove(0);
error.remove(0);
avgTime.remove(0);
}
}
// Getter 메서드들
public List<Long> getTimestamps() {
return timestamps;
}
public List<Integer> getSuccess() {
return success;
}
public List<Integer> getError() {
return error;
}
public List<Double> getAvgTime() {
return avgTime;
}
// 특정 기간 동안의 합계 계산
public Map<String, Integer> calculateTotalCounts() {
int totalSuccess = 0;
int totalError = 0;
for (int i = 0; i < success.size(); i++) {
totalSuccess += success.get(i);
totalError += error.get(i);
}
Map<String, Integer> totals = new HashMap<>();
totals.put("success", totalSuccess);
totals.put("error", totalError);
return totals;
}
}
/**
* 초기화 메서드
* 서비스 로드 시 스케줄러를 시작합니다.
*/
@PostConstruct
public void init() {
log.info("거래현황 집계 서비스 초기화");
// 스케줄러 생성
scheduler = Executors.newScheduledThreadPool(1);
// 시계열 데이터 수집 작업 추가 (10초마다 실행)
scheduler.scheduleWithFixedDelay(this::collectTimeSeriesData, 0, TIME_SERIES_SAMPLING_SECONDS, TimeUnit.SECONDS);
log.info("거래현황 집계 스케줄러 시작됨");
// 전체 데이터용 TOTAL 엔트리 추가
timeSeriesMap.putIfAbsent("TOTAL", new TimeSeriesData());
}
/**
* 종료 메서드
* 서비스 종료 시 스케줄러를 정리합니다.
*/
@PreDestroy
public void destroy() {
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdown();
log.info("거래현황 집계 스케줄러 종료됨");
}
}
/**
* 시계열 데이터 수집
* 10초마다 실행되어 각 서비스별 처리 건수를 수집합니다.
*/
public void collectTimeSeriesData() {
try {
// 수집 시간
long currentTime = System.currentTimeMillis();
// 서비스별 현재 누적 데이터
Map<String, Integer> currentSuccessByService = new HashMap<>();
Map<String, Integer> currentErrorByService = new HashMap<>();
Map<String, Double> currentProcessingTimeByService = new HashMap<>();
// 전체 합계
int totalSuccess = 0;
int totalError = 0;
double totalProcessingTime = 0.0;
int totalCount = 0;
// 모든 온라인 데이터소스 타입에 대해 처리
List<DataSourceType> servers = DataSourceTypeManager.getOnlineDataSourceTypes();
log.debug("온라인 DataSource 개수: {}", servers.size());
for (DataSourceType ds : servers) {
log.debug(" - DataSource: {}", ds.getName());
}
for (DataSourceType server : servers) {
try {
// 서버 컨텍스트 설정
log.debug("DataSource 전환: {}", server.getName());
DataSourceContextHolder.setDataSourceType(server);
// 서버에 대한 인스턴스 목록 조회
List<Map<String, String>> serverList = eaiServerInfoService.getEaiServerIpListDB();
log.debug(" - 서버 목록 개수: {}", serverList != null ? serverList.size() : 0);
if (serverList == null || serverList.isEmpty()) {
log.debug(" - {} DataSource에 대한 서버 목록이 없습니다. 건너뜁니다.", server.getName());
continue;
}
for (Map<String, String> serverInfo : serverList) {
// 트랜잭션 정보 조회를 위한 VO 생성
TransactionTrackingVo origin = new TransactionTrackingVo();
origin.setHostName(serverInfo.get("HOSTNAME"));
origin.setInstanceName(serverInfo.get("EAISVRINSTNM"));
// 트랜잭션 정보 조회
TransactionTrackingVo vo = transactionRepositoryService.getTrackingVo(origin);
if (vo != null) {
// 현재 누적 값 계산
int currentSuccess = vo.getTotalProc();
int currentError = vo.getTotalError();
double timeTotal = vo.getTimeTotal();
// 서비스별 데이터 저장 (서버명_인스턴스명 형식으로 키 생성)
String serviceKey = origin.getHostName() + "_" + origin.getInstanceName();
currentSuccessByService.put(serviceKey, currentSuccess);
currentErrorByService.put(serviceKey, currentError);
currentProcessingTimeByService.put(serviceKey, timeTotal);
// 전체 합계에 추가
totalSuccess += currentSuccess;
totalError += currentError;
totalProcessingTime += timeTotal;
totalCount++;
}
}
} catch (Exception e) {
log.error("DataSource {} 처리 중 오류 발생: {}", server.getName(), e.getMessage(), e);
} finally {
// DataSource 컨텍스트 클리어
DataSourceContextHolder.clearDataSourceType();
}
}
// 각 서비스 타입별 시계열 데이터 업데이트
for (String serviceType : currentSuccessByService.keySet()) {
// 현재 누적 값
int currentSuccess = currentSuccessByService.get(serviceType);
int currentError = currentErrorByService.get(serviceType);
double processingTime = currentProcessingTimeByService.get(serviceType);
// 마지막 누적 값 가져오기
Map<String, Integer> lastValues = lastAccumulatedValuesMap.getOrDefault(serviceType, new HashMap<>());
// 차이 계산
int deltaSuccess = currentSuccess - lastValues.getOrDefault("success", 0);
int deltaError = currentError - lastValues.getOrDefault("error", 0);
// 음수 값 방지 (카운터가 리셋된 경우)
deltaSuccess = Math.max(0, deltaSuccess);
deltaError = Math.max(0, deltaError);
// 평균 처리시간 계산
double avgProcessingTime = (deltaSuccess + deltaError > 0) ? processingTime / (deltaSuccess + deltaError) : 0.0;
// 시계열 데이터 추가
TimeSeriesData timeSeriesData = timeSeriesMap.computeIfAbsent(serviceType, k -> new TimeSeriesData());
timeSeriesData.addDataPoint(currentTime, deltaSuccess, deltaError, avgProcessingTime);
// 마지막 누적 값 업데이트
Map<String, Integer> newLastValues = new HashMap<>();
newLastValues.put("success", currentSuccess);
newLastValues.put("error", currentError);
lastAccumulatedValuesMap.put(serviceType, newLastValues);
}
// TOTAL 시계열 데이터 업데이트
TimeSeriesData totalTimeSeriesData = timeSeriesMap.get("TOTAL");
if (totalTimeSeriesData != null && totalCount > 0) {
// 마지막 누적 값 가져오기
Map<String, Integer> lastTotalValues = lastAccumulatedValuesMap.getOrDefault("TOTAL", new HashMap<>());
// 차이 계산
int deltaSuccess = totalSuccess - lastTotalValues.getOrDefault("success", 0);
int deltaError = totalError - lastTotalValues.getOrDefault("error", 0);
// 음수 값 방지
deltaSuccess = Math.max(0, deltaSuccess);
deltaError = Math.max(0, deltaError);
// 평균 처리시간 계산
double avgProcessingTime = (deltaSuccess + deltaError > 0) ? totalProcessingTime / (deltaSuccess + deltaError) : 0.0;
totalTimeSeriesData.addDataPoint(currentTime, deltaSuccess, deltaError, avgProcessingTime);
// 마지막 누적 값 업데이트
Map<String, Integer> newLastTotalValues = new HashMap<>();
newLastTotalValues.put("success", totalSuccess);
newLastTotalValues.put("error", totalError);
lastAccumulatedValuesMap.put("TOTAL", newLastTotalValues);
}
} catch (Exception e) {
log.error("시계열 데이터 수집 중 오류 발생: {}", e.getMessage(), e);
}
}
/**
* 시계열 데이터 조회
* @param seconds 조회할 초 단위 기간 (최대 120초)
* @return 시계열 데이터
*/
public TimeSeriesData getTimeSeriesData(int seconds) {
// 기간 제한 (1~120초)
seconds = Math.min(Math.max(seconds, 1), TIME_SERIES_RETENTION_SECONDS);
// TOTAL 데이터 사용
TimeSeriesData originalData = timeSeriesMap.get("TOTAL");
// 데이터가 없으면 빈 데이터 반환
if (originalData == null) {
return new TimeSeriesData();
}
// 기간에 맞게 데이터 필터링
TimeSeriesData filteredData = new TimeSeriesData();
long cutoffTime = System.currentTimeMillis() - (seconds * 1000);
List<Long> originalTimestamps = originalData.getTimestamps();
List<Integer> originalSuccess = originalData.getSuccess();
List<Integer> originalError = originalData.getError();
List<Double> originalAvgTime = originalData.getAvgTime();
// 최근 데이터부터 시작하여 지정된 기간 내의 데이터만 필터링
for (int i = originalTimestamps.size() - 1; i >= 0; i--) {
if (originalTimestamps.get(i) >= cutoffTime) {
filteredData.timestamps.add(0, originalTimestamps.get(i));
filteredData.success.add(0, originalSuccess.get(i));
filteredData.error.add(0, originalError.get(i));
filteredData.avgTime.add(0, originalAvgTime.get(i));
} else {
// 시간 범위를 벗어나면 종료
break;
}
}
return filteredData;
}
}
@@ -1,142 +1,142 @@
package com.eactive.eai.rms.onl.dashboard.repository;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.commons.collections.map.MultiKeyMap;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.onl.tracking.vo.DbStaticsVo;
import com.eactive.eai.rms.onl.tracking.vo.MemStaticsVo;
import com.eactive.eai.rms.onl.vo.SmsVO;
import org.apache.commons.collections.map.MultiKeyMap;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
@Scope(value = "singleton")
@Repository("dashboard2Repository")
public class Dashboard2Repository implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -8968729820736492173L;
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -8968729820736492173L;
/** The Constant logger. */
private static final Logger logger = Logger.getLogger(Dashboard2Repository.class);
// 서비스 -> Map(EAI 서비스코드,서버구분코드)
private HashMap<String,HashMap<String,String>> repoEAISevrDstcd;
// 대시보드 거래건수 ( 메모리 버전 )
private MultiKeyMap repoMemTransaction;
// 서비스, 호스트 -> vo
/** The Constant logger. */
private static final Logger logger = Logger.getLogger(Dashboard2Repository.class);
// 서비스 -> Map(EAI 서비스코드,서버구분코드)
private HashMap<String,HashMap<String,String>> repoEAISevrDstcd;
// 대시보드 거래건수 ( 메모리 버전 )
private MultiKeyMap repoMemTransaction;
// 서비스, 호스트 -> vo
private MultiKeyMap repository;
// 서비스 -> 호스트네임 리스트
private HashMap<String,List<String>> repoHostNames;
// 호스트명 -> 인스턴스네임 리스트
private HashMap<String,List<String>> repoInstNames;
// 호스트명 -> datasource, 인스턴스네임 list
private HashMap<String, Map<String, List<String>>> repoDataSourceInstNames;
// DB 에 저장된 통계정보 최대값.
private String maxProcTime;
// 호스트 telnet 연결 성공 여부 ( ip -> "1/0" )
private HashMap<String,String> repoHostAlive;
// SMS 메시지 리스트
private List<SmsVO> repoSms;
// Peak Trade by TPS( service -> date,trade,tps )
private HashMap<String,String> repoPeakTps;
// Peak Trade by Trade ( service -> date,trade,tps )
private HashMap<String,String> repoPeakTrade;
// 일괄전송 전송현황 건수 ( 정상송신,정상수신,에러송신,에러수신,대기송신,대기수신)
private int[] procBatch = new int[6];
private int[] procEaiBatch = new int[6];
//ITSM 대시보드 연동 거래처리 집계
private HashMap<String,HashMap<String,String>> itsmDashTranInfo;
//ITSM PEAK DAY 정보
private HashMap<String,HashMap<String,String>> itsmDashPeakdayInfo;
//ITSM 대시보드 연동 거래처리 집계
private HashMap<String,HashMap<String,String>> itsmDashTranInfo;
//ITSM PEAK DAY 정보
private HashMap<String,HashMap<String,String>> itsmDashPeakdayInfo;
//ITSM 대시보드 연동 날짜별 거래건수
private HashMap<String,List> itsmDashDayTranList;
//ITSM 대시보드 연동 날짜별 거래건수
private HashMap<String,List> itsmDashHourTranList;
//ITSM 대시보드 연동 서비스별 업무에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashBizErrorMap;
//ITSM 대시보드 연동 서비스별 타임아웃에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashTimeoutErrorMap;
//ITSM 통신에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashConnectErrorMap;
//ITSM 대시비도연동 서버 인스턴스별 거래건수
private HashMap<String,HashMap<String,String>> itsmDashServerInstTotalProcMap;
private String itsmDashTranInfoBatch;
private String itsmDashTranInfoBatch2;
private HashMap<String, HashMap<String, String>> itsmDashEaiBatchErrorList;
private HashMap<String, HashMap<String, String>> itsmDashFepBatchErrorList;
private HashMap<String,List> itsmDashDayTranList;
//ITSM 대시보드 연동 날짜별 거래건수
private HashMap<String,List> itsmDashHourTranList;
//ITSM 대시보드 연동 서비스별 업무에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashBizErrorMap;
//ITSM 대시보드 연동 서비스별 타임아웃에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashTimeoutErrorMap;
//ITSM 통신에러 MAP
private HashMap<String,HashMap<String,String>> itsmDashConnectErrorMap;
//ITSM 대시비도연동 서버 인스턴스별 거래건수
private HashMap<String,HashMap<String,String>> itsmDashServerInstTotalProcMap;
private String itsmDashTranInfoBatch;
private String itsmDashTranInfoBatch2;
private HashMap<String, HashMap<String, String>> itsmDashEaiBatchErrorList;
private HashMap<String, HashMap<String, String>> itsmDashFepBatchErrorList;
// 각 서비스별로 집계정보 저장
// private Dashboard2ProcVo inTotalVo;
// private Dashboard2ProcVo outTotalVo;
// private Dashboard2ProcVo commTotalVo;
// private Dashboard2ProcVo dmzTotalVo;
// private Dashboard2ProcVo batchTotalVo;
//
//
// private String lastTime; // 최종으로 저장된 startTime(모든 서비스에 공통)
/**
* 저장소 를 초기화 한다.
*/
@PostConstruct
public void createRepository() {
public void createRepository() {
repoEAISevrDstcd = new HashMap<String,HashMap<String,String>>();
repoMemTransaction = new MultiKeyMap();
repository = new MultiKeyMap();
repoHostNames = new HashMap<String,List<String>>();
repoInstNames = new HashMap<String,List<String>>();
repoHostAlive = new HashMap<String,String>();
repoSms = new ArrayList<SmsVO>();
repoPeakTps = new HashMap<String,String>();
repoPeakTrade = new HashMap<String,String>();
itsmDashTranInfo = new HashMap<String,HashMap<String,String>>();
itsmDashPeakdayInfo = new HashMap<String,HashMap<String,String>>();
itsmDashHourTranList = new HashMap<String,List>();
itsmDashDayTranList = new HashMap<String,List>();
itsmDashBizErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashTimeoutErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashConnectErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashServerInstTotalProcMap = new HashMap<String,HashMap<String,String>>();
itsmDashEaiBatchErrorList = new HashMap<String,HashMap<String,String>>();
itsmDashFepBatchErrorList = new HashMap<String,HashMap<String,String>>();
}
repository = new MultiKeyMap();
repoHostNames = new HashMap<String,List<String>>();
repoInstNames = new HashMap<String,List<String>>();
repoDataSourceInstNames = new HashMap<String,Map<String,List<String>>>();
repoHostAlive = new HashMap<String,String>();
repoSms = new ArrayList<SmsVO>();
repoPeakTps = new HashMap<String,String>();
repoPeakTrade = new HashMap<String,String>();
itsmDashTranInfo = new HashMap<String,HashMap<String,String>>();
itsmDashPeakdayInfo = new HashMap<String,HashMap<String,String>>();
itsmDashHourTranList = new HashMap<String,List>();
itsmDashDayTranList = new HashMap<String,List>();
itsmDashBizErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashTimeoutErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashConnectErrorMap = new HashMap<String,HashMap<String,String>>();
itsmDashServerInstTotalProcMap = new HashMap<String,HashMap<String,String>>();
itsmDashEaiBatchErrorList = new HashMap<String,HashMap<String,String>>();
itsmDashFepBatchErrorList = new HashMap<String,HashMap<String,String>>();
}
/**
* 저장소 데이터를 리셋 한다.
*/
@@ -146,30 +146,31 @@ public class Dashboard2Repository implements Serializable {
repository.clear();
repoHostNames.clear();
repoInstNames.clear();
repoDataSourceInstNames.clear();
repoHostAlive.clear();
repoSms.clear();
repoPeakTps.clear();
repoPeakTrade.clear();
for( int i = 0 ; i < 6 ; i++ ) {
procBatch[i] = 0 ;
procEaiBatch[i] = 0 ;
}
}
public void initMemTrRepository() {
repoMemTransaction.clear();
repoMemTransaction = new MultiKeyMap();
}
public void checkMemTrRepository() {
logger.info("check repoMemTransaction size=" + repoMemTransaction.size() );
}
public void removeMemTrRepository(String host, String inst) {
repoMemTransaction.remove(host, inst);
}
/**
* 주어진 서비스의 DB 에서 읽어온 EAI서비스코드,서버구분코드 맵을 리턴한다.
* @param service
@@ -178,7 +179,7 @@ public class Dashboard2Repository implements Serializable {
public HashMap<String,String> getRepoEAIServrDstcd(String service) {
return repoEAISevrDstcd.get(service);
}
/**
* 주어진 서비스명으로 메모리에서 읽어온 맵을 리턴한다.
* @param service
@@ -187,12 +188,12 @@ public class Dashboard2Repository implements Serializable {
public HashMap<String,String> getItsmDashTranInfo(String service) {
return itsmDashTranInfo.get(service);
}
public HashMap<String,String> getItsmDashPeakdayInfo(String service) {
return itsmDashPeakdayInfo.get(service);
}
/**
* 주어진 서비스명으로 메모리에서 읽어온 리스트을 리턴한다.
* @param service
@@ -201,35 +202,35 @@ public class Dashboard2Repository implements Serializable {
public List itsmDashHourTranList(String service) {
return itsmDashHourTranList.get(service);
}
public List itsmDashDayTranList(String service) {
return itsmDashDayTranList.get(service);
}
public HashMap<String, HashMap<String, String>> itsmDashBizErrorMap() {
return itsmDashBizErrorMap;
}
public HashMap<String, HashMap<String, String>> itsmDashTimeoutErrorMap() {
return itsmDashTimeoutErrorMap;
}
public HashMap<String, HashMap<String, String>> itsmDashConnectErrorMap() {
return itsmDashConnectErrorMap;
}
public HashMap<String,String> itsmDashServerInstTotalProcMap(String service) {
return itsmDashServerInstTotalProcMap.get(service);
}
public HashMap<String,HashMap<String,String>> itsmDashEaiBatchErrorList() {
return itsmDashEaiBatchErrorList;
}
public HashMap<String,HashMap<String,String>> itsmDashFepBatchErrorList() {
return itsmDashFepBatchErrorList;
}
/**
* 주어진 host 명이 포함된 DB 에서 읽어온 EAI서비스코드,서버구분코드 맵을 리턴한다.
* @param host
@@ -240,19 +241,19 @@ public class Dashboard2Repository implements Serializable {
// if( service != null ) {
// return getRepoEAIServrDstcd(service.getKey());
// }
//
//
// return null ;
// }
//TODO JUN
//TODO JUN
public HashMap<String,String> getRepoEAIServrDstcdByHost(String host) {
DataSourceType dataSourceType = getServiceTypeByHost(host);
if( dataSourceType != null ) {
return getRepoEAIServrDstcd(dataSourceType.getName());
}
return null ;
}
/**
* 주어진 host 명이 포함된 DB 의 서비스 타입을 찾아서 리턴한다.
* @param host
@@ -269,10 +270,10 @@ public class Dashboard2Repository implements Serializable {
// }
// }
// }
//
//
// return null ;
// }
//TODO JUN
//TODO JUN
public DataSourceType getServiceTypeByHost(String host) {
Iterator<String> it = repoHostNames.keySet().iterator();
while( it.hasNext() ) {
@@ -284,9 +285,9 @@ public class Dashboard2Repository implements Serializable {
}
}
}
return null ;
}
}
/**
* Repository 에 주어진 서비스를 키로 하여 EAI서비스코드,서버구분코드 맵을 추가한다.
* @param service
@@ -295,7 +296,7 @@ public class Dashboard2Repository implements Serializable {
public void setRepoEAISevrDstcd(String service, HashMap<String,String> map) {
repoEAISevrDstcd.put(service, map);
}
/**
* Repository 에 주어진 서비스를 키로 하여 메모리 거래현황 맵을 추가한다.
* @param service
@@ -304,45 +305,45 @@ public class Dashboard2Repository implements Serializable {
public void setItsmDashTranInfo(String service, HashMap<String,String> map) {
itsmDashTranInfo.put(service, map);
}
public void setItsmDashPeakdayInfo(String service, HashMap<String,String> map) {
itsmDashPeakdayInfo.put(service, map);
}
/**
* Repository 에 주어진 서비스를 키로 하여 메모리 시간별거래건수 맵을 추가한다.
* @param service
* @param map
*/
public void setItsmDashHourTranList(String service, List list) {
itsmDashHourTranList.put(service, list);
}
/**
* Repository 에 주어진 서비스를 키로 하여 메모리 시간별거래건수 맵을 추가한다.
* @param service
* @param map
*/
public void setItsmDashDayTranList(String service, List list) {
itsmDashDayTranList.put(service, list);
}
/**
* Repository 에 주어진 서비스를 키로 하여 메모리 업무에러리스트 맵을 추가한다.
* @param service
* @param map
*/
public void setItsmDashBizErrorMap(HashMap<String,HashMap<String, String>> map) {
this.itsmDashBizErrorMap = map;
}
/**
* Repository 에 주어진 서비스를 키로 하여 메모리 타임아웃에러리스트 맵을 추가한다.
* @param service
@@ -351,38 +352,38 @@ public class Dashboard2Repository implements Serializable {
public void setItsmDashTimeoutErrorMap(HashMap<String, HashMap<String, String>> map) {
this.itsmDashTimeoutErrorMap = map;
}
public void setItsmDashConnectErrorMap(HashMap<String, HashMap<String, String>> map) {
this.itsmDashConnectErrorMap = map;
}
public void setItsmDashServerInstTotalProcMap(String service ,HashMap<String,String> map) {
this.itsmDashServerInstTotalProcMap.put(service, map);
}
public void setItsmDashTranInfoBatch( String batchCount ) {
this.itsmDashTranInfoBatch = batchCount ;
}
public String getItsmDashTranInfoBatch() {
return this.itsmDashTranInfoBatch;
}
public void setItsmDashTranInfoBatch2( String batchCount2 ) {
this.itsmDashTranInfoBatch2 = batchCount2 ;
}
public String getItsmDashTranInfoBatch2() {
return this.itsmDashTranInfoBatch2;
}
public void setItsmDashEaiBatchErrorList(HashMap<String,HashMap<String,String>> eaiBatchErrorList) {
this.itsmDashEaiBatchErrorList = eaiBatchErrorList;
}
public void setItsmDashFepBatchErrorList(HashMap<String,HashMap<String,String>> fepBatchErrorList) {
this.itsmDashFepBatchErrorList = fepBatchErrorList;
}
@@ -394,8 +395,8 @@ public class Dashboard2Repository implements Serializable {
public MultiKeyMap getRepoMemTr() {
return repoMemTransaction;
}
/**
* 저장소 객체를 리턴한다.
* @return
@@ -403,7 +404,7 @@ public class Dashboard2Repository implements Serializable {
public MultiKeyMap getRepository() {
return repository;
}
/**
* 서비스 -> 호스트명 리스트를 저장한다.
* @param service
@@ -412,7 +413,7 @@ public class Dashboard2Repository implements Serializable {
public void setHostNames(String service, List<String> list ) {
repoHostNames.put(service,list);
}
/**
* 호스트명 -> 인스턴스 리스트를 저장한다.
* @param host
@@ -421,7 +422,11 @@ public class Dashboard2Repository implements Serializable {
public void setInstNames(String host, List<String> list ) {
repoInstNames.put(host,list);
}
public void setDataSourceInstNames(String host, Map<String, List<String>> putData ) {
repoDataSourceInstNames.put(host, putData);
}
/**
* Memory 거래현황정보 추가
* @param host
@@ -447,28 +452,28 @@ public class Dashboard2Repository implements Serializable {
vo.setHostName(host);
vo.setInstName(inst);
}
return vo;
}
/**
* 주어진 호스트명 에서 수신된 Vo 리스트를 찾아서 리턴한다.
* @param host
* @return
*/
public List<MemStaticsVo> getMemTradeVoByHost( String host ) {
List<MemStaticsVo> list = new ArrayList<MemStaticsVo>();
List<MemStaticsVo> list = new ArrayList<MemStaticsVo>();
List<String> insts = getInstNames(host);
if( insts != null ) {
for( String inst : insts ) {
list.add( getMemTradeVo(host,inst) );
}
}
return list;
}
/**
* 주어진 서비스에서 수신된 전체 Vo 리스트를 찾아서 리턴한다.
* @param service
@@ -482,86 +487,108 @@ public class Dashboard2Repository implements Serializable {
list.addAll( getMemTradeVoByHost(host) );
}
}
return list;
}
/**
* 주어진 서비스에서 수신된 전체 Vo 리스트를 찾아서 리턴한다.
* repoDataSourceInstNames 에서 host, instance 명 조회 후 MemTradeVo를 리턴한다.
* @param service
* @return
*/
public List<MemStaticsVo> getDashboardMemTradeVoByService(String service) {
return Optional.ofNullable(getHostNames(service))
.orElse(Collections.emptyList())
.stream()
.flatMap(host -> getInstListByHostAndService(host, service).stream()
.map(instNm -> getMemTradeVo(host, instNm)))
.collect(Collectors.toList());
}
private List<String> getInstListByHostAndService(String host, String service) {
return Optional.ofNullable(repoDataSourceInstNames)
.map(m -> m.get(host))
.map(serviceMap -> serviceMap.get(service))
.orElse(Collections.emptyList());
}
public void setTradeVo(String service, String host, DbStaticsVo vo) {
repository.put(service, host, vo);
}
public DbStaticsVo getTradeVo(String service, String host) {
DbStaticsVo vo = (DbStaticsVo)repository.get(service, host);
if( vo == null ) {
vo = new DbStaticsVo();
vo.init();
}
return vo;
}
public List<DbStaticsVo> getTradeVo(String service) {
List<DbStaticsVo> list = new ArrayList<DbStaticsVo>();
List<String> hostNames = repoHostNames.get(service);
if( hostNames != null ) {
for( String host : hostNames ) {
list.add( getTradeVo(service, host) );
}
}
if( list.size() == 0 ) {
DbStaticsVo vo = new DbStaticsVo();
vo.init();
list.add(vo);
}
return list;
}
public DbStaticsVo getTotalVo(String service) {
List<DbStaticsVo> list = getTradeVo(service);
DbStaticsVo retVo = new DbStaticsVo();
retVo.init();
for( DbStaticsVo vo : list ) {
retVo.add( vo );
}
return retVo ;
}
public void setMaxProcTime( String fulltime ) {
this.maxProcTime = fulltime ;
}
public String getMaxProcTime() {
return this.maxProcTime;
}
public boolean isInitHostRepository() {
if( repoHostAlive.size() > 0 )
return true ;
else
return false ;
}
public void addHostKey( List<String> listAddr ) {
if( listAddr != null ) {
for( String addr : listAddr ) {
repoHostAlive.put(addr, "1");
}
}
}
public boolean isHostAlive( String ipaddr, String port ) {
String alive = repoHostAlive.get(ipaddr + ":" + port);
// 디폴트는 성공으로 간주하고, 실패시에만 Fail 처리한다.
if( "0".equals(alive) ) {
return false ;
@@ -569,7 +596,7 @@ public class Dashboard2Repository implements Serializable {
return true ;
}
}
public boolean isHostAlive( String ipaddr ) {
boolean foundDead = false ;
@@ -589,74 +616,74 @@ public class Dashboard2Repository implements Serializable {
}
}
}
if( foundDead ) {
// 모든 inst 가 실패
return false ;
}
// 디폴트
return true ;
}
public void setHostAlive( String ipaddr, String port, boolean alive ) {
String aliveVal = "1" ;
if( alive == false ) {
aliveVal = "0" ;
}
repoHostAlive.put(ipaddr + ":" + port, aliveVal );
}
/**
* ip : port 형태의 주소값 리스트를 리턴한다.
* @return
*/
public List<String> getHostIPList() {
Iterator it = repoHostAlive.keySet().iterator();
List<String> list = new ArrayList<String>();
while( it.hasNext() ) {
String key = (String)it.next();
list.add( key );
}
return list ;
}
public List<String> getHostNames( String service ) {
return repoHostNames.get(service);
}
public List<String> getInstNames( String host ) {
return repoInstNames.get(host);
}
public void addSms( SmsVO vo ) {
repoSms.add( vo );
// 만일 100개가 넘으면 앞에서 부터 50개를 삭제한다.
if( repoSms.size() >= 100 ) {
}
}
public void setPeakTps( String service, String val ) {
repoPeakTps.put(service, val);
}
public String getPeakTps( String service ) {
return repoPeakTps.get(service);
}
public void setPeakTrade( String service, String val ) {
repoPeakTrade.put(service, val);
}
public String getPeakTrade( String service ) {
return repoPeakTrade.get(service);
}
public String getProcBatch( ) {
StringBuffer sb = new StringBuffer();
for( int i = 0 ; i < this.procBatch.length ; i++ ) {
@@ -664,7 +691,7 @@ public class Dashboard2Repository implements Serializable {
}
return sb.toString();
}
public String getProcEaiBatch( ) {
StringBuffer sb = new StringBuffer();
for( int i = 0 ; i < this.procEaiBatch.length ; i++ ) {
@@ -672,7 +699,7 @@ public class Dashboard2Repository implements Serializable {
}
return sb.toString();
}
public void setProcBatch( int p1, int p2, int p3, int p4, int p5, int p6 ) {
this.procBatch[0] = p1 ;
this.procBatch[1] = p2 ;
@@ -691,4 +718,37 @@ public class Dashboard2Repository implements Serializable {
this.procEaiBatch[5] = p6 ;
}
// 주어진 데이터소스명을 기준으로 hostname list를 리턴한다.
public List<Map<String,String>> getDatasourceByHost(String datasourcName){
List<String> hostList = repoHostNames.get(datasourcName);
List<Map<String,String>> serverInfoList = new ArrayList<Map<String,String>>();
if( hostList != null ){
for(String hostName : hostList) {
Map<String, List<String>> dataSourceInst = repoDataSourceInstNames.get(hostName);
if( dataSourceInst != null ){
List<String> instNameList = dataSourceInst.get(datasourcName);
if( instNameList != null ){
for (String instName : instNameList) {
Map<String, String> serverInfo = new HashMap<String, String>();
serverInfo.put("HOSTNAME", hostName);
serverInfo.put("EAISVRINSTNM", instName);
serverInfoList.add(serverInfo);
}
}
}
}
}
return serverInfoList;
}
// 주어진 host 명을 기준으로 map datasource, instance list 를 리턴한다.
public Map<String, List<String>> getDatasourceInstListByHostNm(String hostName){
return repoDataSourceInstNames.getOrDefault(hostName, new HashMap<String, List<String>>());
}
}
@@ -1,13 +1,12 @@
package com.eactive.eai.rms.onl.dashboard.service;
import java.util.HashMap;
import java.util.Vector;
import com.eactive.eai.rms.onl.dashboard.dao.DashboardErrorDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.eactive.eai.rms.onl.dashboard.dao.DashboardErrorDAO;
import java.util.HashMap;
import java.util.Vector;
@Service("dashboardErrorService")
public class DashboardErrorServiceImpl implements DashboardErrorService {
@@ -1,13 +1,8 @@
package com.eactive.eai.rms.onl.dashboard.service;
import java.util.List;
import com.eactive.eai.rms.onl.vo.*;
import com.eactive.eai.rms.onl.vo.AdaptersVO;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import com.eactive.eai.rms.onl.vo.RealTimeAdaptersVO;
import com.eactive.eai.rms.onl.vo.SmsVO;
import com.eactive.eai.rms.onl.vo.TransactionTrackingVo;
import java.util.List;
/**
* The Interface DashboardService.
@@ -1,22 +1,16 @@
package com.eactive.eai.rms.onl.dashboard.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.onl.server.repository.Repository;
import com.eactive.eai.rms.onl.server.repository.TransactionRepositoryService;
import com.eactive.eai.rms.onl.vo.AdaptersVO;
import com.eactive.eai.rms.onl.vo.EAIEngineStatusVo;
import com.eactive.eai.rms.onl.vo.HostStatusVo;
import com.eactive.eai.rms.onl.vo.RealTimeAdaptersVO;
import com.eactive.eai.rms.onl.vo.SmsVO;
import com.eactive.eai.rms.onl.vo.TransactionTrackingVo;
import com.eactive.eai.rms.onl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* The Class DashboardServiceImpl.
@@ -1,17 +1,5 @@
package com.eactive.eai.rms.onl.dashboard.service;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Optional;
import java.util.Vector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.eactive.eai.common.util.SystemUtil;
import com.eactive.eai.data.entity.onl.property.Prop;
import com.eactive.eai.data.entity.onl.property.PropGroup;
@@ -23,6 +11,12 @@ import com.eactive.eai.rms.data.entity.onl.property.PropertyGroupService;
import com.eactive.eai.rms.onl.dashboard.dao.DashboardErrorDAO;
import com.eactive.eai.rms.onl.manage.comm.unifbwk.UnifbwkManService;
import com.eactive.eai.rms.onl.manage.comm.unifbwk.UnifbwkUI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* The Interface DashboardService.
@@ -64,7 +64,7 @@ public class TransactionSendHandler implements IMessageHandler {
// 호스트명, 인스턴스명을 초기화 한다.
//DataSourceContextHolder.setDataSourceType(DataSourceTypeManager.getFirstDataSourceType());
dashboard2Repository.initHostInstNames(false);
dashboard2Repository.initHostInstNames(false, null);
dashboard2Repository.initEaiSevrDstcd(false);
// 참고 : 지정된 호스트 이외의 데이터는 버린다.