Commit 19a461b3cf4109f4c73ed7ab2d8480fc21f06b34
1 parent
9034da66
初始化 API 错误日志模块的代码
Showing
12 changed files
with
417 additions
and
62 deletions
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/filter/ApiAccessLogFilter.java
| @@ -68,20 +68,20 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { | @@ -68,20 +68,20 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { | ||
| 68 | 68 | ||
| 69 | private void createApiAccessLog(HttpServletRequest request, Date beginTime, | 69 | private void createApiAccessLog(HttpServletRequest request, Date beginTime, |
| 70 | Map<String, String> queryString, String requestBody, Exception ex) { | 70 | Map<String, String> queryString, String requestBody, Exception ex) { |
| 71 | + ApiAccessLogCreateDTO accessLog = new ApiAccessLogCreateDTO(); | ||
| 71 | try { | 72 | try { |
| 72 | - ApiAccessLogCreateDTO accessLog = this.buildApiAccessLogDTO(request, beginTime, queryString, requestBody, ex); | 73 | + this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex); |
| 73 | apiAccessLogFrameworkService.createApiAccessLogAsync(accessLog); | 74 | apiAccessLogFrameworkService.createApiAccessLogAsync(accessLog); |
| 74 | - } catch (Exception e) { | ||
| 75 | - log.error("[createApiAccessLog][url({}) 发生异常]", request.getRequestURI(), e); | 75 | + } catch (Throwable th) { |
| 76 | + log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), JsonUtils.toJsonString(accessLog), th); | ||
| 76 | } | 77 | } |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | - private ApiAccessLogCreateDTO buildApiAccessLogDTO(HttpServletRequest request, Date beginTime, | ||
| 80 | - Map<String, String> queryString, String requestBody, Exception ex) { | ||
| 81 | - ApiAccessLogCreateDTO accessLog = new ApiAccessLogCreateDTO(); | 80 | + private void buildApiAccessLogDTO(ApiAccessLogCreateDTO accessLog, HttpServletRequest request, Date beginTime, |
| 81 | + Map<String, String> queryString, String requestBody, Exception ex) { | ||
| 82 | // 处理用户信息 | 82 | // 处理用户信息 |
| 83 | accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); | 83 | accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); |
| 84 | - accessLog.setUserType(WebFrameworkUtils.getUsrType(request)); | 84 | + accessLog.setUserType(WebFrameworkUtils.getUesrType(request)); |
| 85 | // 设置访问结果 | 85 | // 设置访问结果 |
| 86 | CommonResult<?> result = WebFrameworkUtils.getCommonResult(request); | 86 | CommonResult<?> result = WebFrameworkUtils.getCommonResult(request); |
| 87 | if (result != null) { | 87 | if (result != null) { |
| @@ -107,7 +107,6 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { | @@ -107,7 +107,6 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { | ||
| 107 | accessLog.setBeginTime(beginTime); | 107 | accessLog.setBeginTime(beginTime); |
| 108 | accessLog.setEndTime(new Date()); | 108 | accessLog.setEndTime(new Date()); |
| 109 | accessLog.setDuration((int) DateUtils.diff(accessLog.getEndTime(), accessLog.getBeginTime())); | 109 | accessLog.setDuration((int) DateUtils.diff(accessLog.getEndTime(), accessLog.getBeginTime())); |
| 110 | - return accessLog; | ||
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | } | 112 | } |
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/service/ApiErrorLogFrameworkService.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.framework.logger.apilog.core.service; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO; | ||
| 4 | + | ||
| 5 | +import javax.validation.Valid; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * API 错误日志 Framework Service 接口 | ||
| 9 | + * | ||
| 10 | + * @author 芋道源码 | ||
| 11 | + */ | ||
| 12 | +public interface ApiErrorLogFrameworkService { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 创建 API 错误日志 | ||
| 16 | + * | ||
| 17 | + * @param createDTO 创建信息 | ||
| 18 | + */ | ||
| 19 | + void createApiErrorLogAsync(@Valid ApiErrorLogCreateDTO createDTO); | ||
| 20 | + | ||
| 21 | +} |
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/service/dto/ApiErrorLogCreateDTO.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.framework.logger.apilog.core.service.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.experimental.Accessors; | ||
| 5 | + | ||
| 6 | +import javax.validation.constraints.NotNull; | ||
| 7 | +import java.io.Serializable; | ||
| 8 | +import java.util.Date; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * API 错误日志创建 DTO | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@Accessors(chain = true) | ||
| 17 | +public class ApiErrorLogCreateDTO implements Serializable { | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 链路编号 | ||
| 21 | + */ | ||
| 22 | + private String traceId; | ||
| 23 | + /** | ||
| 24 | + * 账号编号 | ||
| 25 | + */ | ||
| 26 | + private Long userId; | ||
| 27 | + /** | ||
| 28 | + * 用户类型 | ||
| 29 | + */ | ||
| 30 | + private Integer userType; | ||
| 31 | + /** | ||
| 32 | + * 应用名 | ||
| 33 | + */ | ||
| 34 | + @NotNull(message = "应用名不能为空") | ||
| 35 | + private String applicationName; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 请求方法名 | ||
| 39 | + */ | ||
| 40 | + @NotNull(message = "http 请求方法不能为空") | ||
| 41 | + private String requestMethod; | ||
| 42 | + /** | ||
| 43 | + * 访问地址 | ||
| 44 | + */ | ||
| 45 | + @NotNull(message = "访问地址不能为空") | ||
| 46 | + private String requestUrl; | ||
| 47 | + /** | ||
| 48 | + * 请求参数 | ||
| 49 | + */ | ||
| 50 | + @NotNull(message = "请求参数不能为空") | ||
| 51 | + private String requestParams; | ||
| 52 | + /** | ||
| 53 | + * 用户 IP | ||
| 54 | + */ | ||
| 55 | + @NotNull(message = "ip 不能为空") | ||
| 56 | + private String userIp; | ||
| 57 | + /** | ||
| 58 | + * 浏览器 UA | ||
| 59 | + */ | ||
| 60 | + @NotNull(message = "User-Agent 不能为空") | ||
| 61 | + private String userAgent; | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 异常时间 | ||
| 65 | + */ | ||
| 66 | + @NotNull(message = "异常时间不能为空") | ||
| 67 | + private Date exceptionTime; | ||
| 68 | + /** | ||
| 69 | + * 异常名 | ||
| 70 | + */ | ||
| 71 | + @NotNull(message = "异常名不能为空") | ||
| 72 | + private String exceptionName; | ||
| 73 | + /** | ||
| 74 | + * 异常发生的类全名 | ||
| 75 | + */ | ||
| 76 | + @NotNull(message = "异常发生的类全名不能为空") | ||
| 77 | + private String exceptionClassName; | ||
| 78 | + /** | ||
| 79 | + * 异常发生的类文件 | ||
| 80 | + */ | ||
| 81 | + @NotNull(message = "异常发生的类文件不能为空") | ||
| 82 | + private String exceptionFileName; | ||
| 83 | + /** | ||
| 84 | + * 异常发生的方法名 | ||
| 85 | + */ | ||
| 86 | + @NotNull(message = "异常发生的方法名不能为空") | ||
| 87 | + private String exceptionMethodName; | ||
| 88 | + /** | ||
| 89 | + * 异常发生的方法所在行 | ||
| 90 | + */ | ||
| 91 | + @NotNull(message = "异常发生的方法所在行不能为空") | ||
| 92 | + private Integer exceptionLineNumber; | ||
| 93 | + /** | ||
| 94 | + * 异常的栈轨迹异常的栈轨迹 | ||
| 95 | + */ | ||
| 96 | + @NotNull(message = "异常的栈轨迹不能为空") | ||
| 97 | + private String exceptionStackTrace; | ||
| 98 | + /** | ||
| 99 | + * 异常导致的根消息 | ||
| 100 | + */ | ||
| 101 | + @NotNull(message = "异常导致的根消息不能为空") | ||
| 102 | + private String exceptionRootCauseMessage; | ||
| 103 | + /** | ||
| 104 | + * 异常导致的消息 | ||
| 105 | + */ | ||
| 106 | + @NotNull(message = "异常导致的消息不能为空") | ||
| 107 | + private String exceptionMessage; | ||
| 108 | + | ||
| 109 | +} |
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/service/package-info.java deleted
| 1 | -package cn.iocoder.dashboard.framework.logger.apilog.core.service; |
src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java
| 1 | package cn.iocoder.dashboard.framework.web.core.handler; | 1 | package cn.iocoder.dashboard.framework.web.core.handler; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.exceptions.ExceptionUtil; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 5 | +import cn.hutool.extra.servlet.ServletUtil; | ||
| 3 | import cn.iocoder.dashboard.common.exception.GlobalException; | 6 | import cn.iocoder.dashboard.common.exception.GlobalException; |
| 4 | import cn.iocoder.dashboard.common.exception.ServiceException; | 7 | import cn.iocoder.dashboard.common.exception.ServiceException; |
| 5 | import cn.iocoder.dashboard.common.pojo.CommonResult; | 8 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 9 | +import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService; | ||
| 10 | +import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO; | ||
| 6 | import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils; | 11 | import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils; |
| 12 | +import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils; | ||
| 13 | +import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils; | ||
| 14 | +import cn.iocoder.dashboard.util.json.JsonUtils; | ||
| 15 | +import cn.iocoder.dashboard.util.servlet.ServletUtils; | ||
| 7 | import io.github.resilience4j.ratelimiter.RequestNotPermitted; | 16 | import io.github.resilience4j.ratelimiter.RequestNotPermitted; |
| 8 | import lombok.extern.slf4j.Slf4j; | 17 | import lombok.extern.slf4j.Slf4j; |
| 18 | +import org.apache.commons.lang3.exception.ExceptionUtils; | ||
| 19 | +import org.springframework.beans.factory.annotation.Value; | ||
| 9 | import org.springframework.security.access.AccessDeniedException; | 20 | import org.springframework.security.access.AccessDeniedException; |
| 21 | +import org.springframework.util.Assert; | ||
| 10 | import org.springframework.validation.BindException; | 22 | import org.springframework.validation.BindException; |
| 11 | import org.springframework.validation.FieldError; | 23 | import org.springframework.validation.FieldError; |
| 12 | import org.springframework.web.HttpRequestMethodNotSupportedException; | 24 | import org.springframework.web.HttpRequestMethodNotSupportedException; |
| @@ -17,10 +29,13 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; | @@ -17,10 +29,13 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
| 17 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; | 29 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; |
| 18 | import org.springframework.web.servlet.NoHandlerFoundException; | 30 | import org.springframework.web.servlet.NoHandlerFoundException; |
| 19 | 31 | ||
| 32 | +import javax.annotation.Resource; | ||
| 20 | import javax.servlet.http.HttpServletRequest; | 33 | import javax.servlet.http.HttpServletRequest; |
| 21 | import javax.validation.ConstraintViolation; | 34 | import javax.validation.ConstraintViolation; |
| 22 | import javax.validation.ConstraintViolationException; | 35 | import javax.validation.ConstraintViolationException; |
| 23 | import javax.validation.ValidationException; | 36 | import javax.validation.ValidationException; |
| 37 | +import java.util.Date; | ||
| 38 | +import java.util.Map; | ||
| 24 | 39 | ||
| 25 | import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.*; | 40 | import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.*; |
| 26 | 41 | ||
| @@ -33,6 +48,12 @@ import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstan | @@ -33,6 +48,12 @@ import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstan | ||
| 33 | @Slf4j | 48 | @Slf4j |
| 34 | public class GlobalExceptionHandler { | 49 | public class GlobalExceptionHandler { |
| 35 | 50 | ||
| 51 | + @Value("spring.application.name") | ||
| 52 | + private String applicationName; | ||
| 53 | + | ||
| 54 | + @Resource | ||
| 55 | + private ApiErrorLogFrameworkService apiErrorLogFrameworkService; | ||
| 56 | + | ||
| 36 | /** | 57 | /** |
| 37 | * 处理所有异常,主要是提供给 Filter 使用 | 58 | * 处理所有异常,主要是提供给 Filter 使用 |
| 38 | * 因为 Filter 不走 SpringMVC 的流程,但是我们又需要兜底处理异常,所以这里提供一个全量的异常处理过程,保持逻辑统一。 | 59 | * 因为 Filter 不走 SpringMVC 的流程,但是我们又需要兜底处理异常,所以这里提供一个全量的异常处理过程,保持逻辑统一。 |
| @@ -232,57 +253,47 @@ public class GlobalExceptionHandler { | @@ -232,57 +253,47 @@ public class GlobalExceptionHandler { | ||
| 232 | return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMessage()); | 253 | return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMessage()); |
| 233 | } | 254 | } |
| 234 | 255 | ||
| 235 | - // TODO 芋艿:增加异常日志 | ||
| 236 | - public void createExceptionLog(HttpServletRequest req, Throwable e) { | ||
| 237 | -// // 插入异常日志 | ||
| 238 | -// SystemExceptionLogCreateDTO exceptionLog = new SystemExceptionLogCreateDTO(); | ||
| 239 | -// try { | ||
| 240 | -// // 增加异常计数 metrics TODO 暂时去掉 | ||
| 241 | -//// EXCEPTION_COUNTER.increment(); | ||
| 242 | -// // 初始化 exceptionLog | ||
| 243 | -// initExceptionLog(exceptionLog, req, e); | ||
| 244 | -// // 执行插入 exceptionLog | ||
| 245 | -// createExceptionLog(exceptionLog); | ||
| 246 | -// } catch (Throwable th) { | ||
| 247 | -// log.error("[createExceptionLog][插入访问日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); | ||
| 248 | -// } | 256 | + private void createExceptionLog(HttpServletRequest req, Throwable e) { |
| 257 | + // 插入错误日志 | ||
| 258 | + ApiErrorLogCreateDTO errorLog = new ApiErrorLogCreateDTO(); | ||
| 259 | + try { | ||
| 260 | + // 初始化 errorLog | ||
| 261 | + initExceptionLog(errorLog, req, e); | ||
| 262 | + // 执行插入 errorLog | ||
| 263 | + apiErrorLogFrameworkService.createApiErrorLogAsync(errorLog); | ||
| 264 | + } catch (Throwable th) { | ||
| 265 | + log.error("[createExceptionLog][url({}) log({}) 发生异常]", req.getRequestURI(), JsonUtils.toJsonString(errorLog), th); | ||
| 266 | + } | ||
| 249 | } | 267 | } |
| 250 | 268 | ||
| 251 | -// // TODO 优化点:后续可以增加事件 | ||
| 252 | -// @Async | ||
| 253 | -// public void createExceptionLog(SystemExceptionLogCreateDTO exceptionLog) { | ||
| 254 | -// try { | ||
| 255 | -// systemExceptionLogRpc.createSystemExceptionLog(exceptionLog); | ||
| 256 | -// } catch (Throwable th) { | ||
| 257 | -// log.error("[addAccessLog][插入异常日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th)); | ||
| 258 | -// } | ||
| 259 | -// } | ||
| 260 | -// | ||
| 261 | -// private void initExceptionLog(SystemExceptionLogCreateDTO exceptionLog, HttpServletRequest request, Throwable e) { | ||
| 262 | -// // 设置账号编号 | ||
| 263 | -// exceptionLog.setUserId(CommonWebUtil.getUserId(request)); | ||
| 264 | -// exceptionLog.setUserType(CommonWebUtil.getUserType(request)); | ||
| 265 | -// // 设置异常字段 | ||
| 266 | -// exceptionLog.setExceptionName(e.getClass().getName()); | ||
| 267 | -// exceptionLog.setExceptionMessage(ExceptionUtil.getMessage(e)); | ||
| 268 | -// exceptionLog.setExceptionRootCauseMessage(ExceptionUtil.getRootCauseMessage(e)); | ||
| 269 | -// exceptionLog.setExceptionStackTrace(ExceptionUtil.getStackTrace(e)); | ||
| 270 | -// StackTraceElement[] stackTraceElements = e.getStackTrace(); | ||
| 271 | -// Assert.notEmpty(stackTraceElements, "异常 stackTraceElements 不能为空"); | ||
| 272 | -// StackTraceElement stackTraceElement = stackTraceElements[0]; | ||
| 273 | -// exceptionLog.setExceptionClassName(stackTraceElement.getClassName()); | ||
| 274 | -// exceptionLog.setExceptionFileName(stackTraceElement.getFileName()); | ||
| 275 | -// exceptionLog.setExceptionMethodName(stackTraceElement.getMethodName()); | ||
| 276 | -// exceptionLog.setExceptionLineNumber(stackTraceElement.getLineNumber()); | ||
| 277 | -// // 设置其它字段 | ||
| 278 | -// exceptionLog.setTraceId(MallUtils.getTraceId()) | ||
| 279 | -// .setApplicationName(applicationName) | ||
| 280 | -// .setUri(request.getRequestURI()) | ||
| 281 | -// .setQueryString(HttpUtil.buildQueryString(request)) | ||
| 282 | -// .setMethod(request.getMethod()) | ||
| 283 | -// .setUserAgent(HttpUtil.getUserAgent(request)) | ||
| 284 | -// .setIp(HttpUtil.getIp(request)) | ||
| 285 | -// .setExceptionTime(new Date()); | ||
| 286 | -// } | 269 | + private void initExceptionLog(ApiErrorLogCreateDTO errorLog, HttpServletRequest request, Throwable e) { |
| 270 | + // 处理用户信息 | ||
| 271 | + errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); | ||
| 272 | + errorLog.setUserType(WebFrameworkUtils.getUesrType(request)); | ||
| 273 | + // 设置异常字段 | ||
| 274 | + errorLog.setExceptionName(e.getClass().getName()); | ||
| 275 | + errorLog.setExceptionMessage(ExceptionUtil.getMessage(e)); | ||
| 276 | + errorLog.setExceptionRootCauseMessage(ExceptionUtil.getRootCauseMessage(e)); | ||
| 277 | + errorLog.setExceptionStackTrace(ExceptionUtils.getStackTrace(e)); | ||
| 278 | + StackTraceElement[] stackTraceElements = e.getStackTrace(); | ||
| 279 | + Assert.notEmpty(stackTraceElements, "异常 stackTraceElements 不能为空"); | ||
| 280 | + StackTraceElement stackTraceElement = stackTraceElements[0]; | ||
| 281 | + errorLog.setExceptionClassName(stackTraceElement.getClassName()); | ||
| 282 | + errorLog.setExceptionFileName(stackTraceElement.getFileName()); | ||
| 283 | + errorLog.setExceptionMethodName(stackTraceElement.getMethodName()); | ||
| 284 | + errorLog.setExceptionLineNumber(stackTraceElement.getLineNumber()); | ||
| 285 | + // 设置其它字段 | ||
| 286 | + errorLog.setTraceId(TracerUtils.getTraceId()); | ||
| 287 | + errorLog.setApplicationName(applicationName); | ||
| 288 | + errorLog.setRequestUrl(request.getRequestURI()); | ||
| 289 | + Map<String, Object> requestParams = MapUtil.<String, Object>builder() | ||
| 290 | + .put("query", ServletUtil.getParamMap(request)) | ||
| 291 | + .put("body", ServletUtil.getBody(request)).build(); | ||
| 292 | + errorLog.setRequestParams(JsonUtils.toJsonString(requestParams)); | ||
| 293 | + errorLog.setRequestMethod(request.getMethod()); | ||
| 294 | + errorLog.setUserAgent(ServletUtils.getUserAgent(request)); | ||
| 295 | + errorLog.setUserIp(ServletUtil.getClientIP(request)); | ||
| 296 | + errorLog.setExceptionTime(new Date()); | ||
| 297 | + } | ||
| 287 | 298 | ||
| 288 | } | 299 | } |
src/main/java/cn/iocoder/dashboard/framework/web/core/util/WebFrameworkUtils.java
| @@ -31,7 +31,7 @@ public class WebFrameworkUtils { | @@ -31,7 +31,7 @@ public class WebFrameworkUtils { | ||
| 31 | return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID); | 31 | return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | - public static Integer getUsrType(HttpServletRequest request) { | 34 | + public static Integer getUesrType(HttpServletRequest request) { |
| 35 | return UserTypeEnum.ADMIN.getValue(); // TODO 芋艿:等后续优化 | 35 | return UserTypeEnum.ADMIN.getValue(); // TODO 芋艿:等后续优化 |
| 36 | } | 36 | } |
| 37 | 37 |
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/logger/InfApiAccessLogDO.java
| @@ -51,6 +51,8 @@ public class InfApiAccessLogDO extends BaseDO { | @@ -51,6 +51,8 @@ public class InfApiAccessLogDO extends BaseDO { | ||
| 51 | */ | 51 | */ |
| 52 | private String applicationName; | 52 | private String applicationName; |
| 53 | 53 | ||
| 54 | + // ========== 请求相关字段 ========== | ||
| 55 | + | ||
| 54 | /** | 56 | /** |
| 55 | * 请求方法名 | 57 | * 请求方法名 |
| 56 | */ | 58 | */ |
| @@ -75,6 +77,8 @@ public class InfApiAccessLogDO extends BaseDO { | @@ -75,6 +77,8 @@ public class InfApiAccessLogDO extends BaseDO { | ||
| 75 | */ | 77 | */ |
| 76 | private String userAgent; | 78 | private String userAgent; |
| 77 | 79 | ||
| 80 | + // ========== 执行相关字段 ========== | ||
| 81 | + | ||
| 78 | /** | 82 | /** |
| 79 | * 开始请求时间 | 83 | * 开始请求时间 |
| 80 | */ | 84 | */ |
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/logger/InfApiErrorLogDO.java
| 1 | package cn.iocoder.dashboard.modules.infra.dal.dataobject.logger; | 1 | package cn.iocoder.dashboard.modules.infra.dal.dataobject.logger; |
| 2 | 2 | ||
| 3 | -public class InfApiErrorLogDO { | 3 | +import cn.iocoder.dashboard.common.enums.UserTypeEnum; |
| 4 | +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | ||
| 5 | +import cn.iocoder.dashboard.modules.infra.enums.logger.ApiErrorLogProcessStatusEnum; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 7 | +import lombok.*; | ||
| 8 | + | ||
| 9 | +import java.util.Date; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * API 异常数据 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@TableName("inf_api_error_log") | ||
| 17 | +@Data | ||
| 18 | +@EqualsAndHashCode(callSuper = true) | ||
| 19 | +@ToString(callSuper = true) | ||
| 20 | +@Builder | ||
| 21 | +@NoArgsConstructor | ||
| 22 | +@AllArgsConstructor | ||
| 23 | +public class InfApiErrorLogDO extends BaseDO { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 编号 | ||
| 27 | + */ | ||
| 28 | + private Integer id; | ||
| 29 | + /** | ||
| 30 | + * 用户编号 | ||
| 31 | + */ | ||
| 32 | + private Integer userId; | ||
| 33 | + /** | ||
| 34 | + * 链路追踪编号 | ||
| 35 | + * | ||
| 36 | + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 | ||
| 37 | + */ | ||
| 38 | + private String traceId; | ||
| 39 | + /** | ||
| 40 | + * 用户类型 | ||
| 41 | + * | ||
| 42 | + * 枚举 {@link UserTypeEnum} | ||
| 43 | + */ | ||
| 44 | + private Integer userType; | ||
| 45 | + /** | ||
| 46 | + * 应用名 | ||
| 47 | + * | ||
| 48 | + * 目前读取 spring.application.name | ||
| 49 | + */ | ||
| 50 | + private String applicationName; | ||
| 51 | + | ||
| 52 | + // ========== 请求相关字段 ========== | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * 请求方法名 | ||
| 56 | + */ | ||
| 57 | + private String requestMethod; | ||
| 58 | + /** | ||
| 59 | + * 访问地址 | ||
| 60 | + */ | ||
| 61 | + private String requestUrl; | ||
| 62 | + /** | ||
| 63 | + * 请求参数 | ||
| 64 | + * | ||
| 65 | + * query: Query String | ||
| 66 | + * body: Quest Body | ||
| 67 | + */ | ||
| 68 | + private String requestParams; | ||
| 69 | + /** | ||
| 70 | + * 用户 IP | ||
| 71 | + */ | ||
| 72 | + private String userIp; | ||
| 73 | + /** | ||
| 74 | + * 浏览器 UA | ||
| 75 | + */ | ||
| 76 | + private String userAgent; | ||
| 77 | + | ||
| 78 | + // ========== 异常相关字段 ========== | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 异常发生时间 | ||
| 82 | + */ | ||
| 83 | + private Date exceptionTime; | ||
| 84 | + /** | ||
| 85 | + * 异常名 | ||
| 86 | + * | ||
| 87 | + * {@link Throwable#getClass()} 的类全名 | ||
| 88 | + */ | ||
| 89 | + private String exceptionName; | ||
| 90 | + /** | ||
| 91 | + * 异常导致的消息 | ||
| 92 | + * | ||
| 93 | + * {@link cn.hutool.core.exceptions.ExceptionUtil#getMessage(Throwable)} | ||
| 94 | + */ | ||
| 95 | + private String exceptionMessage; | ||
| 96 | + /** | ||
| 97 | + * 异常导致的根消息 | ||
| 98 | + * | ||
| 99 | + * {@link cn.hutool.core.exceptions.ExceptionUtil#getRootCauseMessage(Throwable)} | ||
| 100 | + */ | ||
| 101 | + private String exceptionRootCauseMessage; | ||
| 102 | + /** | ||
| 103 | + * 异常的栈轨迹 | ||
| 104 | + * | ||
| 105 | + * {@link org.apache.commons.lang3.exception.ExceptionUtils#getStackTrace(Throwable)} | ||
| 106 | + */ | ||
| 107 | + private String exceptionStackTrace; | ||
| 108 | + /** | ||
| 109 | + * 异常发生的类全名 | ||
| 110 | + * | ||
| 111 | + * {@link StackTraceElement#getClassName()} | ||
| 112 | + */ | ||
| 113 | + private String exceptionClassName; | ||
| 114 | + /** | ||
| 115 | + * 异常发生的类文件 | ||
| 116 | + * | ||
| 117 | + * {@link StackTraceElement#getFileName()} | ||
| 118 | + */ | ||
| 119 | + private String exceptionFileName; | ||
| 120 | + /** | ||
| 121 | + * 异常发生的方法名 | ||
| 122 | + * | ||
| 123 | + * {@link StackTraceElement#getMethodName()} | ||
| 124 | + */ | ||
| 125 | + private String exceptionMethodName; | ||
| 126 | + /** | ||
| 127 | + * 异常发生的方法所在行 | ||
| 128 | + * | ||
| 129 | + * {@link StackTraceElement#getLineNumber()} | ||
| 130 | + */ | ||
| 131 | + private Integer exceptionLineNumber; | ||
| 132 | + | ||
| 133 | + // ========== 处理相关字段 ========== | ||
| 134 | + | ||
| 135 | + /** | ||
| 136 | + * 处理状态 | ||
| 137 | + * | ||
| 138 | + * 枚举 {@link ApiErrorLogProcessStatusEnum} | ||
| 139 | + */ | ||
| 140 | + private Integer processStatus; | ||
| 141 | + /** | ||
| 142 | + * 处理时间 | ||
| 143 | + */ | ||
| 144 | + private Date processTime; | ||
| 145 | + /** | ||
| 146 | + * 处理管理员编号 | ||
| 147 | + * | ||
| 148 | + * 关联 {@link} | ||
| 149 | + */ | ||
| 150 | + private Integer processUserId; | ||
| 151 | + | ||
| 4 | } | 152 | } |
src/main/java/cn/iocoder/dashboard/modules/infra/enums/logger/ApiErrorLogProcessStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.infra.enums.logger; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * API 异常数据的处理状态 | ||
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 10 | + */ | ||
| 11 | +@AllArgsConstructor | ||
| 12 | +@Getter | ||
| 13 | +public enum ApiErrorLogProcessStatusEnum { | ||
| 14 | + | ||
| 15 | + INIT(0, "未处理"), | ||
| 16 | + DONE(1, "已处理"), | ||
| 17 | + IGNORE(2, "已忽略"); | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 状态 | ||
| 21 | + */ | ||
| 22 | + private final Integer status; | ||
| 23 | + /** | ||
| 24 | + * 资源类型名 | ||
| 25 | + */ | ||
| 26 | + private final String name; | ||
| 27 | + | ||
| 28 | +} |
src/main/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogService.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.infra.service.logger; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * API 错误日志 Service 接口 | ||
| 7 | + * | ||
| 8 | + * @author 芋道源码 | ||
| 9 | + */ | ||
| 10 | +public interface InfApiErrorLogService extends ApiErrorLogFrameworkService { | ||
| 11 | + | ||
| 12 | +} |
src/main/java/cn/iocoder/dashboard/modules/infra/service/logger/impl/InfApiAccessLogServiceImpl.java
| @@ -30,7 +30,7 @@ public class InfApiAccessLogServiceImpl implements InfApiAccessLogService { | @@ -30,7 +30,7 @@ public class InfApiAccessLogServiceImpl implements InfApiAccessLogService { | ||
| 30 | 30 | ||
| 31 | @Override | 31 | @Override |
| 32 | @Async | 32 | @Async |
| 33 | - public void createApiAccessLogAsync(@Valid ApiAccessLogCreateDTO createDTO) { | 33 | + public void createApiAccessLogAsync(ApiAccessLogCreateDTO createDTO) { |
| 34 | // 插入 | 34 | // 插入 |
| 35 | InfApiAccessLogDO apiAccessLog = InfApiAccessLogConvert.INSTANCE.convert(createDTO); | 35 | InfApiAccessLogDO apiAccessLog = InfApiAccessLogConvert.INSTANCE.convert(createDTO); |
| 36 | apiAccessLogMapper.insert(apiAccessLog); | 36 | apiAccessLogMapper.insert(apiAccessLog); |
src/main/java/cn/iocoder/dashboard/modules/infra/service/logger/impl/InfApiErrorLogServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.infra.service.logger.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO; | ||
| 4 | +import cn.iocoder.dashboard.modules.infra.service.logger.InfApiErrorLogService; | ||
| 5 | +import org.springframework.scheduling.annotation.Async; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | +import org.springframework.validation.annotation.Validated; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * API 错误日志 Service 实现类 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@Service | ||
| 15 | +@Validated | ||
| 16 | +public class InfApiErrorLogServiceImpl implements InfApiErrorLogService { | ||
| 17 | + | ||
| 18 | + @Override | ||
| 19 | + @Async | ||
| 20 | + public void createApiErrorLogAsync(ApiErrorLogCreateDTO createDTO) { | ||
| 21 | + | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | +} |