自从写javaEE应用开始,就一直在打印日志时饱受麻烦、乱等缺点的折磨,时常感叹命运的不公,为什么不像android移动端开发时的logd打印日志那么好用呢?logd又能给日志划分等级,又能有便捷的日志搜索功能,难道javaEE发展了这么多年,还只能像远古时代一样使用System.out.println()去手动打印日志,再去手动获取时间打印出来吗?
当然不是!
为何要打印日志?
首先,我们必须明白程序日志的重要性,我们在玩一些游戏的时候,如果游戏发生了异常,在闪退的时候经常会弹出一个提示框:“是否向我们发送游戏错误日志来协助我们更好地改进游戏”,这时,如果我们点击确定,就会将我们的程序运行日志发送到开发商手中,协助它们修改bug。但是假如我们没有日志功能,那么我们玩游戏闪退就是闪退了,没有任何提示,开发商也没法修复bug,那么恐怕这家开发商就离倒闭不远了。
知道了日志的重要性,那么我们应该在程序运行时输出多少日志才算是合格呢?答案是几乎每一个方法的传入参数,返回值还有一些重要的对象、变量都要在运行时打印出来它们的值,还要配合一些中文汉字对其进行解释。对于互联网公司来说,公司内部所占存储空间最大的应该非日志莫属了。试想,莫一天黑客盗刷了你的支付宝什么的,你需要去找阿里巴巴申诉希望能把钱要回来,那么你被盗刷的唯一证据就是程序日志了。日志在平时不怎么起眼,但是在程序调试和还原数据的时候能起的作用那可是大大的。
使用Log4j
不同于我们打印日志的时候只能使用System.out.print()这种土办法,log4j做到了为我们的日志分级,还有一些更好用的功能,具体的东西后面再说,我们先把log4j跑起来再说。
找了网上很多教程,发现要不就是直接翻译文档,要不就是说的不太全,要不就是太高大上了,对新手不太友好。这里我保证,按照我下面的步骤来,绝对可以把log4j跑起来,并且跑起来之后,完全已经可以用于开发了。当然,只是入门的用法,一些进阶用法请自行学习,本篇博客面向新手,因为本人也比较菜,见谅。
1.下载安装
下载安装有两种方式:
-
下载安装jar包
https://www-eu.apache.org/dist/logging/log4j/2.11.1/apache-log4j-2.11.1-bin.zip
下载完成后直接拖进bin目录下即可 -
使用maven等下载
如果你是maven项目,那就简单了,直接在pom.xml中粘贴以下依赖,然后保存,等待下载完成即可:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
2.使用
接下来,我们新建一个类,在里面使用log4j打印一句话来证明我们会用了:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
public static final Logger logger = LogManager.getLogger(Test.class);//获取日志打印对象
public static void main(String[] args) {
logger.debug("Hello World!");//打印调试日志
}
}
解释一下,获取日志打印对象的那一行相当于我们取得了一个打印机,而打印日志的那一行是我们用这台打印机打印出来了日志。什么是debug日志呢?log4j也把日志分为了几个等级,从低级到高级分别为:
- ALL:表示输出所有
- trace: 追踪日志,就是程序执行推进一步,你就可以写个trace日志,所以trace可能会特别多。
- debug: 调试日志,本人一般就只用这个作为最低级别的日志,trace压根不用,当然这是习惯问题,还是按照规范来比较好。
- info: 信息日志,输出一下重要的信息。
- warn: 警告日志,有些信息不是错误信息,但是有可能有隐患或者不规范,要给程序员一些提示。
- error: 错误信息日志,当程序执行到哪一步出现了执行错误或者异常时使用。
- fatal: 致命错误信息日志,表示重大错误,这种级别你可以直接中断程序运行了。
- OFF:表示不输出任何日志
上面的代码我们就是打印了一段调试日志,说完了这几行代码的意思,我们来运行一下试试看:
运行结果:
ERROR StatusLogger No Log4j 2 configuration file found. Using default configuration (logging only errors to the console), or user programmatically provided configurations. Set system property 'log4j2.debug' to show Log4j 2 internal initialization logging. See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2
咦?报错了,没能输出任何日志,这是为什么呢?
我们翻译这段错误信息,它说的是没有找到Log4j配置文件,让我们使用默认的配置文件(这样只能在控制台输出日志)或者使用用户创建的配置文件。
那么解决方法很简单,我们给它建一个配置文件好了:
我们在src目录下main文件夹中的resource文件夹下新建一个log4j2.xml,内容如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
这相当于是log4j的默认配置,别忘了保存。
好了,配置文件有了,现在让我们再去试试刚才的代码,这次运行之后什么反应也没有了,打开控制台,我们发现并没有输出任何信息,这是为什么呢?
log4j默认的是按等级显示日志,只会显示大于等于配置文件中设置的等级的日志,比如现在,我们这句话:
<Root level="error">
设置的就是只显示大于等于error等级的日志,也就是现在只显示error和fatal日志,不信我们来试试,多来几句:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
public static final Logger logger = LogManager.getLogger(Test.class);
public static void main(String[] args) {
logger.debug("Hello World!");
logger.error("Hello World!");
logger.warn("aaa");
}
}
运行结果:
可以看到,只有error日志被输出了
那么我们只要更改这个等级,就可以输出不同等级的日志出来了:
改为debug等级:
<Root level="debug">
输出结果:
可以看到,这样我们的三句日志就都输出来了
3. 配置文件解析:
下面我们直接上一个活生生的配置文件例子来讲解一下我们的log4j2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="error">
<!-- 先定义所有的appender,appender相当于是各种各样的打印机配置,有向控制台打印的打印机,有向文件中打印的打印机等等 -->
<appenders>
<!-- 这个是输出到控制台的打印机配置 -->
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制台只输出level及以上级别的信息(onMatch="ACCEPT"),其他的直接拒绝(onMismatch="DENY") -->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 这个是日志的格式 -->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!-- 这个是输入进文件保存下来的打印机配置,这个打印机每次运行时之前保存的日志文件自动清空,由append属性决定,这个适合临时测试用 -->
<!-- append为TRUE表示日志增加到指定文件中,false表示日志覆盖指定的文件内容,默认值是true -->
<File name="log" fileName="log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!-- 添加过滤器ThresholdFilter,可以有选择的输出某个级别以上的类别 onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否则直接拒绝 -->
<File name="ERROR" fileName="logs/error.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!-- 这个打印机会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
<RollingFile name="RollingFile" fileName="logs/web.log"
filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="2MB"/>
</RollingFile>
</appenders>
<!-- 然后定义logger,只有定义了logger并引入刚才的appender配置,appender才会生效 -->
<loggers>
<!-- 建立一个默认的root的logger -->
<root level="trace">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
<appender-ref ref="ERROR" />
<appender-ref ref="log"/>
</root>
</loggers>
</configuration>
到此,我们的springMVC配置log4j就完成了,接下来你要做的就是看懂我们刚刚的log4j.xml配置文件中的注释,然后尝试去自定义日志格式,日志存储位置等一系列自定义配置了。