Skip to content

Commit e1bcecc

Browse files
authored
logtail: use tstime (tailscale#8607)
Updates tailscale#8587 Signed-off-by: Claire Wang <[email protected]>
1 parent bb4b35e commit e1bcecc

File tree

3 files changed

+34
-33
lines changed

3 files changed

+34
-33
lines changed

logtail/backoff/backoff.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"math/rand"
1010
"time"
1111

12+
"tailscale.com/tstime"
1213
"tailscale.com/types/logger"
1314
)
1415

@@ -23,9 +24,8 @@ type Backoff struct {
2324
// logf is the function used for log messages when backing off.
2425
logf logger.Logf
2526

26-
// NewTimer is the function that acts like time.NewTimer.
27-
// It's for use in unit tests.
28-
NewTimer func(time.Duration) *time.Timer
27+
// tstime.Clock.NewTimer is used instead time.NewTimer.
28+
Clock tstime.Clock
2929

3030
// LogLongerThan sets the minimum time of a single backoff interval
3131
// before we mention it in the log.
@@ -40,7 +40,7 @@ func NewBackoff(name string, logf logger.Logf, maxBackoff time.Duration) *Backof
4040
name: name,
4141
logf: logf,
4242
maxBackoff: maxBackoff,
43-
NewTimer: time.NewTimer,
43+
Clock: tstime.StdClock{},
4444
}
4545
}
4646

@@ -72,10 +72,10 @@ func (b *Backoff) BackOff(ctx context.Context, err error) {
7272
if d >= b.LogLongerThan {
7373
b.logf("%s: [v1] backoff: %d msec", b.name, d.Milliseconds())
7474
}
75-
t := b.NewTimer(d)
75+
t, tChannel := b.Clock.NewTimer(d)
7676
select {
7777
case <-ctx.Done():
7878
t.Stop()
79-
case <-t.C:
79+
case <-tChannel:
8080
}
8181
}

logtail/logtail.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,18 @@ type Encoder interface {
4949
}
5050

