前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >走进Java接口测试之日志框架Logback

走进Java接口测试之日志框架Logback

作者头像
高楼Zee
发布于 2019-07-17 09:54:32
发布于 2019-07-17 09:54:32
1K00
代码可运行
举报
文章被收录于专栏:7DGroup7DGroup
运行总次数:0
代码可运行

引言

对于一个成熟的接口测试框架,日志管理这个是必不可少的。在开发和调试阶段,日志可以帮助我们更快的定位问题;而在测试的运维过程中,日志系统又可以帮助我们记录大部分的异常信息,通常很多测试框架会通过收集日志信息来对接口测试状态进行实时监控预警。

前言

Spring Boot 在所有内部日志中使用 CommonsLogging,但是默认配置也提供了对常用日志的支持,如: Java.Util.LoggingLog4J, Log4J2Logback。每种 Logger 都可以通过配置使用控制台或者文件输出日志内容。

LogBack、Slf4j和Log4j之间的关系

Slf4j 是 The Simple Logging Facade for Java的简称,是一个简单日志门面抽象框架,它本身只提供了日志 Facade API和一个简单的日志类实现,一般常配合Log4j,LogBack,java.util.logging使用。Slf4j作为应用层的Log接入时,程序可以根据实际应用场景动态调整底层的日志实现框架(Log4j/LogBack/JdkLog等)。

LogBack和Log4j都是开源日记工具库,LogBack 是 Log4j 的改良版本,比 Log4j 拥有更多的特性,同时也带来很大性能提升,同时天然支持SLF4J。

LogBack 官方建议配合 Slf4j 使用,这样可以灵活地替换底层日志框架。

TIPS:为了优化log4j,以及更大性能的提升,Apache基金会已经着手开发了log4j 2.0, 其中也借鉴和吸收了logback的一些先进特性。

默认日志Logback

默认情况下,Spring Boot 会用 Logback 来记录日志,并用 INFO 级别输出到控制台。在运行应用程序和其他例子时,你应该已经看到很多INFO级别的日志了。

从上图可以看到,日志输出内容元素具体如下:

  • 时间日期:精确到毫秒
  • 日志级别:ERROR, WARN, INFO, DEBUG or TRACE
  • 进程 ID
  • 分隔符:--- 标识实际日志的开始
  • 线程名:方括号括起来(可能会截断控制台输出)
  • Logger名:通常使用源代码的类名
  • 日志内容

配置详解

添加日志依赖

假如maven依赖中添加了 spring-boot-starter-logging

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

那么,我们的Spring Boot应用将自动使用 logback 作为应用日志框架,Spring Boot 启动的时候,由 org.springframework.boot.logging.Logging-Application-Listener根据情况初始化并使用。

但是呢,实际开发中我们不需要直接添加该依赖,你会发现 spring-boot-starter其中包含了 spring-boot-starter-logging,该依赖内容就是 Spring Boot 默认的日志框架 logback

配置文件

Spring Boot 官方推荐优先使用带有 -spring的文件名作为你的日志配置(如使用 logback-spring.xml,而不是 logback.xml),命名为 logback-spring.xml的日志配置文件,spring boot 可以为它添加一些 spring boot 特有的配置项(下面会提到)。并且放在 src/main/resources 下面即可。

