In the last chapter, we preliminarily realized the function of adding, deleting and checking the background management system. However, many features are still not perfect. In this chapter, we first set up the system log, whether it is production problem investigation, or convenient development and debugging, log is an essential core function. For example, if we wanted to log every method entry, we would need to write a line of parameter statements in each method, which would be very tedious. So you need to extract the section “method before”, “method after”, and so on, and then program in that section so that the statement that records the input parameter only needs to be written once. The overall process is roughly as follows:

  

This section uses the RMS module as an example. If other modules need to record logs, refer to this module.

First, introduce dependencies

In Java, logging is generally implemented as common-logging+ Log4j2 or SLf4J + Logback, where common-logging and SLF4J are the interface definitions and log4j2 and logback are the concrete implementations. Log4j (2.11.2, also known as log4j2, and 1.x) is used in the poM to log in to log4j (2.11.2, also known as log4j2, 1.x).

<! Log4j </groupId> <artifactId>log4j-core</artifactId> The < version > 2.11.2 < / version > < / dependency >Copy the code

2. Add a configuration file

Create “log4j2.xml” under the “/resources/” resources file directory, which is the default configuration path and file name for log4j.

<? The XML version = "1.0" encoding = "utf-8"? > <Configuration status="OFF" monitorInterval="1800"> <properties> <property name="LOG_HOME">/logs/idlewow-rms/</property> </properties> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <RollingFile name="info" fileName="${LOG_HOME}/info.log" filePattern="${LOG_HOME}/info-%d{yyyyMMdd}-%i.log" immediateFlush="true"> <! -- Output only messages of level and above (onMatch), --> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} %level [%thread][%X{sessionId}][%file:%line] - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy  interval="1" modulate="true" /> <SizeBasedTriggeringPolicy size="20 MB"/> </Policies> </RollingFile> <RollingFile name="warn" fileName="${LOG_HOME}/warn.log" filePattern="${LOG_HOME}/warn-%d{yyyyMMdd}-%i.log" immediateFlush="true"> <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} %level [%thread][%X{sessionId}][%file:%line] - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <SizeBasedTriggeringPolicy size="20 MB"/> </Policies> <! -- Save a maximum of 20 log files in one folder. Default: 7 --> <DefaultRolloverStrategy Max ="20"/> </RollingFile> <RollingFile name="error" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyyMMdd}-%i.log" immediateFlush="true"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{HH:mm:ss.SSS} %level [%thread][%X{sessionId}][%file:%line] - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <SizeBasedTriggeringPolicy size="20 MB"/> </Policies> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <Loggers> <! <logger name="org. springFramework "level="INFO"></logger> <logger name="org.mybatis"  level="INFO"></logger> <Root level="all"> <AppenderRef ref="Console"/> <AppenderRef ref="info"/> <AppenderRef ref="warn"/> <AppenderRef ref="error"/> </Root> </Loggers> </Configuration>Copy the code

log4j2.xml

In this configuration file, we define the log path “/logs/idlewow-rms/”, the default drive D on Windows. Console log output format, and three levels of INFO, WARN, ERROR file output. In addition, the log level of the Spring component is increased to INFO and debug information is filtered out.

For example, for info level logs, we define the output format of logs as “[time][Log level][thread name][SessionId][file name – number of lines of code] – log information. A log file is generated every day. If the log file is larger than 20MB, a log file is generated.

3. Log printing SessionId

In the above configuration, we defined that the Sessionid should be printed for logs to facilitate precise problem locating. However, log4j does not support this function by default, so we need to implement a separate Filter to retrieve the sessionId when the request comes in and store it in the log4j context.

package com.idlewow.rms.filter; import org.apache.logging.log4j.ThreadContext; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException; public class LogSessionFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { HttpSession session = ((HttpServletRequest) request).getSession(false); if (session ! = null) { ThreadContext.put("sessionId", session.getId()); } chain.doFilter(request, response); } finally { ThreadContext.remove("sessionId"); } } @Override public void destroy() { } }Copy the code

LogSessionFilter.java

Filter is a servlet-specific mechanism, so you need to add the following configuration to the web.xml file:

<! -- log4j logging session --> <filter> <filter-name>logSessionFilter</filter-name> <filter-class>com.idlewow.rms.filter.LogSessionFilter</filter-class> </filter> <filter-mapping> <filter-name>logSessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>Copy the code

Four, specific use

If we want to use log4j to print logs, we need to obtain a logger. We declare a final member variable in contoller as follows:

    private final Logger logger = LogManager.getLogger(this.getClass().getName());
Copy the code

Then, in each method, when you want to log, you simply print the corresponding level of log as follows,

logger.info("hello world");
logger.warn("hello world");
logger.error("hello world");
Copy the code

Normally, when printing an exception, stack information is also printed to help locate the problem, as follows (exception information is passed in the first argument, exception object is passed in the second argument) :

logger.error(ex.getMessage(), ex);
Copy the code

Five, the implementation of section log

