Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-goats-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@livekit/protocol": patch
---

add duration seconds reporting
3 changes: 2 additions & 1 deletion observability/agentsobs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 11 additions & 9 deletions observability/agentsobs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion observability/agentsv2obs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 11 additions & 9 deletions observability/agentsv2obs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion observability/corecallobs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions observability/corecallobs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion observability/roomobs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions observability/roomobs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 33 additions & 7 deletions observability/sessiontimer.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
package observability

import "time"
import (
"time"

"github.com/livekit/protocol/utils/options"
)

type SessionTimer struct {
lastMilli int64
lastSec int64
lastMin int64
minSecs int64
minMins int64
}

type SessionTimerOption func(*SessionTimer)

// WithMinSeconds ensures the first Advance that produces a non-zero secs
// return reports at least n seconds. Subsequent advances behave normally.
func WithMinSeconds(n int64) SessionTimerOption {
return func(h *SessionTimer) { h.minSecs = n }
}

func NewSessionTimer(startTime time.Time) *SessionTimer {
// WithMinMinutes ensures the first Advance that produces a non-zero mins
// return reports at least n minutes. Subsequent advances behave normally.
func WithMinMinutes(n int64) SessionTimerOption {
return func(h *SessionTimer) { h.minMins = n }
}

func NewSessionTimer(startTime time.Time, opts ...SessionTimerOption) *SessionTimer {
ts := startTime.UnixMilli()
return &SessionTimer{ts, ts}
return options.Apply(&SessionTimer{lastMilli: ts, lastSec: ts, lastMin: ts}, opts)
}

func (h *SessionTimer) Advance(now time.Time) (millis, mins int64) {
func (h *SessionTimer) Advance(now time.Time) (millis, secs, mins int64) {
ts := now.UnixMilli()
if ts > h.lastMilli {
millis = ts - h.lastMilli
h.lastMilli = ts
}
if ts > h.lastSec {
secs = max((ts-h.lastSec+999)/1000, h.minSecs)
h.minSecs = 0
h.lastSec += secs * 1000
}
if ts > h.lastMin {
n := (ts - h.lastMin + 59999) / 60000
mins += n
h.lastMin += n * 60000
mins = max((ts-h.lastMin+59999)/60000, h.minMins)
h.minMins = 0
h.lastMin += mins * 60000
}
return
}
65 changes: 62 additions & 3 deletions observability/sessiontimer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,80 @@ func TestSessionTimer(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts)

millis, mins := st.Advance(ts.Add(100 * time.Millisecond))
millis, secs, mins := st.Advance(ts.Add(100 * time.Millisecond))
require.EqualValues(t, 100, millis)
require.EqualValues(t, 1, secs)
require.EqualValues(t, 1, mins)

millis, mins = st.Advance(ts.Add(200 * time.Millisecond))
millis, secs, mins = st.Advance(ts.Add(200 * time.Millisecond))
require.EqualValues(t, 100, millis)
require.EqualValues(t, 0, secs)
require.EqualValues(t, 0, mins)
})

t.Run("advance 2.5m", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts)

millis, mins := st.Advance(ts.Add(150 * time.Second))
millis, secs, mins := st.Advance(ts.Add(150 * time.Second))
require.EqualValues(t, 150000, millis)
require.EqualValues(t, 150, secs)
require.EqualValues(t, 3, mins)
})

t.Run("WithMinSeconds floors first advance and consumes watermark", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts, WithMinSeconds(60))

_, secs, _ := st.Advance(ts.Add(time.Second))
require.EqualValues(t, 60, secs)

_, secs, _ = st.Advance(ts.Add(30 * time.Second))
require.EqualValues(t, 0, secs)

_, secs, _ = st.Advance(ts.Add(62 * time.Second))
require.EqualValues(t, 2, secs)
})

t.Run("WithMinSeconds does not lower larger natural value", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts, WithMinSeconds(60))

_, secs, _ := st.Advance(ts.Add(120 * time.Second))
require.EqualValues(t, 120, secs)
})

t.Run("WithMinSeconds does not trigger on no-op advance", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts, WithMinSeconds(60))

_, secs, _ := st.Advance(ts)
require.EqualValues(t, 0, secs)

_, secs, _ = st.Advance(ts.Add(time.Second))
require.EqualValues(t, 60, secs)
})

t.Run("WithMinMinutes floors first advance", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts, WithMinMinutes(5))

_, _, mins := st.Advance(ts.Add(time.Second))
require.EqualValues(t, 5, mins)

_, _, mins = st.Advance(ts.Add(2 * time.Minute))
require.EqualValues(t, 0, mins)

_, _, mins = st.Advance(ts.Add(7 * time.Minute))
require.EqualValues(t, 2, mins)
})

t.Run("WithMinSeconds and WithMinMinutes apply independently", func(t *testing.T) {
ts := time.Now()
st := NewSessionTimer(ts, WithMinSeconds(45), WithMinMinutes(3))

_, secs, mins := st.Advance(ts.Add(time.Second))
require.EqualValues(t, 45, secs)
require.EqualValues(t, 3, mins)
})
}
3 changes: 2 additions & 1 deletion observability/sipcallobs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions observability/sipcallobs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion observability/telephonyobs/gen_reporter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions observability/telephonyobs/gen_reporter_noop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading