| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 | package internalimport (	"log"	"os"	"time"	"github.com/v2ray/v2ray-core/common/platform"	"github.com/v2ray/v2ray-core/common/signal")type LogWriter interface {	Log(LogEntry)	Close()}type NoOpLogWriter struct {}func (this *NoOpLogWriter) Log(entry LogEntry) {	entry.Release()}func (this *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(),	}}func (this *StdOutLogWriter) Log(log LogEntry) {	this.logger.Print(log.String() + platform.LineSeparator())	log.Release()}func (this *StdOutLogWriter) Close() {	time.Sleep(500 * time.Millisecond)}type FileLogWriter struct {	queue  chan string	logger *log.Logger	file   *os.File	cancel *signal.CancelSignal}func (this *FileLogWriter) Log(log LogEntry) {	select {	case this.queue <- log.String():	default:		// We don't expect this to happen, but don't want to block main thread as well.	}	log.Release()}func (this *FileLogWriter) run() {	for {		entry, open := <-this.queue		if !open {			break		}		this.logger.Print(entry + platform.LineSeparator())	}	this.cancel.Done()}func (this *FileLogWriter) Close() {	close(this.queue)	<-this.cancel.WaitForDone()	this.file.Close()}func NewFileLogWriter(path string) (*FileLogWriter, error) {	file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)	if err != nil {		return nil, err	}	logger := &FileLogWriter{		queue:  make(chan string, 16),		logger: log.New(file, "", log.Ldate|log.Ltime),		file:   file,		cancel: signal.NewCloseSignal(),	}	go logger.run()	return logger, nil}
 |