- 오류율 및 지연 판정 쿼리 조건 수정 - 상태 판정 진단 로그 메시지 포맷 및 로직 업데이트
This commit is contained in:
@@ -83,11 +83,13 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 판정 구간 내 오류율 0% 초과 API 목록. 개발 모드(-Deai.systemmode=D) 진단 로그 전용.
|
* 판정 구간에 트래픽이 있는 API 의 오류율·지연 판정값. 개발 모드(-Deai.systemmode=D) 진단 로그 전용.
|
||||||
*
|
*
|
||||||
* <p>{@code findApiStatusEvents} 는 임계값을 넘고 <b>상태 전이까지 일어난</b> API 만 돌려주므로
|
* <p>{@code findApiStatusEvents} 는 임계값을 넘고 <b>상태 전이까지 일어난</b> API 만 돌려주므로
|
||||||
* "오류는 나는데 왜 장애로 안 잡히나" 를 볼 수 없다. 이 쿼리는 임계값·현재 상태와 무관하게
|
* "오류는 나는데 왜 장애로 안 잡히나", "느린데 왜 지연이 아닌가" 를 볼 수 없다. 이 쿼리는
|
||||||
* 집계된 오류율을 그대로 보여준다.</p>
|
* 임계값·현재 상태와 무관하게 집계값을 그대로 보여준다.</p>
|
||||||
|
*
|
||||||
|
* <p>오류가 0건이어도 지연 판정값은 확인해야 하므로 오류 발생 여부로 거르지 않는다.</p>
|
||||||
*
|
*
|
||||||
* <p>컬럼 alias 는 반드시 <b>따옴표로 감싼 camelCase</b> 로 둔다. 인터페이스 프로젝션은 tuple
|
* <p>컬럼 alias 는 반드시 <b>따옴표로 감싼 camelCase</b> 로 둔다. 인터페이스 프로젝션은 tuple
|
||||||
* alias 를 getter 프로퍼티명으로 찾는데, 따옴표가 없으면 Oracle 이 alias 를 대문자로 올려
|
* alias 를 getter 프로퍼티명으로 찾는데, 따옴표가 없으면 Oracle 이 alias 를 대문자로 올려
|
||||||
@@ -95,15 +97,22 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
|||||||
* (단일 단어는 대소문자만 달라 우연히 매칭된다).</p>
|
* (단일 단어는 대소문자만 달라 우연히 매칭된다).</p>
|
||||||
*/
|
*/
|
||||||
@Query(nativeQuery = true, value =
|
@Query(nativeQuery = true, value =
|
||||||
" SELECT S.API_NAME AS \"eaisvcname\""
|
" SELECT N.API_NAME AS \"eaisvcname\""
|
||||||
+ " , NVL(B.STATUS_CODE,'N') AS \"statusCode\""
|
+ " , NVL(B.STATUS_CODE,'N') AS \"statusCode\""
|
||||||
+ " , S.TOTAL AS \"total\""
|
+ " , NVL(S.TOTAL,0) AS \"total\""
|
||||||
+ " , S.SUCCESS AS \"success\""
|
+ " , NVL(S.SUCCESS,0) AS \"success\""
|
||||||
+ " , ROUND((S.TOTAL - S.SUCCESS) * 100 / S.TOTAL, 2) AS \"errorRate\""
|
+ " , CASE WHEN NVL(S.TOTAL,0) > 0 THEN ROUND((S.TOTAL - S.SUCCESS) * 100 / S.TOTAL, 2) END AS \"errorRate\""
|
||||||
+ " , ROUND(S.RESP_SUM / S.TOTAL, 2) AS \"avgRespTime\""
|
+ " , CASE WHEN NVL(S.TOTAL,0) > 0 THEN ROUND(S.RESP_SUM / S.TOTAL, 2) END AS \"avgRespTime\""
|
||||||
+ " , NVL(D.TOTAL,0) AS \"delayTotal\""
|
+ " , NVL(D.TOTAL,0) AS \"delayTotal\""
|
||||||
+ " , CASE WHEN NVL(D.TOTAL,0) > 0 THEN ROUND(D.RESP_SUM / D.TOTAL, 2) END AS \"delayAvgRespTime\""
|
+ " , CASE WHEN NVL(D.TOTAL,0) > 0 THEN ROUND(D.RESP_SUM / D.TOTAL, 2) END AS \"delayAvgRespTime\""
|
||||||
+ " FROM (SELECT API_NAME"
|
// 두 창 중 넓은 쪽으로 대상 API 를 먼저 뽑는다. 오류 창만 기준으로 잡으면 오류 창에 거래가
|
||||||
|
// 없을 때 지연 판정값까지 통째로 사라진다 (창 길이가 서로 다르다)
|
||||||
|
+ " FROM (SELECT DISTINCT API_NAME"
|
||||||
|
+ " FROM API_STATS_MINUTE"
|
||||||
|
+ " WHERE TO_CHAR(STAT_TIME,'YYYYMMDDHH24MI')"
|
||||||
|
+ " BETWEEN TO_CHAR(SYSDATE - NUMTODSINTERVAL(GREATEST(:errorRangeMinute, :delayRangeMinute),'MINUTE'),'YYYYMMDDHH24MI')"
|
||||||
|
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')) N"
|
||||||
|
+ " LEFT OUTER JOIN (SELECT API_NAME"
|
||||||
+ " , NVL(SUM(SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT),0) AS TOTAL"
|
+ " , NVL(SUM(SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT),0) AS TOTAL"
|
||||||
+ " , NVL(SUM(SUCCESS_CNT),0) AS SUCCESS"
|
+ " , NVL(SUM(SUCCESS_CNT),0) AS SUCCESS"
|
||||||
+ " , NVL(SUM((SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT) * AVG_RESP_TIME),0) AS RESP_SUM"
|
+ " , NVL(SUM((SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT) * AVG_RESP_TIME),0) AS RESP_SUM"
|
||||||
@@ -111,7 +120,7 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
|||||||
+ " WHERE TO_CHAR(STAT_TIME,'YYYYMMDDHH24MI')"
|
+ " WHERE TO_CHAR(STAT_TIME,'YYYYMMDDHH24MI')"
|
||||||
+ " BETWEEN TO_CHAR(SYSDATE - NUMTODSINTERVAL(:errorRangeMinute,'MINUTE'),'YYYYMMDDHH24MI')"
|
+ " BETWEEN TO_CHAR(SYSDATE - NUMTODSINTERVAL(:errorRangeMinute,'MINUTE'),'YYYYMMDDHH24MI')"
|
||||||
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')"
|
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')"
|
||||||
+ " GROUP BY API_NAME) S"
|
+ " GROUP BY API_NAME) S ON N.API_NAME = S.API_NAME"
|
||||||
// 지연은 판정 구간이 따로다(delayRangeMinute). 오류 구간 평균으로 비교하면 실제 판정과 어긋난다
|
// 지연은 판정 구간이 따로다(delayRangeMinute). 오류 구간 평균으로 비교하면 실제 판정과 어긋난다
|
||||||
+ " LEFT OUTER JOIN (SELECT API_NAME"
|
+ " LEFT OUTER JOIN (SELECT API_NAME"
|
||||||
+ " , NVL(SUM(SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT),0) AS TOTAL"
|
+ " , NVL(SUM(SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT),0) AS TOTAL"
|
||||||
@@ -120,11 +129,11 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
|||||||
+ " WHERE TO_CHAR(STAT_TIME,'YYYYMMDDHH24MI')"
|
+ " WHERE TO_CHAR(STAT_TIME,'YYYYMMDDHH24MI')"
|
||||||
+ " BETWEEN TO_CHAR(SYSDATE - NUMTODSINTERVAL(:delayRangeMinute,'MINUTE'),'YYYYMMDDHH24MI')"
|
+ " BETWEEN TO_CHAR(SYSDATE - NUMTODSINTERVAL(:delayRangeMinute,'MINUTE'),'YYYYMMDDHH24MI')"
|
||||||
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')"
|
+ " AND TO_CHAR(SYSDATE,'YYYYMMDDHH24MI')"
|
||||||
+ " GROUP BY API_NAME) D ON S.API_NAME = D.API_NAME"
|
+ " GROUP BY API_NAME) D ON N.API_NAME = D.API_NAME"
|
||||||
+ " LEFT OUTER JOIN API_STATUS B ON S.API_NAME = B.EAISVCNAME"
|
+ " LEFT OUTER JOIN API_STATUS B ON N.API_NAME = B.EAISVCNAME"
|
||||||
+ " WHERE S.TOTAL > 0"
|
// 두 창 중 어느 쪽이든 거래가 있으면 찍는다 (오류 0건, 오류 창 무거래 모두 포함)
|
||||||
+ " AND S.TOTAL - S.SUCCESS > 0"
|
+ " WHERE NVL(S.TOTAL,0) > 0 OR NVL(D.TOTAL,0) > 0"
|
||||||
+ " ORDER BY (S.TOTAL - S.SUCCESS) / S.TOTAL DESC, S.API_NAME")
|
+ " ORDER BY CASE WHEN NVL(S.TOTAL,0) > 0 THEN (S.TOTAL - S.SUCCESS) / S.TOTAL ELSE -1 END DESC, N.API_NAME")
|
||||||
List<ApiErrorRateRow> findApiErrorRates(
|
List<ApiErrorRateRow> findApiErrorRates(
|
||||||
@Param("errorRangeMinute") int errorRangeMinute,
|
@Param("errorRangeMinute") int errorRangeMinute,
|
||||||
@Param("delayRangeMinute") int delayRangeMinute
|
@Param("delayRangeMinute") int delayRangeMinute
|
||||||
|
|||||||
@@ -99,11 +99,14 @@ public class ApiStatusService {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 오류율 0% 초과 API 목록을 debug 로그로 남긴다. 개발 모드(-Deai.systemmode=D) 에서만 동작한다.
|
* 판정 구간에 거래가 있는 API 의 오류율·지연 판정값을 debug 로그로 남긴다.
|
||||||
|
* 개발 모드(-Deai.systemmode=D) 에서만 동작한다.
|
||||||
*
|
*
|
||||||
* <p>상태 전이 조건(정상/지연 → 장애)을 못 넘긴 API 는 {@code findApiStatusEvents} 결과에
|
* <p>상태 전이 조건을 못 넘긴 API 는 {@code findApiStatusEvents} 결과에 나오지 않아
|
||||||
* 나오지 않아 "오류는 나는데 장애로 안 잡힌다" 를 로그로 확인할 수 없다. 임계값·현재 상태와
|
* "오류는 나는데 장애로 안 잡힌다", "느린데 지연이 아니다" 를 로그로 확인할 수 없다.
|
||||||
* 무관하게 집계된 오류율을 그대로 찍어 판정 결과와 대조할 수 있게 한다.</p>
|
* 임계값·현재 상태와 무관하게 집계값을 그대로 찍어 판정 결과와 대조할 수 있게 한다.</p>
|
||||||
|
*
|
||||||
|
* <p>오류 0건이어도 지연 판정값은 봐야 하므로 거래만 있으면 무조건 찍는다.</p>
|
||||||
*
|
*
|
||||||
* <p>진단 목적이므로 조회 실패가 상태 판정 자체를 막아서는 안 된다 - 예외는 삼킨다.</p>
|
* <p>진단 목적이므로 조회 실패가 상태 판정 자체를 막아서는 안 된다 - 예외는 삼킨다.</p>
|
||||||
*/
|
*/
|
||||||
@@ -115,12 +118,13 @@ public class ApiStatusService {
|
|||||||
try {
|
try {
|
||||||
List<ApiErrorRateRow> rows = apiStatusRepository.findApiErrorRates(errorRangeMinute, delayRangeMinute);
|
List<ApiErrorRateRow> rows = apiStatusRepository.findApiErrorRates(errorRangeMinute, delayRangeMinute);
|
||||||
if (rows.isEmpty()) {
|
if (rows.isEmpty()) {
|
||||||
log.debug("오류율 탐지: 최근 {}분간 오류 발생 API 없음", errorRangeMinute);
|
log.debug("상태 판정 진단: 최근 {}분(오류)/{}분(지연) 거래 발생 API 없음",
|
||||||
|
errorRangeMinute, delayRangeMinute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("오류율 탐지: 장애 임계 ").append(errorRate).append("% 초과(최근 ").append(errorRangeMinute)
|
sb.append("상태 판정 진단: 장애 임계 ").append(errorRate).append("% 초과(최근 ").append(errorRangeMinute)
|
||||||
.append("분), 지연 임계 ").append(delayAvgRespTime).append("ms 초과(최근 ").append(delayRangeMinute)
|
.append("분), 지연 임계 ").append(delayAvgRespTime).append("ms 초과(최근 ").append(delayRangeMinute)
|
||||||
.append("분), 대상 ").append(rows.size()).append("건");
|
.append("분), 대상 ").append(rows.size()).append("건");
|
||||||
|
|
||||||
@@ -139,7 +143,7 @@ public class ApiStatusService {
|
|||||||
log.debug(sb.toString());
|
log.debug(sb.toString());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("오류율 탐지 로그 생성 실패", e);
|
log.debug("상태 판정 진단 로그 생성 실패", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user