diff --git a/app/log/internal/log_writer.go b/app/log/internal/log_writer.go index 8ec14e40..2f61931e 100644 --- a/app/log/internal/log_writer.go +++ b/app/log/internal/log_writer.go @@ -1,12 +1,11 @@ package internal import ( + "context" "log" "os" - "time" "v2ray.com/core/common/platform" - "v2ray.com/core/common/signal" ) type LogWriter interface { @@ -24,13 +23,11 @@ func (v *NoOpLogWriter) Close() { type StdOutLogWriter struct { logger *log.Logger - cancel *signal.CancelSignal } func NewStdOutLogWriter() LogWriter { return &StdOutLogWriter{ logger: log.New(os.Stdout, "", log.Ldate|log.Ltime), - cancel: signal.NewCloseSignal(), } } @@ -38,42 +35,41 @@ func (v *StdOutLogWriter) Log(log LogEntry) { v.logger.Print(log.String() + platform.LineSeparator()) } -func (v *StdOutLogWriter) Close() { - time.Sleep(500 * time.Millisecond) -} +func (v *StdOutLogWriter) Close() {} type FileLogWriter struct { queue chan string logger *log.Logger file *os.File - cancel *signal.CancelSignal + ctx context.Context + cancel context.CancelFunc } func (v *FileLogWriter) Log(log LogEntry) { select { + case <-v.ctx.Done(): + return case v.queue <- log.String(): default: // We don't expect this to happen, but don't want to block main thread as well. } } -func (v *FileLogWriter) run() { - v.cancel.WaitThread() - defer v.cancel.FinishThread() - +func (v *FileLogWriter) run(ctx context.Context) { +L: for { - entry, open := <-v.queue - if !open { - break + select { + case <-ctx.Done(): + break L + case entry := <-v.queue: + v.logger.Print(entry + platform.LineSeparator()) } - v.logger.Print(entry + platform.LineSeparator()) } + v.file.Close() } func (v *FileLogWriter) Close() { - close(v.queue) - v.cancel.WaitForDone() - v.file.Close() + v.cancel() } func NewFileLogWriter(path string) (*FileLogWriter, error) { @@ -81,12 +77,14 @@ func NewFileLogWriter(path string) (*FileLogWriter, error) { if err != nil { return nil, err } + ctx, cancel := context.WithCancel(context.Background()) logger := &FileLogWriter{ queue: make(chan string, 16), logger: log.New(file, "", log.Ldate|log.Ltime), file: file, - cancel: signal.NewCloseSignal(), + ctx: ctx, + cancel: cancel, } - go logger.run() + go logger.run(ctx) return logger, nil } diff --git a/common/signal/cancel.go b/common/signal/cancel.go deleted file mode 100644 index 2a46cdc8..00000000 --- a/common/signal/cancel.go +++ /dev/null @@ -1,51 +0,0 @@ -package signal - -import ( - "sync" -) - -// CancelSignal is a signal passed to goroutine, in order to cancel the goroutine on demand. -type CancelSignal struct { - cancel chan struct{} - done sync.WaitGroup -} - -// NewCloseSignal creates a new CancelSignal. -func NewCloseSignal() *CancelSignal { - return &CancelSignal{ - cancel: make(chan struct{}), - } -} - -func (v *CancelSignal) WaitThread() { - v.done.Add(1) -} - -// Cancel signals the goroutine to stop. -func (v *CancelSignal) Cancel() { - close(v.cancel) -} - -func (v *CancelSignal) Cancelled() bool { - select { - case <-v.cancel: - return true - default: - return false - } -} - -// WaitForCancel should be monitored by the goroutine for when to stop. -func (v *CancelSignal) WaitForCancel() <-chan struct{} { - return v.cancel -} - -// FinishThread signals that current goroutine has finished. -func (v *CancelSignal) FinishThread() { - v.done.Done() -} - -// WaitForDone is used by caller to wait for the goroutine finishes. -func (v *CancelSignal) WaitForDone() { - v.done.Wait() -}