olekukonko/ll
GitHub: olekukonko/ll
`ll` 是一个面向 Go 语言的现代结构化日志库,通过分层命名空间、条件日志和丰富的调试工具解决开发与生产环境中日志细粒度控制和高性能输出的痛点。
Stars: 1 | Forks: 0
# ll - 一个现代的结构化 Go 日志库
`ll` 是一个高性能、可用于生产环境的 Go 日志库,旨在提供**分层命名空间**、**结构化日志**、**中间件管道**、**条件日志**,并支持多种输出格式,包括文本、JSON、彩色日志、syslog、VictoriaLogs 以及兼容 Go 的 `slog`。它非常适合需要对日志进行细粒度控制、要求高可扩展性和扩展性的应用程序。
## 主要特性
- **默认开启日志** - 零配置即可开始记录日志
- **分层命名空间** - 通过对子系统(例如 "app/db")的细粒度控制来组织日志
- **结构化日志** - 添加键值对元数据,以实现机器可读的日志
- **中间件管道** - 通过限流、采样和去重来自定义日志处理
- **条件与基于错误的日志** - 通过流式的 `If`、`IfErr`、`IfAny`、`IfOne` 链优化性能
- **多种输出格式** - 文本、JSON、彩色 ANSI、syslog、VictoriaLogs 以及 `slog` 集成
- **高级调试工具** - 感知源码的 `Dbg()`、十六进制/ASCII `Dump()`、私有字段 `Inspect()` 以及堆栈跟踪
- **生产就绪** - 缓冲批处理、日志轮转、重复抑制和限流
- **线程安全** - 专为高并发构建,使用原子操作、分片互斥锁和无锁快速路径
- **性能优化** - 禁用的日志零分配,sync.Pool 缓冲区,源文件的 LRU 缓存
## 安装说明
使用 Go modules 安装 `ll`:
```
go get github.com/olekukonko/ll
```
需要 Go 1.21 或更高版本。
## 快速入门
```
package main
import "github.com/olekukonko/ll"
func main() {
// Logger is ENABLED by default - no .Enable() needed!
logger := ll.New("app")
// Basic logging - works immediately
logger.Info("Server starting") // Output: [app] INFO: Server starting
logger.Warn("Memory high") // Output: [app] WARN: Memory high
logger.Error("Connection failed") // Output: [app] ERROR: Connection failed
// Structured fields
logger.Fields("user", "alice", "status", 200).Info("Login successful")
// Output: [app] INFO: Login successful [user=alice status=200]
}
```
**就是这样。不需要 `.Enable()`,也不需要配置 handler——它直接就能工作。**
## 核心概念
### 1. 默认启用,按需配置
与许多需要显式启用的日志库不同,`ll` **立即记录日志**。这消除了样板代码,并降低了在生产环境中遗漏日志的风险。
```
// This works out of the box:
ll.Info("Service started") // Output: [] INFO: Service started
// But you still have full control:
ll.Disable() // Global shutdown
ll.Enable() // Reactivate
```
### 2. 分层命名空间
通过分层组织日志,精确控制各个子系统:
```
// Create a logger hierarchy
root := ll.New("app")
db := root.Namespace("database")
cache := root.Namespace("cache").Style(lx.NestedPath)
// Control logging per namespace
root.NamespaceEnable("app/database") // Enable database logs
root.NamespaceDisable("app/cache") // Disable cache logs
db.Info("Connected") // Output: [app/database] INFO: Connected
cache.Info("Hit") // No output (disabled)
```
### 3. 具有有序字段的结构化日志
字段保持插入顺序,并支持流式链式调用:
```
// Fluent key-value pairs
logger.
Fields("request_id", "req-123").
Fields("user", "alice").
Fields("duration_ms", 42).
Info("Request processed")
// Map-based fields
logger.Field(map[string]interface{}{
"method": "POST",
"path": "/api/users",
}).Debug("API call")
// Persistent context (included in ALL subsequent logs)
logger.AddContext("environment", "production", "version", "1.2.3")
logger.Info("Deployed") // Output: ... [environment=production version=1.2.3]
```
### 4. 条件与基于错误的日志
通过流式条件链优化性能,当条件为假时,**会完全跳过处理过程**:
```
// Boolean conditions
logger.If(debugMode).Debug("Detailed diagnostics") // No overhead when false
logger.If(featureEnabled).Info("Feature used")
// Error conditions
err := db.Query()
logger.IfErr(err).Error("Query failed") // Logs only if err != nil
// Multiple conditions - ANY true
logger.IfErrAny(err1, err2, err3).Fatal("System failure")
// Multiple conditions - ALL true
logger.IfErrOne(validateErr, authErr).Error("Both checks failed")
// Chain conditions
logger.
If(debugMode).
IfErr(queryErr).
Fields("query", sql).
Debug("Query debug")
```
**性能表现**:当条件为假时,logger 会立即返回,并且是零分配的。
### 5. 强大的调试工具包
`ll` 包含标准日志库中没有的高级调试工具:
#### Dbg() - 感知源码的变量检查
从你的源代码中捕获变量名和值:
```
x := 42
user := &User{Name: "Alice"}
ll.Dbg(x, user)
// Output: [file.go:123] x = 42, *user = &{Name:Alice}
```
#### Dump() - 十六进制/ASCII 二进制检查
非常适合协议调试和二进制数据:
```
ll.Handler(lh.NewColorizedHandler(os.Stdout))
ll.Dump([]byte("hello\nworld"))
// Output: Colorized hex/ASCII dump with offset markers
```
#### Inspect() - 私有字段反射
揭示未导出的字段、嵌入式 struct 和指针内部结构:
```
type secret struct {
password string // unexported!
}
s := secret{password: "hunter2"}
ll.Inspect(s)
// Output: [file.go:123] INSPECT: {
// "(password)": "hunter2" // Note the parentheses
// }
```
#### Stack() - 可配置的堆栈跟踪
```
ll.StackSize(8192) // Larger buffer for deep stacks
ll.Stack("Critical failure")
// Output: ERROR: Critical failure [stack=goroutine 1 [running]...]
```
#### Mark() - 执行流程追踪
```
func process() {
ll.Mark() // *MARK*: [file.go:123]
ll.Mark("phase1") // *phase1*: [file.go:124]
// ... work ...
}
```
### 6. 生产就绪的 handler
```
import (
"github.com/olekukonko/ll"
"github.com/olekukonko/ll/lh"
"github.com/olekukonko/ll/l3rd/syslog"
"github.com/olekukonko/ll/l3rd/victoria"
)
// JSON for structured logging
logger.Handler(lh.NewJSONHandler(os.Stdout))
// Colorized for development
logger.Handler(lh.NewColorizedHandler(os.Stdout,
lh.WithColorTheme("dark"),
lh.WithColorIntensity(lh.IntensityVibrant),
))
// Buffered for high throughput (100 entries or 10 seconds)
buffered := lh.NewBuffered(
lh.NewJSONHandler(os.Stdout),
lh.WithBatchSize(100),
lh.WithFlushInterval(10 * time.Second),
)
logger.Handler(buffered)
defer buffered.Close() // Ensures flush on exit
// Syslog integration
syslogHandler, _ := syslog.New(
syslog.WithTag("myapp"),
syslog.WithFacility(syslog.LOG_LOCAL0),
)
logger.Handler(syslogHandler)
// VictoriaLogs (cloud-native)
victoriaHandler, _ := victoria.New(
victoria.WithURL("http://victoria-logs:9428"),
victoria.WithAppName("payment-service"),
victoria.WithEnvironment("production"),
victoria.WithBatching(200, 5*time.Second),
)
logger.Handler(victoriaHandler)
```
### 7. 中间件管道
通过中间件管道转换、过滤或拒绝日志:
```
// Rate limiting - 10 logs per second maximum
rateLimiter := lm.NewRateLimiter(lx.LevelInfo, 10, time.Second)
logger.Use(rateLimiter)
// Sampling - 10% of debug logs
sampler := lm.NewSampling(lx.LevelDebug, 0.1)
logger.Use(sampler)
// Deduplication - suppress identical logs for 2 seconds
deduper := lh.NewDedup(logger.GetHandler(), 2*time.Second)
logger.Handler(deduper)
// Custom middleware
logger.Use(ll.Middle(func(e *lx.Entry) error {
if strings.Contains(e.Message, "password") {
return fmt.Errorf("sensitive information redacted")
}
return nil
}))
```
### 8. 全局便捷 API
使用包级别的函数进行快速日志记录,无需创建 logger:
```
import "github.com/olekukonko/ll"
func main() {
ll.Info("Server starting") // Global logger
ll.Fields("port", 8080).Info("Listening")
// Conditional logging at package level
ll.If(simulation).Debug("Test mode")
ll.IfErr(err).Error("Startup failed")
// Debug utilities
ll.Dbg(config)
ll.Dump(requestBody)
ll.Inspect(complexStruct)
}
```
## 真实场景示例
### 带有结构化日志的 Web 服务器
```
package main
import (
"github.com/olekukonko/ll"
"github.com/olekukonko/ll/lh"
"net/http"
"time"
)
func main() {
// Root logger - enabled by default
log := ll.New("server")
// JSON output for production
log.Handler(lh.NewJSONHandler(os.Stdout))
// Request logger with context
http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
reqLog := log.Namespace("http").Fields(
"method", r.Method,
"path", r.URL.Path,
"request_id", r.Header.Get("X-Request-ID"),
)
start := time.Now()
reqLog.Info("request started")
// ... handle request ...
reqLog.Fields(
"status", 200,
"duration_ms", time.Since(start).Milliseconds(),
).Info("request completed")
})
log.Info("Server listening on :8080")
http.ListenAndServe(":8080", nil)
}
```
### 使用 VictoriaLogs 的微服务
```
package main
import (
"github.com/olekukonko/ll"
"github.com/olekukonko/ll/l3rd/victoria"
)
func main() {
// Production setup
vlHandler, _ := victoria.New(
victoria.WithURL("http://logs.internal:9428"),
victoria.WithAppName("payment-api"),
victoria.WithEnvironment("production"),
victoria.WithVersion("1.2.3"),
victoria.WithBatching(500, 2*time.Second),
victoria.WithRetry(3),
)
defer vlHandler.Close()
logger := ll.New("payment").
Handler(vlHandler).
AddContext("region", "us-east-1")
logger.Info("Payment service initialized")
// Conditional error handling
if err := processPayment(); err != nil {
logger.IfErr(err).
Fields("payment_id", paymentID).
Error("Payment processing failed")
}
}
```
## 性能表现
`ll` 专为高性能环境而设计:
| 操作 | Time/op | 内存分配 |
|-----------|---------|-------------|
| **禁用的日志** | **15.9 ns** | **0 allocs** |
| 简单文本日志 | 176 ns | 2 allocs |
| 带有 2 个字段 | 383 ns | 4 allocs |
| JSON 输出 | 1006 ns | 13 allocs |
| 命名空间查找(已缓存) | 550 ns | 6 allocs |
| 去重 | 214 ns | 2 allocs |
**关键优化**:
- 当日志被跳过时(条件不满足或禁用)实现零分配
- 针对热点路径的原子操作
- 用于缓冲区重用的 sync.Pool
- 用于源文件行的 LRU 缓存
- 用于去重的分片互斥锁
## 为什么选择 `ll`?
| 特性 | `ll` | `slog` | `zap` | `logrus` |
|---------|------|--------|-------|----------|
| **默认启用** | ✅ | ❌ | ❌ | ❌ |
| 分层命名空间 | ✅ | ❌ | ❌ | ❌ |
| 条件日志 | ✅ | ❌ | ❌ | ❌ |
| 基于错误的条件 | ✅ | ❌ | ❌ | ❌ |
| 感知源码的 Dbg() | ✅ | ❌ | ❌ | ❌ |
| 私有字段检查 | ✅ | ❌ | ❌ | ❌ |
| 十六进制/ASCII Dump() | ✅ | ❌ | ❌ | ❌ |
| 中间件管道 | ✅ | ❌ | ✅(有限) | ❌ |
| 去重 | ✅ | ❌ | ❌ | ❌ |
| 限流 | ✅ | ❌ | ❌ | ❌ |
| 支持 VictoriaLogs | ✅ | ❌ | ❌ | ❌ |
| 支持 syslog | ✅ | ❌ | ❌ | ✅ |
| 禁用日志零分配 | ✅ | ❌ | ❌ | ❌ |
| 线程安全 | ✅ | ✅ | ✅ | ✅ |
## 文档
- [GoDoc](https://pkg.go.dev/github.com/olekukonko/ll) - 完整的 API 文档
- [示例](_example/) - 可运行的示例代码
- [基准测试](tests/ll_bench_test.go) - 性能基准测试
## 贡献
欢迎提交贡献!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解指南。
## 许可证
MIT 许可证 - 详情请参阅 [LICENSE](LICENSE)。
标签:EVTX分析, Go, Linux安全, Ruby工具, SOC Prime, 中间件, 并发编程, 开发工具, 日志审计, 日志库, 结构化日志