accesslog、errorlog日志记录简化

This commit is contained in:
gaoqr
2025-01-14 11:47:44 +08:00
parent e0023a68b2
commit bc6275bca3
17 changed files with 75 additions and 337 deletions
@@ -1,15 +1,10 @@
package com.cf.imes.framework.apilog.config; package com.cf.imes.framework.apilog.config;
import com.cf.imes.framework.apilog.core.filter.ApiAccessLogFilter; import com.cf.imes.framework.apilog.core.filter.ApiAccessLogFilter;
import com.cf.imes.framework.apilog.core.service.ApiAccessLogFrameworkService;
import com.cf.imes.framework.apilog.core.service.ApiAccessLogFrameworkServiceImpl;
import com.cf.imes.framework.apilog.core.service.ApiErrorLogFrameworkService;
import com.cf.imes.framework.apilog.core.service.ApiErrorLogFrameworkServiceImpl;
import com.cf.imes.framework.common.enums.WebFilterOrderEnum; import com.cf.imes.framework.common.enums.WebFilterOrderEnum;
import com.cf.imes.framework.web.config.WebProperties; import com.cf.imes.framework.web.config.WebProperties;
import com.cf.imes.framework.web.config.ChenfengWebAutoConfiguration; import com.cf.imes.framework.web.config.ChenfengWebAutoConfiguration;
import com.cf.imes.module.infra.api.logger.ApiAccessLogApi; import com.cf.imes.module.infra.api.logger.ApiAccessLogApi;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -21,16 +16,6 @@ import javax.servlet.Filter;
@AutoConfiguration(after = ChenfengWebAutoConfiguration.class) @AutoConfiguration(after = ChenfengWebAutoConfiguration.class)
public class ChenfengApiLogAutoConfiguration { public class ChenfengApiLogAutoConfiguration {
@Bean
public ApiAccessLogFrameworkService apiAccessLogFrameworkService(ApiAccessLogApi apiAccessLogApi) {
return new ApiAccessLogFrameworkServiceImpl(apiAccessLogApi);
}
@Bean
public ApiErrorLogFrameworkService apiErrorLogFrameworkService(ApiErrorLogApi apiErrorLogApi) {
return new ApiErrorLogFrameworkServiceImpl(apiErrorLogApi);
}
/** /**
* 创建 ApiAccessLogFilter Bean,记录 API 请求日志 * 创建 ApiAccessLogFilter Bean,记录 API 请求日志
*/ */
@@ -38,8 +23,8 @@ public class ChenfengApiLogAutoConfiguration {
@ConditionalOnProperty(prefix = "chenfeng.access-log", value = "enable", matchIfMissing = true) // 允许使用 chenfeng.access-log.enable=false 禁用访问日志 @ConditionalOnProperty(prefix = "chenfeng.access-log", value = "enable", matchIfMissing = true) // 允许使用 chenfeng.access-log.enable=false 禁用访问日志
public FilterRegistrationBean<ApiAccessLogFilter> apiAccessLogFilter(WebProperties webProperties, public FilterRegistrationBean<ApiAccessLogFilter> apiAccessLogFilter(WebProperties webProperties,
@Value("${spring.application.name}") String applicationName, @Value("${spring.application.name}") String applicationName,
ApiAccessLogFrameworkService apiAccessLogFrameworkService) { ApiAccessLogApi apiAccessLogApi) {
ApiAccessLogFilter filter = new ApiAccessLogFilter(webProperties, applicationName, apiAccessLogFrameworkService); ApiAccessLogFilter filter = new ApiAccessLogFilter(webProperties, applicationName, apiAccessLogApi);
return createFilterBean(filter, WebFilterOrderEnum.API_ACCESS_LOG_FILTER); return createFilterBean(filter, WebFilterOrderEnum.API_ACCESS_LOG_FILTER);
} }
@@ -11,7 +11,6 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
* @author 晨丰科技 * @author 晨丰科技
*/ */
@AutoConfiguration @AutoConfiguration
@EnableFeignClients(clients = {ApiAccessLogApi.class, // 主要是引入相关的 API 服务 @EnableFeignClients(clients = {ApiAccessLogApi.class, ApiErrorLogApi.class})
ApiErrorLogApi.class})
public class ChenfengApiLogRpcAutoConfiguration { public class ChenfengApiLogRpcAutoConfiguration {
} }
@@ -3,8 +3,6 @@ package com.cf.imes.framework.apilog.core.filter;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import com.cf.imes.framework.apilog.core.service.ApiAccessLog;
import com.cf.imes.framework.apilog.core.service.ApiAccessLogFrameworkService;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.monitor.TracerUtils; import com.cf.imes.framework.common.util.monitor.TracerUtils;
@@ -12,6 +10,8 @@ import com.cf.imes.framework.common.util.servlet.ServletUtils;
import com.cf.imes.framework.web.config.WebProperties; import com.cf.imes.framework.web.config.WebProperties;
import com.cf.imes.framework.web.core.filter.ApiRequestFilter; import com.cf.imes.framework.web.core.filter.ApiRequestFilter;
import com.cf.imes.framework.web.core.util.WebFrameworkUtils; import com.cf.imes.framework.web.core.util.WebFrameworkUtils;
import com.cf.imes.module.infra.api.logger.ApiAccessLogApi;
import com.cf.imes.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
@@ -35,12 +35,12 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
private final String applicationName; private final String applicationName;
private final ApiAccessLogFrameworkService apiAccessLogFrameworkService; private final ApiAccessLogApi apiAccessLogApi;
public ApiAccessLogFilter(WebProperties webProperties, String applicationName, ApiAccessLogFrameworkService apiAccessLogFrameworkService) { public ApiAccessLogFilter(WebProperties webProperties, String applicationName, ApiAccessLogApi apiAccessLogApi) {
super(webProperties); super(webProperties);
this.applicationName = applicationName; this.applicationName = applicationName;
this.apiAccessLogFrameworkService = apiAccessLogFrameworkService; this.apiAccessLogApi = apiAccessLogApi;
} }
@Override @Override
@@ -66,16 +66,16 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
private void createApiAccessLog(HttpServletRequest request, LocalDateTime beginTime, private void createApiAccessLog(HttpServletRequest request, LocalDateTime beginTime,
Map<String, String> queryString, String requestBody, Exception ex) { Map<String, String> queryString, String requestBody, Exception ex) {
ApiAccessLog accessLog = new ApiAccessLog(); ApiAccessLogCreateReqDTO accessLog = new ApiAccessLogCreateReqDTO();
try { try {
this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex); this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex);
apiAccessLogFrameworkService.createApiAccessLog(accessLog); apiAccessLogApi.createApiAccessLogAsync(accessLog);
} catch (Throwable th) { } catch (Throwable th) {
log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th); log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th);
} }
} }
private void buildApiAccessLogDTO(ApiAccessLog accessLog, HttpServletRequest request, LocalDateTime beginTime, private void buildApiAccessLogDTO(ApiAccessLogCreateReqDTO accessLog, HttpServletRequest request, LocalDateTime beginTime,
Map<String, String> queryString, String requestBody, Exception ex) { Map<String, String> queryString, String requestBody, Exception ex) {
// 处理用户信息 // 处理用户信息
accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
@@ -1,85 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* API 访问日志
*
* @author 晨丰科技
*/
@Data
public class ApiAccessLog {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 请求方法名
*/
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/**
* 访问地址
*/
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/**
* 请求参数
*/
@NotNull(message = "请求参数不能为空")
private String requestParams;
/**
* 用户 IP
*/
@NotNull(message = "ip 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/**
* 开始请求时间
*/
@NotNull(message = "开始请求时间不能为空")
private LocalDateTime beginTime;
/**
* 结束请求时间
*/
@NotNull(message = "结束请求时间不能为空")
private LocalDateTime endTime;
/**
* 执行时长,单位:毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "错误码不能为空")
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
}
@@ -1,17 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
/**
* API 访问日志 Framework Service 接口
*
* @author 晨丰科技
*/
public interface ApiAccessLogFrameworkService {
/**
* 创建 API 访问日志
*
* @param apiAccessLog API 访问日志
*/
void createApiAccessLog(ApiAccessLog apiAccessLog);
}
@@ -1,28 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
import cn.hutool.core.bean.BeanUtil;
import com.cf.imes.module.infra.api.logger.ApiAccessLogApi;
import com.cf.imes.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* API 访问日志 Framework Service 实现类
*
* 基于 {@link ApiAccessLogApi} 远程服务,记录访问日志
*
* @author 晨丰科技
*/
@RequiredArgsConstructor
public class ApiAccessLogFrameworkServiceImpl implements ApiAccessLogFrameworkService {
private final ApiAccessLogApi apiAccessLogApi;
@Override
@Async
public void createApiAccessLog(ApiAccessLog apiAccessLog) {
ApiAccessLogCreateReqDTO reqDTO = BeanUtil.copyProperties(apiAccessLog, ApiAccessLogCreateReqDTO.class);
apiAccessLogApi.createApiAccessLog(reqDTO).checkError();
}
}
@@ -1,107 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* API 错误日志
*
* @author 晨丰科技
*/
@Data
public class ApiErrorLog {
/**
* 链路编号
*/
private String traceId;
/**
* 账号编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 请求方法名
*/
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/**
* 访问地址
*/
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/**
* 请求参数
*/
@NotNull(message = "请求参数不能为空")
private String requestParams;
/**
* 用户 IP
*/
@NotNull(message = "ip 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/**
* 异常时间
*/
@NotNull(message = "异常时间不能为空")
private LocalDateTime exceptionTime;
/**
* 异常名
*/
@NotNull(message = "异常名不能为空")
private String exceptionName;
/**
* 异常发生的类全名
*/
@NotNull(message = "异常发生的类全名不能为空")
private String exceptionClassName;
/**
* 异常发生的类文件
*/
@NotNull(message = "异常发生的类文件不能为空")
private String exceptionFileName;
/**
* 异常发生的方法名
*/
@NotNull(message = "异常发生的方法名不能为空")
private String exceptionMethodName;
/**
* 异常发生的方法所在行
*/
@NotNull(message = "异常发生的方法所在行不能为空")
private Integer exceptionLineNumber;
/**
* 异常的栈轨迹异常的栈轨迹
*/
@NotNull(message = "异常的栈轨迹不能为空")
private String exceptionStackTrace;
/**
* 异常导致的根消息
*/
@NotNull(message = "异常导致的根消息不能为空")
private String exceptionRootCauseMessage;
/**
* 异常导致的消息
*/
@NotNull(message = "异常导致的消息不能为空")
private String exceptionMessage;
}
@@ -1,17 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
/**
* API 错误日志 Framework Service 接口
*
* @author 晨丰科技
*/
public interface ApiErrorLogFrameworkService {
/**
* 创建 API 错误日志
*
* @param apiErrorLog API 错误日志
*/
void createApiErrorLog(ApiErrorLog apiErrorLog);
}
@@ -1,28 +0,0 @@
package com.cf.imes.framework.apilog.core.service;
import cn.hutool.core.bean.BeanUtil;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import com.cf.imes.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* API 错误日志 Framework Service 实现类
*
* 基于 {@link ApiErrorLogApi} 远程服务,记录错误日志
*
* @author 晨丰科技
*/
@RequiredArgsConstructor
public class ApiErrorLogFrameworkServiceImpl implements ApiErrorLogFrameworkService {
private final ApiErrorLogApi apiErrorLogApi;
@Override
@Async
public void createApiErrorLog(ApiErrorLog apiErrorLog) {
ApiErrorLogCreateReqDTO reqDTO = BeanUtil.copyProperties(apiErrorLog, ApiErrorLogCreateReqDTO.class);
apiErrorLogApi.createApiErrorLog(reqDTO).checkError();
}
}
@@ -1,13 +1,13 @@
package com.cf.imes.framework.web.config; package com.cf.imes.framework.web.config;
import com.cf.imes.framework.aop.ControllerResolver; import com.cf.imes.framework.aop.ControllerResolver;
import com.cf.imes.framework.apilog.core.service.ApiErrorLogFrameworkService;
import com.cf.imes.framework.common.enums.WebFilterOrderEnum; import com.cf.imes.framework.common.enums.WebFilterOrderEnum;
import com.cf.imes.framework.web.core.filter.CacheRequestBodyFilter; import com.cf.imes.framework.web.core.filter.CacheRequestBodyFilter;
import com.cf.imes.framework.web.core.filter.DataSourceFilter; import com.cf.imes.framework.web.core.filter.DataSourceFilter;
import com.cf.imes.framework.web.core.handler.GlobalExceptionHandler; import com.cf.imes.framework.web.core.handler.GlobalExceptionHandler;
import com.cf.imes.framework.web.core.handler.GlobalResponseBodyHandler; import com.cf.imes.framework.web.core.handler.GlobalResponseBodyHandler;
import com.cf.imes.framework.web.core.util.WebFrameworkUtils; import com.cf.imes.framework.web.core.util.WebFrameworkUtils;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -59,8 +59,8 @@ public class ChenfengWebAutoConfiguration implements WebMvcConfigurer {
} }
@Bean @Bean
public GlobalExceptionHandler globalExceptionHandler(ApiErrorLogFrameworkService ApiErrorLogFrameworkService) { public GlobalExceptionHandler globalExceptionHandler(ApiErrorLogApi apiErrorLogApi) {
return new GlobalExceptionHandler(applicationName, ApiErrorLogFrameworkService); return new GlobalExceptionHandler(applicationName, apiErrorLogApi);
} }
@Bean @Bean
@@ -3,15 +3,14 @@ package com.cf.imes.framework.web.core.handler;
import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.cf.imes.framework.apilog.core.service.ApiErrorLog;
import com.cf.imes.framework.apilog.core.service.ApiErrorLogFrameworkService;
import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.monitor.TracerUtils; import com.cf.imes.framework.common.util.monitor.TracerUtils;
import com.cf.imes.framework.web.core.util.WebFrameworkUtils; import com.cf.imes.framework.web.core.util.WebFrameworkUtils;
import com.cf.imes.framework.common.util.json.JsonUtils; import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.servlet.ServletUtils; import com.cf.imes.framework.common.util.servlet.ServletUtils;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import com.cf.imes.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.DuplicateKeyException;
@@ -50,7 +49,7 @@ public class GlobalExceptionHandler {
private final String applicationName; private final String applicationName;
private final ApiErrorLogFrameworkService apiErrorLogFrameworkService; private final ApiErrorLogApi apiErrorLogApi;
/** /**
* 处理所有异常,主要是提供给 Filter 使用 * 处理所有异常,主要是提供给 Filter 使用
@@ -251,14 +250,6 @@ public class GlobalExceptionHandler {
return tableNotExistsResult; return tableNotExistsResult;
} }
if(ex instanceof NullPointerException){
// 处理异常
log.error("[defaultExceptionHandler]", ex);
// 插入异常日志
this.createExceptionLog(req, ex);
return CommonResult.error(DATA_EXCEPTION_ERROR.getCode(), DATA_EXCEPTION_ERROR.getMsg());
}
// 情况二:部分特殊的库的处理 // 情况二:部分特殊的库的处理
if (Objects.equals("io.github.resilience4j.ratelimiter.RequestNotPermitted", ex.getClass().getName())) { if (Objects.equals("io.github.resilience4j.ratelimiter.RequestNotPermitted", ex.getClass().getName())) {
return requestNotPermittedExceptionHandler(req, ex); return requestNotPermittedExceptionHandler(req, ex);
@@ -274,18 +265,18 @@ public class GlobalExceptionHandler {
private void createExceptionLog(HttpServletRequest req, Throwable e) { private void createExceptionLog(HttpServletRequest req, Throwable e) {
// 插入错误日志 // 插入错误日志
ApiErrorLog errorLog = new ApiErrorLog(); ApiErrorLogCreateReqDTO errorLog = new ApiErrorLogCreateReqDTO();
try { try {
// 初始化 errorLog // 初始化 errorLog
initExceptionLog(errorLog, req, e); buildExceptionLog(errorLog, req, e);
// 执行插入 errorLog // 执行插入 errorLog
apiErrorLogFrameworkService.createApiErrorLog(errorLog); apiErrorLogApi.createApiErrorLogAsync(errorLog);
} catch (Throwable th) { } catch (Throwable th) {
log.error("[createExceptionLog][url({}) log({}) 发生异常]", req.getRequestURI(), JsonUtils.toJsonString(errorLog), th); log.error("[createExceptionLog][url({}) log({}) 发生异常]", req.getRequestURI(), JsonUtils.toJsonString(errorLog), th);
} }
} }
private void initExceptionLog(ApiErrorLog errorLog, HttpServletRequest request, Throwable e) { private void buildExceptionLog(ApiErrorLogCreateReqDTO errorLog, HttpServletRequest request, Throwable e) {
// 处理用户信息 // 处理用户信息
errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
errorLog.setUserType(WebFrameworkUtils.getLoginUserType(request)); errorLog.setUserType(WebFrameworkUtils.getLoginUserType(request));
@@ -306,12 +297,12 @@ public class GlobalExceptionHandler {
errorLog.setApplicationName(applicationName); errorLog.setApplicationName(applicationName);
errorLog.setRequestUrl(request.getRequestURI()); errorLog.setRequestUrl(request.getRequestURI());
Map<String, Object> requestParams = MapUtil.<String, Object>builder() Map<String, Object> requestParams = MapUtil.<String, Object>builder()
.put("query", ServletUtil.getParamMap(request)) .put("query", ServletUtils.getParamMap(request))
.put("body", ServletUtil.getBody(request)).build(); .put("body", ServletUtils.getBody(request)).build();
errorLog.setRequestParams(JsonUtils.toJsonString(requestParams)); errorLog.setRequestParams(JsonUtils.toJsonString(requestParams));
errorLog.setRequestMethod(request.getMethod()); errorLog.setRequestMethod(request.getMethod());
errorLog.setUserAgent(ServletUtils.getUserAgent(request)); errorLog.setUserAgent(ServletUtils.getUserAgent(request));
errorLog.setUserIp(ServletUtil.getClientIP(request)); errorLog.setUserIp(ServletUtils.getClientIP(request));
errorLog.setExceptionTime(LocalDateTime.now()); errorLog.setExceptionTime(LocalDateTime.now());
} }
@@ -6,6 +6,7 @@ import com.cf.imes.module.infra.enums.ApiConstants;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -21,4 +22,13 @@ public interface ApiAccessLogApi {
@Operation(summary = "创建 API 访问日志") @Operation(summary = "创建 API 访问日志")
CommonResult<Boolean> createApiAccessLog(@Valid @RequestBody ApiAccessLogCreateReqDTO createDTO); CommonResult<Boolean> createApiAccessLog(@Valid @RequestBody ApiAccessLogCreateReqDTO createDTO);
/**
* 【异步】创建 API 访问日志
*
* @param createDTO 访问日志 DTO
*/
@Async
default void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) {
createApiAccessLog(createDTO).checkError();
}
} }
@@ -6,6 +6,7 @@ import com.cf.imes.module.infra.enums.ApiConstants;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -21,4 +22,8 @@ public interface ApiErrorLogApi {
@Operation(summary = "创建 API 异常日志") @Operation(summary = "创建 API 异常日志")
CommonResult<Boolean> createApiErrorLog(@Valid @RequestBody ApiErrorLogCreateReqDTO createDTO); CommonResult<Boolean> createApiErrorLog(@Valid @RequestBody ApiErrorLogCreateReqDTO createDTO);
@Async
default void createApiErrorLogAsync(ApiErrorLogCreateReqDTO createDTO) {
createApiErrorLog(createDTO).checkError();
}
} }
@@ -25,6 +25,16 @@ import java.time.LocalDateTime;
@AllArgsConstructor @AllArgsConstructor
public class ApiAccessLogDO extends BaseDO { public class ApiAccessLogDO extends BaseDO {
/**
* {@link #requestParams} 的最大长度
*/
public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000;
/**
* {@link #resultMsg} 的最大长度
*/
public static final Integer RESULT_MSG_MAX_LENGTH = 512;
/** /**
* 编号 * 编号
*/ */
@@ -25,6 +25,11 @@ import java.time.LocalDateTime;
@KeySequence(value = "infra_api_error_log_seq") @KeySequence(value = "infra_api_error_log_seq")
public class ApiErrorLogDO extends BaseDO { public class ApiErrorLogDO extends BaseDO {
/**
* {@link #requestParams} 的最大长度
*/
public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000;
/** /**
* 编号 * 编号
*/ */
@@ -1,7 +1,10 @@
package com.cf.imes.module.infra.service.logger; package com.cf.imes.module.infra.service.logger;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.organ.core.util.OrganUtils;
import com.cf.imes.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; import com.cf.imes.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import com.cf.imes.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; import com.cf.imes.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import com.cf.imes.module.infra.dal.dataobject.logger.ApiAccessLogDO; import com.cf.imes.module.infra.dal.dataobject.logger.ApiAccessLogDO;
@@ -13,6 +16,9 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import static com.cf.imes.module.infra.dal.dataobject.logger.ApiAccessLogDO.REQUEST_PARAMS_MAX_LENGTH;
import static com.cf.imes.module.infra.dal.dataobject.logger.ApiAccessLogDO.RESULT_MSG_MAX_LENGTH;
/** /**
* API 访问日志 Service 实现类 * API 访问日志 Service 实现类
* *
@@ -29,10 +35,13 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService {
@Override @Override
public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {
ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class); ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class);
try { apiAccessLog.setRequestParams(StrUtil.maxLength(apiAccessLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH));
apiAccessLog.setResultMsg(StrUtil.maxLength(apiAccessLog.getResultMsg(), RESULT_MSG_MAX_LENGTH));
if (OrganContextHolder.getOrganId() != null) {
apiAccessLogMapper.insert(apiAccessLog); apiAccessLogMapper.insert(apiAccessLog);
}catch (Exception e) { } else {
log.error("插入API 访问日志发生异常,异常信息{},日志内容{}", e.getMessage(), apiAccessLog); // 极端情况下,上下文中没有租户时,此时忽略租户上下文,避免插入失败!
OrganUtils.executeIgnore(() -> apiAccessLogMapper.insert(apiAccessLog));
} }
} }
@@ -1,7 +1,10 @@
package com.cf.imes.module.infra.service.logger; package com.cf.imes.module.infra.service.logger;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.organ.core.util.OrganUtils;
import com.cf.imes.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; import com.cf.imes.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import com.cf.imes.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; import com.cf.imes.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import com.cf.imes.module.infra.dal.dataobject.logger.ApiErrorLogDO; import com.cf.imes.module.infra.dal.dataobject.logger.ApiErrorLogDO;
@@ -15,6 +18,7 @@ import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.infra.dal.dataobject.logger.ApiErrorLogDO.REQUEST_PARAMS_MAX_LENGTH;
import static com.cf.imes.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_NOT_FOUND; import static com.cf.imes.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_NOT_FOUND;
import static com.cf.imes.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_PROCESSED; import static com.cf.imes.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_PROCESSED;
@@ -35,10 +39,12 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService {
public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) {
ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class) ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class)
.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); .setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus());
try { apiErrorLog.setRequestParams(StrUtil.maxLength(apiErrorLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH));
if (OrganContextHolder.getOrganId() != null) {
apiErrorLogMapper.insert(apiErrorLog); apiErrorLogMapper.insert(apiErrorLog);
}catch (Exception e) { } else {
log.error("插入系统异常日志发生异常,异常信息{},日志内容{}",e.getMessage(), apiErrorLog); // 极端情况下,上下文中没有租户时,此时忽略租户上下文,避免插入失败!
OrganUtils.executeIgnore(() -> apiErrorLogMapper.insert(apiErrorLog));
} }
} }