Web基础之日志

  日志在企业开发中有着不可或缺的作用,它可以用以记录用户操作、系统运行状态和错误信息。日志记录的好坏直接关系到系统出现问题时定位的速度。

  最开始的日志一般使用log4j,后来sun公司心有不甘,在jdk 1.4中加入了一个叫java.util.logging的日志包,简称jul。两种日志的api肯定是不同的,此时日志就出现了混乱。log4j的作者Ceki Gülcü就写了一个叫Jakarta Commons Logging的接口,简称jcl,来共同管理log4j和jul,并且jcl中提供了一个日志实现simplelog。接着又改良了下log4j,写出了logback。再后来Ceki Gülcü觉得jcl不好用(的确用问题),然后写了一个新的接口slf4j,来共同管理这些日志系统。接着呢Ceki Gülcü又觉得logj4性能不够了,又写了一个log4j2,。真是专注日志100年啊。

  所以他们之间的关系是这样的:

  其中slf4j并不提供日志实现,而是使用外观模式创建了一个接口,来统一这些日志的api。

  这也是为什么阿里规范上强制使用slf4j的原因:

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(Test.class);

slf4j + log4j / log4j2

  认识了之后接下来就是使用了,首先在maven中导入依赖:

<!-- log4j依赖,好像不更新了,我看版本还是12年的 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- slf4j的依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<!-- 告诉slf4j使用log4j,也就是绑定 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
<scope>test</scope>
</dependency>

  如果使用log4j2的话这么配:

<!-- log4j2的核心 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.1</version>
</dependency>
<!-- log4j2的api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.12.1</version>
</dependency>
<!-- slf4j绑定log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.1</version>
</dependency>
<!-- slf4j的依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>

  这里我将使用log4j2的xml和properties两种方式来简单配置。


  在resources目录下创建log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<!-- 输出源的配置:日志输出的目的地 -->
<Appenders>
<!--
Console标签;指定这是一个控制台输出源。
name:名称,需要在被引用才会生效
target: 控制台字体的颜色
SYSTEM_ERR:红色字体
SYSTEM_OUT:黑色字体
PatternLayout:布局,输出到控制台日志的格式。
-->
<Console name="myConsole" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %5level %logger{36} - %msg%n"/>
</Console> <!-- 文件输出源
fileName:指定保存日志的文件的名字和位置。
一般写绝对路径。
-->
<File name="myFile" fileName="D://demo.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File> <!--
多文件输出源:
fileName:实时记录日志的文件名和位置
filePattern : 文件封存的位置和格式
-->
<RollingFile name="rollingFile" fileName="D://demo2.log" filePattern="D://logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<!-- 多文件拆分的规则 -->
<Policies>
<!-- 基于时间的 此处interval属性值的单位是由filePattern属性中文件名时间精确的单位 决定的。 -->
<TimeBasedTriggeringPolicy interval="1" />
<!-- 基于文件大小的 -->
<SizeBasedTriggeringPolicy size="512 MB"/>
</Policies>
</RollingFile> </Appenders>
<Loggers>
<!-- 配置日志输出的级别的
将当前级别以及比当前级别高的消息进行输出。
-->
<Root level="trace">
<AppenderRef ref="myConsole"/>
<!-- 可以同时多种方式输出日志 -->
<AppenderRef ref="MyFile"/>
<AppenderRef ref="RollingFile"/> </Root>
</Loggers>
</Configuration>

  log4j使用properties方式:

# 配置输出源的   log4j.appender.输出源名=输出源的实现类
# 属性的配置 log4j.appender.输出源名.属性名=属性值
log4j.appender.a=org.apache.log4j.ConsoleAppender
log4j.appender.a.Target=System.out
log4j.appender.a.layout=org.apache.log4j.PatternLayout
log4j.appender.a.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n ### log4j.rootLogger=输出级别,输出源1,输出源2....
log4j.rootLogger=debug,a,file

log4j2的properties(参考):

status = warn
name = MyApp appender.console.type = Console
appender.console.name = consoleLogDemo
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = debug
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
appender.console.target = System_out appender.rolling.type = File
appender.rolling.name = fileLogDemo
appender.rolling.filter.threshold.type = ThresholdFilter
appender.rolling.filter.threshold.level = error
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d-%m%n
appender.rolling.append = true
appender.rolling.fileName = e:\\propertiesTest.log rootLogger.level = debug
rootLogger.appenderRef.consolelogdemo.ref = consoleLogDemo
rootLogger.appenderRef.filelogdemo.ref = fileLogDemo

输出格式参数为:

%p:输出日志信息的优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%d:输出日志时间点的日期或时间,默认格式为ISO8601,可以指定格式如:%d{yyyy/MM/dd HH:mm:ss,SSS}
%r:输出自应用程序启动到输出该log信息耗费的毫秒数
%t:输出产生该日志事件的线程名
%l:输出日志事件的发生位置,相当于%c.%M(%F:%L)的组合,包括类全名、方法、文件名以及在代码中的行数
%c:输出日志信息所属的类目,通常就是类全名
%M:输出产生日志信息的方法名
%F:输出日志消息产生时所在的文件名
%L:输出代码中的行号
%m:输出代码中指定的具体日志信息
%n:输出一个回车换行符,Windows平台为"rn",Unix平台为"n"
%x:输出和当前线程相关联的NDC(嵌套诊断环境)
%%:输出一个"%"字符

  这是几种常用的配置,如果觉得不够的话可以查看官方文档

  顺便这里推荐个讲的很详细的博客

打日志

在log4j2中可以这么用:

public class MyApp {
private static final Logger logger = LoggerFactory.getLogger(MyApp.class); public static void main(String[] args) {
logger.warn("Hello, {}","slf4j");
}
}

使用{}作为占位符,性能要比log4j直接字符串拼接性能好(毕竟字符串拼接的底层原理是创建StringBuilder)


至于一大堆jar包的关系如下:



关于log4j2的如下:

参考关于slf4j log4j log4j2的jar包配合使用的那些事

最新文章

  1. 02-C#入门(循环)
  2. C#实现把指定文件夹下的所有文件复制到指定路径下以及修改指定文件的后缀名
  3. GENERATED_UCLASS_BODY 和 GENERATED_BODY 区别
  4. oracle中的装换函数
  5. Android GPS 临近触发
  6. hdu 5150 Sum Sum Sum 水
  7. 老周的ABP框架系列教程 -》 一、框架理论初步学习
  8. sql快捷键
  9. ubuntu14.04中安装QuartusII9.1步骤
  10. C语言练习题_北理工的恶龙
  11. Fragment 常见问题
  12. VS Code开发调试.NET Core
  13. 【Android LibGDX游戏引擎开发教程】第08期:中文字体的显示和绘制(下)
  14. FPGA学习体会
  15. 51 nod 1211 数独 DLX
  16. Android5.1设备无法识别exFAT文件系统的64G TF卡问题
  17. AppBoxFuture(一): Hello Future!
  18. 【转载】C#处理空格和换行
  19. 测试那些事儿—LR脚本插入DOS命令
  20. struts2_struts类型转换

热门文章

  1. node.js中的事件轮询Event Loop
  2. Day11-G - Calendar Game HDU - 1079
  3. 「BOI2007」Mokia
  4. Lamda表达式学习笔记一
  5. Python Web 框架原理
  6. LeetCode中等题(一)
  7. 「译」forEach循环中你不知道的3件事
  8. 103、Java中String类之compareTo()方法
  9. 吴裕雄--天生自然JAVAIO操作学习笔记:压缩流与回退流
  10. ES6中 ,var,let和const的区别