日志框架 log4j2 全解析
概述
logging翻译为日志记录
那问题是什么是日志?
日志实际上是日记的一种,用于记录某个时间点发生了什么事情,比如大学老师的教学日志,工作日志等
为什么要记录日志?
在实际生活中记录日志主要为了日后复查,
比如某个大学老师每天记录自己讲的什么内容,后面有学生某科成绩优异获奖了,校长想要奖励对应的老师,但由于每个老师教的班级都很多,并不一定记得是谁教的,这时候就可以查看教学日志来获取需要的信息了
再比如,工厂的生产日志,如果某个产品除了因为某个零件出现了故障,通过生成日志,可以找到与这个产品同批次的其他产品,进行返工,或是通过日志找到该零件的供应商,进行沟通解决!
程序中的日志
我们的程序开发完成后会被不同系统环境的用户下载使用,期间可能就会出现问题,直接把错误信息展示给用户看是没有任何意义的,用户看不懂也不会解决,那这时候就可以将用户执行的所有操作,以及代码运行的过程,记录到日志中,程序员通过分析日志内容,可以快速的定位问题
综上: 日志就是用来记录发生的事件的
日志并不会立即产生作用,而是当程序出现了问题时在去分析日志文件提取有用信息
java下的日志框架
门面
门面是Facade(外观模式)的实现,也称为门面模式,
是对内部多个子系统的封装,并对外提供一套统一的使用接口,从而屏蔽各个子系统在使用上的不同,大大降低了系统的使用难度,同时提高了系统的可维护性和扩展性;
实际上真正干活的还是是内部的子系统;就像给这些子系统加了一层装饰,Facede也得名于此;
图示:
因其性能优越性,实际开发中log4j是使用最多一个日志框架,也是我们需要掌握的目标;
官方性能对比:
log4j
日志级别:
日志级别其实指的就是日志信息应用场景,我们的程序会在不同的环境中运行,某些日志只有用在某些特殊场景中,例如:在开发阶段,我们为了检查错误,会输出一些调试信息,但是这些信息在生产环境下是不需要的,当然.我们可以在发布前删除这些调试代码,但这就显得非常low了,通过对日志信息区别对待,我们可以很方便的控制哪些日志在哪些场景下正常输出;
日志级别也在后续的问题定位中发挥着重要作用,当程序出现了问题,我们要根据日志来定位问题,这时便可以通过日志级别来快速过滤掉不需要的记录;
log4j日志级别:
log4j定义了8个级别,优先级从高到低依次为:
OFF>FATAL> ERROR> WARN> INFO> DEBUG> TRACE> ALL
- ALL 最低等级的 用于打开所有日志记录
- TRACE 很低的日志级别 一般不会使用
- DEBUG 该级别信息对调试应用程序是非常有帮助的 主要用于开发过程中打印 一些运行信息
- INFO 突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息 可用于生产环境中输出程序运行的一些重要信息,但是不能滥用 避免打印过多的日志
- WARN 表明会出现潜在错误的情形 有些信息不是错误信息 但是也要给程序员的一些提示
- ERROR 指出虽然发生错误事件 但仍然不影响系统的继续运行。打印错误和异常信息 如果不想输出太多日志 太多数情况下可以使用这个级别
- FATAL 指出严重的错误事件,将会导致应用程序的退出。
- OFF 最高等级的,用于关闭所有日志记录
依赖包:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
配置文件:
2.x往后的版本不在支持properties作为配置文件,因其无法表达较为复杂的语法结构
log4j2会在classpath下查找配置文件,如果找不到则使用基础配置(输出到控制台),log4j支持 xml,json,jsn三种格式的配置文件,并可为测试环境和生产环境编写不同的配置文件;若有多个配置文件log4j将按照以下顺序读取:
- classpath下的名为log4j2-test.json 或者log4j2-test.jsn的文件.
- classpath下的名为log4j2-test.xml的文件.
- classpath下名为log4j2.json 或者log4j2.jsn的文件.
- classpath下名为log4j2.xml的文件.
示例log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- status="WARN" 用于设置log4j框架本身的日志级别-->
<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="all">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
测试代码:
@Test
public void test1(){
Logger myLogger = LogManager.getLogger("myLogger");
myLogger.debug("debug msg");
}
Appenders节点:
该节点配置日志信息的输出目的地,可以是控制台,文件,邮件或数据库,控制台和文件是表常用的两个目的地;
上述案例既将日志信息输出到控制台,其子节点PatternLayout用于设置日志输出的字符传格式;
PatternLayout可用的格式化字符:
%d{HH:mm:ss.SSS} 表示输出到毫秒的时间
%t 输出当前线程名称
%-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补空格
%logger 输出logger名称,因为Root Logger没有名称
%msg 日志文本
%n 换行
%F 输出所在的类文件名,如Client.java
%L 输出行号
%M 输出所在方法名
%C 产生log事件的java完全限定类名
%l 输出语句所在的行数, 包括类名、方法名、文件名、行数
输出到文件:
<?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 - %msg%n"/>
</Console>
<File name="fileAppender" fileName="logs/app.log" append="false"><!--默认以当前项目为相对路径-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="all">
<AppenderRef ref="Console"/>
<AppenderRef ref="fileAppender"/><!--一个logger可配置对个appender输出到不同位置-->
</Root>
</Loggers>
</Configuration>
<!--File属性:
name用于给appender指定名字,以便logger引用
fileName默认以当前项目为相对路径
append参数表示是否将是追加到文件末尾 默认为true 为false即直接覆盖原文件-->
上面的配置会将所有日志输出到同一个文件,随着时间的推移该文件会越来越大,甚至无法打开,但是实际有用的日志都是近期的产生的,太久远的日志大多数是无用的,这就用到了滚动日志,其可以帮助我们实现日志文件的切割,以及无用日志的删除操作;
滚动日志配置:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<!--自定义属性信息-->
<properties>
<property name="LOG_HOME">logs</property>
<property name="FILE_NAME">applog</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<!--滚动日志配置
filePattern用于设置滚动文件的命名规则
若以.zip为结尾则会自动归档日志文件 也支持其他的格式.gz, .zip, .bz2, 等-->
<RollingRandomAccessFile name="RollingAppender"
fileName="${LOG_HOME}/${FILE_NAME}.log"
filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i.log">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<!--滚动时间间隔 该参数需结合filePattern中的时间格式 此时表示为1分钟更换一个新文件
若时间格式为%d{yyyy-MM-dd HH}则表示每小时更换一个新文件-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--单个日志文件最大容量 -->
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<!--最大保留的日志文件个数 默认为7个 -->
<DefaultRolloverStrategy max="20"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="all">
<AppenderRef ref="RollingAppender"/>
</Root>
</Loggers>
</Configuration>
上述配置的整体含义:统一使用rootLogger,所有级别日志都会被记录到文件中,文件位于项目目录下的logs中,当单个文件超过1MB或是时间超过1分钟后则更换日志文件,最多保存20个日志文件;
补充:RollingFile也是做滚动日志的,但是据官方说效率没有RollingRandomAccessFile高;
Loggers节点:
需求:某个类或模块中产生的需要同时输出到控制台和文件,其他模块则仅输出到控制台,当遇到类似需求时,就需要定义不同的logger了,然后在程序中根据名称获取所需的logger
如果在配置中找不到名称匹配的logger时使用rootLogger;
logger配置:
注意:appender使用的还是上面的例子中的
<Loggers>
<Root level="all">
<AppenderRef ref="Console" />
</Root>
<Logger name="fileAndConsole" level="all" additivity="false">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingAppender" />
</Logger>
</Loggers>
<!-- additivity表示是否将日志传递给root继续输出 默认为true-->
测试代码:
@Test
public void test1(){
Logger myLogger = LogManager.getLogger("myLogger");//rootlogger
Logger myLogger2 = LogManager.getLogger("fileAndConsole");//fileAndConsole
for (int i = 0;i < 50;i++){
myLogger.debug("debug msg1");
}
for (int i = 0;i < 50;i++){
myLogger2.debug("debug msg2");
}
}
msg1将只出现在控制台,而msg2同时出现在控制台和日志文件;
Filter节点:
Filter用于对日志进行过滤,一些情况下我们可能需要对日志进行更加个性化的限制,
例如:
输出日志消息包含某个字符串的
按照时间不同输出到不同文件
日志的生命周期 :
一个日志事件(LogEvent)产生后到最终输出到目的地会经过以下环节:
全局过滤器 -> logger过滤器 -> logger -> appender过滤器 -> appender->输出
无论哪个环节的过滤器,每个过滤器在匹配或是不匹配时都要明确该日志事件的处理方式,包含三种:
- ACCEPT接受(继续传递该LogEvent)
- DENY拒绝(直接丢弃该LogEvent)
- NEUTRAL中立(不清楚该怎么办继续往后传递LogEvent)
全局过滤器:评估结果为接受时,其他全局过滤器将不会再对该事件进行评估,且不再交给Logger过滤器评估
Logger过滤器:评估为拒绝时不再交给Appdener过滤器
Appdener过滤器:最终决定改日志是否输出
通常需要根据实际需求来配置过滤器:
下例配置列出了三种过滤器的示例(无实意义):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" monitorInterval="5" packages="com.kanq.extend.cat.log4j2">
<Filters>
<!-- 全局级别Filter -->
<BurstFilter level="INFO" rate="16" maxBurst="100"/>
</Filters>
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
<!-- Appender级别的Filter -->
<BurstFilter level="INFO" rate="16" maxBurst="100"/>
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<!-- Logger级别的Filter -->
<Root level="error">
<BurstFilter level="INFO" rate="16" maxBurst="100"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
过滤器案例:
通过时间过滤器实现将白天和夜晚的是指写入不同位置:
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="DayAppender" fileName="logs/appDay.log" append="true">
<TimeFilter start="06:00:00" end="24:00:00" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
</File>
<File name="NightAppender" fileName="logs/appNight.log" append="true">
<TimeFilter start="24:00:00" end="06:00:00" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="all">
<AppenderRef ref="Console" />
<AppenderRef ref="DayAppender" />
<AppenderRef ref="NightAppender" />
</Root>
</Loggers>
</Configuration>
当然官网还有其他的过滤器,如正则过滤等,大家根据需求选择即可;地址:官方手册
web项目中的使用
web环境下需要额外的依赖包:
<!-- web容器中需要添加log4j-web -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.5</version>
</dependency>
controller中获取logger:
@Controller
@RequestMapping("/customer")
public class CustomerController {
//为controller添加属性 用于获取一个日志记录器(Logger)
private Logger logger = LogManager.getLogger("user");
@RequestMapping("/list")
public String getCustomerList(Model model, SearchInfo searchInfo){
logger.info("request this /list interface");
//...
}
}
也可以注册到Spring中,使用DI
<bean id="userLogger" class="org.apache.logging.log4j.LogManager" factory-method="getLogger">
<constructor-arg name="name" value="user"/>
</bean>
若配置文件名称不是默认的则可以通过以下代码来加载:
File file = new File("/Users/jerry/LOGfj/src/main/resources/log4j3.xml");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
ConfigurationSource source = new ConfigurationSource(in);
Configurator.initialize(null, source);
日志框架 log4j2 全解析的更多相关文章
- SpringBoot整合Logback日志框架配置全解析
目录 本篇要点 一.Logback日志框架介绍 二.SpringBoot与Logback 1.默认日志格式 2.控制台输出 3.文件输出 4.日志级别 5.日志组 6.自定义log配置 三.logba ...
- Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能
我们的Glide系列文章终于要进入收尾篇了.从我开始写这个系列的第一篇文章时,我就知道这会是一个很长的系列,只是没有想到竟然会写这么久. 在前面的六篇文章中,我们对Glide的方方面面都进行了学习,包 ...
- Android图片加载框架最全解析(六),探究Glide的自定义模块功能
不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间.在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍, ...
- Android图片加载框架最全解析(四),玩转Glide的回调与监听
大家好,今天我们继续学习Glide. 在上一篇文章当中,我带着大家一起深入探究了Glide的缓存机制,我们不光掌握了Glide缓存的使用方法,还通过源码分析对缓存的工作原理进行了了解.虽说上篇文章和本 ...
- Golang最强大的访问控制框架casbin全解析
Golang最强大的访问控制框架casbin全解析 Casbin是一个强大的.高效的开源访问控制框架,其权限管理机制支持多种访问控制模型.目前这个框架的生态已经发展的越来越好了.提供了各种语言的类库, ...
- Android图片载入框架最全解析(一),Glide的基本使用方法
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/53759439 本文同步发表于我的微信公众号.扫一扫文章底部的二维码或在微信搜索 郭 ...
- Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
本篇将是我们这个Glide系列的最后一篇文章. 其实在写这个系列第一篇文章的时候,Glide就推出4.0.0的RC版了.那个时候因为我一直研究的都是Glide 3.7.0版本,再加上RC版本还不太稳定 ...
- Android图片加载框架最全解析(五),Glide强大的图片变换功能
大家好,又到了学习Glide的时间了.前段时间由于项目开发紧张,再加上后来又生病了,所以停更了一个月,不过现在终于又可以恢复正常更新了.今天是这个系列的第五篇文章,在前面四篇文章的当中,我们已经学习了 ...
- Android图片加载框架最全解析(三),深入探究Glide的缓存机制
在本系列的上一篇文章中,我带着大家一起阅读了一遍Glide的源码,初步了解了这个强大的图片加载框架的基本执行流程. 不过,上一篇文章只能说是比较粗略地阅读了Glide整个执行流程方面的源码,搞明白了G ...
随机推荐
- Java类成员之内部类
内部类含义: 在Java中允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类. Inner class 一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称. Inner ...
- 恕我直言,牛逼哄哄的MongoDB你可能只会30%
MongoDB闪亮登场 自我介绍 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库 ...
- 虚拟机下 windows 自动配置 IPv4 地址 169.254.X.X(首选)
问题: windows server上,自己手动配置的ip不生效,自动获取地址虽然ok,但是服务器必须指定ip. 诊段: ipconfig/all里查看 自动配置 IPv4 地址 169.254.X ...
- Java StringBuilder类
StringBuilder的原理 String类 字符串是常量,它们的值在创建之后不能更改 字符串的底层是一个被final修饰的数组,不能改变 private final byte[] value; ...
- django操作命令
下载安装 pip3 install django==1.11.21 -i https://pypi.tuna.tsinghua.edu.cn/simple 创建项目 1.终端找到存放项目的文件夹,dj ...
- vue引用外部JS的两种种方案
前言 肯定会遇到没有npm化的库 自己写的js 方法 在Vue中该怎么引用呢 第一种 如果库是es6写的 就可以用import 引入 比如我自己写的http 封装接口的方法 就可以这样子导入哦 第二种 ...
- java intellij 工具的简单用法
一.目录结构 1.新建项目(Empty Project) -> 新建module(可以有多个) => 出来src文件夹 -> 在src文件夹中新建package -> 在pa ...
- 【转载】Notepad++源码分析
在网上发现了一个哥们写了关于Notepad++源码的文章,不过就写了一就没有了,我就接着他的工作再说说吧! 大三了,也写了一点儿程序了,但是如果只是按照自己的思路写下去恐怕难以提高,于是准备开始阅读一 ...
- python练习-8.12
注:本代码是<python核心编程(第二版)>的第八章8-12的练习题的代码实现. 完成的功能:用户给出起始和结束的数字后给出一个下面的表格,分别显示出两个数字间所有整型的十进制.二进制. ...
- 各种反弹shell方法总结
获取shell的方法总结: shell分为两种,一种是正向shell,另一种是反向shell.如果客户端连接服务器,客户端主动连接服务器,就称为正向shell.如果客户端连接服务器,服务器想要获得客户 ...