log4j2的升级和使用

说明:公司系统采取的是log4j12结合slj4f,需要升级为log4j2结合slj4j,特地学习log4j的日志操作。

1.log4j12的升级

升级前,使用Apache Log4j和1.7.7版本的slf4j,说明:引用的是Apache Log4j,而不是Apache Log4j Core 或者 Apache Log4j API。
第一步:删除pom.xml中的log4j和slf4j的引入;
第二步:添加以下jar包引入:

<dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>${
    
    slf4j.version}</version>
 </dependency>
 <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-api</artifactId>
     <version>${
    
    log4j.version}</version>
 </dependency>
 <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-core</artifactId>
     <version>${
    
    log4j.version}</version>
 </dependency>
 <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-slf4j-impl</artifactId>
     <version>${
    
    log4j.version}</version>
 </dependency>
 <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-web</artifactId>
     <version>${
    
    log4j.version}</version>
     <scope>runtime</scope>
 </dependency>
 <dependency>
     <groupId>org.apache.logging.log4j</groupId>
     <artifactId>log4j-1.2-api</artifactId>
     <version>${
    
    log4j.version}</version>
 </dependency>
<dependency>
	<groupId>org.apache.struts</groupId>
	<artifactId>struts2-json-plugin</artifactId>
	<version>2.1.8.1</version>
</dependency>
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.2.0</version>
</dependency>


<log4j.version>2.7</log4j.version>
<slf4j.version>1.7.26</slf4j.version>

第三步:web.xml中去除log4jConfigLocation的context-param
log4j2在使用上,不需要再在web.xml引入log4jConfigLocation进行启动,而是自动在/src/resources目录下找到log4j2.xml文件,进行加载。
第四步:添加log4j2.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <Appenders>
        <Console name="console_appender" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{MM/dd/yyyy HH:mm:ss.SSS} %c %-5p %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="ERROR">
            <appender-ref ref="console_appender"/>
        </Root>
    </Loggers>
</configuration>

2.实现日志控制台输出

使用的是Console的Appender。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <Appenders>
        <Console name="console_appender" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{MM/dd/yyyy HH:mm:ss.SSS} %c %-5p %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="INFO">
            <appender-ref ref="console_appender"/>
        </Root>
    </Loggers>
</configuration>

相当于properties中以下配置:

log4j.rootLogger=INFO, console_appender
log4j.appender.console_appender=org.apache.log4j.ConsoleAppender
log4j.appender.console_appender.layout=org.apache.log4j.PatternLayout
log4j.appender.console_appender.layout.ConversionPattern=%d{
    
    MM/dd/yyyy HH:mm:ss.SSS} %c %-5p %m%n

3.实现日志文件输出

3.1.自定义的Appender

(以下代码基本来源于网络):

package com.fracong.test.log4j;

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

@Plugin(name = "FileAppender", category = "Core", elementType = "appender", printObject = true)
public class Log4jCustomizeFileAppender extends AbstractAppender {
    
    
	private String fileName;
	
    public Log4jCustomizeFileAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String fileName) {
    
    
        super(name, filter, layout, ignoreExceptions);
        this.fileName = fileName;
    }

    @Override
    public void append(LogEvent event) {
    
    
        final byte[] bytes = getLayout().toByteArray(event);
        writerFile(bytes);
    }

    @PluginFactory
    public static Log4jCustomizeFileAppender createAppender(@PluginAttribute("name") String name,
                                              @PluginAttribute("fileName") String fileName,
                                              @PluginElement("Filter") final Filter filter,
                                              @PluginElement("Layout") Layout<? extends Serializable> layout,
                                              @PluginAttribute("ignoreExceptions") boolean ignoreExceptions) {
    
    
        if (name == null) {
    
    
            LOGGER.error("no name defined in conf.");
            return null;
        }
        if (layout == null) {
    
    
            layout = PatternLayout.createDefaultLayout();
        }
        if (!createFile(fileName)) {
    
    
            return null;
        }
        return new Log4jCustomizeFileAppender(name, filter, layout, ignoreExceptions, fileName);
    }

    private static boolean createFile(String fileName) {
    
    
        Path filePath = Paths.get(fileName);
        try {
    
    
            if (Files.exists(filePath)) {
    
    
                Files.delete(filePath);
            }
            Files.createFile(filePath);
        } catch (IOException e) {
    
    
            LOGGER.error("create file exception", e);
            return false;
        }
        return true;
    }

    private void writerFile(byte[] log) {
    
    
        try {
    
    
            Files.write(Paths.get(fileName), log, StandardOpenOption.APPEND);
        } catch (IOException e) {
    
    
            LOGGER.error("write file exception", e);
        }
    }
}

说明:@Plugin注解中的name,会作为log4j2.xml中的一个标签。

3.2.使用自定义的Appender进行输出

