feat: batch logging 반영

dev
gitea-관리자 1 year ago
parent 411ccb2d16
commit 5ee5c5eec3

@ -1,279 +0,0 @@
package kr.xit.core.aop;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.servlet.http.HttpServletRequest;
import kr.xit.core.biz.model.LoggingDTO;
import kr.xit.core.biz.service.ILoggingService;
import kr.xit.core.exception.BizRuntimeException;
import kr.xit.core.model.ApiResponseDTO;
import kr.xit.core.spring.util.error.ErrorParse;
import kr.xit.core.support.slack.SlackWebhookPush;
import kr.xit.core.support.utils.JsonUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* <pre>
* description : logging trace aspect
* core LoggerAspect -> traceLogging / traceLoggingError / traceLoggingResult
*
* Logging trace
* - MDC(Mapped Diagnostic Context : logback, log4j )
* - ThreadLocal
* - nginx : proxy_set_header X-RequestID $request_id;
* - logback log pattern : [traceId=%X{request_id}]
*
* app.slack-webhook.enabled: true slack push
* Slack webhook : SlackWebhookPush
*
* packageName : kr.xit.core.aop
* fileName : TraceLoggerAspect
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
* 2023-06-12 julim RequestContextHolder.HttpServletRequest
* </pre>
* @see kr.xit.core.support.slack.SlackWebhookPush#sendSlackAlertLog(String, String, String)
*/
@Slf4j
//@Aspect
//@Component
public class TraceLoggerAspect {
@Value("${app.slack-webhook.enabled:false}")
private boolean isSlackEnabled;
@Value("#{'${app.log.mdc.exclude-patterns}'.split(',')}")
private String[] excludes;
private final ILoggingService loggingService;
private final SlackWebhookPush slackWebhookPush;
private static final String REQUEST_TRACE_ID = "request_trace_id";
public TraceLoggerAspect(@Lazy ILoggingService loggingService, SlackWebhookPush slackWebhookPush) {
this.loggingService = loggingService;
this.slackWebhookPush = slackWebhookPush;
}
@Pointcut("execution(public * egovframework..*.*(..)) || execution(public * kr.xit..*.*(..))")
public void errorPointCut() {
}
@Around(value = "@annotation(kr.xit.core.spring.annotation.TraceLogging)")
public Object serviceTraceLogging(final ProceedingJoinPoint pjp) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes != null? attributes.getRequest(): null;
traceLogging(JsonUtils.toJson(pjp.getArgs()), request);
Object result = pjp.proceed();
//noinspection rawtypes
if(result instanceof CompletableFuture future){
while(true) {
if (future.isDone()) break;
}
traceLoggingResult(future.get());
}else{
traceLoggingResult(result);
}
return result;
}
//@AfterThrowing(value = "@annotation(kr.xit.core.spring.annotation.TraceLogging)", throwing = "error")
@AfterThrowing(value = "errorPointCut()", throwing="error")
public void afterThrowingProceed(final JoinPoint jp, final Throwable error) {
log.error("+++++++++++++++>>>>>>> Batch Error log trace::{}", error.getMessage());
traceLoggingError(jp, error);
}
/**
* set MDC batch reading , tasklet set trace_id set
* @param params
* @param request
*/
protected void traceLogging(final String params, final HttpServletRequest request) {
if(request != null) {
String uri = request.getRequestURI().toString();
if(Arrays.asList(excludes).stream().anyMatch(regx -> uri.matches(regx))) return;
MDC.put(REQUEST_TRACE_ID,
StringUtils.defaultString(MDC.get("request_trace_batch_id"), UUID.randomUUID().toString().replaceAll("/-/g", "")));
MDC.put("method", request.getMethod());
MDC.put("uri", uri);
MDC.put("ip", request.getRemoteAddr());
MDC.put("sessionId", request.getSession().getId());
// batch로 실행되는 경우 task에서 설정 : uri / method
}else{
// request_id는 중복 처리 되면 않되므로 여기에서 생성
MDC.put(REQUEST_TRACE_ID, StringUtils.defaultString(MDC.get("request_trace_batch_id"), UUID.randomUUID().toString().replaceAll("-", "")));
}
//TODO::systemId, reqSystemId 설정 필요
log.info("@@@@@@@@@@@@@@@@@로깅 start : [\n{}\n]",MDC.getCopyOfContextMap());
MDC.put("systemId", "ENS");
MDC.put("reqSystemId", "KAKAO");
MDC.put("param", params);
MDC.put("accessToken", "");
LoggingDTO loggingDTO = LoggingDTO.builder()
.requestId(MDC.getCopyOfContextMap().get(REQUEST_TRACE_ID))
.systemId("ENS")
.reqSystemId("KAKAO")
.method(MDC.getCopyOfContextMap().get("method"))
.uri(MDC.getCopyOfContextMap().get("uri"))
.param(params)
.ip(MDC.getCopyOfContextMap().get("ip"))
.accessToken("")
.sessionId(MDC.getCopyOfContextMap().get("sessionId"))
.build();
loggingService.saveLogging(loggingDTO);
}
protected void traceLoggingResult(final Object result) {
String success = "true";
//FIXME: slack webhook log push
if(result instanceof ApiResponseDTO<?> apiResponseDTO){
if(!apiResponseDTO.isSuccess()){
success = "false";
if(isSlackEnabled) {
if(RequestContextHolder.getRequestAttributes() != null) {
slackWebhookPush.sendSlackAlertLog(
String.format("[%s]%s", MDC.get(REQUEST_TRACE_ID), apiResponseDTO.getMessage()),
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest());
}else{
slackWebhookPush.sendSlackAlertLog(
String.format("[%s]%s", MDC.get(REQUEST_TRACE_ID), apiResponseDTO.getMessage()),
MDC.get("uri"),
"batch call");
}
}
}else{
if(apiResponseDTO.getData() != null){
log.info("~~~~");
}
}
}
LoggingDTO reqDTO = LoggingDTO
.builder()
.requestId(MDC.get(REQUEST_TRACE_ID))
.success(success)
.response(getResult(result))
.message(HttpStatus.OK.name())
.build();
//}
loggingService.modifyLogging(reqDTO);
//loggingService.saveLogging(reqDTO);
log.info("@@@@@@@@@@@@@@로깅 end[\n{}\n]", MDC.getCopyOfContextMap());
//if(RequestContextHolder.getRequestAttributes() != null)
MDC.clear();
//}
}
private String getResult(final Object o){
//noinspection rawtypes
if(o instanceof Future future) {
try {
return JsonUtils.toJson(future.get());
} catch (InterruptedException ie){
// thread pool에 에러 상태 전송
Thread.currentThread().interrupt();
throw BizRuntimeException.create(ie);
} catch (ExecutionException ee) {
throw BizRuntimeException.create(ee);
}
}else{
return JsonUtils.toJson(o);
}
}
protected void traceLoggingError(final JoinPoint jp, final Throwable e) {
log.info("~~~~~~~~~~~~~~~~~~~~~~~>>>>{}", MDC.get(REQUEST_TRACE_ID));
// if(Checks.isEmpty(MDC.get(REQUEST_TRACE_ID))) return;
@SuppressWarnings("rawtypes")
ApiResponseDTO dto = ErrorParse.extractError(e);
loggingService.modifyLogging(
LoggingDTO
.builder()
.requestId(MDC.get(REQUEST_TRACE_ID))
.success("false")
.response(JsonUtils.toJson(dto))
.message(dto.getMessage())
.build());
//FIXME :: slack webhook log push
if(isSlackEnabled){
if(RequestContextHolder.getRequestAttributes() != null) {
slackWebhookPush.sendSlackAlertLog(
String.format("[%s]%s(%s)", MDC.get(REQUEST_TRACE_ID), dto.getCode(), dto.getMessage()),
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest());
}else{
slackWebhookPush.sendSlackAlertLog(
String.format("[%s]%s(%s)", MDC.get(REQUEST_TRACE_ID), dto.getCode(), dto.getMessage()),
MDC.get("uri"),
"batch call");
}
}
log.info("@@@@@@@@@@@@ 로깅 end[\n{}\n]", MDC.getCopyOfContextMap());
//if(RequestContextHolder.getRequestAttributes() != null)
MDC.clear();
}
@Getter
enum ApiSystemId {
KAKAO("KAKAO", "카카오", "/kakao/"),
KT_BC("KT-BC", "공공알림문자", "/kt/"),
PPLUS("POST-PLUS", "Post Plus", "/pplus/"),
NICE("NICE", "NICE CI", "/nice/"),
EPOST("EPOST", "E-POST", "/ag/"),
NONE("NONE", "미정의", "/미정의/"),
;
private final String code;
private final String desc;
private final String uri;
ApiSystemId(final String code, final String desc, final String uri) {
this.code = code;
this.desc = desc;
this.uri = uri;
}
public static ApiSystemId compareByUri(final String uri){
return Arrays.stream(ApiSystemId.values())
.filter(ssc -> uri.contains(ssc.getUri()))
.findFirst()
.orElseGet(() -> ApiSystemId.valueOf("NONE"));
}
}
}