配置文件 logback-spring.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 日志根目录-->
    <springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="./logs/spring-boot-logback"/>

    <!-- 日志级别 -->
    <springProperty scope="context" name="LOG_ROOT_LEVEL" source="logging.level.root" defaultValue="DEBUG"/>

    <!--  标识这个"STDOUT" 将会添加到这个logger -->
    <springProperty scope="context" name="STDOUT" source="log.stdout" defaultValue="STDOUT"/>

    <!-- 日志文件名称-->
    <property name="LOG_PREFIX" value="spring-boot-logback" />

    <!-- 日志文件编码-->
    <property name="LOG_CHARSET" value="UTF-8" />

    <!-- 日志文件路径+日期-->
    <property name="LOG_DIR" value="${LOG_HOME}/%d{yyyyMMdd}" />

    <!--对日志进行格式化-->
    <property name="LOG_MSG" value="- | [%X{requestUUID}] | [%d{yyyyMMdd HH:mm:ss.SSS}] | [%level] | [${HOSTNAME}] | [%thread] | [%logger{36}] | --> %msg|%n "/>

    <!--文件大小,默认10MB-->
    <property name="MAX_FILE_SIZE" value="50MB" />

    <!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
    <property name="MAX_HISTORY" value="10"/>

    <!--输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 输出的日志内容格式化-->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>${LOG_MSG}</pattern>
        </layout>
    </appender>

    <!--输出到文件-->
    <appender name="0" class="ch.qos.logback.core.rolling.RollingFileAppender">
    </appender>

    <!-- 定义 ALL 日志的输出方式:-->
    <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志文件路径,日志文件名称-->
        <File>${LOG_HOME}/all_${LOG_PREFIX}.log</File>

        <!-- 设置滚动策略,当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!--日志文件路径,新的 ALL 日志文件名称,“ i ” 是个变量 -->
            <FileNamePattern>${LOG_DIR}/all_${LOG_PREFIX}%i.log</FileNamePattern>

            <!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
            <MaxHistory>${MAX_HISTORY}</MaxHistory>

            <!--当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB-->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>

        </rollingPolicy>

        <!-- 输出的日志内容格式化-->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>${LOG_MSG}</pattern>
        </layout>
    </appender>

    <!-- 定义 ERROR 日志的输出方式:-->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 下面为配置只输出error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <OnMismatch>DENY</OnMismatch>
            <OnMatch>ACCEPT</OnMatch>
        </filter>
        <!--日志文件路径,日志文件名称-->
        <File>${LOG_HOME}/err_${LOG_PREFIX}.log</File>

        <!-- 设置滚动策略,当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!--日志文件路径,新的 ERR 日志文件名称,“ i ” 是个变量 -->
            <FileNamePattern>${LOG_DIR}/err_${LOG_PREFIX}%i.log</FileNamePattern>

            <!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
            <MaxHistory>${MAX_HISTORY}</MaxHistory>

            <!--当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB-->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>

        <!-- 输出的日志内容格式化-->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${LOG_MSG}</Pattern>
        </layout>
    </appender>

    <!-- additivity 设为false,则logger内容不附加至root ,配置以配置包下的所有类的日志的打印,级别是 ERROR-->

    <logger name="org.springframework"     level="ERROR" />
    <logger name="org.apache.commons"      level="ERROR" />
    <logger name="org.apache.zookeeper"    level="ERROR"  />
    <logger name="com.alibaba.dubbo.monitor" level="ERROR"/>
    <logger name="com.alibaba.dubbo.remoting" level="ERROR" />

    <!-- ${LOG_ROOT_LEVEL} 日志级别 -->
    <root level="${LOG_ROOT_LEVEL}">

        <!-- 标识这个"${STDOUT}"将会添加到这个logger -->
        <appender-ref ref="${STDOUT}"/>

        <!-- FILE_ALL 日志输出添加到 logger -->
        <appender-ref ref="FILE_ALL"/>

        <!-- FILE_ERROR 日志输出添加到 logger -->
        <appender-ref ref="FILE_ERROR"/>
    </root>

</configuration>

配置文件 application.yml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server:
  port: 8888  # 端口号

logging:
  path: ./logs/zuozewei
  level:
    root: info #日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出

日志会每天新建一个文件夹,日文文件配置的每 50MB,一个文本文件,超过新写入一个

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
文件夹:20181228
文件夹内容:all_spring-boot-logback0.log 
文件夹内容:all_spring-boot-logback1.log
文件夹内容:all_spring-boot-logback2.log

文件夹内容:err_spring-boot-logback0.log

多环境日志输出

根据不同环境(prod:生产环境,test:测试环境,dev:开发环境)来定义不同的日志输出,在 logback-spring.xml 中使用 springProfile 节点来定义,方法如下:

文件名称不是 logback.xml,想使用 spring 扩展 profile 支持,要以 logback-spring.xml 命名

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- 生产环境生效 -->
    <springProfile name="prod">
        <root level="error">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>


    <!-- 测试和开发环境日志级别为INFO/并且记录日志文件 -->
    <springProfile name="dev,test">
        <!-- 日志输出级别 -->
        <root level="INFO">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

可以启动服务的时候指定 profile (如不指定使用默认),如指定 prod 的方式为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java -jar xxx.jar –spring.profiles.active=prod

