利用Spring的Aop實現項目的日誌監控

導入依賴

        <!--引入AOP依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- 用於日誌切面中,以 json 格式打印出入參(本來使用阿里的 FASTJSON, 但是對於文件上傳的接口,打印參數會報錯,換爲 Gson) -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
            
        <!-- 日誌 start -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>

Controller層的日誌

/***
 *      1.controller方法耗時
 *      2.打印入參
 *      3.打印異常信息
 */
@Component
@Aspect
@Slf4j
public class ControllerAop {
​
    //切入點
    @Pointcut("execution(public * com.yfy.study.controller..*.*(..))")
    public void point() {
    }
​
    /**
     * 在切點之前織入
     * @param joinPoint
     * @throws Throwable
     */
    @Before("point()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 開始打印請求日誌
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
​
        // 打印請求相關參數
        log.info("========================================== Start ==========================================");
        // 打印請求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印調用 controller 的全路徑以及執行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印請求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印請求入參
        log.info("Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
    }
​
    /**
     * 環繞
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("point()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 打印出參
        log.info("Response Args  : {}", new Gson().toJson(result));
        // 執行耗時
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }
​
    /**
     * 在切點之後織入
     * @throws Throwable
     */
    @After("point()")
    public void doAfter() throws Throwable {
        log.info("=========================================== End ===========================================");
        // 每個請求之間空一行
        log.info("");
    }
​
}

Service層日誌

/***
 *      1.service方法
 *      2.打印入參
 *      3.打印異常信息
 */
@Component
@Aspect
@Slf4j
public class ServiceAop {
​
    //切入點
    @Pointcut("execution(public * com.yfy.study.service.impl..*.*(..))")
    public void point() {
    }
​
    /**
     * 在切點之前織入
     * @param joinPoint
     * @throws Throwable
     */
    @Before("point()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 打印調用 service 的全路徑以及執行方法
        log.info("   Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印請求入參
        log.info("   Request Args   : {}", new Gson().toJson(joinPoint.getArgs()));
    }
​
    /**
     * 環繞
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("point()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = proceedingJoinPoint.proceed();
        // 打印出參
        log.info("   Response Args  : {}", new Gson().toJson(result));
        return result;
    }
​
    /**
     * 在切點之後織入
     * @throws Throwable
     */
    @After("point()")
    public void doAfter() throws Throwable {
        // 每個請求之間空一行
        log.info("");
    }
​
}

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds" debug="false">
​
    <contextName>logback</contextName>
​
    <property name="log_path" value="log"/><!-- 如果在Windows環境下使用/開頭的路徑,將會被指定到項目所在的盤符 -->
    <property name="log_pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{50} - %msg%n"/>
    <property name="log_fileNamePattern" value="%d{yyyy-MM-dd}.%i.log"/>
    <property name="log_maxFileSize" value="100MB"/>
    <property name="log_maxHistory" value="30"/>
​
    <!-- 輸出到控制檯 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder charset="UTF-8">
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>
​
    <!-- 輸出到paopao-push.log文件 -->
    <appender name="APP" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/paopao-push.log</file>
        <encoder charset="UTF-8">
            <pattern>${log_pattern}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_path}/paopao-push-${log_fileNamePattern}</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${log_maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>${log_maxHistory}</maxHistory>
        </rollingPolicy>
    </appender>
​
    <!-- 輸出到sql.log文件 -->
    <appender name="SQL" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/sql.log</file>
        <encoder charset="UTF-8">
            <pattern>${log_pattern}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_path}/sql-${log_fileNamePattern}</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${log_maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>${log_maxHistory}</maxHistory>
        </rollingPolicy>
    </appender>
​
    <!-- mapper的sql配置 -->
    <logger name="com.yfy.study.persistence.dao" level="DEBUG" additivity="false">
        <appender-ref ref="SQL" />
        <appender-ref ref="CONSOLE" />
    </logger>
​
    <!-- 自定義包或者類輸出的級別和策略 -->
    <logger name="com.yfy.study" level="INFO" additivity="false">
        <appender-ref ref="SQL" />
        <appender-ref ref="APP" />
        <appender-ref ref="CONSOLE" />
    </logger>
​
    <!-- root用來指定最基礎的日誌輸出級別 -->
    <root level="INFO">
        <appender-ref ref="APP"/>
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="SQL" />
    </root>
</configuration>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章