@ -49,7 +49,7 @@ public class BatchEndTasklet implements Tasklet {
.batchLogId(MDC.get("batch_log_id"))
.traceId(StringUtils.defaultString(MDC.get("request_trace_id"), MDC.get("request_trace_batch_id")))
.build();
log.info("@@@@@@@@@@@@@ BatchEndTask :: {}", MDC.getCopyOfContextMap());
batchCmmService.modifyBatchLock(dto);
batchCmmService.modifyBatchLog(dto);
return RepeatStatus.FINISHED;

@ -49,11 +49,9 @@ public class BatchFailEndTasklet implements Tasklet {
.batchLogId(MDC.get("batch_log_id"))
.traceId(StringUtils.defaultString(MDC.get("request_trace_id"), MDC.get("request_trace_batch_id")))
.build();
log.info("@@@@@@@@@@@@@ Batch Fail EndTask :: {}", MDC.getCopyOfContextMap());
batchCmmService.modifyBatchLock(dto);
batchCmmService.modifyBatchLog(dto);
return RepeatStatus.FINISHED;
}
}

@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.xit.core.biz.mapper.ILoggingMapper">
<insert id="saveLogging" parameterType="kr.xit.core.biz.model.LoggingDTO">
/** logging-mysql-mapper|saveLogging|julim */
INSERT INTO tb_cmm_api_log (
request_id
, system_id
, req_system_id
, method
, uri
, param
, ip
, access_token
, session_id
, success
, response
, message
, regist_dt
, regist_id
) VALUES (
#{requestId}
, #{systemId}
, #{reqSystemId}
, #{method}
, #{uri}
, #{param}
, #{ip}
, #{accessToken}
, #{sessionId}
, #{success}
, #{response}
, #{message}
, now(3)
, #{registId}
)
</insert>
<update id="updateLogging" parameterType="kr.xit.core.biz.model.LoggingDTO">
/** logging-mysql-mapper|updateLogging|julim */
UPDATE tb_cmm_api_log
SET success = #{success}
, response = #{response}
, message = #{message}
, updt_dt = now(3)
, updt_id = #{updtId}
WHERE request_id = #{requestId}
</update>
<select id="selectLogging" resultType="kr.xit.core.biz.model.LoggingDTO">
/** logging-mysql-mapper|selectLogging|julim */
SELECT request_id
, system_id
, req_system_id
, method
, uri
, param
, ip
, access_token
, session_id
, regist_dt
, regist_id
FROM tb_cmm_api_log
<where>
<if test='requestId != null and requestId != ""'>
AND request_id = #{requestId}
</if>
<if test='systemId != null and systemId != ""'>
AND system_id = #{systemId}
</if>
<if test='uri != null and uri != ""'>
AND uri LIKE CONCAT('%', #{url}, '%')
</if>
</where>
</select>
</mapper>
Loading…
Cancel
Save