Skip to content

Commit

Permalink
Always store a page view, even if bounced, fixed time on page when fi…
Browse files Browse the repository at this point in the history
…rst page is reloaded multiple times.
  • Loading branch information
Kugelschieber committed Feb 11, 2025
1 parent c89c14f commit d19312e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 52 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## 6.19.7

* always store a page view, even if bounced
* fixed time on page when first page is reloaded multiple times
* updated to Go 1.24

## 6.19.6
Expand Down
49 changes: 16 additions & 33 deletions pkg/tracker/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,16 @@ func (tracker *Tracker) PageView(r *http.Request, clientID uint64, options Optio
}

if ignoreReason == "" {
session, cancelSession, timeOnPage, bounced := tracker.getSession(pageView, clientID, r, now, userAgent, ipAddress, options)
session, cancelSession, timeOnPage := tracker.getSession(pageView, clientID, r, now, userAgent, ipAddress, options)
var saveRequest *model.Request

if session != nil {
if cancelSession == nil {
saveRequest = tracker.requestFromSession(session, clientID, ipAddress, userAgent.UserAgent, "")
}

var pv *model.PageView

if !bounced {
tagKeys, tagValues := options.getTags()
pv = tracker.pageViewFromSession(session, timeOnPage, tagKeys, tagValues)
}

tagKeys, tagValues := options.getTags()
pv := tracker.pageViewFromSession(session, timeOnPage, tagKeys, tagValues)
tracker.data <- data{
session: session,
cancelSession: cancelSession,
Expand Down Expand Up @@ -153,21 +148,16 @@ func (tracker *Tracker) Event(r *http.Request, clientID uint64, eventOptions Eve
}

if ignoreReason == "" {
session, cancelSession, timeOnPage, _ := tracker.getSession(event, clientID, r, now, userAgent, ipAddress, options)
session, cancelSession, timeOnPage := tracker.getSession(event, clientID, r, now, userAgent, ipAddress, options)
var saveRequest *model.Request

if session != nil {
if cancelSession == nil {
saveRequest = tracker.requestFromSession(session, clientID, ipAddress, userAgent.UserAgent, eventOptions.Name)
}

var pv *model.PageView
tagKeys, tagValues := options.getTags()

if cancelSession == nil || cancelSession.PageViews < session.PageViews {
pv = tracker.pageViewFromSession(session, timeOnPage, tagKeys, tagValues)
}

pv := tracker.pageViewFromSession(session, timeOnPage, tagKeys, tagValues)
metaKeys, metaValues := eventOptions.getMetaData(tagKeys, tagValues)
tracker.data <- data{
session: session,
Expand Down Expand Up @@ -203,7 +193,7 @@ func (tracker *Tracker) ExtendSession(r *http.Request, clientID uint64, options
now = options.Time
}

session, cancelSession, _, _ := tracker.getSession(sessionUpdate, clientID, r, now, userAgent, ipAddress, options)
session, cancelSession, _ := tracker.getSession(sessionUpdate, clientID, r, now, userAgent, ipAddress, options)

if session != nil {
tracker.data <- data{
Expand Down Expand Up @@ -233,7 +223,7 @@ func (tracker *Tracker) Accept(r *http.Request, clientID uint64, options Options
}

if ignoreReason == "" {
session, _, _, _ := tracker.getSession(pageView, clientID, r, now, userAgent, ipAddress, options)
session, _, _ := tracker.getSession(pageView, clientID, r, now, userAgent, ipAddress, options)
return session
}

Expand Down Expand Up @@ -503,7 +493,7 @@ func (tracker *Tracker) browserVersionBefore(version string, min int) bool {
return v < min
}

func (tracker *Tracker) getSession(t eventType, clientID uint64, r *http.Request, now time.Time, ua ua.UserAgent, ip string, options Options) (*model.Session, *model.Session, uint32, bool) {
func (tracker *Tracker) getSession(t eventType, clientID uint64, r *http.Request, now time.Time, ua ua.UserAgent, ip string, options Options) (*model.Session, *model.Session, uint32) {
fingerprint := tracker.fingerprint(tracker.config.Salt, ua.UserAgent, ip, now)
m := tracker.config.SessionCache.NewMutex(clientID, fingerprint)
m.Lock()
Expand All @@ -530,11 +520,10 @@ func (tracker *Tracker) getSession(t eventType, clientID uint64, r *http.Request
defer m.Unlock()

if t == sessionUpdate && session == nil {
return nil, nil, 0, false
return nil, nil, 0
}

var timeOnPage uint32
bounced := false // bounced not including session creation
var cancelSession *model.Session

if session == nil || tracker.referrerOrCampaignChanged(r, session, options.Referrer, options.Hostname) {
Expand All @@ -543,17 +532,17 @@ func (tracker *Tracker) getSession(t eventType, clientID uint64, r *http.Request
} else {
if options.MaxPageViews > 0 && session.PageViews >= options.MaxPageViews ||
options.MaxPageViews == 0 && tracker.config.MaxPageViews > 0 && session.PageViews >= tracker.config.MaxPageViews {
return nil, nil, 0, false
return nil, nil, 0
}

sessionCopy := *session
cancelSession = &sessionCopy
cancelSession.Sign = -1
timeOnPage, bounced = tracker.updateSession(t, r, session, now, options.Hostname, options.Path, options.Title)
timeOnPage = tracker.updateSession(t, r, session, now, options.Hostname, options.Path, options.Title)
tracker.config.SessionCache.Put(clientID, fingerprint, session)
}

return session, cancelSession, timeOnPage, bounced
return session, cancelSession, timeOnPage
}

func (tracker *Tracker) newSession(clientID uint64, r *http.Request, fingerprint uint64, now time.Time, ua ua.UserAgent, ip string, options Options) *model.Session {
Expand Down Expand Up @@ -624,7 +613,7 @@ func (tracker *Tracker) newSession(clientID uint64, r *http.Request, fingerprint
}
}

func (tracker *Tracker) updateSession(t eventType, r *http.Request, session *model.Session, now time.Time, hostname, path, title string) (uint32, bool) {
func (tracker *Tracker) updateSession(t eventType, r *http.Request, session *model.Session, now time.Time, hostname, path, title string) uint32 {
top := now.Unix() - session.Time.Unix()

if top < 0 {
Expand All @@ -640,17 +629,11 @@ func (tracker *Tracker) updateSession(t eventType, r *http.Request, session *mod
if t == event {
session.Time = session.Time.Add(time.Millisecond)
session.IsBounce = false

if session.ExitPath != path {
session.PageViews++
}
session.PageViews++
} else if t == pageView {
session.Time = now
session.IsBounce = session.IsBounce && path == session.ExitPath

if !session.IsBounce {
session.PageViews++
}
session.PageViews++
} else if session.Extended < math.MaxUint16-1 {
session.Time = now
session.Extended++
Expand All @@ -666,7 +649,7 @@ func (tracker *Tracker) updateSession(t eventType, r *http.Request, session *mod
session.Hostname = hostname
session.ExitPath = path
session.ExitTitle = title
return uint32(top), session.IsBounce
return uint32(top)
}

func (tracker *Tracker) getLanguage(r *http.Request) string {
Expand Down
45 changes: 26 additions & 19 deletions pkg/tracker/tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestTracker(t *testing.T) {
pageViews := client.GetPageViews()
events := client.GetEvents()
assert.Len(t, sessions, 7)
assert.Len(t, pageViews, 2)
assert.Len(t, pageViews, 3)
assert.Len(t, events, 1)
assert.Equal(t, uint16(1), sessions[0].Version)
assert.Equal(t, uint16(1), sessions[1].Version)
Expand All @@ -57,16 +57,19 @@ func TestTracker(t *testing.T) {
assert.Equal(t, uint16(4), sessions[6].Version)
assert.Equal(t, sessions[6].VisitorID, pageViews[0].VisitorID)
assert.Equal(t, sessions[6].VisitorID, pageViews[1].VisitorID)
assert.Equal(t, sessions[6].VisitorID, pageViews[2].VisitorID)
assert.Equal(t, sessions[6].VisitorID, events[0].VisitorID)
assert.Equal(t, sessions[6].SessionID, pageViews[0].SessionID)
assert.Equal(t, sessions[6].SessionID, pageViews[1].SessionID)
assert.Equal(t, sessions[6].SessionID, pageViews[2].SessionID)
assert.Equal(t, sessions[6].SessionID, events[0].SessionID)
assert.Equal(t, uint16(2), sessions[6].PageViews)
assert.Equal(t, uint16(3), sessions[6].PageViews)
assert.Equal(t, "/foo", sessions[6].EntryPath)
assert.Equal(t, "/bar", sessions[6].ExitPath)
assert.Equal(t, uint32(4), sessions[6].DurationSeconds)
assert.Equal(t, "/foo", pageViews[0].Path)
assert.Equal(t, "/bar", pageViews[1].Path)
assert.Equal(t, "/foo", pageViews[1].Path)
assert.Equal(t, "/bar", pageViews[2].Path)
assert.Equal(t, "test", events[0].Name)
assert.Equal(t, "/foo", events[0].Path)
}
Expand Down Expand Up @@ -304,10 +307,10 @@ func TestTracker_PageViewBounce(t *testing.T) {
sessions := client.GetSessions()
pageViews := client.GetPageViews()
assert.Len(t, sessions, 3)
assert.Len(t, pageViews, 1)
assert.Len(t, pageViews, 2)
assert.Equal(t, uint16(1), sessions[0].PageViews)
assert.Equal(t, uint16(1), sessions[1].PageViews)
assert.Equal(t, uint16(1), sessions[2].PageViews)
assert.Equal(t, uint16(2), sessions[2].PageViews)
assert.Equal(t, uint32(0), sessions[2].DurationSeconds)
}

Expand Down Expand Up @@ -745,6 +748,7 @@ func TestTracker_PageViewSessionDurationAndTimeOnPage(t *testing.T) {
delay time.Duration
}{
{path: "/", delay: 9},
{path: "/", delay: 2},
{path: "/pricing", delay: 5},
{path: "/pricing", delay: 3},
{path: "/about", delay: 10},
Expand All @@ -765,17 +769,19 @@ func TestTracker_PageViewSessionDurationAndTimeOnPage(t *testing.T) {
tracker.Flush()
sessions := client.GetSessions()
pageViews := client.GetPageViews()
assert.Len(t, sessions, 11)
assert.Len(t, pageViews, 6)
assert.Len(t, sessions, 13)
assert.Len(t, pageViews, 7)
assert.Equal(t, sessions[0].VisitorID, pageViews[0].VisitorID)
assert.Equal(t, sessions[0].SessionID, pageViews[0].SessionID)
assert.Equal(t, uint32(34), sessions[10].DurationSeconds)
assert.Equal(t, uint32(36), sessions[12].DurationSeconds)
assert.Equal(t, uint16(7), sessions[12].PageViews)
assert.Equal(t, uint32(0), pageViews[0].DurationSeconds)
assert.Equal(t, uint32(9), pageViews[1].DurationSeconds)
assert.Equal(t, uint32(5), pageViews[2].DurationSeconds)
assert.Equal(t, uint32(3), pageViews[3].DurationSeconds)
assert.Equal(t, uint32(10), pageViews[4].DurationSeconds)
assert.Equal(t, uint32(7), pageViews[5].DurationSeconds)
assert.Equal(t, uint32(2), pageViews[2].DurationSeconds)
assert.Equal(t, uint32(5), pageViews[3].DurationSeconds)
assert.Equal(t, uint32(3), pageViews[4].DurationSeconds)
assert.Equal(t, uint32(10), pageViews[5].DurationSeconds)
assert.Equal(t, uint32(7), pageViews[6].DurationSeconds)
}

func TestTracker_Event(t *testing.T) {
Expand Down Expand Up @@ -992,11 +998,11 @@ func TestTracker_EventPageView(t *testing.T) {
pageViews = client.GetPageViews()
events = client.GetEvents()
assert.Len(t, sessions, 3) // first + cancel + new
assert.Len(t, pageViews, 1)
assert.Len(t, pageViews, 2)
assert.Len(t, events, 2)
assert.Equal(t, uint16(1), sessions[0].PageViews)
assert.Equal(t, uint16(1), sessions[1].PageViews)
assert.Equal(t, uint16(1), sessions[2].PageViews)
assert.Equal(t, uint16(2), sessions[2].PageViews)
assert.True(t, sessions[0].IsBounce)
assert.True(t, sessions[1].IsBounce)
assert.False(t, sessions[2].IsBounce)
Expand All @@ -1020,20 +1026,21 @@ func TestTracker_EventPageView(t *testing.T) {
pageViews = client.GetPageViews()
events = client.GetEvents()
assert.Len(t, sessions, 5) // cancel + new
assert.Len(t, pageViews, 2)
assert.Len(t, pageViews, 3)
assert.Len(t, events, 3)
assert.Equal(t, uint16(1), sessions[0].PageViews)
assert.Equal(t, uint16(1), sessions[1].PageViews)
assert.Equal(t, uint16(1), sessions[2].PageViews)
assert.Equal(t, uint16(1), sessions[3].PageViews)
assert.Equal(t, uint16(2), sessions[4].PageViews)
assert.Equal(t, uint16(2), sessions[2].PageViews)
assert.Equal(t, uint16(2), sessions[3].PageViews)
assert.Equal(t, uint16(3), sessions[4].PageViews)
assert.True(t, sessions[0].IsBounce)
assert.True(t, sessions[1].IsBounce)
assert.False(t, sessions[2].IsBounce)
assert.False(t, sessions[3].IsBounce)
assert.False(t, sessions[4].IsBounce)
assert.Equal(t, "/event/page", pageViews[0].Path)
assert.Equal(t, "/new/event/page", pageViews[1].Path)
assert.Equal(t, "/event/page", pageViews[1].Path)
assert.Equal(t, "/new/event/page", pageViews[2].Path)
assert.Equal(t, "event", events[0].Name)
assert.Equal(t, "event", events[1].Name)
assert.Equal(t, "event", events[2].Name)
Expand Down

0 comments on commit d19312e

Please sign in to comment.