<?xml version="1.0" encoding="UTF-8"?>
<configuration packages="com.fracong.test.log4j">
    <Properties>
        <Property name="LOG_HOME">/logs/test</Property>
        <Property name="LOG_FILE">info</Property>
    </Properties>
    
    <Appenders>
        <FileAppender name="file_appender" fileName="${LOG_HOME}/${LOG_FILE}.log">
            <PatternLayout pattern="%d{MM/dd/yyyy HH:mm:ss.SSS} %c %-5p %m%n" />
        </FileAppender>
    </Appenders>

    <Loggers>
        <Root level="INFO">
            <appender-ref ref="file_appender"/>
        </Root>
    </Loggers>
</configuration>

说明
1.configuration中的packages是将该目录下的Appender引入到标签中,Appender中定义的name需要和标签名保持一致。
2.Properties定义的属性,引用时使用格式:${Xxxx}
3.如上XML定义相当于properties中如下定义:

log4j.rootLogger=INFO,file_appender
log4j.appender.file_appender=com.fracong.test.log4j.Log4jCustomizeFileAppender
log4j.appender.file_appender.File=/logs/test/info.log
log4j.appender.file_appender.layout=org.apache.log4j.PatternLayout
log4j.appender.file_appender.layout.ConversionPattern=%d{
    
    MM/dd/yyyy HH:mm:ss.SSS} %c %-5p %m%n

4.实现日志写入数据库

4.1.数据库结构

CREATE TABLE public.log_test (
	log_id bigserial NOT NULL,            //主键,且实现自增长
	user_id varchar NULL,
	log_type varchar NULL,
	log_date timestampt NULL,
	"log_level" varchar NULL,
	"exception" text NULL,
	CONSTRAINT log_test_pk PRIMARY KEY (log_id)
);

4.2.数据库连接

package com.fracong.test.log4j;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;

public class Log4j2ConnectionFactory {
    
    
	private static BasicDataSource dataSource;

	private Log4j2ConnectionFactory() {
    
    }

    public static Connection getConnection() throws SQLException {
    
    
      if (dataSource == null) {
    
    
         dataSource = new BasicDataSource();
         //postgresql
         /*dataSource.setUrl("jdbc:postgresql://localhost:5432/fracong-test?useSSL=false");
         dataSource.setDriverClassName("org.postgresql.Driver");
         dataSource.setUsername("postgres");
         dataSource.setPassword("123456");*/
         
		//mysql
         dataSource.setUrl("jdbc:mysql://localhost:3306/test_demo?useSSL=false&serverTimezone=UTC");
         dataSource.setDriverClassName("com.mysql.jdbc.Driver");//8.0版本以下
         //dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");//8.0版本以上
         dataSource.setUsername("root");
         dataSource.setPassword("root");
      }
      return dataSource.getConnection();
    }
}

4.3.log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>    
    <Appenders>
        <JDBC name="jdbcDatadase_appender" tableName="log_test">
			<ConnectionFactory class="com.fracong.test.log4j.Log4j2ConnectionFactory" 
			method="getConnection" />
			<Column name="user_id" pattern="%X{userId}" isUnicode="false"/>
			<Column name="log_type" pattern="%logger" isUnicode="false"/>
			<Column name="log_date" isEventTimestamp="true" />
			<Column name="log_level" pattern="%level" isUnicode="false"/>
			<Column name="exception" pattern="%message %ex{full}" isUnicode="false"/>
	    </JDBC>
    </Appenders>

    <Loggers>
        <logger name="log_type_one" level="DEBUG">
        	<appender-ref ref="jdbcDatadase_appender"/>
        </logger>
        <logger name="log_type_two" level="DEBUG">
        	<appender-ref ref="jdbcDatadase_appender"/>
        </logger>
    </Loggers>
</configuration>

说明:
1.Appenders下的JDBC是log4j2自带的JDBCAppender.
2.JDBC的tableName是指在连接的数据库下的数据库表.
3.ConnectionFactory是连接数据库的连接,其中class是调用的类,method为调用的方法.
4.Column为数据库的字段,name的值和数据库一一对应,pattern为从logEvent中获取的数据的格式,如果值为string类型,那么使用 isUnicode="false"进行转换.
5.%logger获取的是LogFactory.getLog("log_type_one");中的log_type_one;%level为获取的日志等级如ERROR/DEBUG等;%message为获取的是logger.error("test");中的test;%ex{full}获取的logger.error("test",new Exception("Error one"));中的new Exception(“Error one”)打印出来的日志异常;

4.4.java程序使用

	//log_type_one的值和xml定义的保持一致,才能被日志绑定
	private static Log logger = LogFactory.getLog("log_type_one");
	@POST
	@Path("/newTest")
	public String newTest(@QueryParam("userId") String userId) throws IOException {
    
    
		if(StringUtils.isNotBlank(plant_code)) MDC.put("userId", userId);
		logger.error("test");
		return "ok";
	}

说明:如果想将java数据中的param传递到log4j2.xml中,可以使用MDC.put(key, value),其中value不能为空,而log4j2.xml使用**%X{key}**进行接收数据。

猜你喜欢

转载自blog.csdn.net/m0_37356874/article/details/102802545