- 修改记录存储格式为 [4B len][8B offset][4B CRC][16B UUID][data] - 修复 TopicProcessor 中 WaitGroup 使用错误导致 handler 不执行的问题 - 修复写入保护逻辑,避免 dirtyOffset=-1 时误判为写入中 - 添加统计信息定期持久化功能 - 改进 UTF-8 字符截断处理,防止 CJK 字符乱码 - 优化 Web UI:显示人类可读的文件大小,支持点击外部关闭弹窗 - 重构示例代码,添加 webui 和 webui_integration 示例 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
82 lines
2.9 KiB
Go
82 lines
2.9 KiB
Go
package seqlog
|
||
|
||
import "github.com/google/uuid"
|
||
|
||
// seqlog 是一个 Go 语言日志收集和处理库
|
||
//
|
||
// 核心特性:
|
||
// - 单文件日志处理:专注于单个日志文件的读取和处理
|
||
// - 游标尺机制:通过游标跟踪日志文件的读取位置,支持断点续读
|
||
// - 自动恢复:程序重启时自动发现已存在的日志文件并从上次位置继续处理
|
||
// - 日志收集:提供高效的日志收集和解析能力
|
||
// - tail -f 模式:支持持续监控日志文件的新增内容
|
||
// - UUID 去重:每条日志自动生成唯一 UUID,便于外部去重
|
||
// - slog 集成:内置 slog.Logger 支持,提供结构化日志记录
|
||
// - 统计功能:提供可恢复的统计信息,包括写入/处理次数、字节数、错误计数等
|
||
// - 双向查询:支持基于当前处理位置的向前/向后查询,自动标注记录状态
|
||
// - 事件通知:支持订阅各种事件(写入、处理、启动、停止等),实时状态变化通知
|
||
//
|
||
// 使用示例:
|
||
//
|
||
// // 写入日志
|
||
// writer, _ := seqlog.NewLogWriter("app.log")
|
||
// offset, _ := writer.Append([]byte("log message"))
|
||
//
|
||
// // 读取日志
|
||
// cursor, _ := seqlog.NewCursor("app.log")
|
||
// defer cursor.Close()
|
||
// for {
|
||
// rec, err := cursor.Next()
|
||
// if err != nil {
|
||
// break
|
||
// }
|
||
// // rec.UUID 是自动生成的唯一标识符,可用于去重
|
||
// fmt.Printf("UUID: %s, Data: %s\n", rec.UUID, string(rec.Data))
|
||
// }
|
||
//
|
||
// // tail -f 模式
|
||
// handler := func(rec *Record) error {
|
||
// fmt.Println(string(rec.Data))
|
||
// return nil
|
||
// }
|
||
// tailer, _ := seqlog.NewTailer("app.log", handler, nil)
|
||
// tailer.Start()
|
||
//
|
||
// // 使用 LogHub 管理器(带 slog 支持和自动恢复)
|
||
// logger := slog.Default()
|
||
// handler := func(topic string, rec *seqlog.Record) error {
|
||
// fmt.Printf("[%s] %s\n", topic, string(rec.Data))
|
||
// return nil
|
||
// }
|
||
// seq := seqlog.NewLogHub("/tmp/logs", logger, handler)
|
||
// seq.Start() // 自动发现并恢复已存在的日志文件
|
||
// seq.Write("app", []byte("application log"))
|
||
//
|
||
// // 获取统计信息
|
||
// stats, _ := seq.GetTopicStats("app")
|
||
// fmt.Printf("写入: %d 条, %d 字节\n", stats.WriteCount, stats.WriteBytes)
|
||
//
|
||
// // 查询记录
|
||
// query, _ := seq.NewTopicQuery("app")
|
||
// defer query.Close()
|
||
// current, _ := query.GetCurrent() // 获取当前处理位置
|
||
// backward, _ := query.QueryBackward(5) // 向后查询 5 条
|
||
// forward, _ := query.QueryForward(5) // 向前查询 5 条
|
||
//
|
||
// // 订阅事件
|
||
// seq.Subscribe("app", seqlog.EventWriteSuccess, func(event *seqlog.Event) {
|
||
// fmt.Printf("写入成功: offset=%d\n", event.Position)
|
||
// })
|
||
//
|
||
// seq.Stop()
|
||
|
||
// Record 日志记录
|
||
//
|
||
// 存储格式:[4B len][8B offset][4B CRC][16B UUID][data]
|
||
type Record struct {
|
||
Len uint32 // 数据长度
|
||
CRC uint32 // CRC 校验和
|
||
UUID uuid.UUID // UUID,用于去重
|
||
Data []byte // 实际数据
|
||
}
|