瀏覽代碼

日志改使用第三方日志库 zerolog

shizhongqi 11 月之前
父節點
當前提交
98de475680
共有 8 個文件被更改,包括 159 次插入58 次删除
  1. 3 0
      .env.example
  2. 4 0
      go.mod
  3. 15 0
      go.sum
  4. 33 0
      logger/logger.go
  5. 29 13
      main.go
  6. 2 1
      wsClient/client.go
  7. 59 33
      wsClient/redis.go
  8. 14 11
      wsClient/room.go

+ 3 - 0
.env.example

@@ -1,3 +1,6 @@
+LOG_MODE=color
+LOG_LEVEL=0
+
 REDIS_ADDR=118.178.193.23:6379
 REDIS_PASSWORD=byt6gc1w0aed2q7h
 REDIS_DB=0

+ 4 - 0
go.mod

@@ -11,4 +11,8 @@ require (
 require (
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/rs/zerolog v1.33.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
 )

+ 15 - 0
go.sum

@@ -4,11 +4,26 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
 github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
 github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
+github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

+ 33 - 0
logger/logger.go

@@ -0,0 +1,33 @@
+package logger
+
+import (
+	"os"
+	"time"
+
+	"github.com/rs/zerolog"
+	"github.com/rs/zerolog/log"
+)
+
+// InitLogger 初始化日志
+func InitLogger(logMode string, logLevel zerolog.Level) {
+	if logMode == "color" { // 控制台模式 + 彩色输出
+		consoleWriter := zerolog.ConsoleWriter{
+			Out:        os.Stdout,
+			TimeFormat: time.RFC3339,
+		}
+		// 默认 Info 级别
+		log.Logger = log.Output(consoleWriter).Level(logLevel)
+	} else if logMode == "standard" { // 生产模式:标准 JSON 日志
+		// 生产模式:标准 JSON 日志
+		zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+		log.Logger = log.Output(os.Stdout).Level(logLevel)
+	} else {
+		// 默认模式:控制台模式 + 彩色输出
+		consoleWriter := zerolog.ConsoleWriter{
+			Out:        os.Stdout,
+			TimeFormat: time.RFC3339,
+		}
+		// 默认 Info 级别
+		log.Logger = log.Output(consoleWriter).Level(logLevel)
+	}
+}

+ 29 - 13
main.go

@@ -3,15 +3,18 @@
 package main
 
 import (
+	"chatapp/logger"
 	"chatapp/templates"
 	"chatapp/wsClient"
 	"flag"
 	"fmt"
-	"log"
 	"net/http"
 	"os"
+	"strconv"
 
 	"github.com/joho/godotenv"
+	"github.com/rs/zerolog"
+	"github.com/rs/zerolog/log"
 )
 
 func main() {
@@ -19,7 +22,19 @@ func main() {
 	if err := godotenv.Load(); err != nil {
 		panic("没有找到 .env 文件,将使用系统环境变量和默认值")
 	}
-	
+
+	logMode := os.Getenv("LOG_MODE")
+	if logMode == "" {
+		logMode = "color" // 默认开发环境
+	}
+	//logLevel, err := strconv.ParseInt(os.Getenv("LOG_LEVEL"), 10, 8)
+	logLevel, err := strconv.Atoi(os.Getenv("LOG_LEVEL"))
+	if err != nil {
+		log.Error().Err(err).Msg("获取 log level 失败,使用默认值 0")
+		logLevel = 0 // 默认 debug log level.
+	}
+	logger.InitLogger(logMode, zerolog.Level(logLevel))
+
 	var addr = flag.String("addr", ":8080", "Addr of the App")
 	flag.Parse()
 
@@ -30,8 +45,8 @@ func main() {
 
 	// 初始化Redis连接
 	if err := wsClient.InitializeRedisFromEnv(); err != nil {
-		log.Printf("Redis初始化失败: %v", err)
-		log.Println("将继续运行,但不会存储消息到Redis")
+		log.Error().Err(err).Msg("Redis初始化失败")
+		log.Info().Msg("将继续运行,但不会存储消息到Redis")
 	} else {
 		// 确保程序退出时关闭Redis连接
 		defer wsClient.CloseRedis()
@@ -40,7 +55,7 @@ func main() {
 	// 设置静态文件服务器,处理 CSS、JS 等静态资源
 	// StripPrefix 会移除 URL 前缀 "/static/",然后从 "static" 目录提供文件
 	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
-	
+
 	// 主页路由,渲染 index.html 模板
 	http.Handle("/", &templates.TemplateHandler{Filename: "index.html"})
 
@@ -49,19 +64,19 @@ func main() {
 
 	// Handle all websocket connections for chat rooms dynamically
 	http.HandleFunc("/room", func(w http.ResponseWriter, r *http.Request) {
-		log.Println("--------------------------------")
-		log.Println("Received request for room")
+		log.Info().Msg("--------------------------------")
+		log.Info().Msg("Received request for room")
 		// 从WebSocket子协议中预解析房间名称
 		protocols := r.Header["Sec-Websocket-Protocol"]
 		if len(protocols) == 0 {
-			log.Println("No protocols found")
+			log.Warn().Msg("No protocols found")
 			return
 		}
 
 		// 解析房间参数
 		roomParams, err := wsClient.ParseWebSocketProtocols(protocols)
 		if err != nil {
-			log.Printf("解析WebSocket协议参数失败: %v", err)
+			log.Error().Err(err).Msg("解析WebSocket协议参数失败")
 			http.Error(w, "Invalid WebSocket protocols", http.StatusBadRequest)
 			return
 		}
@@ -69,10 +84,11 @@ func main() {
 		// 组合房间名称
 		roomName := fmt.Sprintf("custom_id-%dANDshop_id-%d", roomParams.CustomId, roomParams.ShopId)
 		if roomName == "" {
-            http.Error(w, "Room name required in WebSocket protocols or URL parameter", http.StatusBadRequest)
+			http.Error(w, "Room name required in WebSocket protocols or URL parameter", http.StatusBadRequest)
 		}
 		roomParams.RoomName = roomName
-		log.Printf("---- 房间名称: %s\n\n", roomName)
+		// log.Printf("---- 房间名称: %s\n\n", roomName)
+		log.Info().Str("roomName", roomName).Msg("---- 房间名称")
 
 		// 获取(或创建)指定名称的房间,并启动房间的消息处理协程
 		room := wsClient.GetRoomAndRun(roomName)
@@ -81,9 +97,9 @@ func main() {
 	})
 
 	// 启动 HTTP 服务器
-	log.Println("正在启动 Web 服务器,监听地址:", *addr)
+	log.Info().Str("addr", *addr).Msg("正在启动 Web 服务器")
 	// 开始监听并处理 HTTP 请求,如果启动失败则退出程序
 	if err := http.ListenAndServe(*addr, nil); err != nil {
-		log.Fatal("服务器启动失败:", err)
+		log.Fatal().Err(err).Msg("服务器启动失败")
 	}
 }

+ 2 - 1
wsClient/client.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 
 	"github.com/gorilla/websocket" // WebSocket 库
+	"github.com/rs/zerolog/log"
 )
 
 // Client represents connection to a single chatting user
@@ -70,7 +71,7 @@ func (c *Client) read() {
 		// 将消息对象编码为 JSON 格式
 		jsMessage, err := json.Marshal(outgoing)
 		if err != nil {
-			fmt.Println("Enconding failed!")
+			log.Error().Err(err).Msg("Enconding failed!")
 			continue
 		}
 

+ 59 - 33
wsClient/redis.go

@@ -5,12 +5,12 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"log"
 	"os"
 	"strconv"
 	"time"
 
 	"github.com/redis/go-redis/v9"
+	"github.com/rs/zerolog/log"
 )
 
 // Redis客户端实例,全局变量
@@ -76,10 +76,10 @@ func InitRedis(addr, password string, db int) error {
 	// 测试Redis连接
 	pong, err := redisClient.Ping(ctx).Result()
 	if err != nil {
-		log.Printf("Redis连接失败: %v", err)
+		log.Error().Err(err).Msg("Redis连接失败")
 		return err
 	}
-	log.Printf("Redis连接成功: %s", pong)
+	log.Info().Str("pong", pong).Msg("Redis连接成功")
 	return nil
 }
 
@@ -87,7 +87,7 @@ func InitRedis(addr, password string, db int) error {
 // 使用房间名作为Redis列表的键,存储消息历史记录
 func StoreRawMessage(roomName string, rawMessage []byte) error {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil
 	}
 
@@ -101,7 +101,7 @@ func StoreRawMessage(roomName string, rawMessage []byte) error {
 	// 将消息序列化为JSON
 	msgBytes, err := json.Marshal(chatMsg)
 	if err != nil {
-		log.Printf("消息序列化失败: %v", err)
+		log.Error().Err(err).Msg("消息序列化失败")
 		return err
 	}
 
@@ -110,14 +110,14 @@ func StoreRawMessage(roomName string, rawMessage []byte) error {
 	key := "room_messages:" + roomName
 	err = redisClient.RPush(ctx, key, msgBytes).Err()
 	if err != nil {
-		log.Printf("消息存储到Redis失败: %v", err)
+		log.Error().Err(err).Str("key", key).Msg("消息存储到Redis失败")
 		return err
 	}
 
 	// 设置过期时间(可选)- 7天后自动删除
 	redisClient.Expire(ctx, key, 7*24*time.Hour)
 
-	log.Printf("消息已存储到Redis - 房间: %s\n\n", roomName)
+	log.Debug().Str("roomName", roomName).Msg("消息已存储到Redis")
 	return nil
 }
 
@@ -125,7 +125,7 @@ func StoreRawMessage(roomName string, rawMessage []byte) error {
 // 使用房间名作为Redis列表的键,存储消息历史记录
 func StoreMessage(roomName, username, message string) error {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil
 	}
 
@@ -143,7 +143,7 @@ func StoreMessage(roomName, username, message string) error {
 // 使用浮点数分数同时存储时间戳和未读消息数
 func UpdateRecentContacts(client *Client) error {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil
 	}
 
@@ -233,7 +233,7 @@ func UpdateRecentContacts(client *Client) error {
 		}
 	}
 
-	log.Printf("最近联系人列表已更新 - client name: %s", client.name)
+	log.Debug().Str("clientName", client.name).Msg("最近联系人列表已更新")
 	return nil
 }
 
@@ -241,7 +241,7 @@ func UpdateRecentContacts(client *Client) error {
 // 为接收者(对方)的联系人列表增加未读消息数
 func IncrementUnreadCount(sender *Client, count int) error {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil
 	}
 
@@ -261,14 +261,14 @@ func IncrementUnreadCount(sender *Client, count int) error {
 		receiverID = sender.userInfo.ShopId
 		senderMember = strconv.Itoa(int(sender.userInfo.CustomId))
 	} else {
-		log.Printf("未知的客户端类型: %s", sender.userInfo.Type)
+		log.Warn().Str("clientType", sender.userInfo.Type).Msg("未知的客户端类型")
 		return nil
 	}
 
 	// 获取接收者的联系人列表键
 	key := getContactKey(receiverType, receiverID)
 	if key == "" {
-		log.Printf("无法生成联系人键 - 类型: %s, ID: %d", receiverType, receiverID)
+		log.Error().Str("receiverType", receiverType).Int32("receiverID", receiverID).Msg("无法生成联系人键")
 		return nil
 	}
 
@@ -296,8 +296,14 @@ func IncrementUnreadCount(sender *Client, count int) error {
 	// 设置过期时间
 	redisClient.Expire(ctx, key, ContactTTL)
 
-	log.Printf("未读消息数已增加 - 接收者类型: %s, 接收者ID: %d, 发送者ID: %s, 未读数: %d, 新分数: %f",
-		receiverType, receiverID, senderMember, newUnread, newScore)
+	// log.Printf("未读消息数已增加 - 接收者类型: %s, 接收者ID: %d, 发送者ID: %s, 未读数: %d, 新分数: %f", receiverType, receiverID, senderMember, newUnread, newScore)
+	log.Debug().
+		Str("receiverType", receiverType).
+		Int32("receiverID", receiverID).
+		Str("senderMember", senderMember).
+		Int("newUnread", newUnread).
+		Float64("newScore", newScore).
+		Msg("未读消息数已增加")
 	return nil
 }
 
@@ -305,7 +311,7 @@ func IncrementUnreadCount(sender *Client, count int) error {
 // 返回指定数量的最新消息
 func GetRoomMessages(roomName string, count int64) ([]ChatMessage, error) {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil, nil
 	}
 
@@ -315,7 +321,8 @@ func GetRoomMessages(roomName string, count int64) ([]ChatMessage, error) {
 	// -count 表示从列表末尾开始的count个元素
 	result, err := redisClient.LRange(ctx, key, -count, -1).Result()
 	if err != nil {
-		log.Printf("从Redis获取消息失败: %v", err)
+		//log.Printf("从Redis获取消息失败: %v", err)
+		log.Error().Err(err).Str("key", key).Msg("从Redis获取消息失败")
 		return nil, err
 	}
 
@@ -323,7 +330,8 @@ func GetRoomMessages(roomName string, count int64) ([]ChatMessage, error) {
 	for _, msgStr := range result {
 		var msg ChatMessage
 		if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {
-			log.Printf("消息反序列化失败: %v", err)
+			// log.Printf("消息反序列化失败: %v", err)
+			log.Error().Err(err).Str("message", msgStr).Msg("消息反序列化失败")
 			continue
 		}
 		messages = append(messages, msg)
@@ -384,7 +392,7 @@ func getContactKey(userType string, id int32) string {
 // 返回按最后聊天时间排序的联系人列表(最新的在前)
 func GetRecentContacts(userType string, userID int32, limit int64) ([]ContactInfo, error) {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return nil, nil
 	}
 
@@ -396,7 +404,7 @@ func GetRecentContacts(userType string, userID int32, limit int64) ([]ContactInf
 	// 获取最近的联系人(按分数降序,最新的在前)
 	result, err := redisClient.ZRevRangeWithScores(ctx, key, 0, limit-1).Result()
 	if err != nil {
-		log.Printf("获取最近联系人失败: %v", err)
+		log.Error().Err(err).Str("key", key).Msg("获取最近联系人失败")
 		return nil, err
 	}
 
@@ -404,7 +412,8 @@ func GetRecentContacts(userType string, userID int32, limit int64) ([]ContactInf
 	for _, item := range result {
 		contactID, err := strconv.Atoi(item.Member.(string))
 		if err != nil {
-			log.Printf("解析联系人ID失败: %v", err)
+			// log.Printf("解析联系人ID失败: %v", err)
+			log.Error().Err(err).Any("member", item.Member).Msg("解析联系人ID失败")
 			continue
 		}
 
@@ -431,7 +440,7 @@ func GetRecentContacts(userType string, userID int32, limit int64) ([]ContactInf
 // GetTotalUnreadCount 获取用户的总未读消息数
 func GetTotalUnreadCount(userType string, userID int32) (int, error) {
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return 0, nil
 	}
 
@@ -443,7 +452,7 @@ func GetTotalUnreadCount(userType string, userID int32) (int, error) {
 	// 获取所有联系人的分数
 	result, err := redisClient.ZRangeWithScores(ctx, key, 0, -1).Result()
 	if err != nil {
-		log.Printf("获取联系人分数失败: %v", err)
+		log.Error().Err(err).Str("key", key).Msg("获取联系人分数失败")
 		return 0, err
 	}
 
@@ -470,13 +479,13 @@ func ClearUnreadCount(client *Client) error {
 	}
 
 	if redisClient == nil {
-		log.Println("Redis客户端未初始化")
+		log.Warn().Msg("Redis客户端未初始化")
 		return fmt.Errorf("redis client is not initialized")
 	}
 
 	key := getContactKey(client.userInfo.Type, id)
 	if key == "" {
-		log.Printf("无效的用户类型: %s", client.userInfo.Type)
+		log.Error().Str("userType", client.userInfo.Type).Msg("无效的用户类型")
 		return fmt.Errorf("invalid user type: %s", client.userInfo.Type)
 	}
 
@@ -486,13 +495,22 @@ func ClearUnreadCount(client *Client) error {
 	if err != nil {
 		if err == redis.Nil {
 			// 如果联系人不存在,这并非一个错误,只是无需清理。
-			log.Printf("Contact not found, no unread count to clear - UserType: %s, UserID: %d, ContactID: %d",
-				client.userInfo.Type, id, contactID)
+			// log.Printf("Contact not found, no unread count to clear - UserType: %s, UserID: %d, ContactID: %d", client.userInfo.Type, id, contactID)
+			log.Debug().
+				Str("userType", client.userInfo.Type).
+				Int32("userID", id).
+				Int32("contactID", contactID).
+				Msg("Contact not found, no unread count to clear")
 			return nil
 		}
 		// 对于其他类型的错误(如连接问题),则返回错误。
-		log.Printf("failed to get score for contact - UserType: %s, UserID: %d, ContactID: %d, Error: %v",
-			client.userInfo.Type, id, contactID, err)
+		// log.Printf("failed to get score for contact - UserType: %s, UserID: %d, ContactID: %d, Error: %v",client.userInfo.Type, id, contactID, err)
+		log.Error().
+			Err(err).
+			Str("userType", client.userInfo.Type).
+			Int32("userID", id).
+			Int32("contactID", contactID).
+			Msg("failed to get score for contact")
 		return err
 	}
 
@@ -505,12 +523,20 @@ func ClearUnreadCount(client *Client) error {
 		Score:  newScore,
 		Member: contactIDStr,
 	}).Err(); err != nil {
-		log.Printf("failed to clear unread count - UserType: %s, UserID: %d, ContactID: %d, Error: %v",
-			client.userInfo.Type, id, contactID, err)
+		log.Error().
+			Err(err).
+			Str("userType", client.userInfo.Type).
+			Int32("userID", id).
+			Int32("contactID", contactID).
+			Msg("failed to clear unread count")
 		return err
 	}
 
-	log.Printf("未读消息数已清除 - 用户类型: %s, 用户ID: %d, 联系人ID: %d",
-		client.userInfo.Type, id, contactID)
+	// log.Printf("未读消息数已清除 - 用户类型: %s, 用户ID: %d, 联系人ID: %d", client.userInfo.Type, id, contactID)
+	log.Info().
+		Str("userType", client.userInfo.Type).
+		Int32("userID", id).
+		Int32("contactID", contactID).
+		Msg("未读消息数已清除")
 	return nil
 }

+ 14 - 11
wsClient/room.go

@@ -5,7 +5,6 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"log"
 	"math/rand"
 	"net/http"
 	"net/url"
@@ -13,6 +12,7 @@ import (
 	"sync"
 
 	"github.com/gorilla/websocket"
+	"github.com/rs/zerolog/log"
 )
 
 // 全局房间 map,存储所有创建的房间
@@ -105,7 +105,8 @@ func (r *Room) run() {
 			}
 			// 将新客户端添加到房间的客户端集合中
 			r.clientConns[client] = true // 使用 true 作为值,实际上只使用 key(client 指针)
-			log.Printf("客户端 %v 加入房间 %v", client.name, r.name)
+			// log.Printf("客户端 %v 加入房间 %v", client.name, r.name)
+			log.Info().Str("clientName", client.name).Str("roomName", r.name).Msg("客户端加入房间")
 			// 清空未读消息数
 			go ClearUnreadCount(client)
 
@@ -119,9 +120,9 @@ func (r *Room) run() {
 			delete(r.clientConns, client)
 			// 关闭客户端的接收 channel,通知客户端的 write() 方法退出
 			close(client.receive)
-			log.Printf("客户端 %v 离开房间 %v", client.name, r.name)
+			log.Info().Str("clientName", client.name).Str("roomName", r.name).Msg("客户端离开房间")
 			if len(r.clientConns) == 0 {
-				log.Printf("房间 %v 没有客户端,关闭房间", r.name)
+				log.Info().Str("roomName", r.name).Msg("房间没有客户端,关闭房间")
 				close(r.forward)
 				close(r.join)
 				close(r.leave)
@@ -136,7 +137,7 @@ func (r *Room) run() {
 				return // channel已关闭,退出goroutine
 			}
 			// 打印消息内容与发送者信息
-			log.Printf("Received message from %v: --- %s", msg.sender, string(msg.content))
+			log.Debug().Str("sender", msg.sender.name).Str("message", string(msg.content)).Msg("Received message")
 
 			// 直接存储原始消息内容到Redis,使用房间名作为键
 			go StoreRawMessage(r.name, msg.content) // 异步存储,不阻塞消息转发
@@ -227,7 +228,7 @@ func ParseWebSocketProtocols(protocols []string) (*RoomParams, error) {
 			// 分割协议字符串,获取各个参数部分
 			parts := strings.Split(protocol, ",")
 			if len(parts) < 2 {
-				log.Printf("协议格式错误,参数不足: %s", protocol)
+				log.Warn().Str("protocol", protocol).Msg("协议格式错误,参数不足")
 				continue
 			}
 
@@ -235,15 +236,17 @@ func ParseWebSocketProtocols(protocols []string) (*RoomParams, error) {
 			for i := 1; i < len(parts); i++ {
 				part := strings.TrimSpace(parts[i])
 				if err := parseProtocolPart(part, &params); err != nil {
-					log.Printf("解析协议部分失败 %s: %v", part, err)
+					// log.Printf("解析协议部分失败 %s: %v", part, err)
+					log.Error().Err(err).Str("part", part).Msg("解析协议部分失败")
 					continue
 				}
 			}
 
-			log.Printf("成功解析WebSocket协议参数: %+v\n", params)
+			// log.Printf("成功解析WebSocket协议参数: %+v\n", params)
+			log.Info().Any("params", params).Msg("成功解析WebSocket协议参数")
 			return &params, nil
 		} else {
-			log.Printf("跳过非chat协议: %s", protocol)
+			log.Debug().Str("protocol", protocol).Msg("跳过非chat协议")
 		}
 	}
 
@@ -341,7 +344,7 @@ func parseProtocolPart(part string, params *RoomParams) error {
 	// 当有 p4 参数时,解析 p4 参数
 
 	default:
-		log.Printf("未知的参数前缀: %s", prefix)
+		log.Warn().Str("prefix", prefix).Msg("未知的参数前缀")
 	}
 
 	return nil
@@ -356,7 +359,7 @@ func (r *Room) HttpServe(w http.ResponseWriter, req *http.Request,roomParams *Ro
 	
 	socket, err := upgrader.Upgrade(w, req, responseHeader)
 	if err != nil {
-		log.Println("Upgrade error:", err)
+		log.Error().Err(err).Msg("Upgrade error")
 		return
 	}