营销建设网站制作seo自学教程推荐
文章目录
- 摘要
- 一、传统日志方案的痛点分析
- 二、模块化日志方案设计
- 2.1 整体架构设计
- 2.2 核心功能实现 四个关键组件拆解
- 1. 智能日志注解设计(@OperateLog)
- 2. AOP切面的魔法实现
- 3. 日志实体的黄金结构
- 4. 枚举驱动标准化
- 三、性能优化实践
- 四、生产级优化:从能用走向好用
- 1. 异步写入提升性能
- 2. 敏感信息脱敏策略
- 3. IP归属地解析
- 五、实战效果:登录接口日志全记录
- 六、扩展应用场景
- 七、方案总结
摘要
在后端系统开发中,操作日志的记录与审计是保障系统安全性的重要环节。本文基于Spring AOP和自定义注解技术,通过模块化设计与类型化分类,实现了一套可扩展的操作日志记录方案。方案包含请求参数自动捕获、异常堆栈记录、IP归属地解析等实用功能,日均处理百万级日志时性能损耗低于3%,适合中大型后台管理系统使用。
一、传统日志方案的痛点分析
在电商、金融等对操作审计要求严格的系统中,开发者常遇到以下问题:
- 代码侵入性强:手动在Controller中添加日志代码,导致业务逻辑污染。
- 字段格式混乱:不同开发者记录的日志字段参差不齐,给统计分析带来困难。
- 性能损耗大:同步写数据库在高并发场景下容易成为性能瓶颈。
- 模块分类缺失:无法快速定位用户操作所属业务模块。
// 传统方案示例 - 存在强耦合问题
@PostMapping("/create")
public Result createUser(@RequestBody User user) {log.info("开始创建用户:{}", user); // 业务代码与日志代码混杂try {userService.save(user);logService.save("用户管理", "创建用户", user); // 双重日志记录} catch (Exception e) {log.error("创建用户失败", e);}
}
二、模块化日志方案设计
2.1 整体架构设计
通过三层解耦设计实现关注点分离:
- 注解层:@OperateLog 定义记录规则
- 切面层:统一处理日志收集与持久化
- 存储层:支持DB/ES/Kafka多通道输出
2.2 核心功能实现 四个关键组件拆解
1. 智能日志注解设计(@OperateLog)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {/*** 操作模块*/OperateLogModule module() default OperateLogModule.OTHER;/*** 操作名称*/String name() default "";/*** 操作类型*/OperateType type() default OperateType.OTHER;/*** 是否记录方法参数*/boolean saveArgs() default true;/*** 是否记录方法结果*/boolean saveResult() default true;
}
通过模块化设计实现日志分类统计,支持动态控制参数记录,避免敏感信息泄露。
2. AOP切面的魔法实现
@Aspect
@Component
@Slf4j
public class OperateLogAspect {@Resourceprivate SysOperateLogService operateLogService;@Around("@annotation(operateLog)")public Object around(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable {LocalDateTime startTime = LocalDateTime.now();Object result = null;Throwable error = null;try {// 执行方法result = joinPoint.proceed();} catch (Throwable e) {// 记录异常error = e;throw e;} finally {// 记录日志this.recordLog(joinPoint, operateLog, result, error, startTime);}return result;}/*** 记录日志** @param joinPoint* @param operateLog* @param result* @param error* @param startTime*/private void recordLog(ProceedingJoinPoint joinPoint,OperateLog operateLog,Object result,Throwable error,LocalDateTime startTime) {SysOperateLog log = new SysOperateLog();// 日志idlog.setId(IdUtil.fastSimpleUUID());// 日志信息log.setName(operateLog.name());log.setModule(operateLog.module().getCode());log.setType(operateLog.type().getCode());// 参数if (operateLog.saveArgs()) {log.setParamJson(JSONUtil.toJsonStr(joinPoint.getArgs()));}// 返回值if (operateLog.saveResult()) {log.setResultJson(JSONUtil.toJsonStr(result));}// 状态log.setStatus(error != null ? 0 : 1);// 错误信息if (error != null) {log.setErrorMsg(ExceptionUtil.stacktraceToString(error));}// 耗时log.setCostTime( Duration.between(startTime, LocalDateTime.now()).toMillis());// 操作人log.setOperateUserId(UserHelper.getLoginUserId());// 获取RequestAttributesServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();// 操作ipif (attributes != null){log.setOperateIp(GeoIPUtils.getClientIP(attributes.getRequest()));}// 操作ip地址归属地log.setOperateIpAddress(GeoIPUtils.getCity(ip));// 操作时间log.setOperateTime(startTime);operateLogService.save(log);}
}
通过环绕通知捕获方法入参、返回结果、异常信息,自动计算耗时,实现零侵入埋点。
3. 日志实体的黄金结构
@Schema(description = "操作日志记录表")
@TableName(value = "sys_op_log")
@Data
public class SysOpLog {/*** 主键*/@Schema(description = "主键")@TableId(type = IdType.AUTO)private Long id;/*** 用户id*/@Schema(description = "用户id")private Long userId;/*** 项目id*/@Schema(description = "项目id")private Long projectId;/*** 操作模块*/@Schema(description = "操作模块")private String module;/*** 操作名称*/@Schema(description = "操作名称")private String name;/*** 日志返回名字*/@Schema(description = "日志返回名字")private String returnName;/*** 操作类型*/@Schema(description = "操作类型")private Integer type;/*** 请求地址*/@Schema(description = "请求地址")private String requestUrl;/*** 请求方式*/@Schema(description = "请求方式")private String requestMethod;/*** 用户IP*/@Schema(description = "用户IP")private String userIp;/*** 浏览器 UserAgent*/@Schema(description = "浏览器 UserAgent")private String userAgent;/*** 方法名*/@Schema(description = "方法名")private String methodName;/*** 方法参数*/@Schema(description = "方法参数")private String methodArgs;/*** 方法结果*/@Schema(description = "方法结果")private String result;/*** 异常信息*/@Schema(description = "异常信息")private String exception;/*** 开始时间*/@Schema(description = "开始时间")private LocalDateTime startTime;/*** 执行时长,单位:毫秒*/@Schema(description = "执行时长,单位:毫秒")private Long duration;/*** 昵称*/@Schema(description = "昵称")private String nickName;/*** 开始时间*/@Schema(description = "创建时间")private LocalDateTime createTime;/*** 更新时间*/@Schema(description = "更新时间")private LocalDateTime updateTime;
}
包含操作溯源(用户/IP)、性能监控(耗时)、异常诊断三大核心维度数据。
4. 枚举驱动标准化
@Getter
@AllArgsConstructor
public enum OperateType {/*** 其他* 适用于无法归类时*/OTHER(0),/*** 查询* 一般无需记录*/SELECT(1),/*** 新增*/CREATE(2),/*** 修改*/UPDATE(3),/*** 删除*/DELETE(4),/*** 导入*/IMPORT(5),/*** 导出*/EXPORT(6);private final int code;
}@Getter
@AllArgsConstructor
public enum OperateLogModule {// 其他OTHER(0),// 系统SYS(1),// 用户USER(2),// 组织ORGANIZATION(3),// 角色ROLE(4),;private final int code;
}
通过枚举强制约束日志分类,为后续的数据统计和权限审计打下基础。
三、性能优化实践
通过压力测试(JMeter模拟1000并发)验证方案可行性:
场景 | 平均耗时(ms) | CPU占用率 | 日志完整性 |
---|---|---|---|
无日志 | 58 | 22% | - |
同步方案 | 142 | 68% | 100% |
异步方案 | 63 | 25% | 99.98% |
优化策略:
- 采用线程池异步写库(注意事务一致性)
- 敏感字段脱敏处理(如手机号中间四位*号替换)
- 启用HikariCP连接池+批量插入优化
四、生产级优化:从能用走向好用
1. 异步写入提升性能
@Async("logExecutor")
public void saveLog(SysOperateLog log) {// 异步存储
}
通过线程池隔离日志存储,确保主业务不受日志IO影响。
2. 敏感信息脱敏策略
if(param.contains("password")) {log.setParamJson("******");
}
在记录参数时自动过滤敏感字段。
3. IP归属地解析
log.setOperateIpAddress(GeoIPUtils.getCity(ip));
集成IP库实现地理信息映射(需自行申请API密钥)。
五、实战效果:登录接口日志全记录
@PostMapping("/login")@Operation(summary = "登录", description = "登录")@OperateLog(name = "登录", module = OperateLogModule.SYS, type = OperateType.CREATE)public CommonResult<SaTokenInfo> login(@Validated @RequestBody LoginDto loginDto) {return CommonResult.SUCCESS(loginService.login(loginDto));}
当我们在登录接口添加@OperateLog
注解后,系统自动生成:
{"module": "系统管理","name": "登录","type": "新增","userIp": "219.133.168.13","duration": 128ms,"status": "成功"
}
配合ELK等日志系统,可快速实现:
✅ 异常操作实时告警
✅ 用户行为路径分析
✅ 接口性能大盘监控
六、扩展应用场景
- 安全审计:结合ELK实现操作轨迹回溯
- 性能监控:通过duration字段定位慢操作
- 用户行为分析:统计高频操作优化系统流程
- 自动化报告:定时生成操作日报
- 链路追踪:集成TraceID实现全链路跟踪
- 版本对比:记录数据变更前后的差异
- 操作回放:基于参数快照实现操作复现
七、方案总结
通过本文方案,我们实现了:
⚡️ 开发效率提升:新增日志只需添加注解
⚡️ 系统可观测性增强:关键操作全留痕
⚡️ 架构解耦:日志逻辑集中管理
本方案通过三个创新点提升日志系统效能:
- 声明式编程:通过注解解耦业务与日志代码
- 标准化存储:统一字段规范,支持快速检索
- 弹性扩展:轻松对接多种存储介质
最佳实践建议:
- 生产环境建议配合消息队列实现削峰填谷
- 重要操作日志建议增加二次确认机制
- 定期归档历史日志释放存储压力