使用redis作为消息中间件异步保存日志

使用redis作为消息中间件异步保存日志

自定义日志拦截器,在拦截器中发送日志信息
@Component
public class LogInterceptor implements HandlerInterceptor {
    
    /**
     * 加锁标志
     */
    public static final String LOCKED = "TRUE";
    
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private static ThreadLocal<Long> START = new ThreadLocal<Long>();
    
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * 得到进接口时间
         */
        START.set(System.currentTimeMillis());
        return true;
    }
    
    
    /**
     * 使用redis进行日志操作
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return;
        }
        HandlerMethod method = (HandlerMethod) handler;
        LogInfo logInfo = method.getMethod().getDeclaredAnnotation(LogInfo.class);
        if (null == logInfo) {
            return;
        }
        LogType lt = logInfo.targetType();
        String action = logInfo.value();
        //得到运行接口花费的时间
        Long spendTime = System.currentTimeMillis() - START.get();
        START.remove();
        Log log = new Log();
        log.setException(null == ex ? null : ex.getClass().toString());
        log.setHandler(method.getMethod().getDeclaringClass().getName() + " " + method.getMethod().getName());
        log.setMethod(request.getMethod().toUpperCase());
        //得到接口入参
        log.setParams(getRequestParams(request));
        log.setRemoteAddr(HttpUtil.getIPAddress(request));
        log.setRequestUri(request.getRequestURI());
        log.setTitle(action);
        log.setType(lt.name());
        log.setUserAgent(request.getHeader("User-Agent"));
        log.setSpendTime(spendTime.intValue());
        log.setUserId(Session.getCurrentUserIdIfNullReturnN1());
        String jsonLog = JSON.toJSONString(log);
        //redis发布日志信息
        stringRedisTemplate.convertAndSend("operationLog", jsonLog);
        //设置日志的过期时间 时间单位是秒
        //stringRedisTemplate.expire("operationLog", 1000, TimeUnit.MILLISECONDS);
        stringRedisTemplate.opsForValue().setIfAbsent("operationLog", LOCKED);
    }
    
    /**
     * 得到入参
     *
     * @param request
     * @return
     */
    private static String getRequestParams(HttpServletRequest request) {
        Map<String, String[]> ParameterMap = request.getParameterMap();
        Map<String, String> reqMap = new HashMap<>();
        Set<Map.Entry<String, String[]>> entry = ParameterMap.entrySet();
        Iterator<Map.Entry<String, String[]>> it = entry.iterator();
        while (it.hasNext()) {
            Map.Entry<String, String[]> me = it.next();
            String key = me.getKey();
            String value = me.getValue()[0];
            reqMap.put(key, value);
        }
        return JSONObject.toJSONString(reqMap);
    }
自定义日志注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogInfo {

    @AliasFor("action")
    String value() default "";

    @AliasFor("value")
    String action() default "";

    LogType targetType() default LogType.A;

}

自定义日志注解使用

    @PostMapping
    @ApiOperation(value = "更新附件", notes = "更新附件")
    @LogInfo("更新附件")
    public Result updateAttach(@ModelAttribute Attach attach) {
        attachService.updateById(attach);
        return Result.success();
    }
订阅保存日志信息
   @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, LogService logService) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(new MessageListenerAdapter() {
            @Override
            public void onMessage(Message message, byte[] pattern) {
                logger.error("收到:" + new String(new String(message.getBody())));
                //得到redis订阅的信息并保存到数据库
                JSONObject logJson = JSONObject.parseObject(new String(message.getBody()));
                Log logObj = logJson.toJavaObject(Log.class);
                logService.save(logObj);
            }
        }, new PatternTopic("operationLog"));

        return container;
    }

log实体类

@lombok
public class Log extends BaseEntity {
    
    private static final long serialVersionUID = 211107161244665895L;
    // 日志类型(1:接入日志;2:错误日志)
    private String type;
    // 日志标题
    private String title;
    // 操作用户的IP地址
    private String remoteAddr;
    // 操作的URI
    private String requestUri;
    // 操作的方式
    private String method;
    // 操作提交的数据
    private String params;
    // 操作用户代理信息
    private String userAgent;
    // 异常信息
    private String exception;
    // 备注
    private String remarks;
    // 后台处理时间
    private int spendTime;
    // 处理器
    private String handler;
    // 用户ID
    private String userId;
}

总结:

1、在订阅得到消息后会开始一个新的线程,不用自己写线程
2、该operationLog并不是指在redis中的key,而是一个管道,消息通过管道发送,订阅者得到管道的消息,管道里可以有很多这种消息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值