怎么处理日志
1.定义一个注解
package com.hainei.aop.annotation; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyLog { /** * 用户操作哪个模块 */ String title() default ""; /** * 记录用户操作的动作 */ String action() default ""; }
config类
package com.hainei.aop.aspect; import com.alibaba.fastjson.JSON; import com.hainei.aop.annotation.MyLog; import com.hainei.common.constants.BaseConstant; import com.hainei.common.token.JwtTokenUtil; import com.hainei.common.utils.HttpContextUtils; import com.hainei.common.utils.IPUtils; import com.hainei.common.utils.TypeHelper; import com.hainei.mapper.base.BaseLogMapper; import com.hainei.pojo.model.base.BaseLog; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Date; import java.util.UUID; /** * Created with IntelliJ IDEA. * User: lzx * Date: 2020/02/21 * Time: 15:00 * Description: 系统日志切面 */ @Aspect @Component @Slf4j public class SysLogAspect { @Autowired private BaseLogMapper logMapper; /** * 配置织入点(以@MyLog注解为标志) * 只要出现 @MyLog注解都会进入 */ @Pointcut("@annotation(com.hainei.aop.annotation.MyLog)") public void logPointCut(){ } /** * 环绕增强 * @param point * @return * @throws Throwable */ @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { Throwable ex =null; Object result = null; long beginTime = System.currentTimeMillis(); //执行方法 try { result = point.proceed(); }catch (Throwable e){ ex = e; } //执行时长(毫秒) long time = System.currentTimeMillis() - beginTime; //保存日志 try { saveSysLog(point, time,ex); } catch (Exception e) { log.error("e={}",e); } if (ex!=null){ throw ex; } return result; } /** * 把日志保存 * @param joinPoint * @throws */ private void saveSysLog(ProceedingJoinPoint joinPoint, long time,Throwable ex) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); BaseLog baseLog = new BaseLog(); MyLog myLog = method.getAnnotation(MyLog.class); if(myLog != null){ //注解上的描述 baseLog.setOperation(myLog.title()+"-"+myLog.action()); } //请求的方法名 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); baseLog.setMethod(className + "." + methodName + "()"); //打印该方法耗时时间 log.info("请求{}.{}耗时{}毫秒",className,methodName,time); try { //请求的参数 Object[] args = joinPoint.getArgs(); String params=null; if(args.length!=0){ params= JSON.toJSONString(args); } baseLog.setParams(params); } catch (Exception e) { } if (ex!=null){ baseLog.setResult("error"); if (StringUtils.isNotEmpty(ex.getMessage())){ int messageLength = Math.min(ex.getMessage().length(), 1000); String errorMessage = StringUtils.isEmpty(ex.getMessage()) ? null : ex.getMessage().substring(0, messageLength); baseLog.setErrorMsg(errorMessage); } String stackTraceFullMessage = TypeHelper.getExcetionStackTrace(ex); if (!StringUtils.isEmpty(stackTraceFullMessage)){ int stackTraceLength = Math.min(stackTraceFullMessage.length(), 4000); String stackTrace = org.springframework.util.StringUtils.isEmpty(stackTraceFullMessage) ? null : stackTraceFullMessage.substring(0, stackTraceLength); baseLog.setErrorStackTrace(stackTrace); } }else { baseLog.setResult("success"); } //获取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); //设置IP地址 baseLog.setIp(IPUtils.getIpAddr(request)); log.info("Ip{},接口地址{},请求方式{},入参:{}",baseLog.getIp(),request.getRequestURL(),request.getMethod(),baseLog.getParams()); //用户名 String token = request.getHeader(BaseConstant.ACCESS_TOKEN); baseLog.setId(UUID.randomUUID().toString().replace("-","")); String userId= JwtTokenUtil.getUserId(token); String userLoginId= JwtTokenUtil.getLoginId(token); baseLog.setUserLoginId(userLoginId); baseLog.setUserId(userId); baseLog.setTime((int) time); baseLog.setGmtCreatedTime(new Date()); log.info(baseLog.toString()); logMapper.insertSelective(baseLog); } }
日志的controller
package com.hainei.controller.base; import com.hainei.aop.annotation.MyLog; import com.hainei.aop.annotation.SwaggerApi_Base; import com.hainei.common.utils.DataResult; import com.hainei.common.utils.PageVO; import com.hainei.pojo.bo.base.BaseLogPageReqBo; import com.hainei.pojo.model.base.BaseLog; import com.hainei.service.base.BaseLogService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * Created with IntelliJ IDEA. * User: lzx * Date: 2020/02/21 * Time: 17:26 * Description: 系统日志 */ @RestController @RequestMapping("/base/log") @Api(value = "系统日志", tags = {"系统日志"}) @SwaggerApi_Base public class BaseLogController { @Autowired private BaseLogService logService; @PostMapping("/pageInfo") @ApiOperation(value = "分页查找操作日志接口") public DataResult<PageVO<BaseLog>> pageInfo(@RequestBody BaseLogPageReqBo bo){ PageVO<BaseLog> baseLogPageVO = logService.pageInfo(bo); return DataResult.success(baseLogPageVO); } @PostMapping("/delete") @ApiOperation(value = "删除日志接口") @MyLog(title = "系统管理-日志管理",action = "删除日志接口") @RequiresPermissions("base:log:delete") public DataResult deleted(@RequestBody @ApiParam(value = "日志id集合") List<String> logIds){ logService.deletedLog(logIds); return DataResult.success(); } @PostMapping("/deleteAll") @ApiOperation(value = "清空日志接口") @MyLog(title = "系统管理-日志管理",action = "清空日志接口") @RequiresPermissions("base:log:deleteAll") public DataResult deleteAll(){ logService.deleteAll(); return DataResult.success(); } }
日志的service
package com.hainei.service.impl.base; import com.github.pagehelper.PageHelper; import com.hainei.common.utils.PageUtil; import com.hainei.common.utils.PageVO; import com.hainei.mapper.base.BaseLogMapper; import com.hainei.pojo.bo.base.BaseLogPageReqBo; import com.hainei.pojo.model.base.BaseLog; import com.hainei.service.base.BaseLogService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import tk.mybatis.mapper.entity.Example; import java.util.List; /** * Created with IntelliJ IDEA. * User: lzx * Date: 2020/02/21 * Time: 17:27 * Description: No Description */ @Service("BaseLogService") public class BaseLogServiceImpl implements BaseLogService { @Autowired private BaseLogMapper logMapper; @Override public PageVO<BaseLog> pageInfo(BaseLogPageReqBo bo) { Example example = new Example(BaseLog.class); example.orderBy("gmtCreatedTime").desc(); Example.Criteria criteria = example.createCriteria(); if (StringUtils.isNotEmpty(bo.getUserId())){ criteria.andLike("userId", bo.getUserId()); } String test; if (StringUtils.isNotEmpty(bo.getUserLoginId())){ test = "%" + bo.getUserLoginId() + "%"; criteria.andLike("userLoginId", test); } if (StringUtils.isNotEmpty(bo.getOperation())){ test = "%" + bo.getOperation() + "%"; criteria.andLike("operation", test); } if (bo.getStartTime()!=null){ criteria.andGreaterThanOrEqualTo("gmtCreatedTime", bo.getStartTime()); } if (bo.getEndTime()!=null){ criteria.andLessThanOrEqualTo("gmtCreatedTime", bo.getEndTime()); } if (StringUtils.isNotEmpty(bo.getResult())){ test = "%" + bo.getResult() + "%"; criteria.andLike("result", test); } PageHelper.startPage(bo.getPageNum(), bo.getPageSize()); return PageUtil.getPageVO(logMapper.selectByExample(example)); } @Override public void deletedLog(List<String> logIds) { Example example = new Example(BaseLog.class); Example.Criteria criteria = example.createCriteria(); criteria.andIn("id",logIds); logMapper.deleteByExample(example); } @Override public void deleteAll() { Example example = new Example(BaseLog.class); logMapper.deleteByExample(example); } }
日志xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
<contextName>logback</contextName>
<springProperty scope="context" name="logPath" source="logging.path" defaultValue="logs"/>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="${logPath}"/>
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
以及指定<appender>。<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前logger将会继承上级的级别。
addtivity:是否向上级logger传递打印信息。默认是true。
-->
<!--<logger name="org.springframework.web" level="info"/>-->
<!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
-->
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
不能设置为INHERITED或者同义词NULL。默认是DEBUG
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!-- <logger name="com.hainei" level="debug"/>-->
<root level="dev">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
<appender-ref ref="WARN_FILE"/>
</root>
</springProfile>
<root level="info">
<!-- <appender-ref ref="CONSOLE"/>-->
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- 生产环境:输出到文件-->
<springProfile name="prod">
<root level="info">
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
<appender-ref ref="WARN_FILE"/>
</root>
</springProfile>
</configuration>


个人学习笔记,记录日常学习,便于查阅及加深,仅为方便个人使用。

浙公网安备 33010602011771号