Golang单元测试

news2024/10/5 12:42:47

文章目录

  • 传统测试方法
    • 基本介绍
    • 主要缺点
  • 单元测试
    • 基本介绍
    • 测试函数
    • 基准测试
    • 示例函数

传统测试方法

基本介绍

基本介绍

  • 代码测试是软件开发中的一项重要实践,用于验证代码的正确性、可靠性和预期行为。通过代码测试,开发者可以发现和修复潜在的错误、确保代码按预期工作,并提高系统的质量和稳定性。
  • 单元测试是针对代码中最小的可测试单元(如函数、方法或类)进行的测试,以验证代码单元在给定输入下的行为是否正确。单元测试通常由开发者编写,并使用特定的测试框架和断言库来定义测试用例、执行测试代码,并验证测试结果。

例如,现在要求对cal.go文件中的函数进行代码测试。cal文件中的代码如下:

package cal

func Add(num1 float64, num2 float64) float64 {
	return num1 + num2
}

func Sub(num1 float64, num2 float64) float64 {
	return num1 + num2 // 代码错误
}

func Mul(num1 float64, num2 float64) float64 {
	return num1 * num2
}

func Div(num1 float64, num2 float64) float64 {
	return num1 * num2 // 代码错误
}

常见的测试方法是将测试代码直接写到main函数中,或在main函数中调用对应的测试函数。如下:

package main

import (
	"fmt"
	"go_code/UnitTest/cal"
)

