- 后端:增加异常日志的记录
This commit is contained in:
parent
25ecc25139
commit
6697f4f723
@ -47,8 +47,16 @@ public class ExceptionUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getMessage(Throwable th) {
|
||||||
|
return ExceptionUtils.getMessage(th);
|
||||||
|
}
|
||||||
|
|
||||||
public static String getRootCauseMessage(Throwable th) {
|
public static String getRootCauseMessage(Throwable th) {
|
||||||
return ExceptionUtils.getRootCauseMessage(th);
|
return ExceptionUtils.getRootCauseMessage(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getStackTrace(Throwable th) {
|
||||||
|
return ExceptionUtils.getStackTrace(th);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,21 @@ package cn.iocoder.mall.spring.boot.web.handler;
|
|||||||
|
|
||||||
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
||||||
import cn.iocoder.common.framework.exception.ServiceException;
|
import cn.iocoder.common.framework.exception.ServiceException;
|
||||||
|
import cn.iocoder.common.framework.util.ExceptionUtil;
|
||||||
|
import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
|
import cn.iocoder.common.framework.util.MallUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.admin.api.SystemLogService;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.ExceptionLogAddDTO;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.apache.dubbo.config.annotation.Reference;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
@ -13,12 +24,19 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String applicationName;
|
||||||
|
|
||||||
|
@Reference(validation = "true", version = "${dubbo.consumer.AdminAccessLogService.version:1.0.0}")
|
||||||
|
private SystemLogService adminAccessLogService;
|
||||||
|
|
||||||
// 逻辑异常
|
// 逻辑异常
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler(value = ServiceException.class)
|
@ExceptionHandler(value = ServiceException.class)
|
||||||
@ -47,24 +65,58 @@ public class GlobalExceptionHandler {
|
|||||||
+ detailMessage.toString());
|
+ detailMessage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿,应该还有其它的异常,需要进行翻译
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler(value = Exception.class)
|
@ExceptionHandler(value = Exception.class)
|
||||||
public CommonResult resultExceptionHandler(HttpServletRequest req, Exception e) {
|
public CommonResult exceptionHandler(HttpServletRequest req, Exception e) {
|
||||||
logger.error("[resultExceptionHandler]", e);
|
logger.error("[exceptionHandler]", e);
|
||||||
// 返回
|
// 插入异常日志
|
||||||
|
ExceptionLogAddDTO exceptionLog = new ExceptionLogAddDTO();
|
||||||
try {
|
try {
|
||||||
addExceptionLog();
|
// 初始化 exceptionLog
|
||||||
|
initExceptionLog(exceptionLog, req, e);
|
||||||
|
// 执行插入 exceptionLog
|
||||||
|
addExceptionLog(exceptionLog);
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
// TODO
|
logger.error("[exceptionHandler][插入访问日志({}) 发生异常({})", JSON.toJSONString(exceptionLog), ExceptionUtils.getRootCauseMessage(th));
|
||||||
}
|
}
|
||||||
|
// 返回 ERROR CommonResult
|
||||||
return CommonResult.error(SysErrorCodeEnum.SYS_ERROR.getCode(), SysErrorCodeEnum.SYS_ERROR.getMessage());
|
return CommonResult.error(SysErrorCodeEnum.SYS_ERROR.getCode(), SysErrorCodeEnum.SYS_ERROR.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 芋艿,应该还有其它的异常,需要进行翻译
|
private void initExceptionLog(ExceptionLogAddDTO exceptionLog, HttpServletRequest request, Exception e) {
|
||||||
|
// 设置用户编号
|
||||||
|
exceptionLog.setUserId(MallUtil.getUserId(request));
|
||||||
|
if (exceptionLog.getUserId() == null) {
|
||||||
|
exceptionLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
|
||||||
|
}
|
||||||
|
exceptionLog.setUserType(MallUtil.getUserType(request));
|
||||||
|
// 设置异常字段
|
||||||
|
exceptionLog.setExceptionName(e.getClass().getName());
|
||||||
|
exceptionLog.setExceptionMessage(ExceptionUtil.getMessage(e));
|
||||||
|
exceptionLog.setExceptionRootCauseMessage(ExceptionUtil.getRootCauseMessage(e));
|
||||||
|
exceptionLog.setExceptionStackTrace(ExceptionUtil.getStackTrace(e));
|
||||||
|
StackTraceElement[] stackTraceElements = e.getStackTrace();
|
||||||
|
Assert.notEmpty(stackTraceElements, "异常 stackTraceElements 不能为空");
|
||||||
|
StackTraceElement stackTraceElement = stackTraceElements[0];
|
||||||
|
exceptionLog.setExceptionClassName(stackTraceElement.getClassName());
|
||||||
|
exceptionLog.setExceptionFileName(stackTraceElement.getFileName());
|
||||||
|
exceptionLog.setExceptionMethodName(stackTraceElement.getMethodName());
|
||||||
|
exceptionLog.setExceptionLineNumber(stackTraceElement.getLineNumber());
|
||||||
|
// 设置其它字段
|
||||||
|
exceptionLog.setTraceId(MallUtil.getTraceId())
|
||||||
|
.setApplicationName(applicationName)
|
||||||
|
.setUri(request.getRequestURI()) // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
||||||
|
.setQueryString(HttpUtil.buildQueryString(request))
|
||||||
|
.setMethod(request.getMethod())
|
||||||
|
.setUserAgent(HttpUtil.getUserAgent(request))
|
||||||
|
.setIp(HttpUtil.getIp(request))
|
||||||
|
.setExceptionTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
public void addExceptionLog() {
|
public void addExceptionLog(ExceptionLogAddDTO exceptionLog) {
|
||||||
|
adminAccessLogService.addExceptionLog(exceptionLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,28 +50,9 @@ public class AccessLogInterceptor extends HandlerInterceptorAdapter {
|
|||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
AccessLogAddDTO accessLog = new AccessLogAddDTO();
|
AccessLogAddDTO accessLog = new AccessLogAddDTO();
|
||||||
try {
|
try {
|
||||||
// 设置用户编号
|
// 初始化 accessLog
|
||||||
accessLog.setUserId(MallUtil.getUserId(request));
|
initAccessLog(accessLog, request);
|
||||||
if (accessLog.getUserId() == null) {
|
// 执行插入 accessLog
|
||||||
accessLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
|
|
||||||
}
|
|
||||||
accessLog.setUserType(MallUtil.getUserType(request));
|
|
||||||
// 设置访问结果
|
|
||||||
CommonResult result = MallUtil.getCommonResult(request);
|
|
||||||
Assert.isTrue(result != null, "result 必须非空");
|
|
||||||
accessLog.setErrorCode(result.getCode())
|
|
||||||
.setErrorMessage(result.getMessage());
|
|
||||||
// 设置其它字段
|
|
||||||
accessLog.setTraceId(MallUtil.getTraceId())
|
|
||||||
.setApplicationName(applicationName)
|
|
||||||
.setUri(request.getRequestURI()) // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
|
||||||
.setQueryString(HttpUtil.buildQueryString(request))
|
|
||||||
.setMethod(request.getMethod())
|
|
||||||
.setUserAgent(HttpUtil.getUserAgent(request))
|
|
||||||
.setIp(HttpUtil.getIp(request))
|
|
||||||
.setStartTime(START_TIME.get())
|
|
||||||
.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime())); // 默认响应时间设为 0
|
|
||||||
// 执行插入
|
|
||||||
addAccessLog(accessLog);
|
addAccessLog(accessLog);
|
||||||
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
@ -81,6 +62,30 @@ public class AccessLogInterceptor extends HandlerInterceptorAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initAccessLog(AccessLogAddDTO accessLog, HttpServletRequest request) {
|
||||||
|
// 设置用户编号
|
||||||
|
accessLog.setUserId(MallUtil.getUserId(request));
|
||||||
|
if (accessLog.getUserId() == null) {
|
||||||
|
accessLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
|
||||||
|
}
|
||||||
|
accessLog.setUserType(MallUtil.getUserType(request));
|
||||||
|
// 设置访问结果
|
||||||
|
CommonResult result = MallUtil.getCommonResult(request);
|
||||||
|
Assert.isTrue(result != null, "result 必须非空");
|
||||||
|
accessLog.setErrorCode(result.getCode())
|
||||||
|
.setErrorMessage(result.getMessage());
|
||||||
|
// 设置其它字段
|
||||||
|
accessLog.setTraceId(MallUtil.getTraceId())
|
||||||
|
.setApplicationName(applicationName)
|
||||||
|
.setUri(request.getRequestURI()) // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
||||||
|
.setQueryString(HttpUtil.buildQueryString(request))
|
||||||
|
.setMethod(request.getMethod())
|
||||||
|
.setUserAgent(HttpUtil.getUserAgent(request))
|
||||||
|
.setIp(HttpUtil.getIp(request))
|
||||||
|
.setStartTime(START_TIME.get())
|
||||||
|
.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime())); // 默认响应时间设为 0
|
||||||
|
}
|
||||||
|
|
||||||
@Async // 异步入库
|
@Async // 异步入库
|
||||||
public void addAccessLog(AccessLogAddDTO accessLog) {
|
public void addAccessLog(AccessLogAddDTO accessLog) {
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.mall.admin.api;
|
package cn.iocoder.mall.admin.api;
|
||||||
|
|
||||||
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.ExceptionLogAddDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统日志 Service 接口
|
* 系统日志 Service 接口
|
||||||
@ -11,4 +12,6 @@ public interface SystemLogService {
|
|||||||
|
|
||||||
void addAccessLog(AccessLogAddDTO accessLogAddDTO);
|
void addAccessLog(AccessLogAddDTO accessLogAddDTO);
|
||||||
|
|
||||||
|
void addExceptionLog(ExceptionLogAddDTO exceptionLogAddDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.mall.admin.api.dto;
|
package cn.iocoder.mall.admin.api.dto;
|
||||||
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@ -20,78 +19,33 @@ public class AccessLogAddDTO implements Serializable {
|
|||||||
* 用户编号 - 空
|
* 用户编号 - 空
|
||||||
*/
|
*/
|
||||||
public static final Integer USER_ID_NULL = 0;
|
public static final Integer USER_ID_NULL = 0;
|
||||||
/**
|
|
||||||
* 链路追踪编号
|
|
||||||
*
|
|
||||||
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
|
||||||
*/
|
|
||||||
@NotNull(message = "链路追踪编号不能为空")
|
@NotNull(message = "链路追踪编号不能为空")
|
||||||
private String traceId;
|
private String traceId;
|
||||||
/**
|
|
||||||
* 用户编号.
|
|
||||||
*
|
|
||||||
* 当管理员为空时,该值为 {@link #USER_ID_NULL}
|
|
||||||
*/
|
|
||||||
@NotNull(message = "用户编号不能为空")
|
@NotNull(message = "用户编号不能为空")
|
||||||
private Integer userId;
|
private Integer userId;
|
||||||
/**
|
|
||||||
* 用户类型
|
|
||||||
*/
|
|
||||||
@NotNull(message = "用户类型不能为空")
|
@NotNull(message = "用户类型不能为空")
|
||||||
private Integer userType;
|
private Integer userType;
|
||||||
/**
|
|
||||||
* 应用名
|
|
||||||
*
|
|
||||||
* 目前读取 spring.application.name
|
|
||||||
*/
|
|
||||||
@NotNull(message = "应用名不能为空")
|
@NotNull(message = "应用名不能为空")
|
||||||
private String applicationName;
|
private String applicationName;
|
||||||
/**
|
|
||||||
* 访问地址
|
|
||||||
*/
|
|
||||||
@NotNull(message = "访问地址不能为空")
|
@NotNull(message = "访问地址不能为空")
|
||||||
private String uri;
|
private String uri;
|
||||||
/**
|
|
||||||
* 参数
|
|
||||||
*/
|
|
||||||
@NotNull(message = "请求参数不能为空")
|
@NotNull(message = "请求参数不能为空")
|
||||||
private String queryString;
|
private String queryString;
|
||||||
/**
|
|
||||||
* http 方法
|
|
||||||
*/
|
|
||||||
@NotNull(message = "http 请求方法不能为空")
|
@NotNull(message = "http 请求方法不能为空")
|
||||||
private String method;
|
private String method;
|
||||||
/**
|
|
||||||
* User Agent
|
|
||||||
*/
|
|
||||||
@NotNull(message = "User-Agent 不能为空")
|
@NotNull(message = "User-Agent 不能为空")
|
||||||
private String userAgent;
|
private String userAgent;
|
||||||
/**
|
|
||||||
* ip
|
|
||||||
*/
|
|
||||||
@NotNull(message = "ip 不能为空")
|
@NotNull(message = "ip 不能为空")
|
||||||
private String ip;
|
private String ip;
|
||||||
/**
|
|
||||||
* 请求时间
|
|
||||||
*/
|
|
||||||
@NotNull(message = "请求时间不能为空")
|
@NotNull(message = "请求时间不能为空")
|
||||||
private Date startTime;
|
private Date startTime;
|
||||||
/**
|
|
||||||
* 响应时长 -- 毫秒级
|
|
||||||
*/
|
|
||||||
@NotNull(message = "响应时长不能为空")
|
@NotNull(message = "响应时长不能为空")
|
||||||
private Integer responseTime;
|
private Integer responseTime;
|
||||||
/**
|
|
||||||
* 错误码
|
|
||||||
*
|
|
||||||
* 目前的结果,是使用 {@link CommonResult#getCode()} 属性
|
|
||||||
*/
|
|
||||||
@NotNull(message = "错误码不能为空")
|
@NotNull(message = "错误码不能为空")
|
||||||
private Integer errorCode;
|
private Integer errorCode;
|
||||||
/**
|
/**
|
||||||
* 错误提示
|
* 错误提示
|
||||||
*
|
|
||||||
* 目前的结果,是使用 {@link CommonResult#getMessage()} 属性
|
|
||||||
*/
|
*/
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package cn.iocoder.mall.admin.api.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常日志添加 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class ExceptionLogAddDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号 - 空
|
||||||
|
*/
|
||||||
|
public static final Integer USER_ID_NULL = 0;
|
||||||
|
|
||||||
|
@NotNull(message = "链路追踪编号不能为空")
|
||||||
|
private String traceId;
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Integer userId;
|
||||||
|
@NotNull(message = "用户类型不能为空")
|
||||||
|
private Integer userType;
|
||||||
|
@NotNull(message = "应用名不能为空")
|
||||||
|
private String applicationName;
|
||||||
|
@NotNull(message = "访问地址不能为空")
|
||||||
|
private String uri;
|
||||||
|
@NotNull(message = "请求参数不能为空")
|
||||||
|
private String queryString;
|
||||||
|
@NotNull(message = "http 请求方法不能为空")
|
||||||
|
private String method;
|
||||||
|
@NotNull(message = "User-Agent 不能为空")
|
||||||
|
private String userAgent;
|
||||||
|
@NotNull(message = "ip 不能为空")
|
||||||
|
private String ip;
|
||||||
|
@NotNull(message = "异常时间不能为空")
|
||||||
|
private Date 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,7 +1,9 @@
|
|||||||
package cn.iocoder.mall.admin.convert;
|
package cn.iocoder.mall.admin.convert;
|
||||||
|
|
||||||
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.ExceptionLogAddDTO;
|
||||||
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ExceptionLogDO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
@ -14,4 +16,7 @@ public interface AccessLogConvert {
|
|||||||
@Mappings({})
|
@Mappings({})
|
||||||
AccessLogDO convert(AccessLogAddDTO accessLogAddDTO);
|
AccessLogDO convert(AccessLogAddDTO accessLogAddDTO);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
ExceptionLogDO convert(ExceptionLogAddDTO exceptionLogAddDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package cn.iocoder.mall.admin.dao;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ExceptionLogDO;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ExceptionLogMapper extends BaseMapper<ExceptionLogDO> {
|
||||||
|
}
|
@ -1,18 +1,20 @@
|
|||||||
package cn.iocoder.mall.admin.dataobject;
|
package cn.iocoder.mall.admin.dataobject;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理员访问日志 DO
|
* 访问日志 DO
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class AccessLogDO extends DeletableDO {
|
@TableName("access_log")
|
||||||
|
public class AccessLogDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编号
|
* 编号
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
package cn.iocoder.mall.admin.dataobject;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常日志 DO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("exception_log")
|
||||||
|
public class ExceptionLogDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*
|
||||||
|
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 用户编号.
|
||||||
|
*
|
||||||
|
* 当管理员为空时,该值为 {@link cn.iocoder.mall.admin.api.dto.AccessLogAddDTO#USER_ID_NULL}
|
||||||
|
*/
|
||||||
|
private Integer userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*
|
||||||
|
* 目前读取 spring.application.name
|
||||||
|
*/
|
||||||
|
private String applicationName;
|
||||||
|
/**
|
||||||
|
* 访问地址
|
||||||
|
*/
|
||||||
|
private String uri;
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
private String queryString;
|
||||||
|
/**
|
||||||
|
* http 方法
|
||||||
|
*/
|
||||||
|
private String method;
|
||||||
|
/**
|
||||||
|
* userAgent
|
||||||
|
*/
|
||||||
|
private String userAgent;
|
||||||
|
/**
|
||||||
|
* ip
|
||||||
|
*/
|
||||||
|
private String ip;
|
||||||
|
/**
|
||||||
|
* 异常发生时间
|
||||||
|
*/
|
||||||
|
private Date exceptionTime;
|
||||||
|
/**
|
||||||
|
* 异常名
|
||||||
|
*
|
||||||
|
* {@link Throwable#getClass()} 的类全名
|
||||||
|
*/
|
||||||
|
private String exceptionName;
|
||||||
|
/**
|
||||||
|
* 异常导致的消息
|
||||||
|
*
|
||||||
|
* {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}
|
||||||
|
*/
|
||||||
|
private String exceptionMessage;
|
||||||
|
/**
|
||||||
|
* 异常导致的根消息
|
||||||
|
*
|
||||||
|
* {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}
|
||||||
|
*/
|
||||||
|
private String exceptionRootCauseMessage;
|
||||||
|
/**
|
||||||
|
* 异常的栈轨迹
|
||||||
|
*
|
||||||
|
* {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}
|
||||||
|
*/
|
||||||
|
private String exceptionStackTrace;
|
||||||
|
/**
|
||||||
|
* 异常发生的类全名
|
||||||
|
*
|
||||||
|
* {@link StackTraceElement#getClassName()}
|
||||||
|
*/
|
||||||
|
private String exceptionClassName;
|
||||||
|
/**
|
||||||
|
* 异常发生的类文件
|
||||||
|
*
|
||||||
|
* {@link StackTraceElement#getFileName()}
|
||||||
|
*/
|
||||||
|
private String exceptionFileName;
|
||||||
|
/**
|
||||||
|
* 异常发生的方法名
|
||||||
|
*
|
||||||
|
* {@link StackTraceElement#getMethodName()}
|
||||||
|
*/
|
||||||
|
private String exceptionMethodName;
|
||||||
|
/**
|
||||||
|
* 异常发生的方法所在行
|
||||||
|
*
|
||||||
|
* {@link StackTraceElement#getLineNumber()}
|
||||||
|
*/
|
||||||
|
private Integer exceptionLineNumber;
|
||||||
|
|
||||||
|
}
|
@ -32,6 +32,9 @@ public class DataDictServiceImpl implements DataDictService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<List<DataDictBO>> selectDataDictList() {
|
public CommonResult<List<DataDictBO>> selectDataDictList() {
|
||||||
|
if (true) {
|
||||||
|
throw new NullPointerException("阿拉啦啦啦");
|
||||||
|
}
|
||||||
List<DataDictDO> dataDicts = dataDictMapper.selectList();
|
List<DataDictDO> dataDicts = dataDictMapper.selectList();
|
||||||
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDicts));
|
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDicts));
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,12 @@ package cn.iocoder.mall.admin.service;
|
|||||||
import cn.iocoder.common.framework.util.StringUtil;
|
import cn.iocoder.common.framework.util.StringUtil;
|
||||||
import cn.iocoder.mall.admin.api.SystemLogService;
|
import cn.iocoder.mall.admin.api.SystemLogService;
|
||||||
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.ExceptionLogAddDTO;
|
||||||
import cn.iocoder.mall.admin.convert.AccessLogConvert;
|
import cn.iocoder.mall.admin.convert.AccessLogConvert;
|
||||||
import cn.iocoder.mall.admin.dao.AccessLogMapper;
|
import cn.iocoder.mall.admin.dao.AccessLogMapper;
|
||||||
|
import cn.iocoder.mall.admin.dao.ExceptionLogMapper;
|
||||||
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ExceptionLogDO;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -30,8 +33,11 @@ public class SystemLogServiceImpl implements SystemLogService {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccessLogMapper accessLogMapper;
|
private AccessLogMapper accessLogMapper;
|
||||||
|
@Autowired
|
||||||
|
private ExceptionLogMapper exceptionLogMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
public void addAccessLog(AccessLogAddDTO adminAccessLogAddDTO) {
|
public void addAccessLog(AccessLogAddDTO adminAccessLogAddDTO) {
|
||||||
// 创建 AdminAccessLogDO
|
// 创建 AdminAccessLogDO
|
||||||
AccessLogDO accessLog = AccessLogConvert.INSTANCE.convert(adminAccessLogAddDTO);
|
AccessLogDO accessLog = AccessLogConvert.INSTANCE.convert(adminAccessLogAddDTO);
|
||||||
@ -50,4 +56,24 @@ public class SystemLogServiceImpl implements SystemLogService {
|
|||||||
accessLogMapper.insert(accessLog);
|
accessLogMapper.insert(accessLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
public void addExceptionLog(ExceptionLogAddDTO exceptionLogAddDTO) {
|
||||||
|
// 创建 AdminAccessLogDO
|
||||||
|
ExceptionLogDO exceptionLog = AccessLogConvert.INSTANCE.convert(exceptionLogAddDTO);
|
||||||
|
exceptionLog.setCreateTime(new Date());
|
||||||
|
// 截取最大长度
|
||||||
|
if (exceptionLog.getUri().length() > URI_MAX_LENGTH) {
|
||||||
|
exceptionLog.setUri(StringUtil.substring(exceptionLog.getUri(), URI_MAX_LENGTH));
|
||||||
|
}
|
||||||
|
if (exceptionLog.getQueryString().length() > QUERY_STRING_MAX_LENGTH) {
|
||||||
|
exceptionLog.setQueryString(StringUtil.substring(exceptionLog.getQueryString(), QUERY_STRING_MAX_LENGTH));
|
||||||
|
}
|
||||||
|
if (exceptionLog.getUserAgent().length() > USER_AGENT_MAX_LENGTH) {
|
||||||
|
exceptionLog.setUserAgent(StringUtil.substring(exceptionLog.getUserAgent(), USER_AGENT_MAX_LENGTH));
|
||||||
|
}
|
||||||
|
// 插入
|
||||||
|
exceptionLogMapper.insert(exceptionLog);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,14 @@
|
|||||||
<!--create_time-->
|
<!--create_time-->
|
||||||
<!--</sql>-->
|
<!--</sql>-->
|
||||||
|
|
||||||
<insert id="insert" parameterType="AccessLogDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
<!-- <insert id="insert" parameterType="AccessLogDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">-->
|
||||||
INSERT INTO access_log (
|
<!-- INSERT INTO access_log (-->
|
||||||
trace_id, user_id, user_type, uri, query_string, method, user_agent,
|
<!-- trace_id, user_id, user_type, uri, query_string, method, user_agent,-->
|
||||||
ip, start_time, response_time, error_code, error_message, create_time
|
<!-- ip, start_time, response_time, error_code, error_message, create_time-->
|
||||||
) VALUES (
|
<!-- ) VALUES (-->
|
||||||
#{traceId}, #{userId}, #{userType}, #{uri}, #{queryString}, #{method}, #{userAgent},
|
<!-- #{traceId}, #{userId}, #{userType}, #{uri}, #{queryString}, #{method}, #{userAgent},-->
|
||||||
#{ip}, #{startTime}, #{responseTime}, #{errorCode}, #{errorMessage}, #{createTime}
|
<!-- #{ip}, #{startTime}, #{responseTime}, #{errorCode}, #{errorMessage}, #{createTime}-->
|
||||||
)
|
<!-- )-->
|
||||||
</insert>
|
<!-- </insert>-->
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
Loading…
Reference in New Issue
Block a user