clog

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 12 Imported by: 0

README

clog - Genesis 结构化日志组件

Go Reference

clog 是 Genesis 框架的结构化日志组件,基于 Go 标准库 log/slog 构建。

特性

  • 所属层级:L0 (Base) — 框架基石,被所有上层组件依赖
  • 核心职责:提供统一的结构化日志接口,支持命名空间派生和 Context 字段提取
  • 设计原则
    • 抽象接口,不暴露底层实现(slog)
    • 支持层级命名空间,适配微服务架构
    • 零外部依赖(仅依赖 Go 标准库)
    • 采用函数式选项模式,符合 Genesis 标准

2. 目录结构

clog/                     # 根目录 - 扁平化设计
├── README.md             # 本文档
├── clog.go              # 构造函数:New()
├── config.go            # 配置结构:Config + validate()
├── noop.go              # No-op 实现:Discard()
├── options.go           # 函数式选项:Option、WithNamespace 等
├── logger.go            # Logger 接口定义
├── level.go             # 日志级别:Level、ParseLevel
├── fields.go            # 字段构造函数:String、Error 等
├── impl.go              # Logger 实现(私有)
├── context.go           # Context 字段提取(私有)
├── namespace.go         # 命名空间处理(私有)
└── handler.go           # slog Handler 适配器(私有)

说明:采用完全扁平化设计,所有公开 API 直接在根目录,实现细节通过私有函数隐藏。

3. 核心接口

3.1 Logger 接口
// Logger 日志接口,提供结构化日志记录功能
//
// 支持五个日志级别:Debug、Info、Warn、Error、Fatal
// 每个级别都有带 Context 和不带 Context 的版本
//
// 基本使用:
//   logger.Info("Hello, World", clog.String("key", "value"))
//
// 带 Context 的使用:
//   logger.InfoContext(ctx, "Request processed")
//   // 会自动从 Context 中提取配置的字段
type Logger interface {
    // 基础日志级别方法
    Debug(msg string, fields ...Field)
    Info(msg string, fields ...Field)
    Warn(msg string, fields ...Field)
    Error(msg string, fields ...Field)
    Fatal(msg string, fields ...Field)

    // 带 Context 的日志级别方法,用于自动提取 Context 字段
    DebugContext(ctx context.Context, msg string, fields ...Field)
    InfoContext(ctx context.Context, msg string, fields ...Field)
    WarnContext(ctx context.Context, msg string, fields ...Field)
    ErrorContext(ctx context.Context, msg string, fields ...Field)
    FatalContext(ctx context.Context, msg string, fields ...Field)

    // With 创建一个带有预设字段的子 Logger
    With(fields ...Field) Logger

    // WithNamespace 创建一个扩展命名空间的子 Logger
    WithNamespace(parts ...string) Logger

    // SetLevel 动态调整日志级别
    SetLevel(level Level) error

    // Flush 强制同步所有缓冲区的日志
    Flush()
}
3.2 Config 结构体
// Config 日志配置结构,定义日志的基本行为
//
// 支持的配置项:
//   Level: 日志级别 (debug|info|warn|error|fatal)
//   Format: 输出格式 (json|console)
//   Output: 输出目标 (stdout|stderr|文件路径)
//   EnableColor: 是否启用彩色输出(仅 console 格式,已实现)
//   AddSource: 是否显示调用位置信息
//   SourceRoot: 源代码路径前缀,用于裁剪显示的文件路径
type Config struct {
    Level       string `json:"level" yaml:"level"`             // debug|info|warn|error|fatal
    Format      string `json:"format" yaml:"format"`           // json|console
    Output      string `json:"output" yaml:"output"`           // stdout|stderr|<file path>
    EnableColor bool   `json:"enableColor" yaml:"enableColor"` // 仅在 console 格式下有效
    AddSource   bool   `json:"addSource" yaml:"addSource"`
    SourceRoot  string `json:"sourceRoot" yaml:"sourceRoot"` // 用于裁剪文件路径
}
3.3 函数式选项
func WithNamespace(parts ...string) Option              // 命名空间
func WithContextField(key any, fieldName string) Option // 自定义 Context 字段
func WithTraceContext() Option                          // OpenTelemetry trace_id/span_id

4. 工厂函数

// New 创建一个新的 Logger 实例
//
// config 为日志基本配置,opts 为函数式选项。
func New(config *Config, opts ...Option) (Logger, error)

// Discard 返回一个 No-op Logger 实现
//
// 该 Logger 的所有方法都是空操作,不产生任何输出。
// 适用于测试环境或需要临时禁用日志的场景。
func Discard() Logger

