[English]

RainbowLog 是一款简单易用、高可配置、结构化的日志库(For Golang)。
它旨在为RainbowProject的其他工程提供快速可靠的日志记录服务,是RainbowProject的基础之一。

RainbowLog 在设计时,参考了部分ZeroLog的设计思路,同时结合笔者工作中一些需要的特性,让RainbowLog更快、更小、更美观、更易用。

如何使用

README.md中有使用说明(英文)。

注意:README.md中可能并没有完整描述了RainbowLog的全部功能,笔者会再适当的时间将缺失部分补充至README中。

安装

1
go get -u github.com/rambollwong/rainbowlog

使用 global logger

使用默认选项配置的 global logger

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"github.com/rambollwong/rainbowlog/log"
)

func main() {
log.UseDefault()

log.Logger.Info().Msg("Hello world!").Done()
}

// Output: {"_TIME_":"2024-02-19 19:50:09.008","_LEVEL_":"INFO","_CALLER_":"/path/to/main.go:10","message":"Hello world!"}

注意: 默认下,log信息会写入os.Stderr

使用Rainbow默认选项配置的 global logger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"errors"

"github.com/rambollwong/rainbowlog/log"
)

func main() {
log.UseRainbowDefault()

log.Logger.Info().Msg("Hello world!").Done()
log.Logger.Debug().WithLabels("MODEL1").Msg("Something debugging...").Done()
log.Logger.Warn().WithLabels("MODEL2", "SERVICE1").Msg("Something warning!").Int("IntegerValue", 888).Done()
log.Logger.Error().Msg("failed to do something").Err(errors.New("something wrong")).Done()
log.Logger.Fatal().Msg("fatal to do something").Done()
}

Output:

使用通过配置文件配置的 global logger

RainbowLog 支持通过配置文件来配置logger。
如果你要使用配置文件,需要确保配置文件中包含RainbowLog配置项。

RainbowLog 支持三种格式的配置文件:.yaml|.json|.toml
具体配置模板请参见config包中的相应文件。

假设我们准备了一个配置文件rainbowlog.yaml,并将其放在与执行文件同一目录下,然后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"errors"

"github.com/rambollwong/rainbowlog/log"
)

func main() {
log.UseDefaultConfigFile()

log.Logger.Info().Msg("Hello world!").Done()
log.Logger.Debug().WithLabels("MODEL1").Msg("Something debugging...").Done()
log.Logger.Warn().WithLabels("MODEL2", "SERVICE1").Msg("Something warning!").Int("IntegerValue", 888).Done()
log.Logger.Error().Msg("failed to do something").Err(errors.New("something wrong")).Done()
log.Logger.Fatal().Msg("fatal to do something").Done()
}

如果想使用.json.toml类型的配置文件,只需要修改log.DefaultConfigFileName即可,例如:

1
log.DefaultConfigFileName = "rainbowlog.json"

1
log.DefaultConfigFileName = "rainbowlog.toml"

如果你还想指定配置文件所在目录,只需要修改log.DefaultConfigFilePath即可:

1
log.DefaultConfigFilePath = "/path/of/config/files"

注意:修改log.DefaultConfigFileNamelog.DefaultConfigFilePath需要在log.UseDefaultConfigFile()之前执行,否则不会生效。

使用自定义选项配置的 global logger

如果您想对全局记录器使用自定义选项,我们保留了 log.UseCustomOptions(opts ...Option) API 来实现。
支持的 Option 详细信息参见 option.go

自定义 logger

如果不想使用global logger,可以通过New方法初始化一个Logger实例。New方法接收Option参数。
支持的 Option 详细信息请参见 option.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"errors"
"path/filepath"

"github.com/rambollwong/rainbowlog"
)

