package main import ( "fmt" "log/slog" "math/rand" "os" "strings" "sync" "time" "unicode/utf8" "code.tczkiot.com/seqlog" ) func main() { // 创建日志目录 baseDir := "./logs" if err := os.MkdirAll(baseDir, 0755); err != nil { panic(err) } // 创建 LogHub logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelInfo, })) // 自定义处理器:打印处理的记录 handler := func(topic string, record *seqlog.Record) error { previewSize := min(int(record.Len), 100) validPreviewSize := previewSize if previewSize > 0 && previewSize < int(record.Len) { // 只有在截断的情况下才需要检查 // 从后往前最多检查 3 个字节,找到最后一个完整的 UTF-8 字符边界 for i := 0; i < 3 && validPreviewSize > 0; i++ { if utf8.Valid(record.Data[:validPreviewSize]) { break } validPreviewSize-- } } fmt.Printf("[%s] 处理记录: %s\n", topic, string(record.Data[:validPreviewSize])) return nil } hub := seqlog.NewLogHub(baseDir, logger, handler) // 启动 LogHub(会自动发现和启动所有 topic) if err := hub.Start(); err != nil { panic(err) } defer hub.Stop() // topic 列表(会在第一次写入时自动创建) topics := []string{"app", "system", "access"} // 在后台启动 Web UI 服务器 go func() { fmt.Println("启动 Web UI 服务器: http://localhost:8080") if err := hub.ServeUI(":8080"); err != nil { fmt.Printf("Web UI 服务器错误: %v\n", err) } }() // 生成随机大小的数据(2KB 到 10MB) generateRandomData := func(minSize, maxSize int) []byte { size := minSize + rand.Intn(maxSize-minSize) // 使用重复字符填充,模拟实际日志内容 return []byte(strings.Repeat("X", size)) } // 启动多个并发写入器(提高并发数) var wg sync.WaitGroup concurrentWriters := 10 // 10 个并发写入器 for i := range concurrentWriters { wg.Add(1) go func(writerID int) { defer wg.Done() count := 0 ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() for range ticker.C { count++ // 随机选择 topic topic := topics[rand.Intn(len(topics))] // 生成随机大小的数据(2KB 到 2MB) minSize := 2 * 1024 // 2KB maxSize := 2 * 1024 * 1024 // 2MB randomData := generateRandomData(minSize, maxSize) // 组合消息头和随机数据 message := fmt.Sprintf("[Writer-%d] 日志 #%d - %s - 大小: %d bytes\n", writerID, count, time.Now().Format(time.RFC3339), len(randomData)) fullData := append([]byte(message), randomData...) if _, err := hub.Write(topic, fullData); err != nil { fmt.Printf("写入失败: %v\n", err) } } }(i) } // 等待用户中断 fmt.Println("\n==== Seqlog Web UI 示例 ====") fmt.Println("访问 http://localhost:8080 查看 Web UI") fmt.Println("按 Ctrl+C 退出") // 阻塞主线程 select {} }