Java 日志框架 Log4J

  • Post author:
  • Post category:java




引言


Java 日志框架 JUL

在这篇文章中已经向大家介绍了我们为什么要使用日志文件、常见的日志框架、日志框架的发展历程、还向大家介绍了一个Java原生的一个日志框架JUL。我们在说日志文件的发展历程的时候提到Log4J2是现在最优秀的Java日志框架,Log4J当前已经停止维护,不建议使用。但是Log4是Log4J2的前身,Log4J2是在Log4J的基础上做的改进。

知其然并知其所以然 今天我们来聊一下另外一个日志框架Log4J。



什么是Log4J

Log4J是Apache开源项目,通过使用Log4J,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。



Log4J三大组件


Loggers(日志记录器)


Loggers

(日志记录器):负责收集处理日志记录,获取

logger

实例可通过类名或者全限定名获取,并且对于名称具有继承机制。

从log4J 1.2以来,

Logger

类取代了

Category

类,

Logger

类可以视作

Category

类的别名。

在Log4J中包含一个特殊的

logger



rootlogger

,它是所有

logger

的根,其他

logger

会直接或间接的继承该

rootlogger

,可使用

Logger.getLogger()

获取。


Appender(输出端)

Appender 用来指定日志输出到哪个地方,可以同时指定日志的输出目的地。Log4j 常用的输出目的地有以下几种。

输出端 类型 作用
ConsoleAppender 将日志输出到控制台
FileAppender 将日志输出到文件中
DailyRollingFileAppender 将日志输出到一个日志文件,并且每天输出到一个新的文件
RollingFileAppender 将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大 小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件
JDBCAppender 把日志信息保存到数据库中


Layout(日志格式化器)

用于控制日志输出内容的格式,通过使用不同的Layout类型来指定各种需要的格式。

格式化器类型 作用
HTMLLayout 格式化日志输出为HTML表格形式
SimpleLayout 简单的日志输出格式化,打印的日志格式为(info – message)
PatternLayout 最强大的格式化期,可以根据自定义格式输出日志,如果没有指定转换格式,就是用默认的转换格式



Log4J日志级别

Log4J 在 org.

apache

.log4j.Level 类中定义了OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL七种日志级别:

级别 含义
OFF 最高日志级别,关闭左右日志
FATAL 将会导致应用程序退出的错误
ERROR 发生错误事件,但仍不影响系统的继续运行
WARN 警告,即潜在的错误情形
INFO 一般和在粗粒度级别上,强调应用程序的运行全程
DEBUG 一般用于细粒度级别上,对调试应用程序非常有帮助
ALL 最低等级,打开所有日志记录

一般只使用4个级别,优先级从高到低为 ERROR > WARN > INFO > DEBUG



Log4J基本使用

我们知道Log4J是Apache开源项目,那么我们在使用时,需要引入Jar包。

<dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

我们这里先不使用配置文件,直接使用BasicConfigurator.configure() 初始化系统配置,如果我们不使用配置文件又不使用BasicConfigurator.configure() 初始化系统配置将会报错。

public class LogTest {
    public static void main(String[] args) {
        //初始化系统配置,不需要配置文件
        BasicConfigurator.configure();
        //获取logger实例,注意这里的Logger是Log4j的
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

当通过调用方法进行配置时,

logger

实例的父属性

rootlogger



appender



ConsoleAppender

(

formatter



SimpleFormatter

),

logger

实例的日志等级为

DEBUG

。所以

trace

等级的日志并不会输出。



自定义配置文件

将自定义配置文件

log4j.properties

放置到

resource

目录下

#rootLogger配置 第一个参数为日志等级,第二个参数为appender
log4j.rootLogger = trace,console
#console只是作为指定appender的别名
log4j.appender.console = org.apache.log4j.ConsoleAppender
#设置ConsoleAppender的layout为SimpleLayout
log4j.appender.console.layout = org.apache.log4j.SimpleLayout
public class LogTest {
    public static void main(String[] args) {
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印6个不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

当通过配置文件进行配置时,所有级别都输出了。

# 设置rootlogger日志等级为trace、指定appender为下面定义的ConsoleAppender
log4j.rootLogger = trace,console
# 指定ConsoleAppender设置别名为console
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定ConsoleAppender的layout设置为PatternLayout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 设置该layout的自定义格式(解析时会调用)
log4j.appender.console.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

专对于

PatternLayout

类中的

pattern

自定义格式说明

# 占位符相关含义
%p: 输出优先级,及 DEBUG、INFO 等
%m: 输出代码中指定的日志信息
%n: 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n")
%r: 输出自应用启动到输出该 log 信息耗费的毫秒数
%d: 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy-MM-dd HH:mm:ss:SSS}  => 年月日 时分秒毫秒

%l: 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10)
	# %l即可表示下方四个修饰符
    %c: 输出打印语句所属的类的全名
    %t: 输出产生该日志的线程全名
    %F: 输出日志消息产生时所在的文件名称
    %L: 输出代码中的行号
%%: 输出一个 "%" 字符

# 可在例如%m之间加入修饰符来控制最小宽度、最大宽度和文本的对其方式
%5c: 输出category名称,最小宽度是5,category<5,默认的情况下右对齐
%-5c: 输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格
%.5c: 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格
%20.30c: category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉

public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}



Appender示例



FileAppender


FileAppender

:用于输出到文件,其有两个实现类,

DailyRollingFileAppender

提供了轮询功能(可根据指定时间点添加文件)、

RollingFileAppender

提供了根据文件大小拆分的功能。

log4j.rootLogger = trace,file
# FileAppender
#  file为名称   其中属性file:文件路径   encoding:编码
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.file = C:/Users/93997/Desktop/projectexers/logs/log.txt
log4j.appender.file.encoding = UTF-8
#  设置自定义布局(自定义输出格式)
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}



