Java日志知识概括

Java日志知识概括

  • 日志的概念
  • Java日志框架
  • JUL
  • LOG4J
  • JCL
  • 日志门面
  • SLF4J的使用
  • Logback的使用
  • log4j2的使用
  • SpringBoot中的日志使用

日志的概念

日志文件:

  • 日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断 问题的追踪以及理解系统的活动等重要作用。
  • 在计算机中,日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。记录是保持日志的行为。在最简单的情况下,消息被写入单个日志文件。
  • 许多操作系统,软件框架和程序包括日志系统。广泛使用的日志记录标准是在因特网工程任务组 (IETF)RFC5424中定义的syslog。syslog标准使专用的标准化子系统能够生成,过滤,记录和分析日 志消息。

调试日志:

  • 软件开发中,我们经常需要去调试程序,做一些信息,状态的输出便于我们查询程序的运行状况。为了让我们能够更加灵活和方便的控制这些调试的信息,所有我们需要专业的日志技术。
  • java中寻找bug会需要重现。调试也就是debug 可以在程序运行中暂停程序运行,可以查看程序在运行中的情况。日志主要是为了更方便的去重现问题。

系统日志:

  • 系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统日志、应用程 序日志和安全日志。

系统日志的价值:

  • 系统日志策略可以在故障刚刚发生时就向你发送警告信息,系统日志帮助你在最短的时间内发现问题。
  • 系统日志是一种非常关键的组件,因为系统日志可以让你充分了解自己的环境。这种系统日志信息对于决定故障的根本原因或者缩小系统攻击范围来说是非常关键的,因为系统日志可以让你了解故障或者袭击发生之前的所有事件。为虚拟化环境制定一套良好的系统日志策略也是至关重要的,因为系统日志需要和许多不同的外部组件进行关联。良好的系统日志可以防止你从错误的角度分析问题,避免浪费宝贵 的排错时间。
  • 另外一种原因是借助于系统日志,管理员很有可能会发现一些之前从未意识到的问题,在 几乎所有刚刚部署系统日志的环境当中。

Java日志框架

Java日志框架的问题:

  • 控制日志输出的内容和格式
  • 控制日志输出的位置
  • 日志优化:异步日志,日志文件的归档和压缩
  • 日志系统的维护
  • 面向接口开发 – 日志的门面

为什么要用日志框架

  • 因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业 务逻辑设计。
  • 而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事务处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。

现有的日志框架:

  • JUL(java util logging)、logback、log4j、log4j2
  • JCL(Jakarta Commons Logging)、slf4j( Simple Logging Facade for Java)

日志迭代:

  • 日志门面:JCLslf4j
  • 日志实现: JULlogbacklog4jlog4j2
  • 进行slf4j门面日志绑定时logback与log4j2是不用添加绑定jar包的,因此logback与log4j2底层规范使用slf4j的规范。
  • 而其他日志框架如JCL,log4j都需要添加绑定jar包。

JUL

JUL简介:

  • JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框架使用方便,学习简单,能够在小型应用中灵活使用。

