mirror of https://github.com/v2ray/v2ray-core
Darien Raymond
7 years ago
5 changed files with 172 additions and 134 deletions
@ -1,85 +0,0 @@
|
||||
package internal |
||||
|
||||
import ( |
||||
"context" |
||||
"log" |
||||
"os" |
||||
|
||||
"v2ray.com/core/common/platform" |
||||
) |
||||
|
||||
type LogEntry interface { |
||||
String() string |
||||
} |
||||
|
||||
type LogWriter interface { |
||||
Log(LogEntry) |
||||
Close() |
||||
} |
||||
|
||||
type StdOutLogWriter struct { |
||||
logger *log.Logger |
||||
} |
||||
|
||||
func NewStdOutLogWriter() LogWriter { |
||||
return &StdOutLogWriter{ |
||||
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime), |
||||
} |
||||
} |
||||
|
||||
func (w *StdOutLogWriter) Log(log LogEntry) { |
||||
w.logger.Print(log.String() + platform.LineSeparator()) |
||||
} |
||||
|
||||
func (*StdOutLogWriter) Close() {} |
||||
|
||||
type FileLogWriter struct { |
||||
queue chan string |
||||
logger *log.Logger |
||||
file *os.File |
||||
ctx context.Context |
||||
cancel context.CancelFunc |
||||
} |
||||
|
||||
func (w *FileLogWriter) Log(log LogEntry) { |
||||
select { |
||||
case <-w.ctx.Done(): |
||||
return |
||||
case w.queue <- log.String(): |
||||
default: |
||||
// We don't expect this to happen, but don't want to block main thread as well.
|
||||
} |
||||
} |
||||
|
||||
func (w *FileLogWriter) run(ctx context.Context) { |
||||
for { |
||||
select { |
||||
case <-ctx.Done(): |
||||
w.file.Close() |
||||
return |
||||
case entry := <-w.queue: |
||||
w.logger.Print(entry + platform.LineSeparator()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (w *FileLogWriter) Close() { |
||||
w.cancel() |
||||
} |
||||
|
||||
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 |
||||
} |
||||
ctx, cancel := context.WithCancel(context.Background()) |
||||
logger := &FileLogWriter{ |
||||
queue: make(chan string, 16), |
||||
logger: log.New(file, "", log.Ldate|log.Ltime), |
||||
file: file, |
||||
ctx: ctx, |
||||
cancel: cancel, |
||||
} |
||||
go logger.run(ctx) |
||||
return logger, nil |
||||
} |
@ -0,0 +1,132 @@
|
||||
package log |
||||
|
||||
import ( |
||||
"io" |
||||
"log" |
||||
"os" |
||||
"time" |
||||
|
||||
"v2ray.com/core/common/platform" |
||||
"v2ray.com/core/common/signal" |
||||
) |
||||
|
||||
type LogWriter interface { |
||||
io.WriteCloser |
||||
} |
||||
|
||||
type LogWriterCreator func() LogWriter |
||||
|
||||
type generalLogger struct { |
||||
creator LogWriterCreator |
||||
buffer chan Message |
||||
access *signal.Semaphore |
||||
} |
||||
|
||||
// NewLogger returns a generic log handler that can handle all type of messages.
|
||||
func NewLogger(logWriterCreator LogWriterCreator) Handler { |
||||
return &generalLogger{ |
||||
creator: logWriterCreator, |
||||
buffer: make(chan Message, 16), |
||||
access: signal.NewSemaphore(1), |
||||
} |
||||
} |
||||
|
||||
func (l *generalLogger) run() { |
||||
defer l.access.Signal() |
||||
|
||||
dataWritten := false |
||||
ticker := time.NewTicker(time.Minute) |
||||
defer ticker.Stop() |
||||
|
||||
logger := l.creator() |
||||
if logger == nil { |
||||
return |
||||
} |
||||
defer logger.Close() |
||||
|
||||
ls := []byte(platform.LineSeparator()) |
||||
|
||||
for { |
||||
select { |
||||
case msg := <-l.buffer: |
||||
logger.Write([]byte(msg.String())) |
||||
logger.Write(ls) |
||||
dataWritten = true |
||||
case <-ticker.C: |
||||
if !dataWritten { |
||||
return |
||||
} |
||||
dataWritten = false |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (l *generalLogger) Handle(msg Message) { |
||||
select { |
||||
case l.buffer <- msg: |
||||
default: |
||||
} |
||||
|
||||
select { |
||||
case <-l.access.Wait(): |
||||
go l.run() |
||||
default: |
||||
} |
||||
} |
||||
|
||||
type consoleLogWriter struct { |
||||
logger *log.Logger |
||||
} |
||||
|
||||
func (w *consoleLogWriter) Write(b []byte) (int, error) { |
||||
w.logger.Print(string(b)) |
||||
return len(b), nil |
||||
} |
||||
|
||||
func (w *consoleLogWriter) Close() error { |
||||
return nil |
||||
} |
||||
|
||||
type fileLogWriter struct { |
||||
file *os.File |
||||
logger *log.Logger |
||||
} |
||||
|
||||
func (w *fileLogWriter) Write(b []byte) (int, error) { |
||||
w.logger.Print(string(b)) |
||||
return len(b), nil |
||||
} |
||||
|
||||
func (w *fileLogWriter) Close() error { |
||||
return w.file.Close() |
||||
} |
||||
|
||||
func CreateStdoutLogWriter() LogWriterCreator { |
||||
return func() LogWriter { |
||||
return &consoleLogWriter{ |
||||
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime), |
||||
} |
||||
} |
||||
} |
||||
|
||||
func CreateFileLogWriter(path string) (LogWriterCreator, error) { |
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
file.Close() |
||||
return func() LogWriter { |
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) |
||||
if err != nil { |
||||
return nil |
||||
} |
||||
return &fileLogWriter{ |
||||
file: file, |
||||
logger: log.New(file, "", log.Ldate|log.Ltime), |
||||
} |
||||
}, nil |
||||
} |
||||
|
||||
func init() { |
||||
RegisterHandler(NewLogger(CreateStdoutLogWriter())) |
||||
} |
Loading…
Reference in new issue