5151
type Config struct {
52-
Collection string // collection name, a domain name
53-
PrivateID logid.PrivateID // private ID for the primary log stream
54-
CopyPrivateID logid.PrivateID // private ID for a log stream that is a superset of this log stream
55-
BaseURL string // if empty defaults to "https://log.tailscale.io"
56-
HTTPC *http.Client // if empty defaults to http.DefaultClient
57-
SkipClientTime bool // if true, client_time is not written to logs
58-
LowMemory bool // if true, logtail minimizes memory use
59-
TimeNow func() time.Time // if set, substitutes uses of time.Now
60-
Stderr io.Writer // if set, logs are sent here instead of os.Stderr
61-
StderrLevel int // max verbosity level to write to stderr; 0 means the non-verbose messages only
62-
Buffer Buffer // temp storage, if nil a MemoryBuffer
63-
NewZstdEncoder func() Encoder // if set, used to compress logs for transmission
52+
Collection string // collection name, a domain name
53+
PrivateID logid.PrivateID // private ID for the primary log stream
54+
CopyPrivateID logid.PrivateID // private ID for a log stream that is a superset of this log stream
55+
BaseURL string // if empty defaults to "https://log.tailscale.io"
56+
HTTPC *http.Client // if empty defaults to http.DefaultClient
57+
SkipClientTime bool // if true, client_time is not written to logs
58+
LowMemory bool // if true, logtail minimizes memory use
59+
Clock tstime.Clock // if set, Clock.Now substitutes uses of time.Now
60+
Stderr io.Writer // if set, logs are sent here instead of os.Stderr
61+
StderrLevel int // max verbosity level to write to stderr; 0 means the non-verbose messages only
62+
Buffer Buffer // temp storage, if nil a MemoryBuffer
63+
NewZstdEncoder func() Encoder // if set, used to compress logs for transmission
6464

6565
// MetricsDelta, if non-nil, is a func that returns an encoding
6666
// delta in clientmetrics to upload alongside existing logs.
@@ -94,8 +94,8 @@ func NewLogger(cfg Config, logf tslogger.Logf) *Logger {
9494
if cfg.HTTPC == nil {
9595
cfg.HTTPC = http.DefaultClient
9696
}
97-
if cfg.TimeNow == nil {
98-
cfg.TimeNow = time.Now
97+
if cfg.Clock == nil {
98+
cfg.Clock = tstime.StdClock{}
9999
}
100100
if cfg.Stderr == nil {
101101
cfg.Stderr = os.Stderr
@@ -144,7 +144,7 @@ func NewLogger(cfg Config, logf tslogger.Logf) *Logger {
144144
drainWake: make(chan struct{}, 1),
145145
sentinel: make(chan int32, 16),
146146
flushDelayFn: cfg.FlushDelayFn,
147-
timeNow: cfg.TimeNow,
147+
clock: cfg.Clock,
148148
metricsDelta: cfg.MetricsDelta,
149149

150150
procID: procID,
@@ -181,7 +181,7 @@ type Logger struct {
181181
flushDelayFn func() time.Duration // negative or zero return value to upload aggressively, or >0 to batch at this delay
182182
flushPending atomic.Bool
183183
sentinel chan int32
184-
timeNow func() time.Time
184+
clock tstime.Clock
185185
zstdEncoder Encoder
186186
uploadCancel func()
187187
explainedRaw bool
@@ -195,7 +195,7 @@ type Logger struct {
195195

196196
writeLock sync.Mutex // guards procSequence, flushTimer, buffer.Write calls
197197
procSequence uint64
198-
flushTimer *time.Timer // used when flushDelay is >0
198+
flushTimer tstime.TimerController // used when flushDelay is >0
199199

200200
shutdownStartMu sync.Mutex // guards the closing of shutdownStart
201201
shutdownStart chan struct{} // closed when shutdown begins
@@ -380,7 +380,7 @@ func (l *Logger) uploading(ctx context.Context) {
380380
retryAfter, err := l.upload(ctx, body, origlen)
381381
if err != nil {
382382
numFailures++
383-
firstFailure = time.Now()
383+
firstFailure = l.clock.Now()
384384

385385
if !l.internetUp() {
386386
fmt.Fprintf(l.stderr, "logtail: internet down; waiting\n")
@@ -403,7 +403,7 @@ func (l *Logger) uploading(ctx context.Context) {
403403
} else {
404404
// Only print a success message after recovery.
405405
if numFailures > 0 {
406-
fmt.Fprintf(l.stderr, "logtail: upload succeeded after %d failures and %s\n", numFailures, time.Since(firstFailure).Round(time.Second))
406+
fmt.Fprintf(l.stderr, "logtail: upload succeeded after %d failures and %s\n", numFailures, l.clock.Since(firstFailure).Round(time.Second))
407407
}
408408
break
409409
}
@@ -545,7 +545,7 @@ func (l *Logger) sendLocked(jsonBlob []byte) (int, error) {
545545
if flushDelay > 0 {
546546
if l.flushPending.CompareAndSwap(false, true) {
547547
if l.flushTimer == nil {
548-
l.flushTimer = time.AfterFunc(flushDelay, l.tryDrainWake)
548+
l.flushTimer = l.clock.AfterFunc(flushDelay, l.tryDrainWake)
549549
} else {
550550
l.flushTimer.Reset(flushDelay)
551551
}
@@ -559,7 +559,7 @@ func (l *Logger) sendLocked(jsonBlob []byte) (int, error) {
559559
// TODO: instead of allocating, this should probably just append
560560
// directly into the output log buffer.
561561
func (l *Logger) encodeText(buf []byte, skipClientTime bool, procID uint32, procSequence uint64, level int) []byte {
562-
now := l.timeNow()
562+
now := l.clock.Now()
563563

564564
// Factor in JSON encoding overhead to try to only do one alloc
565565
// in the make below (so appends don't resize the buffer).
@@ -674,7 +674,7 @@ func (l *Logger) encodeLocked(buf []byte, level int) []byte {
674674
return l.encodeText(buf, l.skipClientTime, l.procID, l.procSequence, level) // text fast-path
675675
}
676676

677-
now := l.timeNow()
677+
now := l.clock.Now()
678678

679679
obj := make(map[string]any)
680680
if err := json.Unmarshal(buf, &obj); err != nil {

logtail/logtail_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"time"
1616

1717
"tailscale.com/tstest"
18+
"tailscale.com/tstime"
1819
)
1920

2021
func TestFastShutdown(t *testing.T) {
@@ -212,7 +213,7 @@ func TestEncodeSpecialCases(t *testing.T) {
212213
var sink []byte
213214

214215
func TestLoggerEncodeTextAllocs(t *testing.T) {
215-
lg := &Logger{timeNow: time.Now}
216+
lg := &Logger{clock: tstime.StdClock{}}
216217
inBuf := []byte("some text to encode")
217218
procID := uint32(0x24d32ee9)
218219
procSequence := uint64(0x12346)
@@ -226,8 +227,8 @@ func TestLoggerEncodeTextAllocs(t *testing.T) {
226227

227228
func TestLoggerWriteLength(t *testing.T) {
228229
lg := &Logger{
229-
timeNow: time.Now,
230-
buffer: NewMemoryBuffer(1024),
230+
clock: tstime.StdClock{},
231+
buffer: NewMemoryBuffer(1024),
231232
}
232233
inBuf := []byte("some text to encode")
233234
n, err := lg.Write(inBuf)
@@ -309,7 +310,7 @@ func unmarshalOne(t *testing.T, body []byte) map[string]any {
309310
}
310311

311312
func TestEncodeTextTruncation(t *testing.T) {
312-
lg := &Logger{timeNow: time.Now, lowMem: true}
313+
lg := &Logger{clock: tstime.StdClock{}, lowMem: true}
313314
in := bytes.Repeat([]byte("a"), 5120)
314315
b := lg.encodeText(in, true, 0, 0, 0)
315316
got := string(b)
@@ -363,7 +364,7 @@ func TestEncode(t *testing.T) {
363364
for _, tt := range tests {
364365
buf := new(simpleMemBuf)
365366
lg := &Logger{
366-
timeNow: func() time.Time { return time.Unix(123, 456).UTC() },
367+
clock: tstest.NewClock(tstest.ClockOpts{Start: time.Unix(123, 456).UTC()}),
367368
buffer: buf,
368369
procID: 7,
369370
procSequence: 1,

0 commit comments

Comments
 (0)