架构介绍:

  • Loggers:被称为记录器,应用程序通过获取Logger对象,调用其API来来发布日志信息。
  • Logger:通常时应用程序访问日志系统的入口程序。
  • Appenders:也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等。
  • Layouts:也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了数据在一条日志记录中的最终形式。
  • Level:每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫,我可以将Level和Loggers,Appenders做关联以便于我们过滤消息。
    Level只在日志消息输出时指定。
  • Filters:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。
  • 总结一下就是:用户使用Logger来进行日志记录,Logger持有若干个Handler,日志的输出操作是由Handler完成的。在Handler在输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,Handler会将日志内容输出到指定位置(日志文件、控制台等)。Handler在输出日志时会使用Layout,将输出内容进行排版。
    Java日志知识概括_第1张图片
  • 此外:
    tomcat,jvm底层都使用JUL,而其他框架则实现别的日志框架。
    框架和tomcat或自己的应用在初始化时都是通过读取配置文件的默认配置来初始化的,因此我们可以修改配置文件修改初始化配置。
    <1>tomcat中的日志配置文件:$TOMCATHOME\conf\logging.properties
    <2>jdk中的日志配置文件:$JAVAHOME\jre\lib\logging.properties
  • 注意:
    当我们输出一条日志时,日志框架会自动通过不同的Appender把同一条日志输出到不同的目的地。例如:
    <1>console:输出到屏幕;
    <2>file:输出到文件;
    <3>jdbc:输出到数据库;Java日志知识概括_第2张图片
    ②日志输出时可以使用logger.log(Level)输出,也可以使用指定的级别输出,如:logger.info(),logger.error()。
    <1>在logger指定日志级别后,在级别以下的输出将不会输出。
    <2>如:指定了info级别,则info以下的debug,trace将不会输出。
    一般使用logger时会使用本类类名作为logger的名字。例如:private static final Logger logger = Logger.getLogger(类名.class)
  • 日志配置文件总结:
    对于 java.util.logging的rootlogger在配置文件中为空串,即不用指定。而当我们自定义时则需要使用logger的名字,也就是类名。
    对于log4j的rootlogger在配置文件中为log4j.rootLogger,需要指定。而当我们自定义时则需要logger的名字,也就是类名。
    至于logback和log4j2的配置文件使用的xml比较容易理解,不像上面两个使用properties。
    对于springboot的log配置和log4j一样。
    ⑤每个 logger 都有对应的父级关系,它通过包名来决定父级关系,root 是最高级的父元素。 下面定义了四个logger,他们的父子关系从小到大为: com.lwc.qg.test.logbackDemo → com.lwc.qg.tes →com.lwc.qg → root
    一般配置时需要配置一个rootLogger,这样框架里的其他logger会继承rootLogger,自定义的logger不特殊指定的话也会继承rootLogger。
    <1>若不想继承rootLogger可以自己额外在配置文件配置。
---------- java.util.logging---------- 
# RootLogger日志等级
level= INFO
## 自定义Logger
com.itheima.level= error

----------log4j---------- 
# RootLogger配置 
log4j.rootLogger = trace,console 
# 自定义Logger 
log4j.logger.com.itheima = info,file 
# 自定义appender,名字为stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender

----------springboot log---------- 
# 自定义Logger
logging.level.com.itheima=trace

Logger详解:

  • Loggers节点,常见的有两种:Root和Logger。
    Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出。
    Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
  • Root(以Log4j2为例):
    每个配置都必须有一个根记录器Root。如果未配置,则将使用默认根LoggerConfig,其级别为ERROR且附加了Console appender。
    ②根记录器和其他记录器之间的主要区别是:
    <1>根记录器没有name属性。
    <2>根记录器不支持additivity属性,因为它没有父级。
    ③level(Root的属性):日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF
    ④AppenderRef(Root的子节点):用来指定该日志输出到哪个Appender.
  • Logger(以Log4j2为例):
    使用Logger元素必须有一个name属性,root logger不用name元属性
    ②每个Logger可以使用TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一配置级别。
    <1>如果未指定级别,则默认为ERROR。
    <2>可以为additivity属性分配值true或false。如果省略该属性,则将使用默认值true。
    ③Logger还可以配置一个或多个AppenderRef属性。引用的每个appender将与指定的Logger关联。如果在Logger上配置了多个appender,则在处理日志记录事件时会调用每个appender。
    name(Logger的属性):用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点。一般是项目包名或者框架的包名,比如:com.jourwon,org.springframework。
    ⑤level(Logger的属性):日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。
    AppenderRef(Logger的子节点):用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root。如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。
  • 为什么需要使用多个logger?
    首先要清楚一个logger可以指定多个appender。
    如果只有一个 loggger ,那么对于同一输出端的输出,格式都是一样的。
    如果你有两个或者更多loggger ,那么对于同一输出端的输出,比如:console,那么不同的 logger 可以把它输出为不同的格式。

LevelFilter和Level详解:

  • LevelFilter是级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath 和onMismatch接收或拒绝日志。
  • 日志级别(以LogBack为例):TRACE < DEBUG < INFO < WARN < ERROR
    ①Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
    ②Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
    Info:消息在粗粒度级别上突出强调应用程序的运行过程.
    ④Warn:输出警告及warn以下级别的日志.
    ⑤Error:输出错误信息日志.
  • 属性:
    :设置过滤级别
    :用于配置符合过滤条件的操作
    :用于配置不符合过滤条件的操作
  • 总结:
    如果logger没有被分配级别,name它将从有被分配级别的最近的父类那里继承级别,root logger默认级别是DEBUG。
    日志输出的时候,级别大的会输出,根据当前ROOT 级别,日志输出时,级别高于root默认的级别时会输出,比如如果root的级别是info,那么会输出info以及info级别以上的日志。
    <1>级别等于或大于设置的级别时,有该级别的消息才输出,没有则忽略。