// NewDevDefaultConfig 创建开发环境的默认日志配置
//
// sourceRoot 推荐设置为你的项目根目录,例如 "genesis",以获得更简洁的调用源信息。
func NewDevDefaultConfig(sourceRoot string) *Config

// NewProdDefaultConfig 创建生产环境的默认日志配置
//
// sourceRoot 推荐设置为你的项目根目录,例如 "genesis",以获得更简洁的调用源信息。
func NewProdDefaultConfig(sourceRoot string) *Config

5. 命名空间规范

5.1 层级结构
层级 格式 示例
应用级 <app> user-service
组件级 <app>.<component> user-service.dlock
子模块级 <app>.<component>.<sub> user-service.dlock.redis
5.2 使用示例
// main.go - 创建应用级 Logger
logger, _ := clog.New(&clog.Config{
    Level:  "info",
    Format: "json",
    Output: "stdout",
}, clog.WithNamespace("user-service"))

// 组件内部派生
subLogger := logger.WithNamespace("api")
// 最终命名空间: "user-service.api"

6. Field 构造函数

6.1 基础类型
func String(k, v string) Field    // → k="value"
func Int(k string, v int) Field     // → k=123
func Float64(k string, v float64) Field  // → k=123.45
func Bool(k string, v bool) Field     // → k=true
func Time(k string, v time.Time) Field   // → k="2023-01-01T00:00:00Z"
func Any(k string, v any) Field       // → k=<任意值>
6.2 错误处理
func Error(err error) Field                  // 仅 err_msg
func ErrorWithCode(err error, code string) Field      // error={msg, code}
func ErrorWithStack(err error) Field           // error={msg, type, stack}
func ErrorWithCodeStack(err error, code string) Field // error={msg, type, stack, code}

7. 使用示例

7.1 基础用法
logger, _ := clog.New(&clog.Config{
    Level:  "info",
    Format: "console",
    Output: "stdout",
})

logger.Info("service started",
    clog.String("version", "v1.0.0"),
    clog.Int("port", 8080))

logger.Error("operation failed",
    clog.Error(err),
    clog.String("operation", "createUser"))
7.2 使用函数式选项
logger, _ := clog.New(&clog.Config{
    Level:  "info",
    Format: "json",
    Output: "stdout",
},
    clog.WithNamespace("order-service", "api"),
    clog.WithContextField("trace_id", "trace_id"),
    clog.WithContextField("user_id", "user_id"),
    clog.WithContextField("request_id", "request_id"),
)
7.3 Context 字段提取
// 设置 Context
ctx := context.WithValue(context.Background(), "trace_id", "abc123")
ctx = context.WithValue(ctx, "user_id", "user-456")

// 使用 WithContextField 自定义提取
logger, _ := clog.New(&clog.Config{Level: "info"},
    clog.WithContextField("trace_id", "trace_id"),
    clog.WithContextField("user_id", "user_id"),
)
logger.InfoContext(ctx, "Request processed")
// 输出: {"trace_id":"abc123", "user_id":"user-456", "msg":"Request processed", ...}
7.4 使用 No-op Logger
// 测试环境使用 No-op Logger,不产生任何输出
logger := clog.Discard()

logger.Info("This will not be printed")
logger.Error("Neither will this")
7.5 使用默认配置函数
// 开发环境:启用调试级别、彩色输出、控制台输出
logger, _ := clog.New(
    clog.NewDevDefaultConfig("genesis"),
    clog.WithNamespace("user-service"),
)

// 生产环境:启用信息级别、JSON 格式、控制台输出
logger, _ := clog.New(
    clog.NewProdDefaultConfig("genesis"),
    clog.WithNamespace("user-service"),
)
7.6 开发环境彩色输出
logger, _ := clog.New(
    clog.NewDevDefaultConfig("genesis"),
    clog.WithNamespace("user-service"),
)

logger.Debug("Debug message")      // 灰色
logger.Info("Info message")        // 蓝色
logger.Warn("Warning message")     // 黄色
logger.Error("Error message")      // 红色加粗,最醒目

输出示例:

15:01:01.340 | INFO  | user-service.api | main.go:42 | Service started
15:01:02.123 | ERROR | user-service.api | main.go:50 | Failed to connect
7.7 生产环境配置
logger, _ := clog.New(&clog.Config{
    Level:      "warn",
    Format:     "json",
    Output:     "/var/log/app.log",
    AddSource:  true,
    SourceRoot: "/app",
})

