通过Aop手写一个日志框架

1.大致流程

 

2.编写aop采集日志

package com.example.test.aop;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.example.test.utils.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;

/**
 * 一、execution()是最常用的切点函数,其语法如下所示:
 * 整个表达式可以分为五个部分:
 * 1、execution(): 表达式主体。
 * 2、第一个*号:表示返回类型, *号表示所有的类型。
 * 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
 * 4、第二个*号:表示类名,*号表示所有的类。
 * 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
 * 二、在除了ctrl中获取request
 * RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
 *
 */
@Aspect
@Component
public class LogAop {

    @Pointcut("execution(public * com.example.test.ctrl.*.*(..) )")
    public void log () {
    }

    @Before("log()")
    public void beforeLog(JoinPoint point) {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        ServletRequestAttributes attrs = (ServletRequestAttributes) attributes;
        HttpServletRequest request = attrs.getRequest();

        System.out.println("开始采集日志");
        Log.addLog("【请求 时间】:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        Log.addLog("【请求 URL】:" + request.getRequestURL());
        Log.addLog("【请求 IP】:" + request.getRemoteAddr());
        Log.addLog("【类名 Class】:" + point.getSignature().getDeclaringTypeName());
        Log.addLog("【方法名 Method】:" + point.getSignature().getName());
        Log.addLog("【请求参数 Args】:" + JSONUtil.toJsonStr(point.getArgs()));
    }
}

3.存放队列并且写到本地日志文件

package com.example.test.utils;

import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Component;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

@Component
public class Log {

    private static BlockingDeque<String> deque = new LinkedBlockingDeque<>();

    public Log() {
        new Thread(() -> {
            while (true) {
                String poll = deque.poll();
                if (StrUtil.isNotBlank(poll)) {
                    FileUtils.writeText("d:/log/log.txt", poll, true);
                }
            }
        }).start();
    }

    public static void addLog(String message) {
        deque.add(message);
    }
}

写在最后:

在生产环境中,前台发送一个请求到后台,如果把时间浪费在写日志上面,将会增加请求时间,用线程和队列单独处理日志,这样达到了异步高效的作用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值