getLogger方法:

  • public static Logger getLogger(String name)查找或创建一个命名子系统的记录器。如果已经使用给定名称创建了记录器,则返回它。 否则将创建一个新的记录器。
    ①参数 :name - 记录器的名称。 这应该是一个点分隔的名称,通常应该基于子系统的包名或类名,如java.net或javax.swing
    ②结果 :一个合适的记录器
    ③异常 :NullPointerException - 如果名称为空。
  • 如果创建了一个新的记录器,它的日志级别将根据LogManager配置进行配置,并且还将配置为将日志输出发送到其父代的处理程序。它将在LogManager全局命名空间中注册。
  • 注意:LogManager可能只保留对新创建的Logger的弱引用。重要的是要明白,如果没有强有力的引用Logger,以前创建的具有给定名称的Logger可能随时被垃圾回收。
  • 特别地,这意味着像getLogger(“MyLogger”).log(…)这样的两个后退呼叫可能会使用名为“MyLogger”的不同的Logger对象,如果程序中其他地方没有强大的引用名为“MyLogger”的Logger。

入门案例:

public class JULTest {
   
	@Test
	public void testQuick() throws Exception {
   
		// 1.创建日志记录器对象
		Logger logger = Logger.getLogger("com.itheima.log.JULTest");
		// 2.日志记录输出
		logger.info("hello jul");
		logger.log(Level.INFO, "info msg");
		String name = "jack";
		Integer age = 18;
		logger.log(Level.INFO, "用户信息:{0},{1}", new Object[]{
   name, age});
	}
}

日志的级别:

  • java.util.logging.Level中定义了日志的级别:
    SEVERE(最高值)
    WARNING
    INFO (默认级别)
    CONFIG
    FINE
    FINER
    FINEST(最低值)
  • 还有两个特殊的级别:
    ①OFF,可用来关闭日志记录。
    ②ALL,启用所有消息的日志记录。
  • 虽然我们测试了7个日志级别但是默认只实现info以上的级别
@Test
public void testLogLevel() throws Exception {
   
	// 1.获取日志对象
	Logger logger = Logger.getLogger("com.itheima.log.QuickTest");
	// 2.日志记录输出
	logger.severe("severe");
	logger.warning("warning");
	logger.info("info");
	logger.config("cofnig");
	logger.fine("fine");
	logger.finer("finer");
	logger.finest("finest");
}

自定义日志级别配置:

@Test
public void testLogConfig() throws Exception {
   
	// 1.创建日志记录器对象
	Logger logger = Logger.getLogger("com.itheima.log.JULTest");
	
	// 一、自定义日志级别
	// a.关闭系统默认配置
	logger.setUseParentHandlers(false);
	// b.创建handler对象
	ConsoleHandler consoleHandler = new ConsoleHandler();
	// c.创建formatter对象
	SimpleFormatter simpleFormatter = new SimpleFormatter();
	// d.进行关联
	consoleHandler.setFormatter(simpleFormatter);
	logger.addHandler(consoleHandler);
	// e.设置日志级别
	logger.setLevel(Level.ALL);
	consoleHandler.setLevel(Level.ALL);
	
	// 二、输出到日志文件
	FileHandler fileHandler = new FileHandler("d:/logs/jul.log");
	fileHandler.setFormatter(simpleFormatter);
	logger.addHandler(fileHandler);
	
	// 2.日志记录输出
	logger.severe("severe");
	logger.warning("warning");
	logger.info("info");
	logger.config("config");
	logger.fine("fine");
	logger.finer("finer");
	logger.finest("finest");
}

Logger之间的父子关系:

  • JUL中Logger之间存在父子关系,这种父子关系通过树状结构存储,JUL在初始化时会创建一个顶层RootLogger作为所有Logger父Logger,存储上作为树状结构的根节点。并父子关系通过路径来关联。