DailyRollingFileAppender

轮询功能(根据指定是每小时,还是每天输出log日志)

# 日志等级为trace,指定appender为下面以roll作为别名的
log4j.rootLogger = trace,roll
# DailyRollingFileAppender 轮询
log4j.appender.roll = org.apache.log4j.DailyRollingFileAppender
log4j.appender.roll.file = /logs/log4j.log
log4j.appender.roll.encoding = UTF-8
# datePattern指的是根据分钟来进行轮询 可设置年月日时分秒毫秒如右: '.'yyyy-MM-dd-HH-mm-ss-SSS
log4j.appender.roll.datePattern = '.'yyyy-MM-dd-HH-mm
#  设置自定义布局(自定义输出格式)
log4j.appender.roll.layout = org.apache.log4j.PatternLayout
log4j.appender.roll.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

public class LogTest {

    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);

        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}

image-20210305201500407



RollingFileAppender

按照指定文件大小进行拆分,拆分最大的文件数量可指定。

# 日志等级为trace,指定appender为下面以rollfile作为别名的
log4j.rootLogger = trace,rollfile
# RollingFileAppender 分段
log4j.appender.rollfile = org.apache.log4j.RollingFileAppender
log4j.appender.rollfile.file = /logs/log4j.log
log4j.appender.rollfile.encoding = UTF-8
# 设置单个文件最大容量(KB、MB、GB,其他单位默认传为10MB+1)以及最大文件个数 
log4j.appender.rollfile.maxFileSize = 1MB
log4j.appender.rollfile.maxBackupIndex = 5
#  设置自定义布局(自定义输出格式)
log4j.appender.rollfile.layout = org.apache.log4j.PatternLayout
log4j.appender.rollfile.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        for (int i = 0; i < 1000000; i++) {
            //打印不同的日志等级
            logger.fatal("fatal");
            logger.error("error");
            logger.warn("warn");
            logger.info("info");
            logger.debug("debug");
            logger.trace("trace");
        }
}

image-20210305203429897



JDBCAppender

创建log表

CREATE TABLE `log` (
`log_id` int(11) NOT NULL AUTO_INCREMENT,
`project_name` varchar(255) DEFAULT NULL COMMENT '目项名',
`create_date` varchar(255) DEFAULT NULL COMMENT '创建时间',
`level` varchar(255) DEFAULT NULL COMMENT '优先级',
`category` varchar(255) DEFAULT NULL COMMENT '所在类的全名',
`file_name` varchar(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ',
`thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的线程名',
`line` varchar(255) DEFAULT NULL COMMENT '号行',
`all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的发生位置',
`message` varchar(4000) DEFAULT NULL COMMENT '输出代码中指定的消息',
PRIMARY KEY (`log_id`)
);

引入mysql驱动

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.32</version>
</dependency>

配置连接信息

# rootlogger的日志等级是trace,appender为JDBCAppender,logDB是下面指定的别名
log4j.rootLogger = trace,logDB
# JDBCAppender 存储到数据库中
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=123456
log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('changlu','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

public static void main(String[] args) {
    //开启LogLog的debug模式
    LogLog.setInternalDebugging(true);
    //获取logger实例
    Logger logger = Logger.getLogger(LogTest.class);
    for (int i = 0; i < 1000000; i++) {
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}



自定义Logger

通过使用自定义Logger能够将第三方包下调用的类以及自己定义的类进行日志区分,对于自己的类的日志信息输出到文件中,而对于第三方包的类输出到屏幕上。

# rootLogger日志等级为trace,输出到屏幕上
log4j.rootLogger = trace,console
# 设置两个自定义logger
# xu.enbei(自己创建的包)自定义logger,日志等级为info,输出到文件
log4j.logger.xu.enbei = info,file
# 设置org.apache(第三方包)作为一个自定义logger,日志等级为error
log4j.logger.org.apache = err
# console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
# FileAppender
#  file:文件路径   encoding:编码
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.file = C:/Users/93997/Desktop/projectexers/logs/log.log
log4j.appender.file.encoding = UTF-8
#  设置自定义布局(自定义输出格式)
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //自己包下类的自定义logger实例
        //getLogger()参数为xu.enbei包下的类,所以获取到配置文件中xu.enbei的logger实例
        //logger实例与rootLogger的日志等级都为INFO,本身实例输出到文件,rootLogger输出到窗口
        Logger logger = Logger.getLogger(LogTest.class);
        System.out.println(logger.getName());
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace")
        // org.Apache包下的自定义logger实例,只输出到屏幕(本身实例没有设置logger)
        // 本身实例与rootLogger日志等级为error
        Logger logger1 = Logger.getLogger(Logger.class);
        System.out.println(logger1.getName());
        logger1.fatal("fatal logger1");
        logger1.error("error logger1");
        logger1.warn("warn logger1");
        logger1.info("info logger1");
        logger1.debug("debug logger1");
        logger1.trace("trace logger1");
    }
}



版权声明:本文为qq_29917503原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。