diff --git a/common/alloc/buffer_test.go b/common/alloc/buffer_test.go index 9d42170f..2b5ba9cd 100644 --- a/common/alloc/buffer_test.go +++ b/common/alloc/buffer_test.go @@ -1,8 +1,9 @@ -package alloc +package alloc_test import ( "testing" + . "github.com/v2ray/v2ray-core/common/alloc" v2testing "github.com/v2ray/v2ray-core/testing" "github.com/v2ray/v2ray-core/testing/assert" ) diff --git a/common/log/access.go b/common/log/access.go index f858edfb..f4501f61 100644 --- a/common/log/access.go +++ b/common/log/access.go @@ -1,7 +1,7 @@ package log import ( - "github.com/v2ray/v2ray-core/common/alloc" + "github.com/v2ray/v2ray-core/common/log/internal" "github.com/v2ray/v2ray-core/common/serial" ) @@ -14,32 +14,12 @@ const ( ) var ( - accessLoggerInstance logWriter = &noOpLogWriter{} + accessLoggerInstance internal.LogWriter = new(internal.NoOpLogWriter) ) -type accessLog struct { - From serial.String - To serial.String - Status AccessStatus - Reason serial.String -} - -func (this *accessLog) Release() { - this.From = nil - this.To = nil - this.Reason = nil -} - -func (this *accessLog) String() string { - b := alloc.NewSmallBuffer().Clear() - defer b.Release() - - return b.AppendString(this.From.String()).AppendString(" ").AppendString(string(this.Status)).AppendString(" ").AppendString(this.To.String()).AppendString(" ").AppendString(this.Reason.String()).String() -} - // InitAccessLogger initializes the access logger to write into the give file. func InitAccessLogger(file string) error { - logger, err := newFileLogWriter(file) + logger, err := internal.NewFileLogWriter(file) if err != nil { Error("Failed to create access logger on file (", file, "): ", file, err) return err @@ -50,10 +30,10 @@ func InitAccessLogger(file string) error { // Access writes an access log. func Access(from, to serial.String, status AccessStatus, reason serial.String) { - accessLoggerInstance.Log(&accessLog{ + accessLoggerInstance.Log(&internal.AccessLog{ From: from, To: to, - Status: status, + Status: string(status), Reason: reason, }) } diff --git a/common/log/access_test.go b/common/log/access_test.go deleted file mode 100644 index 30aa00aa..00000000 --- a/common/log/access_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package log - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/v2ray/v2ray-core/common/serial" - v2testing "github.com/v2ray/v2ray-core/testing" - "github.com/v2ray/v2ray-core/testing/assert" -) - -func TestAccessLog(t *testing.T) { - v2testing.Current(t) - - filename := "/tmp/test_access_log.log" - InitAccessLogger(filename) - _, err := os.Stat(filename) - assert.Error(err).IsNil() - - Access(serial.StringLiteral("test_from"), serial.StringLiteral("test_to"), AccessAccepted, serial.StringLiteral("test_reason")) - <-time.After(2 * time.Second) - - accessLoggerInstance.(*fileLogWriter).close() - accessLoggerInstance = &noOpLogWriter{} - - content, err := ioutil.ReadFile(filename) - assert.Error(err).IsNil() - - contentStr := serial.StringLiteral(content) - assert.String(contentStr).Contains(serial.StringLiteral("test_from")) - assert.String(contentStr).Contains(serial.StringLiteral("test_to")) - assert.String(contentStr).Contains(serial.StringLiteral("test_reason")) - assert.String(contentStr).Contains(serial.StringLiteral("accepted")) -} diff --git a/common/log/internal/log_entry.go b/common/log/internal/log_entry.go new file mode 100644 index 00000000..abaa92d7 --- /dev/null +++ b/common/log/internal/log_entry.go @@ -0,0 +1,69 @@ +package internal + +import ( + "fmt" + + "github.com/v2ray/v2ray-core/common" + "github.com/v2ray/v2ray-core/common/alloc" + "github.com/v2ray/v2ray-core/common/serial" +) + +type LogEntry interface { + common.Releasable + serial.String +} + +type ErrorLog struct { + Prefix string + Values []interface{} +} + +func (this *ErrorLog) Release() { + for index := range this.Values { + this.Values[index] = nil + } + this.Values = nil +} + +func (this *ErrorLog) String() string { + b := alloc.NewSmallBuffer().Clear() + defer b.Release() + + b.AppendString(this.Prefix) + + for _, value := range this.Values { + switch typedVal := value.(type) { + case string: + b.AppendString(typedVal) + case *string: + b.AppendString(*typedVal) + case serial.String: + b.AppendString(typedVal.String()) + case error: + b.AppendString(typedVal.Error()) + default: + b.AppendString(fmt.Sprint(value)) + } + } + return b.String() +} + +type AccessLog struct { + From serial.String + To serial.String + Status string + Reason serial.String +} + +func (this *AccessLog) Release() { + this.From = nil + this.To = nil + this.Reason = nil +} + +func (this *AccessLog) String() string { + b := alloc.NewSmallBuffer().Clear() + defer b.Release() + + return b.AppendString(this.From.String()).AppendString(" ").AppendString(this.Status).AppendString(" ").AppendString(this.To.String()).AppendString(" ").AppendString(this.Reason.String()).String() +} diff --git a/common/log/internal/log_entry_test.go b/common/log/internal/log_entry_test.go new file mode 100644 index 00000000..f406320d --- /dev/null +++ b/common/log/internal/log_entry_test.go @@ -0,0 +1,27 @@ +package internal_test + +import ( + "testing" + + . "github.com/v2ray/v2ray-core/common/log/internal" + "github.com/v2ray/v2ray-core/common/serial" + v2testing "github.com/v2ray/v2ray-core/testing" + "github.com/v2ray/v2ray-core/testing/assert" +) + +func TestAccessLog(t *testing.T) { + v2testing.Current(t) + + entry := &AccessLog{ + From: serial.StringLiteral("test_from"), + To: serial.StringLiteral("test_to"), + Status: "Accepted", + Reason: serial.StringLiteral("test_reason"), + } + + entryStr := entry.String() + assert.StringLiteral(entryStr).Contains(serial.StringLiteral("test_from")) + assert.StringLiteral(entryStr).Contains(serial.StringLiteral("test_to")) + assert.StringLiteral(entryStr).Contains(serial.StringLiteral("test_reason")) + assert.StringLiteral(entryStr).Contains(serial.StringLiteral("Accepted")) +} diff --git a/common/log/log_writer.go b/common/log/internal/log_writer.go similarity index 57% rename from common/log/log_writer.go rename to common/log/internal/log_writer.go index a783a86d..6e65f900 100644 --- a/common/log/log_writer.go +++ b/common/log/internal/log_writer.go @@ -1,50 +1,45 @@ -package log +package internal import ( - "io" "log" "os" "github.com/v2ray/v2ray-core/common/platform" ) -func createLogger(writer io.Writer) *log.Logger { - return log.New(writer, "", log.Ldate|log.Ltime) -} - -type logWriter interface { +type LogWriter interface { Log(LogEntry) } -type noOpLogWriter struct { +type NoOpLogWriter struct { } -func (this *noOpLogWriter) Log(entry LogEntry) { +func (this *NoOpLogWriter) Log(entry LogEntry) { entry.Release() } -type stdOutLogWriter struct { +type StdOutLogWriter struct { logger *log.Logger } -func newStdOutLogWriter() logWriter { - return &stdOutLogWriter{ - logger: createLogger(os.Stdout), +func NewStdOutLogWriter() LogWriter { + return &StdOutLogWriter{ + logger: log.New(os.Stdout, "", log.Ldate|log.Ltime), } } -func (this *stdOutLogWriter) Log(log LogEntry) { +func (this *StdOutLogWriter) Log(log LogEntry) { this.logger.Print(log.String() + platform.LineSeparator()) log.Release() } -type fileLogWriter struct { +type FileLogWriter struct { queue chan LogEntry logger *log.Logger file *os.File } -func (this *fileLogWriter) Log(log LogEntry) { +func (this *FileLogWriter) Log(log LogEntry) { select { case this.queue <- log: default: @@ -53,7 +48,7 @@ func (this *fileLogWriter) Log(log LogEntry) { } } -func (this *fileLogWriter) run() { +func (this *FileLogWriter) run() { for { entry, open := <-this.queue if !open { @@ -65,16 +60,16 @@ func (this *fileLogWriter) run() { } } -func (this *fileLogWriter) close() { +func (this *FileLogWriter) Close() { this.file.Close() } -func newFileLogWriter(path string) (*fileLogWriter, error) { +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{ + logger := &FileLogWriter{ queue: make(chan LogEntry, 16), logger: log.New(file, "", log.Ldate|log.Ltime), file: file, diff --git a/common/log/internal/log_writer_test.go b/common/log/internal/log_writer_test.go new file mode 100644 index 00000000..e4a75bbb --- /dev/null +++ b/common/log/internal/log_writer_test.go @@ -0,0 +1 @@ +package internal_test diff --git a/common/log/log.go b/common/log/log.go index 661c37e0..82f99bd6 100644 --- a/common/log/log.go +++ b/common/log/log.go @@ -1,13 +1,11 @@ package log import ( - "fmt" - - "github.com/v2ray/v2ray-core/common" - "github.com/v2ray/v2ray-core/common/alloc" - "github.com/v2ray/v2ray-core/common/serial" + "github.com/v2ray/v2ray-core/common/log/internal" ) +type LogLevel int + const ( DebugLevel = LogLevel(0) InfoLevel = LogLevel(1) @@ -16,86 +14,43 @@ const ( NoneLevel = LogLevel(999) ) -type LogEntry interface { - common.Releasable - serial.String -} - -type errorLog struct { - prefix string - values []interface{} -} - -func (this *errorLog) Release() { - for index := range this.values { - this.values[index] = nil - } - this.values = nil -} - -func (this *errorLog) String() string { - b := alloc.NewSmallBuffer().Clear() - defer b.Release() - - b.AppendString(this.prefix) - - for _, value := range this.values { - switch typedVal := value.(type) { - case string: - b.AppendString(typedVal) - case *string: - b.AppendString(*typedVal) - case serial.String: - b.AppendString(typedVal.String()) - case error: - b.AppendString(typedVal.Error()) - default: - b.AppendString(fmt.Sprint(value)) - } - } - return b.String() -} - var ( - noOpLoggerInstance logWriter = &noOpLogWriter{} - streamLoggerInstance logWriter = newStdOutLogWriter() + streamLoggerInstance internal.LogWriter = internal.NewStdOutLogWriter() - debugLogger = noOpLoggerInstance - infoLogger = noOpLoggerInstance - warningLogger = streamLoggerInstance - errorLogger = streamLoggerInstance + debugLogger internal.LogWriter = streamLoggerInstance + infoLogger internal.LogWriter = streamLoggerInstance + warningLogger internal.LogWriter = streamLoggerInstance + errorLogger internal.LogWriter = streamLoggerInstance ) -type LogLevel int - func SetLogLevel(level LogLevel) { - debugLogger = noOpLoggerInstance + debugLogger = new(internal.NoOpLogWriter) if level <= DebugLevel { debugLogger = streamLoggerInstance } - infoLogger = noOpLoggerInstance + infoLogger = new(internal.NoOpLogWriter) if level <= InfoLevel { infoLogger = streamLoggerInstance } - warningLogger = noOpLoggerInstance + warningLogger = new(internal.NoOpLogWriter) if level <= WarningLevel { warningLogger = streamLoggerInstance } - errorLogger = noOpLoggerInstance + errorLogger = new(internal.NoOpLogWriter) if level <= ErrorLevel { errorLogger = streamLoggerInstance } if level == NoneLevel { - accessLoggerInstance = noOpLoggerInstance + accessLoggerInstance = new(internal.NoOpLogWriter) } } func InitErrorLogger(file string) error { - logger, err := newFileLogWriter(file) + logger, err := internal.NewFileLogWriter(file) if err != nil { Error("Failed to create error logger on file (", file, "): ", err) return err @@ -106,32 +61,32 @@ func InitErrorLogger(file string) error { // Debug outputs a debug log with given format and optional arguments. func Debug(v ...interface{}) { - debugLogger.Log(&errorLog{ - prefix: "[Debug]", - values: v, + debugLogger.Log(&internal.ErrorLog{ + Prefix: "[Debug]", + Values: v, }) } // Info outputs an info log with given format and optional arguments. func Info(v ...interface{}) { - infoLogger.Log(&errorLog{ - prefix: "[Info]", - values: v, + infoLogger.Log(&internal.ErrorLog{ + Prefix: "[Info]", + Values: v, }) } // Warning outputs a warning log with given format and optional arguments. func Warning(v ...interface{}) { - warningLogger.Log(&errorLog{ - prefix: "[Warning]", - values: v, + warningLogger.Log(&internal.ErrorLog{ + Prefix: "[Warning]", + Values: v, }) } // Error outputs an error log with given format and optional arguments. func Error(v ...interface{}) { - errorLogger.Log(&errorLog{ - prefix: "[Error]", - values: v, + errorLogger.Log(&internal.ErrorLog{ + Prefix: "[Error]", + Values: v, }) } diff --git a/common/log/log_test.go b/common/log/log_test.go deleted file mode 100644 index 2741024a..00000000 --- a/common/log/log_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package log - -import ( - "bytes" - "log" - "testing" - - "github.com/v2ray/v2ray-core/common/platform" - "github.com/v2ray/v2ray-core/common/serial" - v2testing "github.com/v2ray/v2ray-core/testing" - "github.com/v2ray/v2ray-core/testing/assert" -) - -func TestLogLevelSetting(t *testing.T) { - v2testing.Current(t) - - assert.Pointer(debugLogger).Equals(noOpLoggerInstance) - SetLogLevel(DebugLevel) - assert.Pointer(debugLogger).Equals(streamLoggerInstance) - - SetLogLevel(InfoLevel) - assert.Pointer(debugLogger).Equals(noOpLoggerInstance) - assert.Pointer(infoLogger).Equals(streamLoggerInstance) -} - -func TestStreamLogger(t *testing.T) { - v2testing.Current(t) - - buffer := bytes.NewBuffer(make([]byte, 0, 1024)) - infoLogger = &stdOutLogWriter{ - logger: log.New(buffer, "", 0), - } - Info("Test ", "Stream Logger", " Format") - assert.StringLiteral(string(buffer.Bytes())).Equals("[Info]Test Stream Logger Format" + platform.LineSeparator()) - - buffer.Reset() - errorLogger = infoLogger - Error("Test ", serial.StringLiteral("literal"), " Format") - assert.StringLiteral(string(buffer.Bytes())).Equals("[Error]Test literal Format" + platform.LineSeparator()) -}