Web基础之日志

时间:2019-08-24
本文章向大家介绍Web基础之日志,主要包括Web基础之日志使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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包的关系如下:

jcl-over-slf4j.jar  -->    (jcl    -> slf4j)    将Jakarta Commons Logging日志框架到 slf4j 的桥接  
jul-to-slf4j.jar    -->    (juc    -> slf4j)    将java.util.logging的日志桥接到 slf4j  
log4j-over-slf4j.jar-->    (log4j  -> slf4j)    将log4j 的日志,桥接到slf4j  
osgi-over-slf4j.jar -->    (osgi   -> slf4j)    将osgi环境下的日志,桥接到slf4j  
slf4j-android.jar   -->    (android-> slf4j)    将android环境下的日志,桥接到slf4j  
slf4j-api.jar       -->                         slf4j 的api接口jar包  
slf4j-ext.jar       -->                         扩展功能  
slf4j-jcl.jar       -->    (          slf4j -> jcl )          slf4j 转接到 Jakarta Commons Logging日志输出框架  
slf4j-jdk14.jar     -->    (          slf4j -> jul )          slf4j 转接到 java.util.logging,所以这个包不能和jul-to-slf4j.jar同时用,否则会死循环!!  
slf4j-log4j12.jar   -->    (          slf4j -> log4j)         slf4j 转接到 log4j,所以这个包不能和log4j-over-slf4j.jar同时用,否则会死循环!!  
slf4j-migrator.jar  -->                                       一个GUI工具,支持将项目代码中 JCL,log4j,java.util.logging的日志API转换为slf4j的写法  
slf4j-nop.jar       -->    (          slf4j -> null)          slf4j的空接口输出绑定,丢弃所有日志输出  
slf4j-simple.jar    -->    (          slf4j -> slf4j-simple ) slf4j的自带的简单日志输出接口

------------------------------------------------------

log4j2:

log4j-1.2-api.jar   -->    (log4j  -> log4j2)               将log4j 的日志转接到log4j2日志框架  
log4j-api.jar       -->                                     log4j2的api接口jar包  
log4j-core.jar      -->    (          log4j2 -> log4j-core) log4j2的日志输出核心jar包  
log4j-slf4j-impl.jar-->    (slf4j  -> log4j2)               slf4j 转接到 log4j2 的日志输出框架  (不能和 log4j-to-slf4j同时用)  
log4j-to-slf4j.jar  -->    (          log4j2 -> slf4j)      将 log4j2的日志桥接到 slf4j  (不能和 log4j-slf4j-impl 同时用) 

原文地址:https://www.cnblogs.com/lixin-link/p/11405843.html