跟踪Golang中的在线用户

Long time ago , I built a website with Golang , now , I want to track online users.

I want to do this without Redis and working with SessionID.

What is the best way for my work ?

I wrote a global handler :

type Tracker struct {
    http.Handler
}

func NewManager(handler http.Handler) *Tracker {
    return &Tracker{Handler: handler}
}

func (h *Tracker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    log.Println(r.RemoteAddr)
    h.Handler.ServeHTTP(w,r)
}

. . .

    srv := &http.Server{
        Handler:      newTracker(e),
        Addr:         "127.0.0.1" + port,
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }

    log.Fatal(srv.ListenAndServe())

I think one of work that I can do is :

Add a sessionID in client and save it in a map at server And counting online users and following there.

Is it good and right way ?

A global handler, middleware (if you're using a router pkg look at this) or just calling a stats function on popular pages would be enough. Be careful to exclude bots, rss hits, or other traffic you don't care about.

Assuming you have one process, and want to track users online in last 5 mins or something, yes, a map server side would be fine, you can issue tokens (depends on user allowing cookies, takes bandwidth on each request), or just hash ip (works pretty well, potential for slight undercounting). You then need to expire them after some interval, and use a mutex to protect them. On restart you lose the count, if running two processes you can't do this, this is the downside of in memory storage, you need another caching process to persist. So this is not suitable for large sites, but you could easily move to using a more persistent store later.

var PurgeInterval = 5 * time.Minute
var identifiers = make(map[string]time.Time)
var mu sync.RWMutex

...

// Hash ip + ua for anonymity in our store
hasher := sha256.New()
hasher.Write([]byte(ip))
hasher.Write([]byte(ua))
id := base64.URLEncoding.EncodeToString(hasher.Sum(nil))

// Insert the entry with current time
mu.Lock()
identifiers[id] = time.Now()
mu.Unlock()

...

// Clear the cache at intervals
mu.Lock()
for k, v := range identifiers {
    purgeTime := time.Now().Add(-PurgeInterval)
    if v.Before(purgeTime) {
        delete(identifiers, k)
    }
}
mu.Unlock()

Something like that.