@@ -49,18 +49,18 @@ type Encoder interface {
49
49
}
50
50
51
51
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
64
64
65
65
// MetricsDelta, if non-nil, is a func that returns an encoding
66
66
// delta in clientmetrics to upload alongside existing logs.
@@ -94,8 +94,8 @@ func NewLogger(cfg Config, logf tslogger.Logf) *Logger {
94
94
if cfg .HTTPC == nil {
95
95
cfg .HTTPC = http .DefaultClient
96
96
}
97
- if cfg .TimeNow == nil {
98
- cfg .TimeNow = time . Now
97
+ if cfg .Clock == nil {
98
+ cfg .Clock = tstime. StdClock {}
99
99
}
100
100
if cfg .Stderr == nil {
101
101
cfg .Stderr = os .Stderr
@@ -144,7 +144,7 @@ func NewLogger(cfg Config, logf tslogger.Logf) *Logger {
144
144
drainWake : make (chan struct {}, 1 ),
145
145
sentinel : make (chan int32 , 16 ),
146
146
flushDelayFn : cfg .FlushDelayFn ,
147
- timeNow : cfg .TimeNow ,
147
+ clock : cfg .Clock ,
148
148
metricsDelta : cfg .MetricsDelta ,
149
149
150
150
procID : procID ,
@@ -181,7 +181,7 @@ type Logger struct {
181
181
flushDelayFn func () time.Duration // negative or zero return value to upload aggressively, or >0 to batch at this delay
182
182
flushPending atomic.Bool
183
183
sentinel chan int32
184
- timeNow func () time. Time
184
+ clock tstime. Clock
185
185
zstdEncoder Encoder
186
186
uploadCancel func ()
187
187
explainedRaw bool
@@ -195,7 +195,7 @@ type Logger struct {
195
195
196
196
writeLock sync.Mutex // guards procSequence, flushTimer, buffer.Write calls
197
197
procSequence uint64
198
- flushTimer * time. Timer // used when flushDelay is >0
198
+ flushTimer tstime. TimerController // used when flushDelay is >0
199
199
200
200
shutdownStartMu sync.Mutex // guards the closing of shutdownStart
201
201
shutdownStart chan struct {} // closed when shutdown begins
@@ -380,7 +380,7 @@ func (l *Logger) uploading(ctx context.Context) {
380
380
retryAfter , err := l .upload (ctx , body , origlen )
381
381
if err != nil {
382
382
numFailures ++
383
- firstFailure = time .Now ()
383
+ firstFailure = l . clock .Now ()
384
384
385
385
if ! l .internetUp () {
386
386
fmt .Fprintf (l .stderr , "logtail: internet down; waiting\n " )
@@ -403,7 +403,7 @@ func (l *Logger) uploading(ctx context.Context) {
403
403
} else {
404
404
// Only print a success message after recovery.
405
405
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 ))
407
407
}
408
408
break
409
409
}
@@ -545,7 +545,7 @@ func (l *Logger) sendLocked(jsonBlob []byte) (int, error) {
545
545
if flushDelay > 0 {
546
546
if l .flushPending .CompareAndSwap (false , true ) {
547
547
if l .flushTimer == nil {
548
- l .flushTimer = time .AfterFunc (flushDelay , l .tryDrainWake )
548
+ l .flushTimer = l . clock .AfterFunc (flushDelay , l .tryDrainWake )
549
549
} else {
550
550
l .flushTimer .Reset (flushDelay )
551
551
}
@@ -559,7 +559,7 @@ func (l *Logger) sendLocked(jsonBlob []byte) (int, error) {
559
559
// TODO: instead of allocating, this should probably just append
560
560
// directly into the output log buffer.
561
561
func (l * Logger ) encodeText (buf []byte , skipClientTime bool , procID uint32 , procSequence uint64 , level int ) []byte {
562
- now := l .timeNow ()
562
+ now := l .clock . Now ()
563
563
564
564
// Factor in JSON encoding overhead to try to only do one alloc
565
565
// in the make below (so appends don't resize the buffer).
@@ -674,7 +674,7 @@ func (l *Logger) encodeLocked(buf []byte, level int) []byte {
674
674
return l .encodeText (buf , l .skipClientTime , l .procID , l .procSequence , level ) // text fast-path
675
675
}
676
676
677
- now := l .timeNow ()
677
+ now := l .clock . Now ()
678
678
679
679
obj := make (map [string ]any )
680
680
if err := json .Unmarshal (buf , & obj ); err != nil {
0 commit comments