mirror of https://github.com/v2ray/v2ray-core
Refine log settings
parent
32c3565681
commit
db7d48e48f
|
@ -1,12 +1,5 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/platform"
|
||||
)
|
||||
|
||||
// AccessStatus is the status of an access request from clients.
|
||||
type AccessStatus string
|
||||
|
||||
|
@ -15,16 +8,9 @@ const (
|
|||
AccessRejected = AccessStatus("rejected")
|
||||
)
|
||||
|
||||
type accessLogger interface {
|
||||
Log(from, to string, status AccessStatus, reason string)
|
||||
}
|
||||
|
||||
type noOpAccessLogger struct {
|
||||
}
|
||||
|
||||
func (this *noOpAccessLogger) Log(from, to string, status AccessStatus, reason string) {
|
||||
// Swallow
|
||||
}
|
||||
var (
|
||||
accessLoggerInstance logWriter = &noOpLogWriter{}
|
||||
)
|
||||
|
||||
type accessLog struct {
|
||||
From string
|
||||
|
@ -33,60 +19,27 @@ type accessLog struct {
|
|||
Reason string
|
||||
}
|
||||
|
||||
type fileAccessLogger struct {
|
||||
queue chan *accessLog
|
||||
logger *log.Logger
|
||||
file *os.File
|
||||
func (this *accessLog) String() string {
|
||||
return this.From + " " + string(this.Status) + " " + this.To + " " + this.Reason
|
||||
}
|
||||
|
||||
func (this *fileAccessLogger) close() {
|
||||
this.file.Close()
|
||||
}
|
||||
|
||||
func (logger *fileAccessLogger) Log(from, to string, status AccessStatus, reason string) {
|
||||
select {
|
||||
case logger.queue <- &accessLog{
|
||||
From: from,
|
||||
To: to,
|
||||
Status: status,
|
||||
Reason: reason,
|
||||
}:
|
||||
default:
|
||||
// We don't expect this to happen, but don't want to block main thread as well.
|
||||
}
|
||||
}
|
||||
|
||||
func (this *fileAccessLogger) Run() {
|
||||
for entry := range this.queue {
|
||||
this.logger.Println(entry.From + " " + string(entry.Status) + " " + entry.To + " " + entry.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
func newFileAccessLogger(path string) accessLogger {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
log.Printf("Unable to create or open file (%s): %v%s", path, err, platform.LineSeparator())
|
||||
return nil
|
||||
}
|
||||
return &fileAccessLogger{
|
||||
queue: make(chan *accessLog, 16),
|
||||
logger: log.New(file, "", log.Ldate|log.Ltime),
|
||||
file: file,
|
||||
}
|
||||
}
|
||||
|
||||
var accessLoggerInstance accessLogger = &noOpAccessLogger{}
|
||||
|
||||
// InitAccessLogger initializes the access logger to write into the give file.
|
||||
func InitAccessLogger(file string) {
|
||||
logger := newFileAccessLogger(file)
|
||||
if logger != nil {
|
||||
go logger.(*fileAccessLogger).Run()
|
||||
accessLoggerInstance = logger
|
||||
func InitAccessLogger(file string) error {
|
||||
logger, err := newFileLogWriter(file)
|
||||
if err != nil {
|
||||
Error("Failed to create access logger on file (%s): %v", file, err)
|
||||
return err
|
||||
}
|
||||
accessLoggerInstance = logger
|
||||
return nil
|
||||
}
|
||||
|
||||
// Access writes an access log.
|
||||
func Access(from, to string, status AccessStatus, reason string) {
|
||||
accessLoggerInstance.Log(from, to, status, reason)
|
||||
accessLoggerInstance.Log(&accessLog{
|
||||
From: from,
|
||||
To: to,
|
||||
Status: status,
|
||||
Reason: reason,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ package log
|
|||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
v2testing "github.com/v2ray/v2ray-core/testing"
|
||||
"github.com/v2ray/v2ray-core/testing/assert"
|
||||
)
|
||||
|
@ -22,14 +22,15 @@ func TestAccessLog(t *testing.T) {
|
|||
Access("test_from", "test_to", AccessAccepted, "test_reason")
|
||||
<-time.After(2 * time.Second)
|
||||
|
||||
accessLoggerInstance.(*fileAccessLogger).close()
|
||||
accessLoggerInstance = &noOpAccessLogger{}
|
||||
accessLoggerInstance.(*fileLogWriter).close()
|
||||
accessLoggerInstance = &noOpLogWriter{}
|
||||
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Bool(strings.Contains(string(content), "test_from")).IsTrue()
|
||||
assert.Bool(strings.Contains(string(content), "test_to")).IsTrue()
|
||||
assert.Bool(strings.Contains(string(content), "test_reason")).IsTrue()
|
||||
assert.Bool(strings.Contains(string(content), "accepted")).IsTrue()
|
||||
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"))
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package log
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -13,36 +11,25 @@ const (
|
|||
ErrorLevel = LogLevel(3)
|
||||
)
|
||||
|
||||
type logger interface {
|
||||
WriteLog(prefix, format string, v ...interface{})
|
||||
type errorLog struct {
|
||||
prefix string
|
||||
format string
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
type noOpLogger struct {
|
||||
}
|
||||
|
||||
func (this *noOpLogger) WriteLog(prefix, format string, v ...interface{}) {
|
||||
// Swallow
|
||||
}
|
||||
|
||||
type streamLogger struct {
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (this *streamLogger) WriteLog(prefix, format string, v ...interface{}) {
|
||||
func (this *errorLog) String() string {
|
||||
var data string
|
||||
if v == nil || len(v) == 0 {
|
||||
data = format
|
||||
if len(this.values) == 0 {
|
||||
data = this.format
|
||||
} else {
|
||||
data = fmt.Sprintf(format, v...)
|
||||
data = fmt.Sprintf(this.format, this.values...)
|
||||
}
|
||||
this.logger.Println(prefix + data)
|
||||
return this.prefix + data
|
||||
}
|
||||
|
||||
var (
|
||||
noOpLoggerInstance logger = &noOpLogger{}
|
||||
streamLoggerInstance logger = &streamLogger{
|
||||
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
|
||||
}
|
||||
noOpLoggerInstance logWriter = &noOpLogWriter{}
|
||||
streamLoggerInstance logWriter = newStdOutLogWriter()
|
||||
|
||||
debugLogger = noOpLoggerInstance
|
||||
infoLogger = noOpLoggerInstance
|
||||
|
@ -74,22 +61,48 @@ func SetLogLevel(level LogLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
func InitErrorLogger(file string) error {
|
||||
logger, err := newFileLogWriter(file)
|
||||
if err != nil {
|
||||
Error("Failed to create error logger on file (%s): %v", file, err)
|
||||
return err
|
||||
}
|
||||
streamLoggerInstance = logger
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug outputs a debug log with given format and optional arguments.
|
||||
func Debug(format string, v ...interface{}) {
|
||||
debugLogger.WriteLog("[Debug]", format, v...)
|
||||
debugLogger.Log(&errorLog{
|
||||
prefix: "[Debug]",
|
||||
format: format,
|
||||
values: v,
|
||||
})
|
||||
}
|
||||
|
||||
// Info outputs an info log with given format and optional arguments.
|
||||
func Info(format string, v ...interface{}) {
|
||||
infoLogger.WriteLog("[Info]", format, v...)
|
||||
infoLogger.Log(&errorLog{
|
||||
prefix: "[Info]",
|
||||
format: format,
|
||||
values: v,
|
||||
})
|
||||
}
|
||||
|
||||
// Warning outputs a warning log with given format and optional arguments.
|
||||
func Warning(format string, v ...interface{}) {
|
||||
warningLogger.WriteLog("[Warning]", format, v...)
|
||||
warningLogger.Log(&errorLog{
|
||||
prefix: "[Warning]",
|
||||
format: format,
|
||||
values: v,
|
||||
})
|
||||
}
|
||||
|
||||
// Error outputs an error log with given format and optional arguments.
|
||||
func Error(format string, v ...interface{}) {
|
||||
errorLogger.WriteLog("[Error]", format, v...)
|
||||
errorLogger.Log(&errorLog{
|
||||
prefix: "[Error]",
|
||||
format: format,
|
||||
values: v,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -25,13 +25,14 @@ func TestStreamLogger(t *testing.T) {
|
|||
v2testing.Current(t)
|
||||
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
logger := &streamLogger{
|
||||
infoLogger = &stdOutLogWriter{
|
||||
logger: log.New(buffer, "", 0),
|
||||
}
|
||||
logger.WriteLog("TestPrefix: ", "Test %s Format", "Stream Logger")
|
||||
assert.Bytes(buffer.Bytes()).Equals([]byte("TestPrefix: Test Stream Logger Format\n"))
|
||||
Info("Test %s Format", "Stream Logger")
|
||||
assert.Bytes(buffer.Bytes()).Equals([]byte("[Info]Test Stream Logger Format\n"))
|
||||
|
||||
buffer.Reset()
|
||||
logger.WriteLog("TestPrefix: ", "Test No Format")
|
||||
assert.Bytes(buffer.Bytes()).Equals([]byte("TestPrefix: Test No Format\n"))
|
||||
errorLogger = infoLogger
|
||||
Error("Test No Format")
|
||||
assert.Bytes(buffer.Bytes()).Equals([]byte("[Error]Test No Format\n"))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/platform"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
)
|
||||
|
||||
func createLogger(writer io.Writer) *log.Logger {
|
||||
return log.New(writer, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
|
||||
type logWriter interface {
|
||||
Log(serial.String)
|
||||
}
|
||||
|
||||
type noOpLogWriter struct {
|
||||
}
|
||||
|
||||
func (this *noOpLogWriter) Log(serial.String) {
|
||||
// Swallow
|
||||
}
|
||||
|
||||
type stdOutLogWriter struct {
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func newStdOutLogWriter() logWriter {
|
||||
return &stdOutLogWriter{
|
||||
logger: createLogger(os.Stdout),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *stdOutLogWriter) Log(log serial.String) {
|
||||
this.logger.Print(log.String() + platform.LineSeparator())
|
||||
}
|
||||
|
||||
type fileLogWriter struct {
|
||||
queue chan serial.String
|
||||
logger *log.Logger
|
||||
file *os.File
|
||||
}
|
||||
|
||||
func (this *fileLogWriter) Log(log serial.String) {
|
||||
select {
|
||||
case this.queue <- log:
|
||||
default:
|
||||
// We don't expect this to happen, but don't want to block main thread as well.
|
||||
}
|
||||
}
|
||||
|
||||
func (this *fileLogWriter) run() {
|
||||
for entry := range this.queue {
|
||||
this.logger.Print(entry.String() + platform.LineSeparator())
|
||||
}
|
||||
}
|
||||
|
||||
func (this *fileLogWriter) close() {
|
||||
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 serial.String, 16),
|
||||
logger: log.New(file, "", log.Ldate|log.Ltime),
|
||||
file: file,
|
||||
}
|
||||
go logger.run()
|
||||
return logger, nil
|
||||
}
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
routerconfig "github.com/v2ray/v2ray-core/app/router/config"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
|
@ -12,6 +13,8 @@ type ConnectionConfig interface {
|
|||
|
||||
type LogConfig interface {
|
||||
AccessLog() string
|
||||
ErrorLog() string
|
||||
LogLevel() log.LogLevel
|
||||
}
|
||||
|
||||
type InboundDetourConfig interface {
|
||||
|
|
|
@ -1,9 +1,35 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
)
|
||||
|
||||
type LogConfig struct {
|
||||
AccessLogValue string `json:"access"`
|
||||
ErrorLogValue string `json:"error"`
|
||||
LogLevelValue string `json:"loglevel"`
|
||||
}
|
||||
|
||||
func (config *LogConfig) AccessLog() string {
|
||||
return config.AccessLogValue
|
||||
func (this *LogConfig) AccessLog() string {
|
||||
return this.AccessLogValue
|
||||
}
|
||||
|
||||
func (this *LogConfig) ErrorLog() string {
|
||||
return this.ErrorLogValue
|
||||
}
|
||||
|
||||
func (this *LogConfig) LogLevel() log.LogLevel {
|
||||
level := strings.ToLower(this.LogLevelValue)
|
||||
switch level {
|
||||
case "debug":
|
||||
return log.DebugLevel
|
||||
case "info":
|
||||
return log.InfoLevel
|
||||
case "error":
|
||||
return log.ErrorLevel
|
||||
default:
|
||||
return log.WarningLevel
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package mocks
|
|||
import (
|
||||
routerconfig "github.com/v2ray/v2ray-core/app/router/config"
|
||||
routertestingconfig "github.com/v2ray/v2ray-core/app/router/config/testing"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/shell/point/config"
|
||||
)
|
||||
|
@ -22,6 +23,20 @@ func (config *ConnectionConfig) Settings() interface{} {
|
|||
|
||||
type LogConfig struct {
|
||||
AccessLogValue string
|
||||
ErrorLogValue string
|
||||
LogLevelValue log.LogLevel
|
||||
}
|
||||
|
||||
func (config *LogConfig) AccessLog() string {
|
||||
return config.AccessLogValue
|
||||
}
|
||||
|
||||
func (this *LogConfig) ErrorLog() string {
|
||||
return this.ErrorLogValue
|
||||
}
|
||||
|
||||
func (this *LogConfig) LogLevel() log.LogLevel {
|
||||
return this.LogLevelValue
|
||||
}
|
||||
|
||||
type PortRange struct {
|
||||
|
@ -55,10 +70,6 @@ func (this *OutboundDetourConfig) Tag() string {
|
|||
return this.TagValue
|
||||
}
|
||||
|
||||
func (config *LogConfig) AccessLog() string {
|
||||
return config.AccessLogValue
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PortValue v2net.Port
|
||||
LogConfigValue *LogConfig
|
||||
|
|
|
@ -30,6 +30,25 @@ func NewPoint(pConfig config.PointConfig) (*Point, error) {
|
|||
var vpoint = new(Point)
|
||||
vpoint.port = pConfig.Port()
|
||||
|
||||
if pConfig.LogConfig() != nil {
|
||||
logConfig := pConfig.LogConfig()
|
||||
if len(logConfig.AccessLog()) > 0 {
|
||||
err := log.InitAccessLogger(logConfig.AccessLog())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(logConfig.ErrorLog()) > 0 {
|
||||
err := log.InitErrorLogger(logConfig.ErrorLog())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
log.SetLogLevel(logConfig.LogLevel())
|
||||
}
|
||||
|
||||
ichFactory := connhandler.GetInboundConnectionHandlerFactory(pConfig.InboundConfig().Protocol())
|
||||
if ichFactory == nil {
|
||||
log.Error("Unknown inbound connection handler factory %s", pConfig.InboundConfig().Protocol())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package assert
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
)
|
||||
|
||||
|
@ -31,3 +33,15 @@ func (subject *StringSubject) Equals(expectation string) {
|
|||
subject.Fail(subject.DisplayString(), "is equal to", serial.StringLiteral(expectation))
|
||||
}
|
||||
}
|
||||
|
||||
func (subject *StringSubject) Contains(substring serial.String) {
|
||||
if !strings.Contains(subject.value.String(), substring.String()) {
|
||||
subject.Fail(subject.DisplayString(), "contains", substring)
|
||||
}
|
||||
}
|
||||
|
||||
func (subject *StringSubject) NotContains(substring serial.String) {
|
||||
if strings.Contains(subject.value.String(), substring.String()) {
|
||||
subject.Fail(subject.DisplayString(), "doesn't contain", substring)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue