Compare commits
4 Commits
136626e7c4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bf7f661e3 | |||
| 124df00f51 | |||
| e4de8ebc8b | |||
| 52e8c3be39 |
@@ -29,6 +29,14 @@
|
||||
// (enricher 는 oauth·api_key 를 모두 apiKey-in-header 로 모델링하므로 scheme.type 만으로 구분 불가)
|
||||
var djbAuthType = '';
|
||||
|
||||
// 마지막 저장(또는 최초 로드) 시점의 state.data 스냅샷 — 닫기 전 미저장 변경 여부 판별용.
|
||||
var savedSnapshot = null;
|
||||
function isDirty() { return savedSnapshot !== null && JSON.stringify(state.data) !== savedSnapshot; }
|
||||
function closeEditor() {
|
||||
if (isDirty() && !window.confirm('저장하지 않은 변경사항이 있습니다. 저장하지 않고 닫으시겠습니까?')) return;
|
||||
window.close();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 2. 유틸
|
||||
// ============================================================
|
||||
@@ -1703,7 +1711,7 @@
|
||||
|
||||
var bSave = $('#btn-save'); if (bSave) bSave.addEventListener('click', () => saveSpec(false));
|
||||
var bRegen = $('#btn-regen'); if (bRegen) bRegen.addEventListener('click', regenerate);
|
||||
var bClose = $('#btn-close'); if (bClose) bClose.addEventListener('click', () => window.close());
|
||||
var bClose = $('#btn-close'); if (bClose) bClose.addEventListener('click', closeEditor);
|
||||
|
||||
// Cmd/Ctrl + S → 저장 (브라우저 기본 저장 대화상자 차단)
|
||||
document.addEventListener('keydown', function (e) {
|
||||
@@ -2066,6 +2074,7 @@
|
||||
.then(function (res) {
|
||||
if (res && res.status === 'success') {
|
||||
toast(temp ? '임시저장되었습니다' : '저장되었습니다');
|
||||
savedSnapshot = JSON.stringify(state.data); // 저장 성공 시점을 새 저장 기준선으로 갱신
|
||||
var badge = $('#hdr-source'); if (badge) { badge.textContent = '저장본'; badge.className = 'ml-1 px-2 py-0.5 text-[11px] rounded-full bg-emerald-50 text-emerald-700 border border-emerald-200'; badge.classList.remove('hidden'); }
|
||||
} else toast('저장 실패: ' + (res && res.errorMsg || ''), 'error');
|
||||
})
|
||||
@@ -2102,6 +2111,7 @@
|
||||
// ============================================================
|
||||
function init() {
|
||||
loadInitialData().then(function () {
|
||||
savedSnapshot = JSON.stringify(state.data); // 초기 로드(자동생성 포함) 완료 시점을 저장 기준선으로 설정
|
||||
renderStepper();
|
||||
renderForm();
|
||||
bindGlobalEvents();
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
var url = '<c:url value="/onl/kjb/statistics/apiStatsHourMan.json"/>';
|
||||
var url_view = '<c:url value="/onl/kjb/statistics/apiStatsHourMan.view"/>';
|
||||
var url_minute_view = '<c:url value="/onl/kjb/statistics/apiStatsMinuteMan.view"/>';
|
||||
var url_left_menu = '<c:url value="/leftMenu.do"/>';
|
||||
var DASHBOARD_MENU_ID = '0305001'; // apiStatsMinuteMan(대시보드) 메뉴 ID
|
||||
|
||||
var totalDonutChart, callChart;
|
||||
|
||||
@@ -162,23 +164,20 @@
|
||||
var hour = parseInt(statTime.substring(8, 10));
|
||||
|
||||
var startDate = year + '-' + month + '-' + day;
|
||||
var startTime = (hour < 10 ? '0' + hour : hour) + ':00';
|
||||
|
||||
// 1시간 후 계산 (23시인 경우 다음날 00시로 자동 계산)
|
||||
var d = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), hour, 0, 0);
|
||||
d.setHours(d.getHours() + 1);
|
||||
|
||||
var endDate = d.getFullYear() + '-' +
|
||||
(d.getMonth() + 1 < 10 ? '0' : '') + (d.getMonth() + 1) + '-' +
|
||||
(d.getDate() < 10 ? '0' : '') + d.getDate();
|
||||
var endTime = (d.getHours() < 10 ? '0' : '') + d.getHours() + ':00';
|
||||
var hourStr = (hour < 10 ? '0' + hour : hour);
|
||||
var startTime = hourStr + ':00';
|
||||
// 해당 시간대 끝(정시~59분)으로 이동 (예: 10:00~10:59)
|
||||
var endTime = hourStr + ':59';
|
||||
|
||||
var params = '?searchStartDate=' + startDate + '&searchStartTime=' + startTime
|
||||
+ '&searchEndDate=' + endDate + '&searchEndTime=' + endTime;
|
||||
params += '&menuId='+'${param.menuId}';
|
||||
+ '&searchEndDate=' + startDate + '&searchEndTime=' + endTime;
|
||||
params += '&menuId='+DASHBOARD_MENU_ID;
|
||||
params += '&cmd='+'LIST';
|
||||
params += '&serviceType='+'APIGW';
|
||||
|
||||
// 왼쪽 메뉴도 대시보드(분단위 통계) 메뉴로 전환
|
||||
parent.leftFrame.location.href = url_left_menu + '?menuId=' + DASHBOARD_MENU_ID
|
||||
+ '&serviceType=' + sessionStorage["serviceType"];
|
||||
location.href = url_minute_view + params;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,14 +262,14 @@
|
||||
var diffMinutes = (end - start) / (1000 * 60);
|
||||
|
||||
if (diffMinutes > 60) {
|
||||
// 1시간 초과 시 시작 + 1시간으로 조정
|
||||
endDateTime = updateEndTime(new Date(start.getTime() + 60 * 60 * 1000));
|
||||
// 1시간 초과 시 시작시각 기준 1시간치(정시~59분)로 조정
|
||||
endDateTime = updateEndTime(new Date(start.getTime() + 59 * 60 * 1000));
|
||||
} else {
|
||||
endDateTime = formatDateTime(end);
|
||||
}
|
||||
} else {
|
||||
// 종료시간 미입력 시 시작 + 1시간으로 설정
|
||||
endDateTime = updateEndTime(new Date(start.getTime() + 60 * 60 * 1000));
|
||||
// 종료시간 미입력 시 시작시각 기준 1시간치(정시~59분)로 설정
|
||||
endDateTime = updateEndTime(new Date(start.getTime() + 59 * 60 * 1000));
|
||||
}
|
||||
|
||||
return { start: startDateTime, end: endDateTime };
|
||||
@@ -325,8 +325,8 @@
|
||||
}
|
||||
|
||||
// 조회기간을 정시 단위 1시간 구간으로 이동 (direction: -1 이전, 1 이후)
|
||||
// ex) 시작 08:35, 이전 클릭 -> 08:00~09:00, 다시 -> 07:00~08:00
|
||||
// ex) 시작 08:35, 이후 클릭 -> 09:00~10:00, 다시 -> 10:00~11:00
|
||||
// ex) 시작 08:35, 이전 클릭 -> 08:00~08:59, 다시 -> 07:00~07:59
|
||||
// ex) 시작 08:35, 이후 클릭 -> 09:00~09:59, 다시 -> 10:00~10:59
|
||||
function shiftTimeRange(direction) {
|
||||
var startDate = $("input[name=searchStartDate]").val().replace(/-/g, "");
|
||||
var startTime = $("input[name=searchStartTime]").val().replace(/:/g, "");
|
||||
@@ -350,7 +350,8 @@
|
||||
start.setHours(start.getHours() + 1);
|
||||
}
|
||||
|
||||
var end = new Date(start.getTime() + 60 * 60 * 1000);
|
||||
// 종료시각은 같은 시간대의 59분으로 설정 (예: 10:00~10:59)
|
||||
var end = new Date(start.getTime() + 59 * 60 * 1000);
|
||||
|
||||
function pad(n) { return String(n).padStart(2, '0'); }
|
||||
|
||||
@@ -580,9 +581,9 @@
|
||||
|
||||
$("input[name=searchStartDate]").datepicker();
|
||||
|
||||
// 기본값 설정 (현재 시간(분) 기준 1시간 전 ~ 현재 시간(분))
|
||||
// 기본값 설정 (현재 시간(분) 기준 59분 전 ~ 현재 시간(분))
|
||||
var now = new Date();
|
||||
var oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
|
||||
var oneHourAgo = new Date(now.getTime() - 59 * 60 * 1000);
|
||||
|
||||
function formatDate(d) {
|
||||
return d.getFullYear() + '-' +
|
||||
|
||||
+3
-3
@@ -336,12 +336,12 @@ public class ApiStatsMinuteService
|
||||
|
||||
if (StringUtils.isNotBlank(search.getSearchEndDateTime())) {
|
||||
endDateTime = LocalDateTime.parse(search.getSearchEndDateTime(), DATE_TIME_FORMATTER);
|
||||
// 1시간(60분) 초과 시 시작시간 기준 1시간 후로 강제 설정
|
||||
// 1시간(60분) 초과 시 시작시간 기준 1시간치(정시~59분, statTime 조건이 양끝 포함이므로 -1분)로 강제 설정
|
||||
if (java.time.Duration.between(startDateTime, endDateTime).toMinutes() > MAX_MINUTES) {
|
||||
endDateTime = startDateTime.plusMinutes(MAX_MINUTES);
|
||||
endDateTime = startDateTime.plusMinutes(MAX_MINUTES - 1);
|
||||
}
|
||||
} else {
|
||||
endDateTime = startDateTime.plusMinutes(MAX_MINUTES);
|
||||
endDateTime = startDateTime.plusMinutes(MAX_MINUTES - 1);
|
||||
}
|
||||
|
||||
search.setParsedStartDateTime(startDateTime);
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
|
||||
|
||||
<property name="LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] \\(%F:%L\\) %-20M -%msg%n" />
|
||||
<property name="PREFIX" value="${inst.Type:-ems}" />
|
||||
<property name="LOG_HOME" value="/work/eactive/djb-eapim/workspace/eapim-admin/logs" />
|
||||
<property name="BACKUP_HOME" value="${LOG_HOME}/backup/" />
|
||||
<property name="LOG_LEVEL" value="${LOGBACK_LOG_LEVEL:-DEBUG}" />
|
||||
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_stdout.log</file>
|
||||
<rollingPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${LOG_HOME}/${PREFIX}_stdout.log-%d{yyyy-MM-dd}.%i
|
||||
</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ACCESS_APPENDER"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_access.log</file>
|
||||
<rollingPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${LOG_HOME}/${PREFIX}_access.log-%d{yyyy-MM-dd}.%i
|
||||
</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="SMS_APPENDER"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/sms.log</file>
|
||||
<rollingPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${LOG_HOME}/sms.log-%d{yyyy-MM-dd}.%i
|
||||
</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="QUERY_APPENDER"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_query.log</file>
|
||||
<rollingPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${LOG_HOME}/${PREFIX}_query.log-%d{yyyy-MM-dd}.%i
|
||||
</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="DYNAMIC_APPENDER"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_dynamic.log</file>
|
||||
<rollingPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${LOG_HOME}/${PREFIX}_dynamic.log-%d{yyyy-MM-dd}.%i
|
||||
</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="HIBERNATE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_hibernate.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/${PREFIX}_hibernate.log-%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="HOTSWAP_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/${PREFIX}_hotswap.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/${PREFIX}_hotswap.log-%d{yyyy-MM-dd}.%i</fileNamePattern>
|
||||
<maxFileSize>500MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>utf-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.eactive.eai.rms.onl.server" level="ERROR" />
|
||||
<logger name="com.eactive.eai.rms.onl.dashboard" level="ERROR" />
|
||||
<logger name="com.eactive.eai.rms.common.acl.user.BizDao" level="ERROR" />
|
||||
<logger name="com.eactive.eai.rms.common.acl.user.BizDao" level="ERROR" />
|
||||
<logger name="com.eactive.eai.rms.ext.djb.job" level="DEBUG" />
|
||||
<logger name="com.eactive.eai.rms.ext.djb.apistatus" level="DEBUG" />
|
||||
|
||||
<logger name="org.springframework.orm.jpa.JpaTransactionManager" level="ERROR" additivity="false" />
|
||||
|
||||
<logger name="org.springframework" level="INFO" />
|
||||
<logger name="net.sf.ehcache" level="INFO" />
|
||||
|
||||
|
||||
<logger name="ACCESS_LOGGER" level="DEBUG" >
|
||||
<appender-ref ref="ACCESS_APPENDER" />
|
||||
</logger>
|
||||
<logger name="SMS_LOGGER" level="DEBUG" >
|
||||
<appender-ref ref="SMS_APPENDER" />
|
||||
</logger>
|
||||
<logger name="DYNAMIC_LOGGER" level="DEBUG" >
|
||||
<appender-ref ref="DYNAMIC_APPENDER" />
|
||||
</logger>
|
||||
|
||||
|
||||
<!-- QUERY_APPENDER start -->
|
||||
<!-- Hibernate SQL & 파라미터 바인딩 -->
|
||||
<logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="QUERY_APPENDER" />
|
||||
<appender-ref ref="HIBERNATE_APPENDER" />
|
||||
</logger>
|
||||
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" additivity="false">
|
||||
<appender-ref ref="QUERY_APPENDER" />
|
||||
<appender-ref ref="HIBERNATE_APPENDER" />
|
||||
</logger>
|
||||
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="TRACE" additivity="false">
|
||||
<appender-ref ref="QUERY_APPENDER" />
|
||||
<appender-ref ref="HIBERNATE_APPENDER" />
|
||||
</logger>
|
||||
<!-- Hibernate 일반 로그 (DDL/init/connection 등) -->
|
||||
<logger name="org.hibernate" level="INFO" additivity="false">
|
||||
<appender-ref ref="HIBERNATE_APPENDER" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<!-- iBATIS 2.3.4 (commons-logging 또는 log4j-over-slf4j 통해 SLF4J 도달) -->
|
||||
<logger name="com.ibatis" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="QUERY_APPENDER" />
|
||||
</logger>
|
||||
<logger name="com.eactive.eai.rms.common.base.SchemaIdConfiguredSqlMapTemplate" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="QUERY_APPENDER" />
|
||||
</logger>
|
||||
<!-- QUERY_APPENDER end -->
|
||||
|
||||
<!-- HotswapAgent는 자체 logger를 사용하므로 logback에 안 잡힘. hotswap-agent.properties의 LOGFILE로 직접 파일 출력 -->
|
||||
|
||||
<root>
|
||||
<level value="INFO" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user