[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-en-1-1-all-message-logging-in-websocket-en-all--*":3,"academy-blog-translations-b02q9ypqv7t4g2q":85},{"data":4,"page":72,"perPage":72,"totalItems":72,"totalPages":72},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":80,"keywords":81,"locale":54,"published_at":82,"scheduled_at":13,"school_blog":76,"short_description":83,"status":74,"title":6,"updated":84,"updated_by":13,"slug":77,"views":79},"EP.72 Implementing Message Logging in WebSocket Chat with Go","sclblg987654321","school_blog_translations","\u003Cp>In this episode, we’ll explore how to build a message logging system for WebSocket chat applications using Go. This system enables real-time recording of chat messages sent to and from the WebSocket server, and stores them in a database for later access by users.\u003C\u002Fp>\u003Cp>Message logging is a crucial part of any chat platform. It helps in preserving conversation history, auditing user behavior, troubleshooting system issues, and providing an improved user experience by allowing users to review past messages.\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>Why Use Message Logging in WebSocket?\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>Implementing a message logging system brings several benefits:\u003C\u002Fp>\u003Cul>\u003Cli>Chat history tracking: All messages are stored persistently and can be retrieved later\u003C\u002Fli>\u003Cli>Conversation review: Admins or users can check messages sent at any point in time\u003C\u002Fli>\u003Cli>Security &amp; moderation: Helps monitor user behavior and prevent inappropriate usage\u003C\u002Fli>\u003Cli>Data recovery: Logged messages allow for recovery in case of system crashes or unexpected shutdowns\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>System Architecture Overview\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>A complete message logging system consists of:\u003C\u002Fp>\u003Col>\u003Cli>Saving messages into the database\u003Cbr>Every chat message is saved with metadata such as sender, content, timestamp, and optionally a room ID\u003C\u002Fli>\u003Cli>Receiving messages via WebSocket\u003Cbr>The WebSocket server receives messages in real time and immediately logs them\u003C\u002Fli>\u003Cli>Fetching past messages\u003Cbr>The backend provides a way to retrieve previously logged messages (e.g., for chat history display)\u003C\u002Fli>\u003C\u002Fol>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>Logging Messages in WebSocket Server (Go)\u003C\u002Fh2>\u003Cp>We will set up a WebSocket server and connect it to a PostgreSQL database to store messages in real time.\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch3>1. Setting up the WebSocket Server\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">package main\n\nimport (\n    \"database\u002Fsql\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"sync\"\n    \"time\"\n\n    \"github.com\u002Fgorilla\u002Fwebsocket\"\n    _ \"github.com\u002Flib\u002Fpq\"\n)\n\nvar (\n    clients   = make(map[*websocket.Conn]bool)\n    clientsMu sync.Mutex\n    broadcast = make(chan Message)\n    db        *sql.DB\n)\n\ntype Message struct {\n    User    string    `json:\"user\"`\n    Message string    `json:\"message\"`\n    Time    time.Time `json:\"time\"`\n}\n\nvar upgrader = websocket.Upgrader{\n    CheckOrigin: func(r *http.Request) bool {\n        return true\n    },\n}\n\nfunc init() {\n    var err error\n    db, err = sql.Open(\"postgres\", \"user=username dbname=websocket_chat sslmode=disable\")\n    if err != nil {\n        log.Fatal(\"Database connection error:\", err)\n    }\n}\n\nfunc handleConnections(w http.ResponseWriter, r *http.Request) {\n    conn, err := upgrader.Upgrade(w, r, nil)\n    if err != nil {\n        log.Println(\"Upgrade error:\", err)\n        return\n    }\n    defer conn.Close()\n\n    clientsMu.Lock()\n    clients[conn] = true\n    clientsMu.Unlock()\n\n    for {\n        var msg Message\n        if err := conn.ReadJSON(&amp;msg); err != nil {\n            log.Println(\"Read error:\", err)\n            clientsMu.Lock()\n            delete(clients, conn)\n            clientsMu.Unlock()\n            break\n        }\n\n        msg.Time = time.Now()\n        saveMessage(msg)\n        broadcast &lt;- msg\n    }\n}\n\nfunc saveMessage(msg Message) {\n    _, err := db.Exec(\"INSERT INTO messages (user, message, time) VALUES ($1, $2, $3)\", msg.User, msg.Message, msg.Time)\n    if err != nil {\n        log.Println(\"Save message error:\", err)\n    }\n}\n\nfunc handleMessages() {\n    for msg := range broadcast {\n        clientsMu.Lock()\n        for client := range clients {\n            if err := client.WriteJSON(msg); err != nil {\n                log.Println(\"Broadcast error:\", err)\n                client.Close()\n                delete(clients, client)\n            }\n        }\n        clientsMu.Unlock()\n    }\n}\n\nfunc main() {\n    http.HandleFunc(\"\u002Fws\", handleConnections)\n    go handleMessages()\n\n    log.Println(\"Server started on :8080\")\n    log.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch3>2. Creating the PostgreSQL Table\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-sql\">CREATE TABLE messages (\n    id SERIAL PRIMARY KEY,\n    user VARCHAR(100),\n    message TEXT,\n    time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch3>3. Fetching Past Messages\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">func getMessages() ([]Message, error) {\n    rows, err := db.Query(\"SELECT user, message, time FROM messages ORDER BY time DESC\")\n    if err != nil {\n        return nil, err\n    }\n    defer rows.Close()\n\n    var messages []Message\n    for rows.Next() {\n        var msg Message\n        if err := rows.Scan(&amp;msg.User, &amp;msg.Message, &amp;msg.Time); err != nil {\n            return nil, err\n        }\n        messages = append(messages, msg)\n    }\n    return messages, nil\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>How to Test the Logging System\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>Make sure to cover the following test cases:\u003C\u002Fp>\u003Cul>\u003Cli>✅ Message persistence: Messages sent from clients must be stored correctly in the database\u003C\u002Fli>\u003Cli>✅ History retrieval: Ensure past messages can be fetched accurately\u003C\u002Fli>\u003Cli>✅ Performance under load: Test the server's ability to handle many clients and high message volumes\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Chr>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch3>Challenge for You!\u003C\u002Fh3>\u003Cp>Try adding a search feature to the chat history — allowing users to look up messages based on keywords or time ranges!\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch3>Next EP:\u003C\u002Fh3>\u003Cp>In EP.73, we’ll explore WebSocket Compression — a technique that improves bandwidth usage and speeds up message transmission in WebSocket-based systems.\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp data-start=\"498\" data-end=\"834\">\u003Cstrong>Read more\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp data-start=\"498\" data-end=\"834\">\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fblogs\u002Fcategories\u002FGolang\">\u003Cstrong>Golang The Series\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp data-start=\"498\" data-end=\"834\">\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fblogs\u002Fcategories\u002FJS2GO\">\u003Cstrong>JS2GO\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp data-start=\"498\" data-end=\"834\">\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fen\u002Fblogs\u002Fcategories\u002FTailwind%20CSS\">\u003Cstrong>10 Eps That Will Make You a Pro Tailwind CSS Overnight\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.school.th\">\u003Cstrong>Superdev School &nbsp;(Superdev)\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevschool\u002F\">\u003Cstrong>superdevschool\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevschool\">\u003Cstrong>superdevschool\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp class=\"\" data-start=\"5978\" data-end=\"6095\">\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002F\">\u003Cstrong>www.superdev.school\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>","116_11zon_yam6ns1fs5.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Fai3fxhmkkxys7wr\u002F116_11zon_yam6ns1fs5.webp","2026-03-04 08:47:26.792Z","",{"keywords":15,"locale":48,"school_blog":58},[16,23,28,33,38,43],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":22,"updated_by":13},"sclkey987654321","school_keywords","2026-03-04 08:47:05.949Z","caufix9o52uw4bh","Real-Time Chat","2026-04-10 16:13:23.517Z",{"collectionId":17,"collectionName":18,"created":24,"created_by":13,"id":25,"name":26,"updated":27,"updated_by":13},"2026-03-04 08:45:08.439Z","wscthqnz8vx2sox","PostgreSQL","2026-04-10 16:12:54.755Z",{"collectionId":17,"collectionName":18,"created":29,"created_by":13,"id":30,"name":31,"updated":32,"updated_by":13},"2026-03-04 08:46:50.361Z","5j4lrpjcv3ucyqq","chat system","2026-04-10 16:13:19.700Z",{"collectionId":17,"collectionName":18,"created":34,"created_by":13,"id":35,"name":36,"updated":37,"updated_by":13},"2026-03-04 08:47:26.375Z","rxfyvn7erlu30jf","Message Logging","2026-04-10 16:13:28.739Z",{"collectionId":17,"collectionName":18,"created":39,"created_by":13,"id":40,"name":41,"updated":42,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-04-10 16:07:25.893Z",{"collectionId":17,"collectionName":18,"created":44,"created_by":13,"id":45,"name":46,"updated":47,"updated_by":13},"2026-03-04 08:34:00.920Z","ecac9y661or1xka","WebSocket","2026-04-10 16:08:05.227Z",{"code":49,"collectionId":50,"collectionName":51,"created":52,"flag":53,"id":54,"is_default":55,"label":56,"updated":57},"en","pbc_1989393366","locales","2026-01-22 11:00:02.726Z","twemoji:flag-united-states","qv9c1llfov2d88z",false,"English","2026-04-10 15:42:46.825Z",{"category":59,"collectionId":60,"collectionName":61,"created":13,"expand":62,"id":76,"slug":77,"updated":78,"views":79},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs",{"category":63},{"blogIds":64,"collectionId":65,"collectionName":66,"created":67,"created_by":13,"id":59,"image":68,"image_alt":13,"image_path":69,"label":70,"name":71,"priority":72,"publish_at":73,"scheduled_at":13,"status":74,"updated":75,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":71,"th":71},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-04-25 02:32:15.470Z","b02q9ypqv7t4g2q","message-logging-in-websocket-en","2026-05-11 11:21:08.378Z",211,"ai3fxhmkkxys7wr",[20,25,30,35,40,45],"2025-08-06 05:13:11.167Z","Learn how to build a real-time chat message logging system using WebSocket and Go, with PostgreSQL integration for storing and retrieving chat history","2026-04-25 02:48:15.191Z",{"th":77,"en":77}]