8. 技术实现

  • 底层实现:基于 Go 1.21+ 标准库 log/slog
  • 性能优化:Field 直接映射为 slog.Attr,实现零内存分配(Zero Allocation)
  • 彩色输出:Console 格式支持现代 CLI 风格彩色输出,ERROR 级别加粗显示
  • 扩展性:通过私有函数封装,便于未来替换底层实现
  • 兼容性:提供完整的 API 文档和使用示例

9. API 参考

完整的 API 文档可以通过以下方式查看:

# 查看完整的包文档
go doc -all ./clog

# 查看特定函数
go doc ./clog.New
go doc ./clog.WithNamespace
go doc ./clog.String

10. 最佳实践

  1. 命名空间使用:应用级 Logger 设置主服务名,组件内使用 WithNamespace 追加
  2. Context 提取:使用 WithContextField 自定义字段,或启用 WithTraceContext 自动提取 TraceID/SpanID
  3. 错误处理:使用 Error/ErrorWithCode 统一错误日志格式
  4. 性能考虑:避免在热路径中创建大量 Field,复用 Logger 实例

Documentation

Overview

Package clog 为 Genesis 框架提供基于 slog 的结构化日志组件。 支持 Context 字段提取和命名空间管理。

特性:

  • 抽象接口,不暴露底层实现(slog)
  • 支持层级命名空间,对于子模块 order,可使用 logger.WithNamespace("order")
  • 零外部依赖(仅依赖 Go 标准库)
  • 采用函数式选项模式,符合 Genesis 标准
  • 零内存分配(Zero Allocation)设计,Field 直接映射到 slog.Attr
  • 支持多种错误字段:Error、ErrorWithCode、ErrorWithStack

基本使用:

logger, _ := clog.New(&clog.Config{
    Level:  "info",
    Format: "console",
    Output: "stdout",
})
logger.Info("Hello, World!", clog.String("key", "value"))

使用函数式选项:

logger, _ := clog.New(&clog.Config{Level: "info"},
    clog.WithNamespace("my-service", "api"),
    clog.WithContextField("trace_id", "trace_id"),
    clog.WithContextField("user_id", "user_id"),
    clog.WithContextField("request_id", "request_id"),
)

带 Context 的日志:

ctx := context.WithValue(context.Background(), "trace-id", "abc123")
logger.InfoContext(ctx, "Request processed")

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Level       string `json:"level" yaml:"level"`             // debug|info|warn|error|fatal
	Format      string `json:"format" yaml:"format"`           // json|console
	Output      string `json:"output" yaml:"output"`           // stdout|stderr|<file path>
	EnableColor bool   `json:"enableColor" yaml:"enableColor"` // 仅在 console 格式下有效,开发环境可启用彩色输出
	AddSource   bool   `json:"addSource" yaml:"addSource"`     // 是否添加调用源信息
	SourceRoot  string `json:"sourceRoot" yaml:"sourceRoot"`   // 用于裁剪文件路径,推荐设置为你的项目根目录,获取相对路径
}

Config 日志配置结构

func NewDevDefaultConfig

func NewDevDefaultConfig(sourceRoot string) *Config

NewDevDefaultConfig 创建开发环境的默认日志配置 参数 sourceRoot 推荐设置为你的项目根目录,例如 genesis,以获得更简洁的调用源信息。

func NewProdDefaultConfig

func NewProdDefaultConfig(sourceRoot string) *Config

NewProdDefaultConfig 创建生产环境的默认日志配置 参数 sourceRoot 推荐设置为你的项目根目录,例如 genesis,以获得更简洁的调用源信息。

type ContextField

type ContextField struct {
	Key       any    // Context 中存储的键
	FieldName string // 日志中的字段名
}

ContextField 定义从 Context 中提取字段的规则

type Field

type Field = slog.Attr

Field 是 slog.Attr 的类型别名,实现零内存分配

func Any

func Any(k string, v any) Field

Any 创建任意类型字段

func Bool

func Bool(k string, v bool) Field

Bool 创建布尔字段

func Duration

func Duration(k string, v time.Duration) Field

Duration 创建时间长度字段

func Error

func Error(err error) Field

Error 将错误简化为仅包含错误消息

这是轻量级的错误字段,只输出错误消息,适用于大多数场景。

func ErrorWithCode

func ErrorWithCode(err error, code string) Field

ErrorWithCode 包含错误代码的错误字段

添加业务错误码,适用于需要错误分类的场景。 使用 slog.Group 产生嵌套结构:error={code="ERR_INVALID_INPUT", msg="invalid email"}

func ErrorWithCodeStack

func ErrorWithCodeStack(err error, code string) Field

