View : 211

25/04/2026 02:48am

EP.72 Implementing Message Logging in WebSocket Chat with Go

EP.72 Implementing Message Logging in WebSocket Chat with Go

#Real-Time Chat

#PostgreSQL

#chat system

#Message Logging

#Go

#WebSocket

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.

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.

 

Why Use Message Logging in WebSocket?

 

Implementing a message logging system brings several benefits:

  • Chat history tracking: All messages are stored persistently and can be retrieved later
  • Conversation review: Admins or users can check messages sent at any point in time
  • Security & moderation: Helps monitor user behavior and prevent inappropriate usage
  • Data recovery: Logged messages allow for recovery in case of system crashes or unexpected shutdowns

 

System Architecture Overview

 

A complete message logging system consists of:

  1. Saving messages into the database
    Every chat message is saved with metadata such as sender, content, timestamp, and optionally a room ID
  2. Receiving messages via WebSocket
    The WebSocket server receives messages in real time and immediately logs them
  3. Fetching past messages
    The backend provides a way to retrieve previously logged messages (e.g., for chat history display)

 

Logging Messages in WebSocket Server (Go)

We will set up a WebSocket server and connect it to a PostgreSQL database to store messages in real time.

 

1. Setting up the WebSocket Server

package main

import (
    "database/sql"
    "log"
    "net/http"
    "sync"
    "time"

    "github.com/gorilla/websocket"
    _ "github.com/lib/pq"
)

var (
    clients   = make(map[*websocket.Conn]bool)
    clientsMu sync.Mutex
    broadcast = make(chan Message)
    db        *sql.DB
)

type Message struct {
    User    string    `json:"user"`
    Message string    `json:"message"`
    Time    time.Time `json:"time"`
}

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func init() {
    var err error
    db, err = sql.Open("postgres", "user=username dbname=websocket_chat sslmode=disable")
    if err != nil {
        log.Fatal("Database connection error:", err)
    }
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("Upgrade error:", err)
        return
    }
    defer conn.Close()

    clientsMu.Lock()
    clients[conn] = true
    clientsMu.Unlock()

    for {
        var msg Message
        if err := conn.ReadJSON(&msg); err != nil {
            log.Println("Read error:", err)
            clientsMu.Lock()
            delete(clients, conn)
            clientsMu.Unlock()
            break
        }

        msg.Time = time.Now()
        saveMessage(msg)
        broadcast <- msg
    }
}

func saveMessage(msg Message) {
    _, err := db.Exec("INSERT INTO messages (user, message, time) VALUES ($1, $2, $3)", msg.User, msg.Message, msg.Time)
    if err != nil {
        log.Println("Save message error:", err)
    }
}

func handleMessages() {
    for msg := range broadcast {
        clientsMu.Lock()
        for client := range clients {
            if err := client.WriteJSON(msg); err != nil {
                log.Println("Broadcast error:", err)
                client.Close()
                delete(clients, client)
            }
        }
        clientsMu.Unlock()
    }
}

func main() {
    http.HandleFunc("/ws", handleConnections)
    go handleMessages()

    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

 

2. Creating the PostgreSQL Table

CREATE TABLE messages (
    id SERIAL PRIMARY KEY,
    user VARCHAR(100),
    message TEXT,
    time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

 

3. Fetching Past Messages

func getMessages() ([]Message, error) {
    rows, err := db.Query("SELECT user, message, time FROM messages ORDER BY time DESC")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var messages []Message
    for rows.Next() {
        var msg Message
        if err := rows.Scan(&msg.User, &msg.Message, &msg.Time); err != nil {
            return nil, err
        }
        messages = append(messages, msg)
    }
    return messages, nil
}

 

How to Test the Logging System

 

Make sure to cover the following test cases:

  • ✅ Message persistence: Messages sent from clients must be stored correctly in the database
  • ✅ History retrieval: Ensure past messages can be fetched accurately
  • ✅ Performance under load: Test the server's ability to handle many clients and high message volumes

 


 

Challenge for You!

Try adding a search feature to the chat history — allowing users to look up messages based on keywords or time ranges!

 

Next EP:

In EP.73, we’ll explore WebSocket Compression — a technique that improves bandwidth usage and speeds up message transmission in WebSocket-based systems.

 

Read more

🔵 Facebook: Superdev School  (Superdev)

📸 Instagram: superdevschool

🎬 TikTok: superdevschool

🌐 Website: www.superdev.school