log4j2与拦截器实现统一访问日志

在上一篇讲解的Logback中我们没有引入maven依赖,那是因为spring-boot-starter-logging是SpringBoot默认集成的。但是今天要讲解的log4j2则需要从spring-boot-starter-web中去掉spring-boot-starter-logging依赖并声明依赖包。<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId>    <exclusions>        <exclusion>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-logging</artifactId>        </exclusion>    </exclusions></dependency>12345678910复制代码类型:[java]配置文件在application.yml中进行配置logging:  config: classpath:log4j2-spring.xml12复制代码类型:[java]log4j2-spring.xml在resources目录下新建一个log4j2-spring.xml文件:<?xml version="1.0" encoding="UTF-8"?><configuration>    <properties>        <!--日志位置-->        <property name="LOG_HOME">/Users/admin/Documents/log</property>    </properties>    <Appenders>        <!-- 日志输出到控制台-->        <Console name="CONSOLE" target="SYSTEM_OUT">            <!--设置日志格式及颜色-->            <PatternLayout                    pattern="[%style{%d}{bright,green}][%highlight{%p}][%style{%t}{bright,blue}][%style{%C}{bright,yellow}]: %msg%n%style{%throwable}{red}"                    disableAnsi="false" noConsoleNoAnsi="false"/>        </Console>        <!-- 将日志输出到文件-->        <RollingFile name="FILE-APPENDER"                     fileName="${LOG_HOME}/log4j2-demo.log"                     filePattern="${LOG_HOME}/log4j2-demo-%d{yyyy-MM-dd}-%i.log">            <!--设置日志格式-->            <PatternLayout>                <pattern>[%d][%p][%t][%C] %m%n</pattern>            </PatternLayout>            <Policies>                <!-- 设置日志文件切分参数 -->                <SizeBasedTriggeringPolicy size="100 MB"/>                <TimeBasedTriggeringPolicy/>            </Policies>            <!--设置最大存档数-->            <DefaultRolloverStrategy max="20"/>        </RollingFile>    </Appenders>    <Loggers>        <!-- 根日志设置 -->        <Root level="debug">            <AppenderRef ref="CONSOLE" level="debug"/>            <AppenderRef ref="FILE-APPENDER" level="info"/>        </Root>        <!--spring日志-->        <Logger name="org.springframework" level="info"/>        <!-- mybatis日志 -->        <Logger name="com.mybatis" level="warn"/>    </Loggers></configuration>12345678910111213141516171819202122232425262728293031323334353637383940414243444546复制代码类型:[java]设置日志格式时使用的占位符:%d date时间%p 日志级别%t  thread线程名称%C class类文件名称%msg日志信息%n换行%style{%throwable}{red}异常信息标红色执行代码,在浏览器访问:http://localhost:8888/test异步日志配置Log4j2是基于Disruptor(一个开源的无锁并发框架),具有超高的吞吐量和低延迟,所以如果想提升Log4j2的性能,就需要引入Disruptor开启异步记录日志功能。<dependency>    <groupId>com.lmax</groupId>    <artifactId>disruptor</artifactId>    <version>3.3.6</version></dependency>12345复制代码类型:[java]SpringBoot配置异步日志的方式有两种,一种是在应用启动类中使用System.setProperty,另一种是启动参数来设置全局异步日志。启动类配置package com.javafamily.familydemo;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.ServletComponentScan;@SpringBootApplication@MapperScan(basePackages = {"com.javafamily.familydemo.mapper"})// 扫描Servlet主键(监听器是Servlet主键的一种)@ServletComponentScanpublic class FamilyDemoApplication {    public static void main(String[] args) {        System.setProperty("Log4jContextSelector",                "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");        SpringApplication.run(FamilyDemoApplication.class, args);    }}1234567891011121314151617181920复制代码类型:[java]System.setProperty语句使Log4j2日志输出使用异步处理,减小输出日志对性能的影响。启动参数设置全局异步日志java -jar -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector  javafamily.jar1复制代码类型:[java]通过以上两种中任意一种方法配置好以后,在Logcontroller.java中打好断点,执行代码,在浏览器中访问:http://localhost:8888/test当我们看见Log4j2-TF-1-AsyncLogger线程的时候,说明我们的全局异步日志配置成功了。全局异步模式虽然是性能最好的日志输出方式,但是消耗主机的资源很大,对服务器的要求比较高,如果服务器比较一般还想要好的性能,我们还可以使用同步/异步混合模式。更改log4j2-spring.xml中部分代码:<Loggers>    <!-- 针对com.javafamily.familydemo包下面的日志采用异步日志 -->    <AsyncLogger name="com.javafamily.familydemo" level="debug" additivity="false">        <AppenderRef ref="CONSOLE" level="debug"/>        <AppenderRef ref="FILE-APPENDER" level="info"/>    </AsyncLogger>    <!-- 系统默认日志设置 -->    <Root level="debug">        <AppenderRef ref="CONSOLE" level="debug"/>        <AppenderRef ref="FILE-APPENDER" level="info"/>    </Root></Loggers>12345678910111213复制代码类型:[java]拦截器实现统一访问日志有时我们需要针对系统的每一次接口访问,记录用户名、访问时间、耗时长、使用什么方法访问的、访问结果如何等。这种做法被称为审计日志。首先在model文件夹下创建Log.java:package com.javafamily.familydemo.model;import lombok.Data;import java.util.Date;@Datapublic class Log {    // 访问者用户名    private String username;    // 请求路径    private String url;    // 请求消耗时长    private Integer duration;    // http 方法:GET、POST等    private String httpMethod;    // http 请求响应状态码    private Integer httpStatus;    // 访问者ip    private String ip;    // 此条记录的创建时间    private Date createTime;}12345678910111213141516171819202122复制代码类型:[java]之后通过自定义拦截器的方式,记录审计日志:package com.javafamily.familydemo.config;import com.javafamily.familydemo.model.Log;import com.javafamily.familydemo.utils.AdrressIpUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Date;public class LogInterceptor implements HandlerInterceptor {    // 开始时间    private static final String LOGGER_SEND_TIME = "SEND_TIME";    // 日志实体标识    private static final String LOGGER_LOG = "ENTITY";    private static final Logger logger = LoggerFactory.getLogger("LOG");    /**     * 进入SpringMVC的Controller之前开始记录日志实体     */    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {        // 创建日志实体        Log log = new Log();        // 设置IP地址        log.setIp(AdrressIpUtils.getIpAdrress(request));        // 设置请求方法,GET,POST...        log.setHttpMethod(request.getMethod());        // 设置请求路径        log.setUrl(request.getRequestURI());        // 设置请求开始时间        request.setAttribute(LOGGER_SEND_TIME, System.currentTimeMillis());        // 设置请求实体到request内,方便afterCompletion方法调用        request.setAttribute(LOGGER_LOG, log);        return true;    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {        // 获取本次请求日志实体        Log log = (Log) request.getAttribute(LOGGER_LOG);        // 获取请求错误码,根据需求存入数据库,这里不保存        int status = response.getStatus();        log.setHttpStatus(status);        // 设置访问者        // 因为不同的应用可能将访问者信息放在session里面,有的通过request传递,        // 总之可以获取到,但获取的方法不同        log.setUsername("admin");        // 当前时间        long currentTime = System.currentTimeMillis();        // 请求开始时间        long snedTime = Long.valueOf(request.getAttribute(LOGGER_SEND_TIME).toString());        // 设置请求时间差        log.setDuration(Integer.valueOf((currentTime - snedTime) + ""));        log.setCreateTime(new Date());        // 将sysLog对象持久化保存        logger.info(log.toString());    }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778复制代码类型:[java]之后在util文件夹中编写工具类AdrressIpUtils.java:package com.javafamily.familydemo.utils;import org.apache.commons.lang3.StringUtils;import javax.servlet.http.HttpServletRequest;public class AdrressIpUtils {    public static String getIpAdrress(HttpServletRequest request) {        String Xip = request.getHeader("X-Real-IP");        String XFor = request.getHeader("X-Forwarded-For");        if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {            // 多次反向代理后有多个ip值,第一个ip才是真实ip            int index = XFor.indexOf(",");            if (index != -1) {                return XFor.substring(0, index);            } else {                return XFor;            }        }        XFor = Xip;        if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {            return XFor;        }        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {            XFor = request.getHeader("Proxy-Client-IP");        }        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {            XFor = request.getHeader("WL-Proxy-Client-IP");        }        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {            XFor = request.getHeader("HTTP_CLIENT_IP");        }        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");        }        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {            XFor = request.getRemoteAddr();        }        return XFor;    }}1234567891011121314151617181920212223242526272829303132333435363738394041复制代码类型:[java]对之前编写好的MyWebMvcConfigurer.java进行改写:package com.javafamily.familydemo.config;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class MyWebMvcConfigurer implements WebMvcConfigurer {    // 设置排除路径,spring boot 2.*,注意排除掉静态资源的路径,不然静态资源无法访问    private final String[] excludePath = {"/static"};    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**").excludePathPatterns(excludePath);    }}12345678910111213141516171819复制代码类型:[java]最后在resources文件夹下创建log.xml文件:<?xml version="1.0" encoding="UTF-8"?><configuration>    <properties>        <!--日志输出位置-->        <property name="LOG_HOME">/Users/admin/Documents/log</property>    </properties>    <Appenders>        <!-- 将日志输出到文件-->        <RollingFile name="APPENDER"                     fileName="${LOG_HOME}/access.log"                     filePattern="${LOG_HOME}/access-%d{yyyy-MM-dd}-%i.log">            <!--设置日志格式-->            <PatternLayout>                <pattern>[%d][%p][%t][%C] %m%n</pattern>            </PatternLayout>            <Policies>                <!-- 设置日志文件切分参数 -->                <SizeBasedTriggeringPolicy size="100MB"/>                <TimeBasedTriggeringPolicy/>            </Policies>            <!--设置最大存档数-->            <DefaultRolloverStrategy max="20"/>        </RollingFile>    </Appenders>    <Loggers>        <AsyncLogger name="LOG" level="debug" additivity="false">            <AppenderRef ref="APPENDER" level="info"/>        </AsyncLogger>    </Loggers></configuration>12345678910111213141516171819202122232425262728293031复制代码类型:[java]执行代码,在浏览器访问:http://localhost:8888/test得到最终的结果。

(0)

相关推荐