1.web-info下面添加logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="encoding" value="utf-8"/>
<!-- 设置通道file和输出方式:org.apache.log4j.RollingFileAppender -->
<param name="File" value="${catalina.home}/EHL_logs/ehl_atms_log.log" /><!--
设置File参数:日志输出文件名 -->
<param name="DatePattern" value="'-'yyyy-MM-dd" />
<param name="Append" value="true" /><!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
<param name="MaxFileSize" value="5000KB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %p (%c:%L)- %m%n" /><!--
设置输出文件项目和格式 -->
</layout>
</appender>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<!-- 设置监视器输出方式 -->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-4r [%t] %-5p %c %x - %m%n" />
</layout>
<!--滤镜设置输出的级别 -->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="levelMin" value="info" />
<param name="levelMax" value="info" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<root><!-- 设置接收所有输出的通道 -->
<priority value="info" />
<appender-ref ref="FILE" /><!-- 与前面的通道id相对应 -->
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
2.web.xml引入
<!--logback配置开始-->
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>/WEB-INF/logback.xml</param-value>
</context-param>
<!--自定义监听器-->
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!--logback配置结束-->
3.springmvc.xml中添加配置
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 日志注解 -->
<bean id="LogAspect" class="com.ehl.frame.logback.SysLogAspect"/>
头文件中需增加:
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
4.定义注解
/**
* 系统日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
5.定义日志实体
/**
* @className:OperationLog
* @description: 输出日志内容
*/
public class OperationLog {
/**
* 用户编号
*/
private String userId;
/**
* 用户名
*/
private String userName;
/**
* 操作参数
*/
private String params;
/**
* 返回信息
*/
private String returnMsg;
/**
* 调用方法名称
*/
private String method;
/**
* 请求追踪id
*/
private String traceId;
/**
* 请求Ip
*/
private String requestIp;
/**
* 操作描述
*/
private String operationDescription;
/**
* 操作开始时间
*/
private String operationStarttime;
/**
* 操作结束时间
*/
private String operationEndtime;
/**
* 操作时长
*/
private long time;
}
6.切面处理类
/**
* 系统日志,切面处理类
*
*/
@Aspect
@Component
public class SysLogAspect {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Pointcut("@annotation(com.ehl.frame.logback.SysLog)")
public void logPointCut() {
// 读取切面日志
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 记录开始时间
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//返回参数,暂时去掉,返回值多容易造成读写太慢
String returnMsg = "";
//if (result != null) {
// Class cls = Class.forName(result.getClass().getName());
// if (RespMsg.class.equals(cls)) {
// RespMsg respMsg = (RespMsg) result;
// returnMsg = respMsg.getMessage();
// } else if (List.class.equals(cls)) {
// List list = (List) result;
// if (!list.isEmpty()) {
// returnMsg += "返回数量:" + list.size();
// }
// } else if (Map.class.equals(cls)) {
// Map map = (Map) result;
// if (!map.isEmpty()) {
// returnMsg += "返回数量:" + map.size();
// }
// } else if (String.class.equals(cls)) {
// returnMsg += (String) result;
// } else {
// returnMsg += JSON.toJSONString(result);
// }
//}
long endTime = System.currentTimeMillis();
//保存日志
saveSysLog(point, beginTime, endTime, returnMsg);
return result;
}
private void saveSysLog(ProceedingJoinPoint joinPoint, long beginTime, long endTime, String returnMsg) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
OperationLog operationLog = new OperationLog();
// 获取用户信息 记录用户信息
HttpSession session = HttpUtil.getSession();
String userId = null;
String userName = null;
LoginUserInfo userInfo = (LoginUserInfo) session.getAttribute("userLoginInfo");
if (userInfo != null) {
userId = userInfo.getUserId();
userName = userInfo.getRealName();
}
operationLog.setUserId(userId);
operationLog.setUserName(userName);
SysLog syslog = method.getAnnotation(SysLog.class);
if (syslog != null) {
//注解上的描述
operationLog.setOperationDescription(syslog.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
operationLog.setMethod(methodName);
Logger logger = LoggerFactory.getLogger(className);
//请求的参数
Object[] args = joinPoint.getArgs();
try {
if (args != null && args.length > 0) {
String params = JSON.toJSONString(args);
operationLog.setParams(params);
}
} catch (Exception e) {
logger.error("输出日志参数获取失败");
}
operationLog.setReturnMsg(returnMsg);
// 操作用时
operationLog.setOperationStarttime(df.format(beginTime));
operationLog.setOperationEndtime(df.format(endTime));
operationLog.setTime(endTime - beginTime);
//获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//设置IP地址
operationLog.setRequestIp(IPUtils.getIpAddr(request));
// 跟踪记录id
operationLog.setTraceId(UUID.randomUUID().toString());
//保存系统日志
String sysStr = JSONObject.toJSONString(operationLog);
logger.info(sysStr);
}
}
7.使用
@SysLog("根据id查询厂商信息")
@RequestMapping(value = "/query")
@ResponseBody
public Company query(HttpServletRequest request) {
try {
String id = request.getParameter("id");
return companyServiceImpl.query(id);
} catch (Exception e) {
log.info(e.getMessage());
Log.error("查询失败");
return null;
}
}
8.其他
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
// //使用代理,则获取第一个IP地址
// if(StringUtils.isEmpty(ip) && ip.length() > 15) {
// if(ip.indexOf(",") > 0) {
// ip = ip.substring(0, ip.indexOf(","));
// }
// }
return ip;
}
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}
9.补充:pom引入jar包
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.1</version>
</dependency>
<!--实现slf4j接口并整合-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.2</version>
</dependency>
<!-- 解决屏蔽日志报错问题 -->
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.0.7</version>
</dependency>
<!-- logback日志配置结束 -->