func main() {
DefaultConfigFileName := "rainbowlog.yaml"
DefaultConfigFilePath := "/path/of/config/files"

logger := rainbowlog.New(
rainbowlog.WithDefault(),
rainbowlog.WithConfigFile(filepath.Join(DefaultConfigFilePath, DefaultConfigFileName)),
)

logger.Info().Msg("Hello world!").Done()
logger.Debug().WithLabels("MODEL1").Msg("Something debugging...").Done()
logger.Warn().WithLabels("MODEL2", "SERVICE1").Msg("Something warning!").Int("IntegerValue", 888).Done()
logger.Error().Msg("failed to do something").Err(errors.New("something wrong")).Done()
logger.Fatal().Msg("fatal to do something").Done()
}

SubLogger(子Logger)

SubLogger允许您创建一个继承自父Logger的Logger实例,并可以在需要时重新设置某些Option
例如,子模块中使用与父Logger不同的LABEL的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
"os"

"github.com/rambollwong/rainbowlog"
"github.com/rambollwong/rainbowlog/level"
)

func main() {
logger := rainbowlog.New(
rainbowlog.WithDefault(),
rainbowlog.AppendsEncoderWriters(rainbowlog.JsonEnc, os.Stderr),
rainbowlog.WithCallerMarshalFunc(nil),
rainbowlog.WithLevel(level.Info),
rainbowlog.WithLabels("ROOT"),
)

logger.Debug().Msg("Hello world!").Done()
logger.Info().Msg("Hello world!").Done()

subLogger := logger.SubLogger(
rainbowlog.WithLevel(level.Debug),
rainbowlog.WithLabels("SUBMODULE"),
)

subLogger.Debug().Msg("Hello world!").Done()
subLogger.Info().Msg("Hello world!").Done()
}

// Output:
// {"_TIME_":"2024-02-21 11:28:02.150","_LEVEL_":"INFO","_LABEL_":"ROOT","message": "Hello world!"}
// {"_TIME_":"2024-02-21 11:28:02.150","_LEVEL_":"DEBUG","_LABEL_":"SUBMODULE","message":"Hello world!"}
// {"_TIME_":"2024-02-21 11:28:02.150","_LEVEL_":"INFO","_LABEL_":"SUBMODULE","message":"Hello world!"}

自定义时间输出格式

RainbowLog的默认时间格式是2006-01-02 15:04:05.000
您可以通过 WithTimeFormat(timeFormat string) 选项修改此格式,
格式可以是符合golang时间格式规则的字符串,
也可以是UNIXUNIXMSUNIXMICROUNIXNANO
它们分别表示输出time.TimeUnix()UnixMilli()UnixMicro()UnixNano()的返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"os"

"github.com/rambollwong/rainbowlog"
)

func main() {
logger := rainbowlog.New(
rainbowlog.WithDefault(),
rainbowlog.AppendsEncoderWriters(rainbowlog.JsonEnc, os.Stderr),
rainbowlog.WithTimeFormat(rainbowlog.TimeFormatUnix),
)

logger.Info().Msg("Hello world!").Done()
}

// Output:{"_TIME_":1708346689,"_LEVEL_":"INFO","_CALLER_":"main.go:16","message":"Hello world!"}

Hooks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"fmt"
"os"

"github.com/rambollwong/rainbowlog"
"github.com/rambollwong/rainbowlog/level"
)

func main() {
var hook rainbowlog.HookFunc = func(r rainbowlog.Record, level level.Level, message string) {
fmt.Printf("hook: %s, %s\n", level.String(), message)
}
logger := rainbowlog.New(
rainbowlog.WithDefault(),
rainbowlog.AppendsEncoderWriters(rainbowlog.JsonEnc, os.Stderr),
rainbowlog.WithCallerMarshalFunc(nil),
rainbowlog.AppendsHooks(hook),
rainbowlog.WithLevel(level.Info),
)

logger.Debug().Msg("Hello world!").Done()
logger.Info().Msg("Hello world!").Done()
}

// Output:
// hook: info, Hello world!
// {"_TIME_":"2024-02-21 11:42:17.592","_LEVEL_":"INFO","message":"Hello world!"}

更多功能待补充…

Github仓库

https://github.com/rambollwong/rainbowlog

如果您觉得我做的还不错,希望您能为它点亮一个⭐。您的支持,是我前进的最大动力。