Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go log包异或组合

Go中log包异或组合配置妙用详解

作者:程序员二毛

在 Go 语言的 log 包中,使用“位运算相或” (|) 来配置日志的 flag,可以让我们灵活地组合多种日志信息输出选项,下面我们就来看看这种方法的好处和原理吧

log 中的这种用法,你一定见过:

log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)

没见过的,自我反省下(逃

在 Go 语言的 log 包中,使用“位运算相或” (|) 来配置日志的 flag,是为了让我们灵活地组合多种日志信息输出选项。,比如是否显示日期、时间、微秒、文件名、行号等。

接下来详细解释这种方法的好处和原理。

1. 什么是 log 包中的 flag

log 包中,flag 是用来控制日志输出格式的一些选项。

每种 flag 都是一个二进制位掩码,通过不同的掩码组合,可以控制日志的显示内容。

这些 flag 选项定义如下:

const (
    Ldate         = 1 << iota     // 日期:2009/01/23
    Ltime                         // 时间:01:23:23
    Lmicroseconds                 // 微秒级时间:01:23:23.123123(需要同时有 Ltime)
    Llongfile                     // 完整文件名和行号:/a/b/c/d.go:23
    Lshortfile                    // 文件名和行号:d.go:23(会覆盖 Llongfile)
    LUTC                          // 使用 UTC 时间而非本地时间
    Lmsgprefix                    // 将“前缀”从行首移动到消息之前
    LstdFlags     = Ldate | Ltime // 默认值
)

这些常量是通过位移运算 1 << iota 定义的,保证每个 flag 只占用一位,且是唯一的。

这样一来,我们可以用按位或操作 | 来组合多个选项。

对应的值如下:

const (
	Ldate=1 << iota// iota =0,值为 1 << 0 = 1,二进制:00000001,相当于2的0次方
	Ltime          // iota = 1,值为 1 << 1 = 2,二进制:00000010,相当于2的1次方
	Lmicroseconds  // iota = 2,值为 1 << 2 = 4,二进制:00000100,相当于2的2次方
	Llongfile      // iota = 3,值为 1 << 3 = 8,二进制:00001000,相当于2的3次方
	Lshortfile     // iota = 4,值为 1 << 4 = 16,二进制:00010000,相当于2的4次方
	LUTC           // iota = 5,值为 1 << 5 = 32,二进制:00100000,相当于2的5次方
	Lmsgprefix     // iota = 6,值为 1 << 6 = 64,二进制:01000000,相当于2的6次方
)

2. 为什么使用按位或 (|) 来组合 flag

按位或 (|) 的好处是可以任意组合选项。因为每个 flag 常量代表一个独特的二进制位,所以它们可以通过按位或相加组合在一起,而不会产生冲突。例如:

当我们使用 log.SetFlags(Ltime | Llongfile) 时,相当于将 0b0010 | 0b1000 组合成 0b1010,即同时启用了时间和文件名短格式显示。

通过这种位运算方式,可以组合各种 flag 选项,而不必为每种组合重新定义一个新的常量。

3. 使用按位或组合 flag 的优势

4. 如何识别已设置的flag

当我们通过位或组合多个flag传递给log.SetFlags后,log包在输出日志时会检测该组合值,并根据不同的位设置来确定输出内容。

具体的识别方式:按位与(&)操作

假设我们设置了以下flag组合:

log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)

传入的flag组合会是一个整型值,log包会在生成日志时,通过按位与操作来判断每个flag是否存在。具体步骤如下:

具体来看,假设我们使用log.Ldate | log.Ltime | log.Llongfile

将这些flag组合在一起后的整型值是00001011,它包含了所有的设置信息。

示例:代码实现flag识别的过程

log包的实现原理为例,可以大致模拟flag识别的过程。假设flags变量存储了当前的flag设置值,可以如下判断是否开启各个功能:

package main

import (
    "log"
)

func main() {
    flags := log.Ldate | log.Ltime | log.Llongfile

    if flags&log.Ldate != 0 {
        log.Print("日期已启用")
    }
    if flags&log.Ltime != 0 {
        log.Print("时间已启用")
    }
    if flags&log.Llongfile != 0 {
        log.Print("完整文件路径已启用")
    }
}

5. 使用展示

我们来看一个例子,假设这段代码位于 main.go 文件的第 10 行:

package main

import (
    "log"
)

func main() {
    log.SetFlags(log.Ltime | log.Lshortfile)
    log.Println("这是一个日志消息")
}

如果这段代码在 2024 年 11 月 3 日 15:04:05 执行,日志输出可能会是:

15:04:05 main.go:10: 这是一个日志消息

其中,15:04:05 是时间,main.go:10 是简化的文件名和行号。

6. 总结

使用按位或操作符 | 来配置日志 flag,可以让我们灵活地组合日志的不同显示选项,方便地自定义输出格式。这种方式不仅简化了代码,还提高了日志配置的灵活性和可读性。

到此这篇关于Go中log包异或组合配置妙用详解的文章就介绍到这了,更多相关Go log包异或组合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文