日志管理
1.自定义日志输出
在resources目录下新建log4j.properties文件
自定义配置控制台日志输出格式,以及配置日志输出到本地文件
# 定义输出DEBUG级别以上的日志,自定义console控制台输出,file输出到文件
log4j.rootLogger=debug,console,file
# 指定输出目的地console为输出到控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定console的日志消息的输出最低层次
log4j.appender.console.Threshold=DEBUG
# 指定console输出控制台,默认情况下是:System.out
log4j.appender.console.Target=System.out
# 指定console的布局
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 指定console的布局的输出格式
log4j.appender.console.layout.ConversionPattern=[%5p] %d{yyyy-MM-dd HH:mm:ss} - %m%n
# 指定输出file的方式为输出到文件
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
# 指定INFO的输出日志路径
log4j.appender.file.File=E:/log/info.log
# 设置每天生成日志文件
log4j.appender.file.DatePattern='_'yyyy-MM-dd'.log '
# 追加 设置true则在原来的log文件中追加, false覆盖原来的log文件
log4j.appender.file.Append = true
log4j.appender.file.Threshold = INFO
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%5p] %d{yyyy-MM-dd HH:mm:ss} - %m%n
log4j.appender.file.encoding=UTF-8
2.使用spring Aop记录日志
简介:面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足。同时AOP框架也是Spring的一个关键的组件。
2.1 关于Spring AOP的术语
切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现
连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链
切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。
2.2 通知类型
前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
2.3 开启AOP拦截
在Springs的配置文件中添加:
<!-- 开启AOP拦截 -->
<aop:aspectj-autoproxy/>
2.4 包路径作为切点记录日志
首先新建一个LogAspect.class文件
定义切点为
@Pointcut("execution(* cn.edu.zzti.cs.controller...(..))")
拦截 cn.edu.zzti.cs.controlle包以及子包路径下的所有方法
package cn.edu.zzti.cs.log;
import cn.edu.zzti.cs.entity.student.Student;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Autowired
private HttpServletRequest request;
private String userNum;
private String userName;
private String startTime;
private Date beginTime;
private String durations;
private String methodName;
private String param;
private String returnValues;
private String remoteAddr;
private String requestUri;
private String exceptions;
/**
* @Description: 定义一个切点
*/
@Pointcut("execution(* cn.edu.zzti.cs.controller..*.*(..))")
public void SystemLog(){}
@Before("SystemLog()")
public void SysBefore(JoinPoint joinPoint)throws Exception{
//获取请求的方法名
methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
//获取请求的参数
param= Arrays.toString(joinPoint.getArgs());
//格式化开始时间
beginTime=new Date();
startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(beginTime);
//获取请求来源的IP
String ip=request.getRemoteAddr();
remoteAddr = ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
//获取请求的Url地址
requestUri=request.getRequestURI();
}
@Around("SystemLog()")
public Object aroundExec(ProceedingJoinPoint joinPoint) throws Throwable {
Object ret = joinPoint.proceed();
//从session中获取用户账号和姓名
Student student=(Student) request.getSession().getAttribute("user");
if(student!=null){
userNum=student.getStuNum();
userName = student.getStuName();
}
return ret;
}
/**
*@description 方法抛出异常后执行 记录异常
**/
@AfterThrowing(pointcut = "SystemLog()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
//记录方法抛出的异常
exceptions=e.toString();
//记录用时
long endTime= System.currentTimeMillis();
long number=endTime - beginTime.getTime();
durations=String.valueOf(number)+"ms";
//控制台打印
errorPrint();
}
/**
* @Description: 方法正常调用后触发 记录方法返回值
*/
@AfterReturning(returning = "ret", pointcut = "SystemLog()")
public void SysAfterReturning(Object ret){
//记录用时
long endTime= System.currentTimeMillis();
long number=endTime - beginTime.getTime();
durations=String.valueOf(number)+"ms";
//获取方法返回值
if(ret !=null){
returnValues=ret.toString();
}
//控制台打印
infoPrint();
}
private void infoPrint(){
// 记录请求内容
logger.info("\n"+
"-------------------------------------------------------------------------------------------------------------------"+"\n"+
"BEGIN_TIME(开始时间) : "+startTime+"\n"+
"DURATIONS(用时) : "+durations+"\n"+
"USER_NUM(用户账号) : "+userNum+"\n"+
"USER_NAME(用户姓名) : "+userName+"\n"+
"URL(请求地址) : " + requestUri+"\n"+
"HTTP_METHOD(请求方式): " + request.getMethod()+"\n"+
"IP(IP地址) : " + remoteAddr+"\n"+
"CLASS_METHOD(处理请求的方法) : " + methodName +"\n"+
"ARGS(参数) : " + param+"\n"+
"RESPONSE(返回值) : "+returnValues+"\n"+
"-------------------------------------------------------------------------------------------------------------------");
}
private void errorPrint(){
// 记录请求内容
logger.error("\n"+
"-------------------------------------------------------------------------------------------------------------------"+"\n"+
"BEGIN_TIME(开始时间) : "+startTime+"\n"+
"DURATIONS(用时) : "+durations+"\n"+
"USER_NUM(用户账号) : "+userNum+"\n"+
"USER_NAME(用户姓名) : "+userName+"\n"+
"URL(请求地址) : " + requestUri+"\n"+
"HTTP_METHOD(请求方式): " + request.getMethod()+"\n"+
"IP(IP地址) : " + remoteAddr+"\n"+
"CLASS_METHOD(处理请求的方法) : " + methodName +"\n"+
"ARGS(参数) : " + param+"\n"+
"RESPONSE(返回值) : "+returnValues+"\n"+
"EXCEPTIONS(异常) : "+exceptions+"\n"+
"-------------------------------------------------------------------------------------------------------------------");
}
}
在spring配置文件中定义一个实例,将bean注入到spring容器中
<bean id = "logAspect" class="cn.edu.zzti.cs.log.LogAspect"/>
运行项目发起登录请求即可看到控制台打印出日志:
本地文件中记录日志内容如下:
2.5 自定注解作为切点记录日志
创建自定义注解@LogRecord
package cn.edu.zzti.cs.log;
import java.lang.annotation.*;
/**
*@description 自定义注解记录日志
**/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogRecord {
String description() default "";//记录方法描述
}
新建一个AnnoAspect.java文件
定义切点为
@Pointcut("@annotation(cn.edu.zzti.cs.log.LogRecord)")
拦截所有标注@LogRecord注解的方法
package cn.edu.zzti.cs.log;
import cn.edu.zzti.cs.entity.student.Student;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
*@description: 使用自定义注解方式记录日志
**/
@Aspect
@Component
public class AnnoAspect {
private Logger logger = LoggerFactory.getLogger(AnnoAspect.class);
@Autowired
private HttpServletRequest request;
private String userNum;
private String userName;
private String startTime;
private Date beginTime;
private String durations;
private String methodName;
private String param;
private String returnValues;
private String remoteAddr;
private String requestUri;
private String exceptions = "无";
private String logTitle;
/**
* @Description: 定义一个切点
*/
@Pointcut("@annotation(cn.edu.zzti.cs.log.LogRecord)")
public void AnnoLog(){}
/**
* @Description: 方法调用前触发
*/
@Before("AnnoLog()")
public void doBefore(JoinPoint joinPoint){
//获取请求的方法名
methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
//获取请求的参数
param= Arrays.toString(joinPoint.getArgs());
//格式化开始时间
beginTime=new Date();
startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(beginTime);
//获取请求的Url地址
requestUri=request.getRequestURI();
//获取请求来源的IP
String ip=request.getRemoteAddr();
remoteAddr = ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
@Around("AnnoLog()")
public Object aroundExec(ProceedingJoinPoint joinPoint) throws Throwable {
Object ret = joinPoint.proceed();
Student student=(Student) request.getSession().getAttribute("user");
if(student!=null){
userNum=student.getStuNum();
userName = student.getStuName();
}
return ret;
}
/**
*@description 方法执行后调用(不区分成功或异常)
**/
@After(value = "@annotation(logRecord)",argNames ="logRecord")
public void after(LogRecord logRecord){
//获取方法的自定义描述
logTitle=logRecord.description();
//记录用时
long endTime= System.currentTimeMillis();
long number=endTime - beginTime.getTime();
durations=String.valueOf(number)+"ms";
}
/**
*@description 方法抛出异常后执行 记录异常
**/
@AfterThrowing(pointcut = "AnnoLog()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
e.printStackTrace();
exceptions=e.toString();
errorPrint();
}
/**
* @Description: 方法正常调用后触发 记录方法返回值
*/
@AfterReturning(returning = "ret", pointcut = "AnnoLog()")
public void doAfterReturning(JoinPoint joinPoint,Object ret){
//获取方法返回值
if(ret !=null){
returnValues=ret.toString();
}
infoPrint();
}
private void infoPrint(){
// 记录下请求内容
logger.info("\n"+
"-------------------------------------------------------------------------------------------------------------------"+"\n"+
"LOG_TITLE(日志类型) :"+logTitle+"\n"+
"BEGIN_TIME(开始时间) : "+startTime+"\n"+
"DURATIONS(用时) : "+durations+"\n"+
"USER_NUM(用户账号) : "+userNum+"\n"+
"USER_NAME(用户姓名) : "+userName+"\n"+
"URL(请求地址) : " + requestUri+"\n"+
"HTTP_METHOD(请求方式): " + request.getMethod()+"\n"+
"IP(IP地址) : " + remoteAddr+"\n"+
"CLASS_METHOD(处理请求的方法) : " + methodName +"\n"+
"ARGS(参数) : " + param+"\n"+
"RESPONSE(返回值) : "+returnValues+"\n"+
"-------------------------------------------------------------------------------------------------------------------");
}
private void errorPrint(){
// 记录下请求内容
logger.error("\n"+
"-------------------------------------------------------------------------------------------------------------------"+"\n"+
"LOG_TITLE(日志类型) :"+logTitle+"\n"+
"BEGIN_TIME(开始时间) : "+startTime+"\n"+
"DURATIONS(用时) : "+durations+"\n"+
"USER_NUM(用户账号) : "+userNum+"\n"+
"USER_NAME(用户姓名) : "+userName+"\n"+
"URL(请求地址) : " + requestUri+"\n"+
"HTTP_METHOD(请求方式): " + request.getMethod()+"\n"+
"IP(IP地址) : " + remoteAddr+"\n"+
"CLASS_METHOD(处理请求的方法) : " + methodName +"\n"+
"ARGS(参数) : " + param+"\n"+
"RESPONSE(返回值) : "+returnValues+"\n"+
"EXCEPTIONS(异常) : "+exceptions+"\n"+
"-------------------------------------------------------------------------------------------------------------------");
}
}
在处理登录请求的方法上添加@LogRecord注解
在spring配置文件中在定义一个实例,将bean注入到spring容器中
<bean id = "annoAspect" class="cn.edu.zzti.cs.log.AnnoAspect"/>
运行项目发起登录请求即可看到控制台打印出日志:
本地文件中