单元测试

此处我选择使用 lombok效率插件,所以只需要 @Slf4j注解即可简化 privateLoggerlogger=LoggerFactory.getLogger(this.getClass())的写法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class LogbackdemoApplicationTests {

    @Test
    public void contextLoads() {
        log.info("输出info");
        log.debug("输出debug");
        log.error("输出error");
    }

}

生成的日志:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- | [] | [20181228 22:53:20.756] | [INFO] | [192.168.1.18] | [main] | [c.z.l.LogbackdemoApplicationTests] | --> Starting LogbackdemoApplicationTests on 192.168.1.18 with PID 82507 (started by apple in /Users/apple/Downloads/Springboot-logback-demo)|
- | [] | [20181228 22:53:20.762] | [INFO] | [192.168.1.18] | [main] | [c.z.l.LogbackdemoApplicationTests] | --> No active profile set, falling back to default profiles: default|
- | [] | [20181228 22:53:21.590] | [INFO] | [192.168.1.18] | [main] | [c.z.l.LogbackdemoApplicationTests] | --> Started LogbackdemoApplicationTests in 1.69 seconds (JVM running for 3.525)|
- | [] | [20181228 22:53:21.955] | [INFO] | [192.168.1.18] | [main] | [c.z.l.LogbackdemoApplicationTests] | --> 输出info|
- | [] | [20181228 22:53:21.955] | [ERROR] | [192.168.1.18] | [main] | [c.z.l.LogbackdemoApplicationTests] | --> 输出error|

工程目录

总结

到此为止终于介绍完 Logback日志框架了,平时使用的时候推荐用自定义 logback-spring.xml来配置,代码中使用日志也很简单,类里面添加 privateLoggerlogger=LoggerFactory.getLogger(this.getClass()); 即可,如果使用 lombok效率插件需要 @Slf4j注解。

本文代码:

https://github.com/7DGroup/Java-API-Test-Examples

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 7DGroup 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
初谈Linux多线程--线程控制
在Linux中,线程执行的是进程代码的一部分,也就是说,线程是进程的实体,可以看作是进程内的一个执行单元,我们将这些不同的执行单元称之为轻量级进程,不同线程之间可以通过共享内存来进行通信。
南桥
2024/08/02
2230
初谈Linux多线程--线程控制
线程(一)线程概念+线程控制
pthread_t 到底是什么类型呢?取决于实现。对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。
海盗船长
2020/08/27
1.1K0
linux网络编程之posix 线程(二):线程的属性和 线程特定数据 Thread-specific Data
本文介绍了多线程和多进程的区别,从多个方面进行对比,包括资源占用、调度开销、并发度、线程局部存储、线程间通信、资源竞争、性能评估等方面。同时,还介绍了多线程在操作系统、数据库、网络编程、高性能计算等领域的应用,以及多线程技术的未来展望。
s1mba
2017/12/28
1.1K0
linux网络编程之posix 线程(二):线程的属性和 线程特定数据 Thread-specific Data
《Android 创建线程源码与OOM分析》
| 导语 企鹅FM近几个版本的外网Crash出现很多OutOfMemory(以下简称OOM)问题,Crash的堆栈都在Thread::start方法上。该文详细分析了发生原因。 ---- 有两种栈: 出现次数最多的一种,称之为 堆栈A。 java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory java.lang.Thread.nativeCreate(Native Method)
腾讯Bugly
2018/03/23
4.7K0
多线程编程C语言版
什么是多线程,提出这个问题的时候,我还是很老实的拿出操作系统的书,按着上面的话敲下“为了减少进程切换和创建开销,提高执行效率和节省资源,我们引入了线程的概念,与进程相比较,线程是CPU调度的一个基本单位。”
DeROy
2021/11/16
3.7K0
多线程编程C语言版
Linux之多线程(下)——线程控制
与线程有关的函数构成了一个完整的系列,大多数函数名都是以“pthread_”为开头的,要使用这些函数需要引入头文件pthread.h。链接这些线程函数库需要使用编译器命令的-lpthread选项。
摘星
2023/10/15
7220
Linux之多线程(下)——线程控制
并发问题解密:探索多线程和锁机制
描述: pthread_create()函数在调用进程中启动一个新线程。新线程通过调用start_routine()开始执行;arg作为start_routine()的唯一参数传递。
Lion 莱恩呀
2024/09/26
2800
并发问题解密:探索多线程和锁机制
【Linux篇】程控制全揭秘:如何通过 POSIX 库管理线程的生命周期
站在不同的用户角度线程的说法也不同,在用户角度,就称为线程;在操作系统角度称为轻量级进程(也叫做lwp)。
熬夜学编程的小王
2025/05/02
1110
【Linux篇】程控制全揭秘:如何通过 POSIX 库管理线程的生命周期
Linux线程控制
本篇我将学习如何使用多线程。要使用多线程,因为Linux没有给一般用户直接提供操作线程的接口,我们使用的接口,都是系统工程师封装打包成原生线程库中的。那么就需要用到原生线程库。因此,需要引入-lpthread,即连接原生线程库。
二肥是只大懒蓝猫
2023/03/30
1.1K0
Linux线程控制
【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
GG Bond1
2025/02/19
1530
【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解
线程的概念及linux下线程库相关函数的使用
1.线程的概念 在linux操作系统下,线程的本质任然是进程。是轻量级的进程(light weight process)简称LWP,但线程与进程还是有很多的区别。
lexingsen
2022/02/24
5950
线程的概念及linux下线程库相关函数的使用
《Linux操作系统编程》 第十章 线程与线程控制: 线程的创建、终止和取消,detach以及线程属性
​ 通过对线程与线程控制的相关知识点的编程学习和锻炼,培养学生们对线程相关实例问题的分析与解决能力。
猫头虎
2024/04/08
2590
《Linux操作系统编程》 第十章 线程与线程控制: 线程的创建、终止和取消,detach以及线程属性
初识协程栈
今天开始《Go语言轻松进阶》系列第二章「内存与垃圾回收」第3小节「Go语言垃圾回收原理」。
用户1093396
2023/09/01
2140
初识协程栈
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝里慢慢看 (1)
官方话就是:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
看、未来
2020/08/25
3940
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝里慢慢看  (1)
pthread_create 线程属性-Pthread并发编程之线程基本元素和状态的剖析
  在本篇文章当中讲主要给大家介绍并发编程当中关于线程的基础概念,并且深入剖析进程的相关属性和设置,以及线程在内存当中的布局形式,帮助大家深刻理解线程。