ErrorWithCodeStack 包含错误消息、错误码和堆栈信息的字段

最完整的错误字段,包含消息、类型、堆栈和错误码。 仅在需要最详细调试信息时使用,如系统严重错误。 使用 slog.Group 产生嵌套结构:error={msg="...", type="...", code="...", stack="..."}

func ErrorWithStack

func ErrorWithStack(err error) Field

ErrorWithStack 包含错误消息和堆栈信息的字段

适用于需要调试的场景,包含完整的堆栈信息。 注意:生产环境中谨慎使用,可能产生过多日志。 使用 slog.Group 产生嵌套结构:error={msg="file not found", type="*os.PathError", stack="..."}

func Float64

func Float64(k string, v float64) Field

Float64 创建浮点数字段

func Group

func Group(k string, fields ...any) Field

Group 创建嵌套字段组

func Int

func Int(k string, v int) Field

Int 创建整数字段

func Int64

func Int64(k string, v int64) Field

Int64 创建64位整数字段

func String

func String(k, v string) Field

String 创建字符串字段

func Time

func Time(k string, v time.Time) Field

Time 创建时间字段

func Uint64

func Uint64(k string, v uint64) Field

Uint64 创建64位无符号整数字段

type Level

type Level int

Level 日志级别类型

支持5个级别,按严重程度递增:

DebugLevel: 调试信息,通常只在开发环境使用
InfoLevel:  一般信息,记录正常的业务流程
WarnLevel:  警告信息,表示潜在问题
ErrorLevel: 错误信息,表示程序出错但可恢复
FatalLevel: 致命错误,程序会退出

级别数值越小优先级越高,DebugLevel 最低。

const (
	DebugLevel Level = -4 // 调试级别
	InfoLevel  Level = 0  // 信息级别
	WarnLevel  Level = 4  // 警告级别
	ErrorLevel Level = 8  // 错误级别
	FatalLevel Level = 12 // 致命级别
)

func ParseLevel

func ParseLevel(s string) (Level, error)

ParseLevel 将字符串解析为 Level

支持的字符串(不区分大小写):

"debug", "info", "warn", "error", "fatal"

如果无法解析,会返回 InfoLevel 和错误信息。

func (Level) String

func (l Level) String() string

String 返回 Level 的字符串表示

type Logger

type Logger interface {
	// 基础日志级别方法
	Debug(msg string, fields ...Field)
	Info(msg string, fields ...Field)
	Warn(msg string, fields ...Field)
	Error(msg string, fields ...Field)
	Fatal(msg string, fields ...Field)

	// 带 Context 的日志级别方法,用于自动提取 Context 字段
	DebugContext(ctx context.Context, msg string, fields ...Field)
	InfoContext(ctx context.Context, msg string, fields ...Field)
	WarnContext(ctx context.Context, msg string, fields ...Field)
	ErrorContext(ctx context.Context, msg string, fields ...Field)
	FatalContext(ctx context.Context, msg string, fields ...Field)

	// With 创建一个带有预设字段的子 Logger
	With(fields ...Field) Logger

	// WithNamespace 创建一个扩展命名空间的子 Logger
	WithNamespace(parts ...string) Logger

	// SetLevel 动态调整日志级别
	SetLevel(level Level) error

	// Flush 强制同步所有缓冲区的日志
	Flush()
}

Logger 日志接口,提供结构化日志记录功能

func Discard

func Discard() Logger

Discard 创建一个静默的 Logger 实例

返回的 Logger 实现了 Logger 接口,但所有方法体都是空操作。

func New

func New(config *Config, opts ...Option) (Logger, error)

New 创建一个新的 Logger 实例

config - 日志配置,如果为 nil 会使用默认配置 opts - 函数式选项列表,用于命名空间、Context 字段等配置

Logger - 日志实例

type Option

type Option func(*options)

Option 函数式选项,用于配置 Logger 实例

func WithContextField

func WithContextField(key any, fieldName string) Option

WithContextField 添加自定义的 Context 字段提取规则

可以从 Context 中提取任意字段并添加到日志中。 推荐常用字段:trace_id、user_id、request_id 如果开启了 OpenTelemetry TraceID 提取,则无需手动添加 trace_id 字段。

func WithNamespace

func WithNamespace(parts ...string) Option

WithNamespace 设置日志命名空间,支持多级命名空间

命名空间会以 "." 连接,作为日志中的 namespace 字段。

func WithTraceContext

func WithTraceContext() Option

WithTraceContext 开启 OpenTelemetry TraceID 自动提取

启用后,会自动从 Context 中提取 OTel 的 TraceID 和 SpanID。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL