From efb881d73c852e14a630b65ab201d44310b7ac2a Mon Sep 17 00:00:00 2001 From: V2Ray Date: Tue, 13 Oct 2015 18:27:29 +0200 Subject: [PATCH] Remove log level detection during runtime --- common/log/log.go | 79 ++++++++++++++++++++++++--------- common/log/log_test.go | 19 ++++++++ proxy/freedom/freedom.go | 3 +- proxy/vmess/config.go | 20 +++++---- proxy/vmess/protocol/user/id.go | 11 ++++- proxy/vmess/vmessin.go | 9 ++-- proxy/vmess/vmessout.go | 27 +++++++---- 7 files changed, 125 insertions(+), 43 deletions(-) create mode 100644 common/log/log_test.go diff --git a/common/log/log.go b/common/log/log.go index 1c301c5b5..0c7b3160a 100644 --- a/common/log/log.go +++ b/common/log/log.go @@ -1,9 +1,9 @@ package log import ( - "errors" "fmt" - "log" + "io" + "os" ) const ( @@ -13,41 +13,80 @@ const ( ErrorLevel = LogLevel(3) ) -var logLevel = WarningLevel - -type LogLevel int - -func SetLogLevel(level LogLevel) { - logLevel = level +type logger interface { + WriteLog(prefix, format string, v ...interface{}) } -func writeLog(level LogLevel, prefix, format string, v ...interface{}) string { - if level < logLevel { - return "" - } +type noOpLogger struct { +} + +func (l *noOpLogger) WriteLog(prefix, format string, v ...interface{}) { + // Swallow +} + +type streamLogger struct { + writer io.Writer +} + +func (l *streamLogger) WriteLog(prefix, format string, v ...interface{}) { var data string if v == nil || len(v) == 0 { data = format } else { data = fmt.Sprintf(format, v...) } - log.Println(prefix + data) - return data + l.writer.Write([]byte(prefix + data)) + l.writer.Write([]byte{'\n'}) +} + +var ( + noOpLoggerInstance logger = &noOpLogger{} + streamLoggerInstance logger = &streamLogger{ + writer: os.Stdout, + } + + debugLogger = noOpLoggerInstance + infoLogger = noOpLoggerInstance + warningLogger = noOpLoggerInstance + errorLogger = noOpLoggerInstance +) + +type LogLevel int + +func SetLogLevel(level LogLevel) { + debugLogger = noOpLoggerInstance + if level <= DebugLevel { + debugLogger = streamLoggerInstance + } + + infoLogger = noOpLoggerInstance + if level <= InfoLevel { + infoLogger = streamLoggerInstance + } + + warningLogger = noOpLoggerInstance + if level <= WarningLevel { + warningLogger = streamLoggerInstance + } + + errorLogger = noOpLoggerInstance + if level <= ErrorLevel { + errorLogger = streamLoggerInstance + } } func Debug(format string, v ...interface{}) { - writeLog(DebugLevel, "[Debug]", format, v...) + debugLogger.WriteLog("[Debug]", format, v...) } func Info(format string, v ...interface{}) { - writeLog(InfoLevel, "[Info]", format, v...) + infoLogger.WriteLog("[Info]", format, v...) } func Warning(format string, v ...interface{}) { - writeLog(WarningLevel, "[Warning]", format, v...) + warningLogger.WriteLog("[Warning]", format, v...) } -func Error(format string, v ...interface{}) error { - data := writeLog(ErrorLevel, "[Error]", format, v...) - return errors.New(data) +func Error(format string, v ...interface{}) { + errorLogger.WriteLog("[Error]", format, v...) } diff --git a/common/log/log_test.go b/common/log/log_test.go new file mode 100644 index 000000000..447ae2f91 --- /dev/null +++ b/common/log/log_test.go @@ -0,0 +1,19 @@ +package log + +import ( + "testing" + + "github.com/v2ray/v2ray-core/testing/unit" +) + +func TestLogLevelSetting(t *testing.T) { + assert := unit.Assert(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) +} diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 2106e6305..1e34c0007 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -22,7 +22,8 @@ func (vconn *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray core.Outb log.Info("Freedom: Opening connection to %s", firstPacket.Destination().String()) if err != nil { close(ray.OutboundOutput()) - return log.Error("Freedom: Failed to open connection: %s : %v", firstPacket.Destination().String(), err) + log.Error("Freedom: Failed to open connection: %s : %v", firstPacket.Destination().String(), err) + return err } input := ray.OutboundInput() diff --git a/proxy/vmess/config.go b/proxy/vmess/config.go index 823d9012e..1bcab8a25 100644 --- a/proxy/vmess/config.go +++ b/proxy/vmess/config.go @@ -41,30 +41,32 @@ func (config VNextConfig) HasNetwork(network string) bool { return strings.Contains(config.Network, network) } -func (config VNextConfig) ToVNextServer(network string) VNextServer { - users := make([]user.User, 0, len(config.Users)) - for _, user := range config.Users { +func (c VNextConfig) ToVNextServer(network string) (*VNextServer, error) { + users := make([]user.User, 0, len(c.Users)) + for _, user := range c.Users { vuser, err := user.ToUser() if err != nil { - panic(log.Error("Failed to convert %v to User.", user)) + log.Error("Failed to convert %v to User.", user) + return nil, config.BadConfiguration } users = append(users, vuser) } - ip := net.ParseIP(config.Address) + ip := net.ParseIP(c.Address) if ip == nil { - panic(log.Error("Unable to parse VNext IP: %s", config.Address)) + log.Error("Unable to parse VNext IP: %s", c.Address) + return nil, config.BadConfiguration } - address := v2net.IPAddress(ip, config.Port) + address := v2net.IPAddress(ip, c.Port) var dest v2net.Destination if network == "tcp" { dest = v2net.NewTCPDestination(address) } else { dest = v2net.NewUDPDestination(address) } - return VNextServer{ + return &VNextServer{ Destination: dest, Users: users, - } + }, nil } type VMessOutboundConfig struct { diff --git a/proxy/vmess/protocol/user/id.go b/proxy/vmess/protocol/user/id.go index f3b1fd663..9d382a067 100644 --- a/proxy/vmess/protocol/user/id.go +++ b/proxy/vmess/protocol/user/id.go @@ -3,6 +3,7 @@ package user import ( "crypto/md5" "encoding/hex" + "errors" "github.com/v2ray/v2ray-core/common/log" ) @@ -11,6 +12,10 @@ const ( IDBytesLen = 16 ) +var ( + InvalidID = errors.New("Invalid ID.") +) + // The ID of en entity, in the form of an UUID. type ID struct { String string @@ -21,7 +26,8 @@ type ID struct { func NewID(id string) (ID, error) { idBytes, err := UUIDToID(id) if err != nil { - return ID{}, log.Error("Failed to parse id %s", id) + log.Error("Failed to parse id %s", id) + return ID{}, InvalidID } md5hash := md5.New() @@ -46,7 +52,8 @@ var byteGroups = []int{8, 4, 4, 4, 12} func UUIDToID(uuid string) (v [IDBytesLen]byte, err error) { text := []byte(uuid) if len(text) < 32 { - err = log.Error("uuid: invalid UUID string: %s", text) + log.Error("uuid: invalid UUID string: %s", text) + err = InvalidID return } diff --git a/proxy/vmess/vmessin.go b/proxy/vmess/vmessin.go index 899bf990c..6ecd5565b 100644 --- a/proxy/vmess/vmessin.go +++ b/proxy/vmess/vmessin.go @@ -37,7 +37,8 @@ func (handler *VMessInboundHandler) Listen(port uint16) error { Zone: "", }) if err != nil { - return log.Error("Unable to listen tcp:%d", port) + log.Error("Unable to listen tcp port %d: %v", port, err) + return err } handler.accepting = true go handler.AcceptConnections(listener) @@ -90,7 +91,8 @@ func (handler *VMessInboundHandler) HandleConnection(connection *net.TCPConn) er responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection) if err != nil { - return log.Error("VMessIn: Failed to create encrypt writer: %v", err) + log.Error("VMessIn: Failed to create encrypt writer: %v", err) + return err } // Optimize for small response packet @@ -140,7 +142,8 @@ func (factory *VMessInboundHandlerFactory) Create(vp *core.Point, rawConfig inte for _, client := range config.AllowedClients { user, err := client.ToUser() if err != nil { - panic(log.Error("VMessIn: Failed to parse user id %s: %v", client.Id, err)) + log.Error("VMessIn: Failed to parse user id %s: %v", client.Id, err) + return nil, err } allowedClients.AddUser(user) } diff --git a/proxy/vmess/vmessout.go b/proxy/vmess/vmessout.go index b1ac7c92e..e5efc1725 100644 --- a/proxy/vmess/vmessout.go +++ b/proxy/vmess/vmessout.go @@ -29,11 +29,11 @@ type VNextServer struct { type VMessOutboundHandler struct { vPoint *core.Point - vNextList []VNextServer - vNextListUDP []VNextServer + vNextList []*VNextServer + vNextListUDP []*VNextServer } -func NewVMessOutboundHandler(vp *core.Point, vNextList, vNextListUDP []VNextServer) *VMessOutboundHandler { +func NewVMessOutboundHandler(vp *core.Point, vNextList, vNextListUDP []*VNextServer) *VMessOutboundHandler { return &VMessOutboundHandler{ vPoint: vp, vNextList: vNextList, @@ -41,7 +41,7 @@ func NewVMessOutboundHandler(vp *core.Point, vNextList, vNextListUDP []VNextServ } } -func pickVNext(serverList []VNextServer) (v2net.Destination, user.User) { +func pickVNext(serverList []*VNextServer) (v2net.Destination, user.User) { vNextLen := len(serverList) if vNextLen == 0 { panic("VMessOut: Zero vNext is configured.") @@ -201,14 +201,25 @@ type VMessOutboundHandlerFactory struct { func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, rawConfig interface{}) (core.OutboundConnectionHandler, error) { config := rawConfig.(*VMessOutboundConfig) - servers := make([]VNextServer, 0, len(config.VNextList)) - udpServers := make([]VNextServer, 0, len(config.VNextList)) + servers := make([]*VNextServer, 0, len(config.VNextList)) + udpServers := make([]*VNextServer, 0, len(config.VNextList)) for _, server := range config.VNextList { if server.HasNetwork("tcp") { - servers = append(servers, server.ToVNextServer("tcp")) + aServer, err := server.ToVNextServer("tcp") + if err == nil { + servers = append(servers, aServer) + } else { + log.Warning("Discarding the server.") + } } if server.HasNetwork("udp") { - udpServers = append(udpServers, server.ToVNextServer("udp")) + aServer, err := server.ToVNextServer("udp") + if err == nil { + udpServers = append(udpServers, aServer) + } else { + log.Warning("Discarding the server.") + } + } } return NewVMessOutboundHandler(vp, servers, udpServers), nil