宜轩
2022/12/26
4850
Linux线程基础
  加载到内存中的程序,我们称为进程。我们创建一个进程,简单来说是,分配进程地址空间,加载各种数据,与物理内存之间建立映射关系等。做完这些动作,我们才能说创建了进程,也就是说,创建一个进程的开销(时间空间成本开销)是很大的。
用户11029129
2024/09/24
1340
Linux线程基础
【Linux】盘点<多线程控制>基本操作&演示:创建&中止&等待&分离
YY的秘密代码小屋
2024/10/17
2050
【Linux】盘点<多线程控制>基本操作&演示:创建&中止&等待&分离
【在Linux世界中追寻伟大的One Piece】多线程(一)
同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
枫叶丹
2024/11/26
1240
【在Linux世界中追寻伟大的One Piece】多线程(一)
【Linux线程】线程控制原语详细介绍
线程就是 Light weight process ,LWP,轻量级进程,在Linux环境下它仍然是进程,一个进程内部可以有多个线程,默认情况下一个进程内部有一个线程。不同的是,进程有自己的进程控制块PCB,并且拥有自己独立的地址空间;而线程虽然也有线程控制块(这样来看,如果一个进程内有多个线程,那么进程内将有多个PCB),但是它没有独立的地址空间,而是共享空间,我们可以理解为在进程的虚拟空间中除了栈都是共享的(在实际编程中,线程一般就是一个函数,函数肯定要有自己的栈来运行)。也就是说,进程和线程最大的区别在于是否共享地址空间。在Linux环境下,线程是最小的执行单位,进程是最小的资源分配单位。
mindtechnist
2024/08/08
1630
【Linux线程】线程控制原语详细介绍
pthread的使用
编译的时候发现,报错对‘pthread_create’未定义的引用,由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时,在编译中要加-lpthread参数:然后重新编译
心跳包
2020/08/31
1.2K0
推荐阅读
相关推荐
初谈Linux多线程--线程控制
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档