@Test
public void testLogParent() throws Exception {
   
	// 日志记录器对象父子关系
	Logger logger1 = Logger.getLogger("com.itheima.log");
	Logger logger2 = Logger.getLogger("com.itheima");
	
	System.out.println(logger1.getParent() == logger2);
	// 所有日志记录器对象的顶级父元素 class为java.util.logging.LogManager$RootLoggername为""
	System.out.println("logger2 parent:" + logger2.getParent() + ",name:" +
	logger2.getParent().getName());
	
	// 一、自定义日志级别
	// a.关闭系统默认配置
	logger2.setUseParentHandlers(false);
	// b.创建handler对象
	ConsoleHandler consoleHandler = new ConsoleHandler();
	// c.创建formatter对象
	SimpleFormatter simpleFormatter = new SimpleFormatter();
	// d.进行关联
	consoleHandler.setFormatter(simpleFormatter);
	logger2.addHandler(consoleHandler);
	// e.设置日志级别
	logger2.setLevel(Level.ALL);
	consoleHandler.setLevel(Level.ALL);
	
	// 测试日志记录器对象父子关系
	logger1.severe("severe");
	logger1.warning("warning");
	logger1.info("info");
	logger1.config("config");
	logger1.fine("fine");
	logger1.finer("finer");
	logger1.finest("finest");
}

日志的配置文件:

  • 默认配置文件路径:$JAVAHOME\jre\lib\logging.properties
@Test
public void testProperties() throws Exception {
   
	// 读取自定义配置文件
	InputStream in = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
	// 获取日志管理器对象
	LogManager logManager = LogManager.getLogManager();
	// 通过日志管理器加载配置文件
	logManager.readConfiguration(in);
	
	Logger logger = Logger.getLogger("com.itheima.log.JULTest");
	logger.severe("severe");
	logger.warning("warning");
	logger.info("info");
	logger.config("config");
	logger.fine("fine");
	logger.finer("finer");
	logger.finest("finest");
}
  • 配置文件:
## RootLogger使用的处理器(获取时设置)
handlers= java.util.logging.ConsoleHandler
# RootLogger日志等级
.level= INFO

## 自定义Logger
com.itheima.handlers= java.util.logging.FileHandler
# 自定义Logger日志等级
com.itheima.level= INFO
# 忽略父日志设置
com.itheima.useParentHandlers=false

## 控制台处理器
# 输出日志级别
java.util.logging.ConsoleHandler.level = INFO
# 输出日志格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

## 文件处理器
# 输出日志级别
java.util.logging.FileHandler.level=INFO
# 输出日志格式
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# 输出日志文件路径
java.util.logging.FileHandler.pattern = /java%u.log
# 输出日志文件限制大小(50000字节)
java.util.logging.FileHandler.limit = 50000
# 输出日志文件限制个数
java.util.logging.FileHandler.count = 10
# 输出日志文件 是否是追加
java.util.logging.FileHandler.append=true

日志原理解析:

  • 初始化LogManager
    ①LogManager加载logging.properties配置
    ②添加Logger到LogManager
  • 从单例LogManager获取Logger
  • 设置级别Level,并指定日志记录LogRecord
  • Filter提供了日志级别之外更细粒度的控制
  • Handler是用来处理日志输出位置
  • Formatter是用来格式化LogRecord的Java日志知识概括_第3张图片

LOG4J

LOG4J简介:

  • Log4j是Apache下的一款开源的日志框架,通过在项目中使用 Log4J,我们可以控制日志信息输出到控 制台、文件、甚至是数据库中。
  • 我们可以控制每一条日志的输出格式,通过定义日志的输出级别,可以 更灵活的控制日志的输出过程。方便项目的调试。
  • 官方网站

Log4j入门:

  • 建立maven工程
  • 添加依赖
<dependencies> 
	<dependency> 
		<groupId>log4jgroupId> 
		<artifactId>log4jartifactId> 
		<version>1.2.17version> 
	dependency> 
	<dependency> 
		<groupId>junitgroupId> 
		<artifactId>junitartifactId> 
		<version>4.12version> 
	dependency

你可能感兴趣的:(JavaEE,日志)