The log function above, already can let us record the log at any time in the program, below we realize the function of section log. The two packages you need to rely on here, Spring-AOP and AspectJWeaver, have already been referenced.

Next, we need a class that defines the pointcut and aspect methods. Create a new package com.idlewow.rms.config and create a new class LogAspect under this package.

package com.idlewow.rms.config; import com.alibaba.fastjson.JSON; import com.idlewow.admin.model.SysAdmin; import com.idlewow.rms.controller.BaseController; import com.idlewow.rms.vo.RequestLog; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.Date; import java.util.Random; @Aspect @Component public class LogAspect { private final static Logger logger = LogManager.getLogger(LogAspect.class); / /.. Said this method and sub package on behalf of all the methods of the controller layer the @pointcut (" execution (public * com. Idlewow. RMS) controller). *. * (..) )") public void commonPoint() { } @Pointcut("@annotation(com.idlewow.rms.support.annotation.LogResult)") public void returnPoint() { } @Before("commonPoint()") public void before(JoinPoint joinPoint) throws Exception { HttpServletRequest  request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); HttpSession session = request.getSession(false); String username = "anyone"; if (session ! = null && session.getAttribute(BaseController.LoginUserKey) ! = null) { username = ((SysAdmin) session.getAttribute(BaseController.LoginUserKey)).getUsername(); } String trackId = username + "_" + System.currentTimeMillis() + "_" + new Random().nextInt(100); request.setAttribute("ct_begin", new Date().getTime()); request.setAttribute("ct_id", trackId); RequestLog requestLog = new RequestLog(); requestLog.setUrl(request.getRequestURI()); requestLog.setType(request.getMethod()); requestLog.setIp(request.getRemoteAddr()); requestLog.setMethod(joinPoint.getSignature().toShortString()); requestLog.setArgs(joinPoint.getArgs()); Logger.info ("[" + trackId + "] request start: "+ requestLog.toString()); } @After("commonPoint()") public void after(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String trackId = request.getAttribute("ct_id").toString(); long totalTime = new Date().getTime() - (long) request.getAttribute("ct_begin"); Logger. info("[" + trackId + "] request duration: "+ totalTime + "ms"); } @AfterReturning(returning = "result", pointcut = "commonPoint()") public void afterReturn(JoinPoint joinPoint, Object result) throws Exception { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String trackId = request.getAttribute("ct_id").toString(); Logger. info("[" + trackId + "] request result: "+ json.tojsonString (result)); } @AfterThrowing(value = "commonPoint()", throwing = "t") public void afterThrow(JoinPoint joinPoint, Throwable t) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String trackId = request.getAttribute("ct_id").toString(); Logger. error("[" + trackId + "] : "+ t.gettmessage (), t); }}Copy the code

LogAspect.java

Here we define two pointcuts, commonPoint for all public methods under the Controller package, and returnPoint for all methods annotated with LogResult (which is a custom annotation).

Then, four section methods are implemented, which are currently corresponding to commonPoint pointcuts.

Where, before is executed before each method execution, we print info-level log in this method, record the request URL, IP, input parameters and other information, record the request start time, and assign a trackId to locate the problem (if the same user executes a request N times in a moment, If the SessionId is the same, we can’t determine which of the N times the data is returned.

After is executed after each method, where we record each request time;

AfterThrowing is only executed when an exception is thrown. We print error-level logs in this method.

AfterReturn is executed when the method normally returns, and we print the result in this method. This method corresponds to the commonPoint pointcut, that is, all methods will print the return result. In practice, it can be changed to the corresponding returnPoint pointcut, so that only methods annotated with @logreuslt will print the return result.

Finally, you need to add a line of configuration to the Spring configuration file:

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
Copy the code

Note: This sentence should be configured after the controller package is scanned in spring-mVC.xml. Because we’re intercepting controller methods here, we haven’t scanned the Controller class yet in applicationContext. This is where the order of execution of the various parts of the Java Web, The Spring framework, is easier for the veteran to understand. Novice according to match can, do much nature to understand.

Six, operation effect

Now that the logging function is implemented, let’s run it to see what it looks like:

Note: After adding log4j2 dependency, maven plug-in startup will receive a red message: major: Unable to process Jar entry [META-INF/versions/9/module-info.class] from Jar [the jar file: / D: / apache maven – 3.6.1 track/package/org/apache/logging/log4j/log4j – API / 2.11.2 / log4j – API – 2.11.2. Jar! /] the for Annotations. This is because the Version of Tomcat7.0.47 built into maven is too low, but it does not affect the application.

The Maven plugin cannot modify the Tomcat version, and updates stopped after 13 years. Currently, if there is an error message due to the low version of Tomcat, you can download a new version of Tomcat, such as 7.0.85 in the introduction section, and start tomcat using the IDE integrated startup mode.

summary

This chapter realizes the establishment of the system log, which lays a good foundation for us to quickly locate problems in the future development and debugging.

The source code download address: idlestudio.ctfile.com/fs/14960372…

In this paper, the original address: www.cnblogs.com/lyosaki88/p…

Project Exchange Group: 329989095