func main() {
	if ret := cal.Add(10, 20); ret != 30 {
		fmt.Printf("error: cal.Add(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 30.0)
	}
	if ret := cal.Sub(10, 20); ret != -10 {
		fmt.Printf("error: cal.Sub(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, -10.0)
	}
	if ret := cal.Mul(10, 20); ret != 200 {
		fmt.Printf("error: cal.Mul(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 200.0)
	}
	if ret := cal.Div(10, 20); ret != 0.5 {
		fmt.Printf("error: cal.Div(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 0.5)
	}
}

运行程序后可以得到代码的测试结果。如下:

在这里插入图片描述

主要缺点

主要缺点

将测试代码写到main函数中,主要存在如下缺点:

  • 难以维护和扩展:测试代码与程序代码耦合在一起,每次完成代码测试后都需要恢复程序代码,并且每次新增测试函数时都需要手动在main函数中新增调用逻辑。
  • 缺乏测试框架支持:传统的测试方法通常缺乏成熟的测试框架支持,无法提供丰富的断言函数、测试报告等功能,这使得测试编写和执行过程相对繁琐,并缺乏对测试结构体的全面分析。

单元测试

基本介绍

基本介绍

  • Go语言中自带一个轻量级的测试框架testing,其功能被封装到了标准库的testing包中,结合go test命令可以方便地进行单元测试和性能测试。
  • 在Go中,每个源文件的测试代码都单独写到一个对应的测试文件中,测试文件名必须以_test.go为后缀,并将其与被测试文件放在同一个目录下,比如要对cal.go文件进行测试,测试文件通常命名为cal_test.go,并将其放在cal.go所在的目录下。
  • 在测试文件中由三种类型的函数:测试函数、基准测试函数、示例函数,go test命令会遍历所有测试文件中的这些函数,生成一个临时的main包用于调用相应的测试函数,接着构建并运行、报告测试结果,最后清理测试中生成的临时文件。

说明一下: 文件名以_test.go为后缀的测试函数,在执行go build时不会被构建成包的一部分。

测试函数

测试函数

  • 在Go中,测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头,通常测试函数命名为Test+被测函数名,比如测试Add函数的测试函数命名为TestAdd。

测试函数的签名要求如下:

在这里插入图片描述

T是testing包中的一个结构体类型,用于表示测试状态和提供测试功能。其常用方法如下:

方法名功能
Log采用与fmt.Println相同的格式化语法输出日志信息
Logf采用与fmt.Printf相同的格式化语法输出日志信息
Fail将当前测试标记为失败,但仍继续执行该测试
FailNow将当前测试标记为失败,并停止执行该测试
Error输出错误信息,并将当前测试标记为失败(相当于调用Log之后调用Fail)
Errorf格式化输出错误信息,并将当前测试标记为失败(相当于调用Logf之后调用Fail)
Fatal输出致命错误信息,并将当前测试标记为失败(相当于调用Log之后调用FailNow)
Fatalf格式化输出致命错误信息,并将当前测试标记为失败(相当于调用Log之后调用FailNow)
SkipNow将当前测试标记为跳过,并停止执行该测试
Skip输出跳过信息,并将当前测试标记为跳过(相当于调用Log之后调用SkipNow)

说明一下:

  • 这里所说的“当前测试”指的是“当前testing测试框架正在执行的测试函数”,“将当前测试标记为失败”指的是“将当前正在执行的测试函数标记为失败”,“停止执行当前测试”指的是“停止当前正在执行的测试函数,继续执行下一个测试函数”。
  • 当一个测试被标记为跳过时,如果该测试在此之前已经被标记为失败,那么该测试最终会被判定为FAIL而不是SKIP。
  • SkipNow、Skip和FailNow必须在运行测试的go协程中进行调用,而不能在测试期间创建的go协程中调用,因为SkipNow、Skip和FailNow不会导致其他go协程停止(go协程在后续博客中讲解)。

测试函数案例

比如我们要对之前cal.go文件中的函数进行代码测试,则在cal.go文件所在目录下建立名为cal_test.go的测试文件,并在测试文件中编写对应的测试函数。如下:

package cal

import (
	"testing"
)

func TestAdd(t *testing.T) {
	if ret := Add(10, 20); ret != 30 {
		t.Errorf("cal.Add(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 30.0)
	}
}

func TestSub(t *testing.T) {
	if ret := Sub(10, 20); ret != -10 {
		t.Errorf("cal.Sub(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, -10.0)
	}
}

func TestMul(t *testing.T) {
	if ret := Mul(10, 20); ret != 200 {
		t.Errorf("cal.Mul(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 200.0)
	}
}

func TestDiv(t *testing.T) {
	if ret := Div(10, 20); ret != 0.5 {
		t.Errorf("cal.Div(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 0.5)
	}
}

在测试文件所在目录执行go test命令,它会在当前目录中查找所有的测试文件,逐个执行测试文件中的测试函数并输出测试结果,包括各个测试函数的测试状态、日志信息、运行时间等。如下:

在这里插入图片描述

在任意目录下通过go test 包路径的方式,可以查找指定包路径下的测试文件并执行其测试函数。如下:

在这里插入图片描述

说明一下: 只要本次测试中有一个测试函数的测试状态为FAIL,那么本次测试的状态即为FAIL。

显示详细的测试信息

go test命令默认只会输出测试状态为FAIL的测试函数信息,通过携带-v参数可以查看更详细测试信息。如下:

在这里插入图片描述

测试指定的测试文件

go test命令默认会执行当前目录下所有测试文件中的测试函数,如果只想执行某个或某几个测试文件中的测试函数,可以在go test命令后指明对应的测试文件名,同时需要指明与测试文件相关的go源文件。如下:

在这里插入图片描述

测试指定的测试函数

go test命令默认会执行测试文件中所有的测试函数,通过携带-run参数可以只执行指定的测试函数。如下:

在这里插入图片描述

说明一下: go test命令的-run参数可以接受一个正则表达式,它将执行所有与该正则表达式匹配的测试函数。

测试覆盖率

通过携带-cover参数可以查看本次测试的测试覆盖率,即在本次测试中被测试代码至少被运行一次的代码占总代码数的比例。如下:

在这里插入图片描述

基准测试

基准测试函数

  • 基准测试(Benchmarking)是一种在计算机编程中用于评估程序性能的技术,其目的是测量代码在给定工作负载下的性能指标,如执行时间、内存消耗等。通过基准测试可以对不同实现方式或优化策略之间的性能差异进行比较和评估,这对于优化程序、找出性能瓶颈以及进行系统比较和选型非常有用。
  • 在Go中,基准测试函数的名字必须以Benchmark开头,可选的后缀名必须以大写字母开头,通常基准测试函数命名为Benchmark+被测函数名,比如测试Add函数的基准测试函数命名为BenchmarkAdd。

基准测试函数的签名要求如下:

在这里插入图片描述

B是testing包中的一个结构体类型,用于控制和测量基准测试的执行。其常用方法如下:

方法名功能
ResetTimer重置基准测试的计时器
StartTimer启动基准测试的计时器
StopTimer停止基准测试的计时器

基准测试函数案例

比如我们要对之前cal.go文件中的各个函数进行基准测试,则在cal_test.go文件中增加对应的基准测试函数即可。如下:

func BenchmarkAdd(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Add(10, 20)
	}
}

func BenchmarkSub(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Sub(10, 20)
	}
}

func BenchmarkMul(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Mul(10, 20)
	}
}

func BenchmarkDiv(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Div(10, 20)
	}
}

go test命令默认只会运行普通的测试函数,通过携带-bench参数可以指定要运行的基准测试函数。如下:

在这里插入图片描述

基准测试结果说明:

  • 第一列:BenchmarkXxx表示基准测试函数的名称,后面的数字表示运行基准测试函数时的GOMAXPROCS的值。
  • 第二列:基准测试函数的执行次数。
  • 第三列:每执行一次基准测试函数的平均耗时(ns/op)。
  • 第四列:每执行一次基准测试函数的平均内存分配的总字节数(B/op)。
  • 第五列:每执行一次基准测试函数的平均内存分配次数(allocs/op)。

基准测试函数的运行机制:

  • testing测试框架为了保证测试结果的稳定性和准确性,在B类型中设置了字段N,在基准函数中可以通过b.N指定操作执行的循环次数。测试框架会自动调整b.N的值,确保每个基准测试函数运行至少达到1秒钟,然后再计算出平均每执行一次操作所需的时间。
  • 由于基准测试驱动器开始时并不知道运行每个基准测试函数所需花费的时间,因此在真正运行每一个基准测试函数之前,基准测试驱动器会先尝试将b.N设置为一个较小的值,如果基准测试函数的运行时间小于1秒,则加大b.N的值,直到基准测试函数的运行时间至少达到1秒钟。
  • 经过验证,在本人的机器上b.N的初始值为1,尝试执行基准测试函数后根据计时器的值判断下一次尝试的b.N值,但下一次尝试的b.N值最多为上一次b.N值的100倍,并且b.N的上限为1000000000,当b.N的值达到上限后,即使基准测试函数的运行时间没有达到1秒,也不再增加b.N的值。

说明一下:

  • 使用go test命令运行基准测试函数时仍然会运行普通的测试函数,如果普通的测试函数中存在测试状态为FAIL的测试函数,那么将不会运行基准测试函数。因此在运行基准测试函数之前请保证所有普通的测试函数能正确通过测试,或将-run参数设置为none表示不运行任何普通测试函数。
  • -bench参数指定为.表示运行所有的基准测试函数,也可以将其指定为一个正则表达式,它将执行所有与该正则表达式匹配的基准测试函数。
  • go test命令的-benchmem参数,用于在运行基准测试函数时报告内存分配的统计信息,包括内存分配次数和内存分配的总字节数,否则基准测试只有前三列结果。

重置计时器

如果基准测试函数中存在一些数据准备工作,并且你不希望这部分工作的时间被计时器统计,则可以在数据准备完毕后,通过调用B类型的ResetTimer方法重置计时器。如下:

func BenchmarkDemo(b *testing.B) {

	// 基准测试数据准备工作...

	b.ResetTimer() // 重置计时器

	// [计时区域]

}

说明一下: 计时器会在基准测试函数调用时自动启动,并在函数执行完毕后自动停止。

指定区域计时

在基准测试函数中,如果你希望统计某些非连续区域的耗时,则可以通过调用B类型的StartTimer和StopTimer方法手动启动或停止计时器。如下:

func BenchmarkDemo(b *testing.B) {

	// 其他工作1...

	b.ResetTimer() // 重置计时器
	// [计时区域1]
	b.StopTimer() // 停止计时器

	// 其他工作2...

	b.StartTimer() // 启动计时器
	// [计时区域2]
	b.StopTimer() // 停止计时器

	// 其他工作3...
}

注意: 为了避免统计其他工作1...的耗时,需要在[计时区域1]之前调用ResetTimer方法而不是StartTimer方法。

指定基准测试运行时间

通过go test命令的-benchtime参数,可以指定每个基准测试函数至少需要达到的运行时间。如下:

在这里插入图片描述

注意: 如果基准测试函数的b.N值达到上限后仍无法达到所指定的运行时间,那么b.N的值也不会继续增加。

指定操作迭代次数

通过go test命令的-benchtime参数,也可以指定每个基准测试函数中操作的迭代次数,即b.N的值。如下:

在这里插入图片描述

指定基准测试可用cpu数

通过go test命令的-cpu参数,可以指定运行基准测试时调度器可使用的最大CPU核心数。如下:

在这里插入图片描述

性能分析

通过go test命令的-cpuprofile-memprofile参数,可以分别生成CPU分析文件和内存分析文件。如下:

在这里插入图片描述

pprof是Go语言中自带的性能分析工具,通过go tool pprof 分析文件 命令即可对指定的分析文件进行解析。以内存性能分析为例,执行go tool pprof mem.out命令后会出现pprof的交互式命令行,在命令行中输入top命令可以查看耗费内存资源最多的函数。如下:

在这里插入图片描述

pprof工具分析结果说明:

  • flat:在该函数上直接花费的时间或资源总量(比如CPU时间、内存资源等),不包括该函数调用的其他函数所花费的时间或资源。
  • flat%:flat值占分析总量的百分比,表示该函数直接花费的时间或资源占资源使用的百分比。
  • sum%:这个百分比是累积的,表示到当前行为止所有函数的flat%的总和。
  • cum:该函数及其调用的所有函数总共花费的时间或资源总量。
  • cum%:cum值占分析总量的百分比,表示该函数及其调用的所有函数花费的时间或资源占资源使用的百分比。
小贴士:如果一个函数的flat%值高,则表明该函数本身可能是性能瓶颈,而如果一个函数的cum%值高,则表明该函数调用链上的某个函数可能存在性能瓶颈。

此外,在pprof的交互式命令行中输入web命令,可以生成调用链路图,在链路图中会展示对应资源的耗费情况。如下:

在这里插入图片描述

说明一下:

  • pprof工具的调用链路图显示功能需要安装Graphviz工具,可以在Graphviz官网进行下载,安装并设置PATH环境变量后,即可在pprof的交互式命令行中执行web命令生成调用链路图。

示例函数

示例函数

  • 示例函数是一种用于演示和测试包的功能的特殊函数,其主要目的是提供关于如何使用包中的功能的示例代码以及相应的预期输出,这些示例函数可以作为文档的一部分,帮助其他开发人员理解和学习如何正确使用包中的函数、结构和类型。
  • 在Go中,示例函数没有参数和返回值,其名字必须以Example开头,可选的后缀名必须以大写字母开头,通常示例函数命名为Example+对应函数名,比如Add函数的示例函数命名为ExampleAdd。
  • 通过go test命令运行测试时示例函数也会被执行,如果示例函数内有类似// Output:格式的注释,那么测试工具就会执行这个示例函数,并检查示例函数的标准输出与注释是否匹配,如果匹配则测试通过,否则测试失败。

示例函数案例

比如我们要演示之前cal.go文件中的各个函数的使用,则在cal_test.go文件中增加对应的示例函数即可。如下:

func ExampleAdd() {
	ret := Add(10, 20)
	fmt.Println(ret)
	// Output: 30
}

func ExampleSub() {
	ret := Sub(10, 20)
	fmt.Println(ret)
	// Output: -10
}

func ExampleMul() {
	ret := Mul(10, 20)
	fmt.Println(ret)
	// Output: 200
}

func ExampleDiv() {
	ret := Div(10, 20)
	fmt.Println(ret)
	// Output: 0.5
}

运行go test命令后可以看到所有测试函数和示例函数均被执行。如下:

在这里插入图片描述

如果某个示例函数的// Output:注释中的内容,与实际执行示例函数时的输出不匹配,则该示例函数被标记为失败,从而导致整个测试失败。如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1694331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小猪APP分发:一站式托管服务,轻松玩转应用市场

在当今移动应用爆炸式增长的时代&#xff0c;开发者们面临的挑战不再仅限于创意的火花和代码的实现&#xff0c;更在于如何让精心打造的应用快速触达广大用户。这正是小猪APP分发www.appzhu.net应运而生的背景——作为一个全面、高效的APP托管服务分发平台&#xff0c;它为开发…

相关服务器介绍

服务器是一种高性能的计算机&#xff0c;它被设计用来为其他计算机或终端设备提供服务&#xff0c;如数据处理、文件存储、网络通信等。服务器通常具有强大的计算能力、大容量的存储空间和高效的网络连接能力。 常见的服务器种类及其特点 文件服务器 文件服务器主要负责中央存储…

什么是JDK21虚拟线程

JDK21虚拟线程 1. 来一段小故事2. 什么是虚拟线程3. 虚拟线程的几个关键特点4.细说关键特点1.为什么轻量级的1.传统线程运行时间2.虚拟线程运行时间3.对垃圾回收的影响 2.非绑定OS线程的魅力所在3.和传统相比为何易于使用4.阻塞优化有什么好处1.什么是阻塞优化2.JDK 21虚拟线程…

基于SSH的母婴用品销售管理系统带万字文档

文章目录 母婴商城系统一、项目演示二、项目介绍三、系统部分功能截图四、万字论文参考五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 母婴商城系统 一、项目演示 母婴商城系统 二、项目介绍 基于SSH的母婴商城系统 系统…

海外仓储管理系统:提升效率,标准化海外仓管理,科技赋能业务

海外仓作为跨境物流的关键一环&#xff0c;完全可以说海外仓的效率直接决定了后续物流的整体运作效率。 对于海外仓而言&#xff0c;一套高效&#xff0c;易用的海外仓储系统&#xff0c;无疑将成为提升企业竞争力的重要工具&#xff0c;帮助海外仓实现从野蛮生长到标准化管理…

边用边充电影响寿命吗?看看计算机指令组成与操作类型

计算机指令集体系结构之指令 指令由操作码和地址码字段组成。 操作码指明了指令要完成的操作。 长度可以固定&#xff1a;比如RISC&#xff08;reduced instruction set computer&#xff09;精简指令集计算机 与之对应的RISC&#xff08;复杂指令集计算机&#xff09;&…

【C++进阶】AVL树

0.前言 前面我们已经学习过二叉搜索树了&#xff0c;但如果我们是用二叉搜索树来封装map和set等关联式容器是有缺陷的&#xff0c;很可能会退化为单分支的情况&#xff0c;那样效率就极低了&#xff0c;那么有没有方法来弥补二叉搜索树的缺陷呢&#xff1f; 那么AVL树就出现了&…

【C++】类与对象——多态详解

目录 一、多态的定义 二、重载、覆盖(重写)、隐藏(重定义)的对比 三、析构函数重写 四、C11 override 和 final 1. final 2. override 五、抽象类 六、多态的原理 一、多态的定义 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为…

【机器学习】机器学习与大型预训练模型的前沿探索:跨模态理解与生成的新纪元

&#x1f512;文章目录&#xff1a; &#x1f4a5;1.引言 ☔2.跨模态理解与生成技术概述 &#x1f6b2;3.大型预训练模型在跨模态理解与生成中的应用 &#x1f6f4;4.前沿探索与挑战并存 &#x1f44a;5.未来趋势与展望 &#x1f4a5;1.引言 近年来&#xff0c;机器学习领…

使用C/C++ API接口操作 Zookeeper 数据

ZooKeeper 支持 Java 和 C 的API接口。本文将介绍使用 C/C 语言客户端库的编译安装和使用入门。 一、编译安装 PS&#xff1a;就在上一篇文章还觉得安装和配置 jdk 、maven 麻烦&#xff0c;所以当时选择 apache-zookeeper-[version]-bin.tar.gz 的版本。然而&#xff0c;本文…

【C++要哮着学】类和对象

文章目录 前言面向过程和面相对象初步认识类的定义类的访问限定符及封装访问限定符封装 类的作用域类的实例化类对象模型如何计算类的大小结构体内存对齐规则类对象的存储方式1.对象中包含类的各个成员2.代码只保存一份&#xff0c;在对象中保存存放代码的地址3.只保存成员变量…

权限维持--linux

隐藏文件/夹&-开头文件 如何创建: 在文件名之前加.即可 touch .1.s 如何清除、查找&#xff1a; ls -al rm -fr -文件 已-开头的文件直接读取是不行的需要带目录 隐藏时间戳 ①用其他文件的时间 touch -r zww.php testq.txt 如何清除、查看&#xff1a; stat test…

KDE-Ambari-Metrics-Collector问题排查解决手册

文档说明 本文档是为了解决KDE平台的Ambari-Metrics-Collector服务在运行时遇到的问题而提供的问题排查和解决方法的参考文档 说明: 当前的Ambari-Metrics-Collector服务包括了ams-collector和ams-hbase两个程序,在Ambari-Metrics-Collector安装的节点执行ps -elf|grep am…

【算法】前缀和——二维前缀和模板题

本节博客是通过——二位前缀和模板题来介绍前缀和二维算法&#xff0c;有需要借鉴即可。 目录 1.题目2.暴力求解3.二维前缀和算法3.代码示例4.总结 1.题目 题目链接&#xff1a;LINK 2.暴力求解 这里我们首先想到的就是一个暴力求解的方式&#xff0c;挨个需要的进行遍历就…

基于SA模拟退火优化算法的TSP问题求解matlab仿真,并对比ACO蚁群优化算法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于SA模拟退火优化算法的TSP问题求解matlab仿真,并对比ACO蚁群优化算法,对比两个算法的仿真时间&#xff0c;收敛曲线&#xff0c;以及路径规划的结果&#xff0…

独享IP是原生IP吗?

原生IP&#xff1a; 原生IP是指由Internet服务提供商&#xff08;ISP&#xff09;直接分配给用户的IP地址&#xff0c;这些IP地址通常反映了用户的实际地理位置和网络连接。原生IP是用户在其所在地区或国家使用的真实IP地址&#xff0c;与用户的物理位置直接相关。在跨境电商中…

从零训练yolov8

1.收集数据 2.数据标注 pip install labelimg3.划分数据集 0.2的验证机0.8的训练集 import os from shutil import copyfile from sys import exit import randomsource r"D:\Data\imgs\screenc" \\ target_train r"D:\Data\imgs\datasets\mydata\images\t…

访存优化实践之一 : CPU、GPU、DDR与访存路径介绍

一、CPU的访存路径 上图是目前主流的CPU架构介绍。可以看到,CPU的访存路径:先经过MMU,然后经过Cache,最后到达DRAM。这其中涉及到的关键内容为基于MMU的内存管理以及缓存机制。 1.1、基于MMU的内存管理 众所周知,在计算机设计之处是没有虚拟地址的概念的,CPU发出的地址即…

win中的vscode利用ssh插件,在同一台电脑的virtualbox虚拟出来的ubuntu中编译,调试设置方法

vscode中安装ssh插件virtualbox7.0中的设置&#xff1a; 在网络管理器中添加host-only网卡&#xff0c;用来主机和虚拟机双向通信。这个网卡能在win的设备管理器里面看到手动配置网卡&#xff0c;其中ip地址是另一个网段的&#xff0c;主机ip地址是192.168.1.1。这个网卡对于虚…

ELK 日志监控平台(二)- 优化日志格式

文章目录 ELK 日志监控平台&#xff08;二&#xff09;- 优化日志格式1.日志输出要点2.优化应用的日志格式2.1.确定日志输出要点来源2.1.1.服务名称2.1.2.服务环境2.1.3.日志级别2.1.4.日志输出时间2.1.5.日志内容2.1.6.日志输出对象2.1.7.线程名称 2.2.logback.xml修改日志输出…