ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # **1. 启用注解** `@GoEnableLogger` `@GoLogger` # **2. 注意事项** > 如需使用,需开启@GoEnableLogger,类、方法上加入@GoLogger注解即可,注解优先级 `方法 > 类` print:是否打印,默认开启true format:是否格式化,默认关闭false operation:方法说明,默认空"" storage:日志存储,默认LogStorageProvider(可实现LogStorage接口自定义保存) # **3. 示例说明** ## **3.1 不输出** ``` @GoLogger(print = false) @RequestMapping("/noprint") public Result noprint(BaseVo base, PageVo page) { return R.succ(); } ``` ``` 日志无输出 ``` ## **3.2 默认输出** ``` @GoLogger @RequestMapping("/print") public Result print(BaseVo base, PageVo page) { return R.succ(); } ``` ``` [FastBoot][ INFO][06-27 01:02:19]-->[http-nio-8080-exec-1:3995353][loggerAroundAspect(LoggerAspect.java:109)] | - | request print | [{"id":"-1","keyword":""},{"limit":25,"page":0,"size":25}] [FastBoot][ INFO][06-27 01:02:19]-->[http-nio-8080-exec-1:3995366][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 11ms | print | {"code":0,"msg":"操作成功","status":true} ``` ## **3.3 格式化输出** ``` @GoLogger(format = true) @RequestMapping("/format") public Result format(BaseVo base, PageVo page) { return R.succ(); } ``` ``` [FastBoot][ INFO][06-27 01:03:55]-->[http-nio-8080-exec-5:4091420][loggerAroundAspect(LoggerAspect.java:109)] | - | request format | [ { "id":"-1", "keyword":"" }, { "limit":25, "page":0, "size":25 } ] [FastBoot][ INFO][06-27 01:03:55]-->[http-nio-8080-exec-5:4091421][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 1ms | format | { "code":0, "msg":"操作成功", "status":true } ``` ## **3.4 格式化输出、存储** ``` @GoLogger(format = true, storage = LogStorageMysqlProvider.class) @RequestMapping("/storage") public Result storage(BaseVo base, PageVo page) { return R.succ(); } ``` ``` [FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234217][loggerAroundAspect(LoggerAspect.java:109)] | - | request storage | [ { "id":"-1", "keyword":"" }, { "limit":25, "page":0, "size":25 } ] [FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234232][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 14ms | storage | { "code":0, "msg":"操作成功", "status":true } [FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234267][logSQL(Slf4JLogger.java:60)] | - | time 0ms | statement | insert into xx_log (create_date, ip, is_del, method, req, res, time, type, update_date, url, id) values ('2021-06-27T01:06:17.907+0800', '0:0:0:0:0:0:0:1', false, 'storage', '{}', '{"code":0,"msg":"操作成功","status":true}', 14, 'GET', '2021-06-27T01:06:17.907+0800', '//logger/storage', 'L1408834011744309248') [FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234284][logSQL(Slf4JLogger.java:60)] | - | time 14ms | commit | [FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234285][record(LogStorageMysqlProvider.java:49)] | - log record id L1408834011744309248 ``` ## **3.5 优先级** ``` @RestController @RequestMapping("/body") @GoLogger(storage = LogStorageMysqlProvider.class) public class BodyController extends BaseController { @RequestMapping(value = "result") public Result result() { return R.succ(MockData.map()); } } ``` ``` [FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850503][loggerAroundAspect(LoggerAspect.java:109)] | - | request result | [] [FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850504][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 0ms | result | {"code":0,"msg":"操作成功","data":{"k1":"1","k2":2,"k3":"3","k4":4.1,"k5":5.2,"k6":true,"k7":"7","k8":1624728794169},"status":true} [FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850510][logSQL(Slf4JLogger.java:60)] | - | time 1ms | statement | insert into xx_log (create_date, ip, is_del, method, req, res, time, type, update_date, url, id) values ('2021-06-27T01:33:14.172+0800', '0:0:0:0:0:0:0:1', false, 'result', '{}', '{"code":0,"msg":"操作成功","data":{"k1":"1","k2":2,"k3":"3","k4":4.1,"k5":5.2,"k6":true,"k7":"7","k8":1624728794169},"status":true}', 0, 'GET', '2021-06-27T01:33:14.172+0800', '/body/result', 'L1408840790767177728') [FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850516][logSQL(Slf4JLogger.java:60)] | - | time 4ms | commit | [FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850518][record(LogStorageMysqlProvider.java:49)] | - log record id L1408840790767177728 ``` # **4. 自定义存储** ## **4.1 表结构** ``` CREATE TABLE `xx_log` (   `id` varchar(255) NOT NULL COMMENT '主键',   `create_date` datetime(6) NOT NULL COMMENT '创建时间',   `update_date` datetime NOT NULL COMMENT '更新时间',   `ip` varchar(255) DEFAULT NULL COMMENT '请求ip',   `url` varchar(255) DEFAULT NULL COMMENT '请求地址',   `method` varchar(255) DEFAULT NULL COMMENT '请求方法',   `type` varchar(255) DEFAULT NULL COMMENT '请求类型',   `req` longtext COMMENT '请求参数',   `res` longtext COMMENT '响应结果',   `time` bigint(20) DEFAULT NULL COMMENT '请求耗时',   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ``` ## **4.2 实体类** ``` @Data @Accessors(chain = true) @EqualsAndHashCode(callSuper = false) @FieldNameConstants(innerTypeName = "FIELDS") @Table(name = "xx_log") @Entity @EntityListeners(AuditingEntityListener.class) @DynamicInsert @DynamicUpdate @Where(clause = "is_del=0") @SQLDelete(sql = "update xx_log set is_del=1 where id = ?") @SQLDeleteAll(sql = "update xx_log set is_del=1 where id = ?") public class LogRecord extends JpaPlusEntity<LogRecord> { private static final long serialVersionUID = 1L; /** * 主键,例(L1408447004119666688) */ @Id @GeneratedValue(generator = "idGenerator") @GenericGenerator(name = "idGenerator", // 名称 strategy = "com.xiesx.FastBoot.db.jpa.identifier.IdWorkerGenerator", // 生成策略 parameters = {// 生成参数 @Parameter(name = "prefix", value = "L"), // 前缀,L @Parameter(name = "workerId", value = "1"), // 终端ID,默认0 @Parameter(name = "centerId", value = "1") // 数据中心ID,默认0 }) @JSONField(ordinal = 1) private String id; /** * 创建时间 */ @CreatedDate @Column(updatable = false, nullable = false) @JSONField(ordinal = 2) private Date createDate; /** * 修改时间 */ @LastModifiedDate @Column(nullable = false) @JSONField(ordinal = 3) private Date updateDate; /** * 请求IP */ @Column @JSONField(ordinal = 4) private String ip; /** * 方法 */ @Column @JSONField(ordinal = 5) private String method; /** * 方式 */ @Column @JSONField(ordinal = 6) private String type; /** * 地址 */ @Column @JSONField(ordinal = 7) private String url; /** * 请求参数 */ @JSONField(serialize = false) private String req; /** * 响应结果 */ @JSONField(serialize = false) private String res; /** * 执行时间(毫秒) */ @Column @JSONField(ordinal = 10) private Long time; /** * 是否删除 */ @Column @JSONField(serialize = false) private Boolean isDel = false; ``` 该实体类,可以通过 `fast-generator`生成 ## **4.3 持久类** ``` public interface LogRecordRepository extends JpaPlusRepository<LogRecord, String> { } ``` 该持久类,可以通过 `fast-generator`生成 ## **4.4 实现类** ``` @Log4j2 public class LogStorageMysqlProvider extends LogStorageProvider { private final static String UNKNOWN = "unknown"; private static final String[] HEAD_INFO = { "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED", "HTTP_X_CLUSTER_CLIENT_IP", "HTTP_CLIENT_IP", "HTTP_FORWARDED_FOR", "HTTP_FORWARDED", "HTTP_VIA", "REMOTE_ADDR", "PROXY_FORWARDED_FOR", "X-Real-IP"}; LogRecordRepository mLogRecordRepository; public LogStorageMysqlProvider(String operation, String method, Object[] args, Long time) { super(operation, method, args, time); mLogRecordRepository = SpringHelper.getBean(LogRecordRepository.class); } @Override public void record(HttpServletRequest request, Object result) { super.record(request, result); // 构造日志 LogRecord logRecord = new LogRecord()// .setIp(getIpAddr(request))// .setMethod(method)// .setType(type)// .setUrl(uri)// .setReq(JSON.toJSONString(parameters))// .setRes(JSON.toJSONString(result))// .setTime(time); // 保存日志 logRecord = mLogRecordRepository.insertOrUpdate(logRecord); // 打印日志编号 log.info("log record id {}", logRecord.getId()); } /** * 获取ip * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { for (String header : HEAD_INFO) { String ip = request.getHeader(header); if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { if (ip.contains(",")) { String[] ips = ip.split(","); for (String s : ips) { if (!(UNKNOWN.equalsIgnoreCase(s))) { ip = s; break; } } } return ip; } } return request.getRemoteAddr(); } } ``` > 示例默认实现了mysql的存储,可以存MongoDB...等其他数据库 # **5. p6spy输出** ## **5.1 配置文件**(内置) spy.properties ``` module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory # 自定义日志打印 logMessageFormat=com.xiesx.springboot.core.logger.pkaq.P6SpyLogger # 使用日志系统记录sql appender=com.p6spy.engine.spy.appender.Slf4JLogger # 配置记录Log例外 excludecategories=info,debug,result,batc,resultset # 设置使用p6spy driver代理 deregisterdrivers=true # 日期格式 dateformat=yyyy-MM-dd HH:mm:ss # 实际驱动 driverlist=com.mysql.cj.jdbc.Driver # 是否开启慢SQL记录 outagedetection=true # 慢SQL记录标准 (秒) outagedetectioninterval=2 ``` ## **5.2 使用环境** 实际使用中建议本地开发环境`application-local`使用`p6spy` ### **5.2.1 开发环境** ``` spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://127.0.0.1:3307/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai username: xxxx password: xxxx ``` ### **5.2.1 生产环境** ``` spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3307/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai username: xxxx password: xxxx ``` ## **5.3 验证打印** ### **5.3.1 默认?** ``` [FastBoot][ INFO][06-27 01:43:14]-->[http-nio-9090-exec-3:2007963][logSQL(Slf4JLogger.java:60)] | - | took 1ms | | statement | select * from sys_config where k=? ``` ### **5.3.2 p6spy** ``` [FastBoot][ INFO][06-27 01:43:14]-->[http-nio-9090-exec-3:2007963][logSQL(Slf4JLogger.java:60)] | - | took 1ms | | statement | select * from sys_config where k='update' ```