日志文件
- 调试日志:软件开发中,我们经常需要去调试程序,做一些信息,状态的输出便于我们查询程序的运行状况。为了让我们能够更加灵活和方便的控制这些调试的信息,所有我们需要专业的日志技术。java中寻找bug会需要重现。调试也就是debug可以在程序运行中暂停程序运行,可以查看程序在运行中的情况。日志主要是为了更方便的去重现问题。
- 系统日志:系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统日志、应用程序日志和安全日志。
JAVA日志框架使用需要解决的问题
- 控制日志输出的内容和格式
- 控制日志输出的位置
- 日志优化
- 日志系统的维护
- 面向接口开发(日志的门面)
日志框架
1.JUL
- Java util logging是java原生的日志框架,不需要引用第三方类库
- JUL日志级别:
- SEVERE
- WARNING
- INFO (默认级别)
- CONFIG
- FINE
- FINER
- FINEST
- JUL日志特殊级别:
- OFF,可用来关闭日志记录。
- ALL,启用所有消息的日志记录。
package com.pang;
import org.junit.Test;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JULTest {
@Test
public void test() throws Exception{
//获取日志记录器对象,com.pang.Test是一个唯一标识
Logger logger = Logger.getLogger("com.pang.Test");
//日志记录输出
logger.info("pangjian");
//通用方法进行日志记录
logger.log(Level.INFO,"pangjian222");
//占位符方式输出变量值
String name = "pang";
Integer age = 18;
logger.log(Level.INFO,"我的姓名和年龄:{0},{1}",new Object[]{name,age});
}
@Test
public void Test1() throws Exception{
Logger logger = Logger.getLogger("Test1");
// 2.日志记录输出
logger.severe("severe");
logger.warning("warning");
logger.info("info");//JUL默认级别,当启动info级别,它以下的级别就不会进行输出
logger.config("cofnig");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
}
}
自定义JUL日志级别和自定义输出位置
@Test
public void Test2() throws Exception{
Logger logger = Logger.getLogger("Test2");
//关闭默认的日志级别
logger.setUseParentHandlers(false);
//自定义配置日志级别
//创建ConsoleHandler对象
ConsoleHandler consoleHandler = new ConsoleHandler();
//创建简单格式转换对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
//关联
consoleHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
//要输出到一个文件中
FileHandler fileHandler = new FileHandler("D:\springboot-study\JUL\jul.log");
fileHandler.setFormatter(simpleFormatter);
logger.addHandler(fileHandler);
//控制台日志级别会受logger的日志级别的限制
logger.setLevel(Level.ALL);
//控制台要输出的日志级别
consoleHandler.setLevel(Level.FINEST);
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("cofnig");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
}
通过读取配置文件去自定义JUL日志级别和自定义输出位置
#为 Handler 指定默认的级别(默认为 Level.INFO)。
java.util.logging.ConsoleHandler.level=INFO
# 指定要使用的 Formatter 类的名称(默认为 java.util.logging.SimpleFormatter)。
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# 为 Handler 指定默认的级别(默认为 Level.ALL)。
java.util.logging.FileHandler.level=INFO
# 指定要使用的 Formatter 类的名称(默认为 java.util.logging.XMLFormatter)。
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
# 指定要写入到任意文件的近似最大量(以字节为单位)。如果该数为 0,则没有限制(默认为无限制)。
java.util.logging.FileHandler.limit=50000
# 指定有多少输出文件参与循环(默认为 1)。
java.util.logging.FileHandler.count=1
# 为生成的输出文件名称指定一个模式。有关细节请参见以下内容(默认为 "%h/java%u.log")。
java.util.logging.FileHandler.pattern=C:/SSLog%u.log
# 指定是否应该将 FileHandler 追加到任何现有文件上(默认为 false)。
java.util.logging.FileHandler.append=true
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler
@Test
public void Test3() throws Exception{
//读取配置文件,通过类加载器
InputStream inputStream = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
//创建LogManager
LogManager logManager = LogManager.getLogManager();
//通过LogManager加载配置文件
logManager.readConfiguration(inputStream);
//创建日志记录器
Logger logger = Logger.getLogger("Test3");
}
JUL日志原理
- 应用要进行日志记录要调用logger对象
- logger对象要调用logManager对象去加载配置文件进行初始化
- 设置日志级别Level
- Filter提供了日志级别之外更细粒度的控制
- Handle是用来处理文件的输出位置的
- Formatter是用来格式化LogRecord的
2.Log4j
<!--需要导入的依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
- Log4j日志级别:
- FATAL (严重错误,一般会造成系统崩溃并终止运行)
- ERROR (错误信息,不会影响系统运行)
- WARN(警告信息,可能会发生问题)
- INFO (运行信息,数据库连接,IO操作等)
- Debug(默认级别,调试信息,一般在开发中使用,记录程序变量参数变化和传递)
- Trace(追踪信息)
public class Log4jTest {
@Test
public void test() throws Exception{
//初始化配置信息
BasicConfigurator.configure();
//获取日志记录器对象
Logger logger = Logger.getLogger(Log4jTest.class);
//日志记录输出
logger.info("pangjian");
}
}
Log4j中有三个主要的组件,它们分别是 Loggers、Appender和Layout。
- Loggers是日志记录器,描述它可以改变日志记录的表现。 Log4j 允许开发人员定义多个Loggers,每个Loggers拥有自己的名字。有一个Loggers称为Root,可以通过Logger.getRootLogger()方法获得。 其它Logger通过Logger.getLogger(String name)方法获得。
- Appender是输出端,用来指明将所有的log信息存放到什么地方,Log4j中支持多种appender,如 console、files、GUI components、NT Event Loggers等。一个Logger可以拥有多个Appender。
- Layout是日志格式化器,作用是控制Log信息的输出方式,也就是格式化输出的信息。
使用配置文件加载
public class Log4jTest {
@Test
public void test() throws Exception{
//开启内置的日志对象
//LogLog.setInternalDebugging(true);
//获取日志记录器对象
Logger logger = Logger.getLogger(Log4jTest.class);
logger.fatal("fatal");
logger.error("error");
logger.warn("warn");
logger.debug("debug");
logger.trace("trace");
}
}
配置文件 log4j.properties
# 指定RootLogger 顶级父元素默认的配置信息
# 指定日志级别=trace,使用 apeender 为console
log4j.rootLogger = trace,console
# 指定log4j.appender.(输出端对象)
log4j.appender.console= org.apache.log4j.ConsoleAppender
# 指定输出格式log4j.appender.console.layout
# 值还有(org.apache.log4j.HTMLLayout或org.apache.log4j.xml.XMLLayout或org.apache.log4j.PatternLayout或org.apache.log4j.SimpleLayout)
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
%n - 换行
%m - 日志内容
%p - 日志级别(FATAL, ERROR, WARN, INFO, DEBUG or custom)
%r - 程序启动到现在的毫秒数
%% - percent sign in output
%t - 当前线程名
%d - 日期和时间,常用的格式有 %d{DATE}, %d{ABSOLUTE}, %d{HH:mm:ss,SSS},
%F - java源文件名
%L - java源码行数
%C - java类名,%C{1} 输出最后一个元素
%M - java方法名
%l - 同 %F%L%C%M
log4j.appender.console.layout.conversionPattern = [%p]%r %c %t %F %L %d{yyyy年MM月dd日 HH:mm:ss.SSS} %m%n
# [FATAL]2 Log4jTest main Log4jTest.java 22 2020Äê12ÔÂ12ÈÕ 17:31:59.558 fatal
写入数据库的配置
log4j.rootLogger = trace,logDB
#写入mysql
log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender
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=root
log4j.appender.logDB.sql=insert into pang_log (create_time,log) VALUES ('%d{yyyy-MM-dd hh:mm:ss}', '%c %p %m %n')
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
3.Logback
Logback主要分为三个模块:
- logback-core:其它两个模块的基础模块
- logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API
- logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能
logback会依次读取以下类型配置文件;
- logback.groovy
- logback-test.xml
- logback.xml 如果均不存在会采用默认配置
日志门面
1.JCL
<!--需要导入的依赖-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
- 全称Jakarta commons logging,是Apache提供的一个通用日志API
- 它是为所有的Java日志框架提供一个统一的接口,它自身也提供一个日志实现,但功能弱,一般不会单独使用它。
- JCL有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)
- 作用是为了做到JUL升级到Log4j的统一
2.SLF4J
- 当我们的系统变的更加复杂的时候,我们的日志就容易发生混乱。随着系统开发的进行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制。就算我们强制要求所有的模块使用相同的日志框架,系统中也难以避免使用其他类似spring.mybatis等其他的第三方框架,它们依赖于我们规定不同的日志框架,而且他们自身的日志系统就有着不一致性,依然会出来日志体系的混乱。所以我们需要借鉴JDBC的思想,为日志系统也提供一套门面,那么我们就可以面向这些接口规范来开发,避免了直接依赖具体的日志框架。这样我们的系统在日志中,就存在了日志的门面和日志的实现。
- 常见的日志门面:JCL,slf4j
如果使用log4j实现日志框架和slf4j日志门面,要导入适配器坐标
<!--绑定 log4j 日志实现,需要导入适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
package com.pang;
import org.apache.log4j.Logger;
import org.junit.Test;
public class LogTest {
public static final Logger LOGGER = Logger.getLogger(LogTest.class);
@Test
public void test01(){
LOGGER.info("hello log4j");
/* 一开始我们用的是Log4j日志实现框架,
现在我们要升级迭代成logback,
首先我们要去除Maven的log4j坐标,
加上logback的,然后导入桥接器坐标,(记得把适配器去掉,不然会报栈溢出异常)
然后源代码不用变而日志实现框架变成了logback*/
}
}
桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现
- 1.先去除之前老的日志框架的依赖
- 2.添加SLF4J]提供的桥接组件
- 3.为项目添加SLF4J的具体实现
<!-- 桥接器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>