mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
logtail: rename the unused CheckLogs to DrainLogs
Its semantics has changed slightly, this will let us use it to drive batched logging in special circumstances. Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This commit is contained in:
parent
51a12d1307
commit
6ddbcab71e
@ -15,6 +15,9 @@ type Buffer interface {
|
|||||||
// TryReadLine tries to read a log line from the ring buffer.
|
// TryReadLine tries to read a log line from the ring buffer.
|
||||||
// If no line is available it returns a nil slice.
|
// If no line is available it returns a nil slice.
|
||||||
// If the ring buffer is closed it returns io.EOF.
|
// If the ring buffer is closed it returns io.EOF.
|
||||||
|
//
|
||||||
|
// The returned slice may point to data that will be overwritten
|
||||||
|
// by a subsequent call to TryReadLine.
|
||||||
TryReadLine() ([]byte, error)
|
TryReadLine() ([]byte, error)
|
||||||
|
|
||||||
// Write writes a log line into the ring buffer.
|
// Write writes a log line into the ring buffer.
|
||||||
|
@ -62,8 +62,11 @@ type Config struct {
|
|||||||
TimeNow func() time.Time // if set, subsitutes uses of time.Now
|
TimeNow func() time.Time // if set, subsitutes uses of time.Now
|
||||||
Stderr io.Writer // if set, logs are sent here instead of os.Stderr
|
Stderr io.Writer // if set, logs are sent here instead of os.Stderr
|
||||||
Buffer Buffer // temp storage, if nil a MemoryBuffer
|
Buffer Buffer // temp storage, if nil a MemoryBuffer
|
||||||
CheckLogs <-chan struct{} // signals Logger to check for filched logs to upload
|
|
||||||
NewZstdEncoder func() Encoder // if set, used to compress logs for transmission
|
NewZstdEncoder func() Encoder // if set, used to compress logs for transmission
|
||||||
|
|
||||||
|
// DrainLogs, if non-nil, disables autmatic uploading of new logs,
|
||||||
|
// so that logs are only uploaded when a token is sent to DrainLogs.
|
||||||
|
DrainLogs <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Log(cfg Config) Logger {
|
func Log(cfg Config) Logger {
|
||||||
@ -86,9 +89,6 @@ func Log(cfg Config) Logger {
|
|||||||
}
|
}
|
||||||
cfg.Buffer = NewMemoryBuffer(pendingSize)
|
cfg.Buffer = NewMemoryBuffer(pendingSize)
|
||||||
}
|
}
|
||||||
if cfg.CheckLogs == nil {
|
|
||||||
cfg.CheckLogs = make(chan struct{})
|
|
||||||
}
|
|
||||||
l := &logger{
|
l := &logger{
|
||||||
stderr: cfg.Stderr,
|
stderr: cfg.Stderr,
|
||||||
httpc: cfg.HTTPC,
|
httpc: cfg.HTTPC,
|
||||||
@ -98,7 +98,7 @@ func Log(cfg Config) Logger {
|
|||||||
skipClientTime: cfg.SkipClientTime,
|
skipClientTime: cfg.SkipClientTime,
|
||||||
sent: make(chan struct{}, 1),
|
sent: make(chan struct{}, 1),
|
||||||
sentinel: make(chan int32, 16),
|
sentinel: make(chan int32, 16),
|
||||||
checkLogs: cfg.CheckLogs,
|
drainLogs: cfg.DrainLogs,
|
||||||
timeNow: cfg.TimeNow,
|
timeNow: cfg.TimeNow,
|
||||||
bo: backoff.Backoff{
|
bo: backoff.Backoff{
|
||||||
Name: "logtail",
|
Name: "logtail",
|
||||||
@ -127,7 +127,7 @@ type logger struct {
|
|||||||
skipClientTime bool
|
skipClientTime bool
|
||||||
buffer Buffer
|
buffer Buffer
|
||||||
sent chan struct{} // signal to speed up drain
|
sent chan struct{} // signal to speed up drain
|
||||||
checkLogs <-chan struct{} // external signal to attempt a drain
|
drainLogs <-chan struct{} // if non-nil, external signal to attempt a drain
|
||||||
sentinel chan int32
|
sentinel chan int32
|
||||||
timeNow func() time.Time
|
timeNow func() time.Time
|
||||||
bo backoff.Backoff
|
bo backoff.Backoff
|
||||||
@ -164,6 +164,32 @@ func (l *logger) Close() {
|
|||||||
l.Shutdown(context.Background())
|
l.Shutdown(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drainBlock is called by drainPending when there are no logs to drain.
|
||||||
|
//
|
||||||
|
// In typical operation, every call to the Write method unblocks and triggers
|
||||||
|
// a buffer.TryReadline, so logs are written with very low latency.
|
||||||
|
//
|
||||||
|
// If the caller provides a DrainLogs channel, then unblock-drain-on-Write
|
||||||
|
// is disabled, and it is up to the caller to trigger unblock the drain.
|
||||||
|
func (l *logger) drainBlock() (shuttingDown bool) {
|
||||||
|
if l.drainLogs == nil {
|
||||||
|
select {
|
||||||
|
case <-l.shutdownStart:
|
||||||
|
return true
|
||||||
|
case <-l.sent:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select {
|
||||||
|
case <-l.shutdownStart:
|
||||||
|
return true
|
||||||
|
case <-l.drainLogs:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// drainPending drains and encodes a batch of logs from the buffer for upload.
|
||||||
|
// If no logs are available, drainPending blocks until logs are available.
|
||||||
func (l *logger) drainPending() (res []byte) {
|
func (l *logger) drainPending() (res []byte) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
entries := 0
|
entries := 0
|
||||||
@ -182,12 +208,7 @@ func (l *logger) drainPending() (res []byte) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
batchDone = l.drainBlock()
|
||||||
case <-l.shutdownStart:
|
|
||||||
batchDone = true
|
|
||||||
case <-l.checkLogs:
|
|
||||||
case <-l.sent:
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,10 +325,12 @@ func (l *logger) Flush() error {
|
|||||||
|
|
||||||
func (l *logger) send(jsonBlob []byte) (int, error) {
|
func (l *logger) send(jsonBlob []byte) (int, error) {
|
||||||
n, err := l.buffer.Write(jsonBlob)
|
n, err := l.buffer.Write(jsonBlob)
|
||||||
|
if l.drainLogs == nil {
|
||||||
select {
|
select {
|
||||||
case l.sent <- struct{}{}:
|
case l.sent <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user