按照基本的定义,日志即是对程序运行过程中关键事件的记录;大体日志分为运行日志和开发日志,运行日志在业务层面记录一些关键事件,为后面的跟踪运行提供帮助,而开发日志大多数时候是调试日志,根据事件流的输出来调试程序;因为开发人员本身的关注领域,运行日志可能制作的比较少,难以达到跟踪业务流的作用,而即使是开发日志,因为开发的调试有各种技巧,即使是跟踪事件流,使用println也比日志配置简单多了,这是一个投资回报的问题,而人经常性的是短视的,调试可能在这些人眼里根本不需要认真对待,没有前期的事件记录规划,随着系统规模膨胀,执行流增多,执行事件保障,这时候没有一种合理的“开关”机制来选择查看感兴趣事件流,那结局是明晰的,日志不止提供了一种树形的开关结构,它还有灵活的输出控制,在Java常用日志框架Log4J还提供了JMX等接口,可以通过管理面板来监控和修改日志记录行为,这无疑是非常诱人的。
大体上Java体系中比较常用的日志框架如下
日志框架 |
支持日志级别 |
Log4J |
FATAL ERROR WARN INFO DEBUG TRACE |
Java Logging API |
SEVERE WARNING INFO CONFIG FINE FINER FINEST |
Apache Commons Logging |
FATAL ERROR WARN INFO DEBUG TRACE |
SLF4J |
ERROR WARN INFO DEBUG TRACE |
Logback |
ERROR WARN INFO DEBUG TRACE |
Jboss logging |
FATAL ERROR WARN INFO DEBUG TRACE |
基本上,日志级别是很相似的,这不仅仅是Java生态范围内,整个编程行业应该都有共识,通过日志级别来标记事件的轻重缓急,我们可以通过这个条件进行过滤,显示我们感兴趣的内容,关于日志级别之间的相互关系,这个比较简单,这里就不再说了。
优秀的编程设计原则中有一条“依赖倒置”,要依赖抽象,不要依赖具体,具体的实践就是面向接口设计了,优秀的项目都会定义高层次抽象,通过封装隐藏多余的信息,这样在代码变动或者想不修改原有代码扩展的时候(开闭原则),能够相对容易的满足这些需求,而这些日志框架设计结构中则充分发挥了面向接口设计的优良传统,日志框架的核心接口是Logger类(接口),其他部分则是围绕此类(接口)展开,这里我们看两个定义例子,SLF4J的Logger定义如下
Apache Commons Logging的Log定义如下
因为其他的日志框架实在都太“重量级”了,方法太多,这里就不贴出定义了,日志框架定义了基本的接口,通过提供一个Facade,而后端由谁去实现就不那么重要了,这里面Apache Commons Logging、SLF4J、Jboss logging都容许其他后端实现为别的日志框架(大部分为Java Logging 、Log4J,差异化的部分在讲这些日志框架的时候再详细叙述),如何将Facade的请求转为后端可识别请求,知道一点设计模式的人应该马上想到适配器模式,这里,我们想给出几个日志框架如何实现这个接口适配的解决方法,我们一一道来。
Apache Commons Logging
这是标准的适配器模式,没有什么好讲的,Apache Commons Logging提供的实际工作类如下
这里面我们比较熟悉的是JDK自带的Java Logging和Log4J,其他几个因为不怎么常用就不说了,关于Apache Commons Logging如何选择具体的实现类,这个可以从LogFactory的实现类中查找到逻辑,逻辑代码如下:
因为代码比较长,这里只贴出关键部分逻辑,可以看得很清楚,用户通过配置文件指定后端实现,反之通过查找类路径来选择具体实现类。
SLF4J
SLF4J也存在上述类似的适配方式,这里我们给出SLF4J有些不同的bridge方式,其形式类似适配,如下
这个结构有些复杂,这里是SLF4J到Log4J的桥接,我们看到Log4jLoggerFactory提供了类似的适配功能,这种方式的好处,按照官方文档的说法是提供了编译时绑定,排除了运行时的探测方式,性能会好一些,看着这图有些抽象,这里给出一个具体的应用场景,如下
Spring日志配置
Spring项目使用了Apache Commons Logging日志框架,因为该日志框架比较老旧,我们一般使用Log4J作为其后端实现,通过上面的介绍,我们知道只要将Log4J放入ClassPath中就可以了,如果使用maven,在依赖中添加Log4J就可以了,这里如何使用SLF4J的桥接,结果有些复杂,首先需要去掉Apache Commons Logging依赖,然后添加Spring到SLF4J的Bridge,然后使用一个后端实现Log4J,因此在添加一个SLF4J到Log4J的Bridge,最后是Log4J实现,用maven管理的话,结果如下
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.2.BUILD-SNAPSHOT</version>
<exclusions>
<exclusion>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.2.BUILD-SNAPSHOT</version>
<exclusions>
<exclusion>
<!--排除commons-logging依赖-->
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<!--commons-logging到SLF4J之间的Bridge-->
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<!--SLF4J接口-->
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<!--SLF4J到Log4J之间的Bridge-->
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<!--Log4J实现-->
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
这种方式比较复杂,因为在平时工作中没有用过SLF4J日志框架,所以这种方式看起来有些多此一举,但考虑到SLF4J作为事实上的Java Logging标准,如何更加有效的在不同前端Facade Logger接口到后端实现之间自由适配,SLF4J提供了一个很好的形式,如下
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
这种方式比较复杂,因为在平时工作中没有用过SLF4J日志框架,所以这种方式看起来有些多此一举,但考虑到SLF4J作为事实上的Java Logging标准,如何更加有效的在不同前端Facade Logger接口到后端实现之间自由适配,SLF4J提供了一个很好的形式,如下
前端到后端的适配能够更加方便,这确实是一个非常有趣的想法。
Jboss logging
事实上这个日志框架貌似不是很出名,但是基本上Jboss系的产品、框架都会使用这个日志框架,因此,我们也需要好好的学习一下,该日志结构如下
这里的也是一种适配器方式,只是最终暴露的使用接口是特定的LoggerProvider,查找特定日志框架的LoggerProvider是由LoggerProviders提供的,代码如下
代码显示在LoggerProviders加载时就开始查找特定LoggerProvider,具体查找逻辑如下
上面看到的是通过配置文件查找
后半部分是根据ClassPath查找。
Jboss logging比较奇特的地方是其提供了一个JBossLogManagerLogger,这个Logger使用的内部Logger为JBoss容器托管日志管理器,这个可以注意一下
上面分析了日志框架前端Facade和后端实现如何适配,现在我们选取一个具体的框架来给出一些常见配置,希望能够对大家有用,我们选取的就是Log4J,因为其他框架我使用的频率比较低,二来因为日志框架的概念都类似,熟悉了一个其他的应该也可以快速掌握,下面让我们展开对Log4J的论述。
Log4J来自于Apache社区,是目前应用最广的一个日志框架,官方提供了两个大的版本,为Log4J 1.x和Log4J 2.x,这两个主版本连官网链接都不一样,看来Log4J 2.x应该针对前一版本问题而重新设计,以至于导致和前一版本的不兼容,但因为Log4J 1.x普及的根深蒂固,很多日志框架没有及时跟上对Log4J 2.x后端的支持,Log4J 2.x彻底替换掉Log4J 1.x还有很长的一段路要走。
这里我们给出的是Log4J 1.x的版本介绍,关于Log4J 2.x,我们有机会再进行探索;在Log4J的体系里,有三个最重要的概念:Logger、Appender、Layout,Logger即为日志写入入口,Appender定义了将日志时间输出的策略,Layout给出输出的格式,三者的关系如下
因为Log4J中有Category的概念,这里我把它看成一个Logger,三者的关系这样看起来比较明显,Logger接收日志记录,Appender接收Logger发来的日志事件,然后根据Layout定义格式进行输出,这里没有什么好讲的,我们开始讲如何配置。
Log4J 1.x有两种配置方式,一种是Java properties文件,一种是XML,第一种用的比较多一些,这个和Log4J 2.x正好相反,配置文件配置主要配置上面三个对象,配置Logger,然后配置使用哪种具体Appender,然后定义格式,看一个例子,如下:
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
如上,一定要定义的Logger是root Logger,这里构成了一个类似树形结构,顶部节点定义默认行为,子节点可以对行为进行修改定制,这里定义rootLogger使用DEBUG级别,使用A1这个Appender,注意这里的写法:第一个为日志级别,后面可以跟很多个Appender;线面定义了这个具体的Appender A1,我们看到其使用的是ConsoleAppender,后面我们给这个Appender指定Layout,这里的Layout为PatternLayout,这个比较常用,最后一行定义了日志格式,这种格式写法类似于printf那种格式化字符串,里面的占位符构成为"%[格式修饰符]日志含义符号"(中括号里的为可选),格式修饰符比较简单,“-”代表靠左对其,不加就是靠右对其,后面的数字代表了该日志内容部分的最少显示长度,如果有“.”,"."之后为该日志内容最长显示长度,超过长度会进行裁短;后面的日志含义符号如下表
符号 |
意义 |
c(小写) |
输出日志的类别 |
C(大写) |
输出触发日志请求的类的全称 |
d |
输出日志事件的日期时间 |
F |
输出日志请求类文件名 |
l |
输出请求日志调用位置信息 |
L |
输出请求日志代码行号 |
m |
输出应用提供的日志消息 |
M |
输出请求日志方法名 |
n |
输出平台特定的行分隔符 |
p |
输出日志级别 |
r |
输出从程序启动到现在的毫秒数 |
t |
输出生成这个日志事件线程的名字 |
这里在给出一个例子
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) - %m%n
log4j.logger.org.apache.log4j.examples=INFO, A2
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=${user.home}/test
#如果test文件存在就先清空它
log4j.appender.A2.Append=false
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%5r %-5p [%t] %c{2} - %m%n
上面的例子稍微复杂一些,这里设定了一个rootLogger,并制定了其日志级别和Appender,后面定义了一个名为org.apache.log4j.examples 的Logger,这个Logger又定义了日志级别和Appender,通过这里的例子可以看出Log4J这种树形的关系具有足够的灵活性。
关于XML的配置,这里给出一个实例,大家可以根据上面对properties的理解来配置XML,如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<category name="org.apache.log4j.xml">
<priority value="info" />
</category>
<Root>
<priority value ="debug" />
<appender-ref ref="STDOUT" />
</Root>
</log4j:configuration>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</layout>
</appender>
<category name="org.apache.log4j.xml">
<priority value="info" />
</category>
<Root>
<priority value ="debug" />
<appender-ref ref="STDOUT" />
</Root>
</log4j:configuration>
这里的category如前面分析结构时所说,可以认为其就是一个Logger,这个结构也比较一目了然,没有什么要讲的,大家可以根据自己的实际需要来调整结构。
这里还有个问题是配置文件命名的问题,默认情况下,如果配置文件命名为log4j.xml或log4j.properties时Log4J会自动加载,如果因为某种原因不能这样命名,那么久需要编码来实现配置的加载了,代码片段如下
String resource =
"/app/resources/example.properties";
URL configFileResource =
InitUsingPropertiesFile.class.getResource(resource);
PropertyConfigurator.configure(configFileResource);
日志框架就写这些吧,希望能对大家有所帮助,对单一常用日志框架的详细解析,有机会在写吧
相关推荐
本文将对JAVA日志框架适配中可能出现的冲突进行分析和解决,涵盖日志框架的基本概念、常见的冲突原因和解决方案。 日志框架的基本概念: 在JAVA中,日志框架可以分为两种:日志抽象/门面和日志实现。日志抽象/门面...
下面我们将详细介绍一些常见的Java框架和它们的配置文件。 1. **Spring框架**:Spring以其依赖注入(DI)和面向切面编程(AOP)而闻名。其核心配置文件通常是`applicationContext.xml`,在这里,你可以定义bean的...
Java日志数据脱敏是为了确保在记录日志时,敏感信息不会被泄露,从而保护用户隐私和企业数据安全。在本文中,我们将探讨如何在Java应用程序中实现这一目标。 首先,理解数据脱敏的重要性至关重要。在处理包含敏感...
本文将简要介绍两个常见的Java框架:Struts和Spring。 **Struts框架** Struts是一个基于Sun J2EE平台的MVC(Model-View-Controller)框架,它的核心组件包括: 1. **模型(Model)**:在Struts中,模型通常是一个...
在Android开发中,自定义日志框架是一种常见的实践,它可以帮助开发者更好地监控应用程序的运行状态,定位和解决问题。本文将详细介绍如何在Android环境下构建自己的日志框架,以及这样做的好处。 首先,Android...
Java SSM框架整合是Java Web开发中常见的技术组合,它由Spring、Spring MVC和MyBatis三个组件构成,为开发者提供了强大的数据访问和业务逻辑处理能力。本项目"JavaSSM框架整合demo"是一个示例工程,旨在帮助初学者...
常见的Java分布式ETL框架有: 1. **Apache Nifi**:提供了一个图形化的用户界面,用于定义数据流的处理过程,支持动态调整和监控,易于扩展和集成。 2. **Apache Beam**:一个统一的编程模型,支持批处理和流处理...
Java开发框架Demo主要展示了如何利用Struts2、Spring3和JDBC这三个核心技术构建一个基础的Java应用程序。这个项目对于初学者来说是一个很好的学习资源,它能够帮助理解如何将这些流行框架整合在一起,实现MVC(Model...
本文将详细介绍几个常见的Java日志组件,包括它们的特点、使用场景和配置方法。 首先,让我们来看一下`log4j`。它是Apache组织的一个开源项目,广泛应用于Java应用程序中。Log4j提供了丰富的日志级别(如DEBUG, ...
在实际应用中,常见的日志框架如Java领域的Log4j、Logback,Python的logging模块,以及Node.js的winston等。这些框架提供了灵活的配置选项,允许我们指定日志的存储位置(如文件、数据库、网络等)、格式化方式、...
Log4j 框架是 Apache 的开源日志框架。Log4j 框架的主要特点包括: * 日志记录:Log4j 框架可以将程序中的日志信息输出到控制台和文件中记录日志。 * 可配置性:Log4j 框架可以根据需要配置日志记录的格式和级别,...
Java 项目框架源码是开发Web应用程序的一种常见实践,它为开发者提供了结构化的代码组织方式和高效的开发流程。本项目源码主要基于SpringMVC框架,这是一个强大的、灵活的Java Web开发框架,由Spring社区维护,广泛...
根据提供的文件信息:“JAVA开源框架学习文档”,我们可以深入探讨与JAVA开源框架相关的多个知识点,包括但不限于框架的选择、安装配置、核心概念以及实际应用场景等。由于提供的具体内容为空,本篇文章将基于标题和...
Java日志库是Java开发中不可或缺的一部分,它们用于记录应用程序的运行时信息,帮助开发者调试、追踪错误和监控系统性能。Log4j是其中最著名和广泛使用的日志框架之一,尤其是在早期的Java项目中。这个"java日志jar...
本篇主要介绍一些基础的日志概念、常用的Java日志框架以及如何有效地解决Java日志问题。 1. 日志的重要性 日志在软件开发中起到关键作用,它可以记录程序的执行流程,便于排查问题,特别是在分布式系统中,日志...
2. **常见日志框架** - **JCL (Jakarta Commons Logging)**:早期被广泛使用,但由于其设计问题和维护停滞,现在已被更现代的框架取代。 - **SLF4J (Simple Logging Facade for Java)**:作为日志抽象层,它提供了...
Spring Boot是基于Spring的快速开发工具,它默认配置了很多常见的Java Web开发需求,简化了新项目的初始化和配置过程。 6. **Spring Security**:作为Spring的扩展,Spring Security提供了一套完整的安全解决方案,...
总之,Java发送Syslog日志涉及到网络编程、日志框架和第三方库的使用,以及对Syslog协议的理解。通过这些工具和知识,我们可以构建出高效、可靠的日志管理系统,提升系统的可监控性和故障排查能力。
首先,Java中常见的日志框架有Log4j、SLF4J(Simple Logging Facade for Java)和Java Util Logging (JUL)。这些框架提供了一种结构化和可配置的方式来管理应用程序的日志记录。 1. **Log4j**:由Apache开发的日志...
在提供的压缩包中,包含的PDF电子书和CHM帮助文档很可能是对这三个框架的深入解析和教程,涵盖了它们的基本概念、配置、使用方法以及常见问题的解决方案。这些资源对于初学者来说,是学习和理解三大框架的宝贵资料,...