Browse Source

refactor error messages

Darien Raymond 8 years ago
parent
commit
35248497d2
100 changed files with 529 additions and 349 deletions
  1. 3 0
      app/app.go
  2. 7 6
      app/dispatcher/impl/default.go
  3. 7 0
      app/dispatcher/impl/errors.generated.go
  4. 1 2
      app/dns/config.go
  5. 2 0
      app/dns/dns.go
  6. 5 0
      app/dns/errors.generated.go
  7. 7 0
      app/dns/server/errors.generated.go
  8. 4 5
      app/dns/server/nameserver.go
  9. 6 5
      app/dns/server/server.go
  10. 5 0
      app/errors.generated.go
  11. 2 5
      app/log/access.go
  12. 5 0
      app/log/errors.generated.go
  13. 3 1
      app/log/log.go
  14. 1 2
      app/proxyman/config.go
  15. 7 0
      app/proxyman/errors.generated.go
  16. 1 2
      app/proxyman/inbound/always.go
  17. 3 4
      app/proxyman/inbound/dynamic.go
  18. 7 0
      app/proxyman/inbound/errors.generated.go
  19. 5 4
      app/proxyman/inbound/inbound.go
  20. 2 3
      app/proxyman/inbound/worker.go
  21. 7 0
      app/proxyman/mux/errors.generated.go
  22. 3 4
      app/proxyman/mux/frame.go
  23. 14 13
      app/proxyman/mux/mux.go
  24. 1 2
      app/proxyman/mux/reader.go
  25. 7 0
      app/proxyman/outbound/errors.generated.go
  26. 7 7
      app/proxyman/outbound/handler.go
  27. 2 0
      app/proxyman/outbound/outbound.go
  28. 2 0
      app/proxyman/proxyman.go
  29. 3 4
      app/router/config.go
  30. 5 0
      app/router/errors.generated.go
  31. 6 5
      app/router/router.go
  32. 3 4
      app/space.go
  33. 3 0
      common/buf/buf.go
  34. 5 0
      common/buf/errors.generated.go
  35. 1 1
      common/buf/io.go
  36. 2 0
      common/common.go
  37. 5 6
      common/crypto/auth.go
  38. 2 0
      common/crypto/crypto.go
  39. 5 0
      common/crypto/errors.generated.go
  40. 0 1
      common/crypto/internal/chacha_core.generated.go
  41. 5 0
      common/errors.generated.go
  42. 1 2
      common/net/address.go
  43. 5 0
      common/net/errors.generated.go
  44. 2 0
      common/net/net.go
  45. 2 3
      common/net/port.go
  46. 5 0
      common/protocol/errors.generated.go
  47. 3 0
      common/protocol/protocol.go
  48. 5 9
      common/protocol/user.go
  49. 5 0
      common/retry/errors.generated.go
  50. 4 4
      common/retry/retry.go
  51. 2 3
      common/type.go
  52. 2 2
      common/uuid/uuid.go
  53. 2 0
      core.go
  54. 5 0
      errors.generated.go
  55. 1 2
      loader.go
  56. 5 0
      main/errors.generated.go
  57. 6 5
      main/main.go
  58. 2 0
      proxy/blackhole/blackhole.go
  59. 7 0
      proxy/blackhole/errors.generated.go
  60. 9 8
      proxy/dokodemo/dokodemo.go
  61. 7 0
      proxy/dokodemo/errors.generated.go
  62. 5 0
      proxy/errors.generated.go
  63. 7 0
      proxy/freedom/errors.generated.go
  64. 10 10
      proxy/freedom/freedom.go
  65. 2 3
      proxy/handler_cache.go
  66. 5 0
      proxy/http/errors.generated.go
  67. 3 0
      proxy/http/http.go
  68. 8 8
      proxy/http/server.go
  69. 2 0
      proxy/proxy.go
  70. 2 3
      proxy/shadowsocks/config.go
  71. 1 2
      proxy/shadowsocks/ota.go
  72. 34 35
      proxy/shadowsocks/protocol.go
  73. 15 16
      proxy/shadowsocks/server.go
  74. 5 6
      proxy/socks/client.go
  75. 7 0
      proxy/socks/errors.generated.go
  76. 26 27
      proxy/socks/protocol.go
  77. 12 13
      proxy/socks/server.go
  78. 2 0
      proxy/socks/socks.go
  79. 1 2
      proxy/vmess/account.go
  80. 1 2
      proxy/vmess/encoding/auth.go
  81. 4 5
      proxy/vmess/encoding/client.go
  82. 12 13
      proxy/vmess/encoding/commands.go
  83. 3 0
      proxy/vmess/encoding/encoding.go
  84. 7 0
      proxy/vmess/encoding/errors.generated.go
  85. 15 16
      proxy/vmess/encoding/server.go
  86. 7 0
      proxy/vmess/errors.generated.go
  87. 7 0
      proxy/vmess/inbound/errors.generated.go
  88. 10 8
      proxy/vmess/inbound/inbound.go
  89. 7 0
      proxy/vmess/outbound/errors.generated.go
  90. 10 9
      proxy/vmess/outbound/outbound.go
  91. 2 0
      proxy/vmess/vmess.go
  92. 1 1
      testing/scenarios/common.go
  93. 1 2
      tools/conf/blackhole.go
  94. 5 6
      tools/conf/common.go
  95. 3 0
      tools/conf/conf.go
  96. 5 0
      tools/conf/errors.generated.go
  97. 2 3
      tools/conf/freedom.go
  98. 6 10
      tools/conf/loader.go
  99. 16 17
      tools/conf/router.go
  100. 7 8
      tools/conf/shadowsocks.go

+ 3 - 0
app/app.go

@@ -0,0 +1,3 @@
+package app
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg app -path App

+ 7 - 6
app/dispatcher/impl/default.go

@@ -1,5 +1,7 @@
 package impl
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg impl -path App,Dispatcher,Default
+
 import (
 	"context"
 
@@ -9,7 +11,6 @@ import (
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/app/router"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/ray"
@@ -23,13 +24,13 @@ type DefaultDispatcher struct {
 func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("App", "Dispatcher", "Default")
+		return nil, newError("no space in context")
 	}
 	d := &DefaultDispatcher{}
 	space.OnInitialize(func() error {
 		d.ohm = proxyman.OutboundHandlerManagerFromSpace(space)
 		if d.ohm == nil {
-			return errors.New("OutboundHandlerManager is not found in the space").Path("App", "Dispatcher", "Default")
+			return newError("OutboundHandlerManager is not found in the space")
 		}
 		d.router = router.FromSpace(space)
 		return nil
@@ -58,13 +59,13 @@ func (v *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
 	if v.router != nil {
 		if tag, err := v.router.TakeDetour(ctx); err == nil {
 			if handler := v.ohm.GetHandler(tag); handler != nil {
-				log.Trace(errors.New("taking detour [", tag, "] for [", destination, "]").Path("App", "Dispatcher", "Default"))
+				log.Trace(newError("taking detour [", tag, "] for [", destination, "]"))
 				dispatcher = handler
 			} else {
-				log.Trace(errors.New("nonexisting tag: ", tag).AtWarning().Path("App", "Dispatcher", "Default"))
+				log.Trace(newError("nonexisting tag: ", tag).AtWarning())
 			}
 		} else {
-			log.Trace(errors.New("default route for ", destination).Path("App", "Dispatcher", "Default"))
+			log.Trace(newError("default route for ", destination))
 		}
 	}
 

+ 7 - 0
app/dispatcher/impl/errors.generated.go

@@ -0,0 +1,7 @@
+package impl
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "Dispatcher", "Default")
+}

+ 1 - 2
app/dns/config.go

@@ -4,7 +4,6 @@ import (
 	"net"
 
 	"v2ray.com/core/app/log"
-	"v2ray.com/core/common/errors"
 )
 
 func (v *Config) GetInternalHosts() map[string]net.IP {
@@ -12,7 +11,7 @@ func (v *Config) GetInternalHosts() map[string]net.IP {
 	for domain, ipOrDomain := range v.GetHosts() {
 		address := ipOrDomain.AsAddress()
 		if address.Family().IsDomain() {
-			log.Trace(errors.New("ignoring domain address in static hosts: ", address.Domain()).AtWarning().Path("App", "DNS", "Config"))
+			log.Trace(newError("ignoring domain address in static hosts: ", address.Domain()).AtWarning())
 			continue
 		}
 		hosts[domain] = address.IP()

+ 2 - 0
app/dns/dns.go

@@ -1,5 +1,7 @@
 package dns
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg dns -path App,DNS
+
 import (
 	"net"
 

+ 5 - 0
app/dns/errors.generated.go

@@ -0,0 +1,5 @@
+package dns
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App", "DNS") }

+ 7 - 0
app/dns/server/errors.generated.go

@@ -0,0 +1,7 @@
+package server
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "DNS", "Server")
+}

+ 4 - 5
app/dns/server/nameserver.go

@@ -11,7 +11,6 @@ import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/transport/internet/udp"
 )
@@ -89,7 +88,7 @@ func (v *UDPNameServer) AssignUnusedID(response chan<- *ARecord) uint16 {
 		if _, found := v.requests[id]; found {
 			continue
 		}
-		log.Trace(errors.New("add pending request id ", id).AtDebug().Path("App", "DNS", "UDPNameServer"))
+		log.Trace(newError("add pending request id ", id).AtDebug())
 		v.requests[id] = &PendingRequest{
 			expire:   time.Now().Add(time.Second * 8),
 			response: response,
@@ -105,7 +104,7 @@ func (v *UDPNameServer) HandleResponse(payload *buf.Buffer) {
 	msg := new(dns.Msg)
 	err := msg.Unpack(payload.Bytes())
 	if err != nil {
-		log.Trace(errors.New("failed to parse DNS response").Base(err).AtWarning().Path("App", "DNS", "UDPNameServer"))
+		log.Trace(newError("failed to parse DNS response").Base(err).AtWarning())
 		return
 	}
 	record := &ARecord{
@@ -113,7 +112,7 @@ func (v *UDPNameServer) HandleResponse(payload *buf.Buffer) {
 	}
 	id := msg.Id
 	ttl := DefaultTTL
-	log.Trace(errors.New("handling response for id ", id, " content: ", msg.String()).AtDebug().Path("App", "DNS", "UDPNameServer"))
+	log.Trace(newError("handling response for id ", id, " content: ", msg.String()).AtDebug())
 
 	v.Lock()
 	request, found := v.requests[id]
@@ -201,7 +200,7 @@ func (v *LocalNameServer) QueryA(domain string) <-chan *ARecord {
 
 		ips, err := net.LookupIP(domain)
 		if err != nil {
-			log.Trace(errors.New("failed to lookup IPs for domain ", domain).Path("App", "DNS", "LocalNameServer").Base(err))
+			log.Trace(newError("failed to lookup IPs for domain ", domain).Base(err))
 			return
 		}
 

+ 6 - 5
app/dns/server/server.go

@@ -1,5 +1,7 @@
 package server
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg server -path App,DNS,Server
+
 import (
 	"context"
 	"net"
@@ -12,7 +14,6 @@ import (
 	"v2ray.com/core/app/dns"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 )
 
@@ -35,7 +36,7 @@ type CacheServer struct {
 func NewCacheServer(ctx context.Context, config *dns.Config) (*CacheServer, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("App", "DNS", "CacheServer")
+		return nil, newError("no space in context")
 	}
 	server := &CacheServer{
 		records: make(map[string]*DomainRecord),
@@ -45,7 +46,7 @@ func NewCacheServer(ctx context.Context, config *dns.Config) (*CacheServer, erro
 	space.OnInitialize(func() error {
 		disp := dispatcher.FromSpace(space)
 		if disp == nil {
-			return errors.New("dispatcher is not found in the space").Path("App", "DNS", "CacheServer")
+			return newError("dispatcher is not found in the space")
 		}
 		for idx, destPB := range config.NameServers {
 			address := destPB.Address.AsAddress()
@@ -113,13 +114,13 @@ func (v *CacheServer) Get(domain string) []net.IP {
 				A: a,
 			}
 			v.Unlock()
-			log.Trace(errors.New("returning ", len(a.IPs), " IPs for domain ", domain).AtDebug().Path("App", "DNS", "CacheServer"))
+			log.Trace(newError("returning ", len(a.IPs), " IPs for domain ", domain).AtDebug())
 			return a.IPs
 		case <-time.After(QueryTimeout):
 		}
 	}
 
-	log.Trace(errors.New("returning nil for domain ", domain).AtDebug().Path("App", "DNS", "CacheServer"))
+	log.Trace(newError("returning nil for domain ", domain).AtDebug())
 	return nil
 }
 

+ 5 - 0
app/errors.generated.go

@@ -0,0 +1,5 @@
+package app
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App") }

+ 2 - 5
app/log/access.go

@@ -1,9 +1,6 @@
 package log
 
-import (
-	"v2ray.com/core/app/log/internal"
-	"v2ray.com/core/common/errors"
-)
+import "v2ray.com/core/app/log/internal"
 
 // AccessStatus is the status of an access request from clients.
 type AccessStatus string
@@ -21,7 +18,7 @@ var (
 func InitAccessLogger(file string) error {
 	logger, err := internal.NewFileLogWriter(file)
 	if err != nil {
-		return errors.New("failed to create access logger on file: ", file).Base(err).Path("App", "Log")
+		return newError("failed to create access logger on file: ", file).Base(err)
 	}
 	accessLoggerInstance = logger
 	return nil

+ 5 - 0
app/log/errors.generated.go

@@ -0,0 +1,5 @@
+package log
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App", "Log") }

+ 3 - 1
app/log/log.go

@@ -1,5 +1,7 @@
 package log
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg log -path App,Log
+
 import (
 	"context"
 
@@ -43,7 +45,7 @@ func SetLogLevel(level LogLevel) {
 func InitErrorLogger(file string) error {
 	logger, err := internal.NewFileLogWriter(file)
 	if err != nil {
-		return errors.New("failed to create error logger on file (", file, ")").Base(err).Path("App", "Log")
+		return newError("failed to create error logger on file (", file, ")").Base(err)
 	}
 	streamLoggerInstance = logger
 	return nil

+ 1 - 2
app/proxyman/config.go

@@ -3,7 +3,6 @@ package proxyman
 import (
 	"context"
 
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/proxy"
 )
 
@@ -23,7 +22,7 @@ func (s *AllocationStrategy) GetRefreshValue() uint32 {
 
 func (c *OutboundHandlerConfig) GetProxyHandler(ctx context.Context) (proxy.Outbound, error) {
 	if c == nil {
-		return nil, errors.New("OutboundHandlerConfig is nil").Path("App", "Proxyman", "Outbound", "OutboundHandlerConfig")
+		return nil, newError("OutboundHandlerConfig is nil")
 	}
 	config, err := c.ProxySettings.GetInstance()
 	if err != nil {

+ 7 - 0
app/proxyman/errors.generated.go

@@ -0,0 +1,7 @@
+package proxyman
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "Proxyman")
+}

+ 1 - 2
app/proxyman/inbound/always.go

@@ -7,7 +7,6 @@ import (
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/app/proxyman/mux"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
 )
@@ -37,7 +36,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
 	}
 	for port := pr.From; port <= pr.To; port++ {
 		if nl.HasNetwork(net.Network_TCP) {
-			log.Trace(errors.New("creating tcp worker on ", address, ":", port).AtDebug().Path("App", "Proxyman", "Inbound", "AlwaysOnInboundHandler"))
+			log.Trace(newError("creating tcp worker on ", address, ":", port).AtDebug())
 			worker := &tcpWorker{
 				address:      address,
 				port:         net.Port(port),

+ 3 - 4
app/proxyman/inbound/dynamic.go

@@ -9,7 +9,6 @@ import (
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/app/proxyman/mux"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
 )
@@ -93,7 +92,7 @@ func (h *DynamicInboundHandler) refresh() error {
 		port := h.allocatePort()
 		p, err := proxy.CreateInboundHandler(ctx, h.proxyConfig)
 		if err != nil {
-			log.Trace(errors.New("failed to create proxy instance").Base(err).Path("App", "Proxyman", "Inbound", "DynamicInboundHandler").AtWarning())
+			log.Trace(newError("failed to create proxy instance").Base(err).AtWarning())
 			continue
 		}
 		nl := p.Network()
@@ -108,7 +107,7 @@ func (h *DynamicInboundHandler) refresh() error {
 				dispatcher:   h.mux,
 			}
 			if err := worker.Start(); err != nil {
-				log.Trace(errors.New("failed to create TCP worker").Base(err).AtWarning().Path("App", "Proxyman", "Inbound", "DynamicInboundHandler"))
+				log.Trace(newError("failed to create TCP worker").Base(err).AtWarning())
 				continue
 			}
 			workers = append(workers, worker)
@@ -124,7 +123,7 @@ func (h *DynamicInboundHandler) refresh() error {
 				dispatcher:   h.mux,
 			}
 			if err := worker.Start(); err != nil {
-				log.Trace(errors.New("failed to create UDP worker").Base(err).AtWarning().Path("App", "Proxyman", "Inbound", "DynamicInboundHandler"))
+				log.Trace(newError("failed to create UDP worker").Base(err).AtWarning())
 				continue
 			}
 			workers = append(workers, worker)

+ 7 - 0
app/proxyman/inbound/errors.generated.go

@@ -0,0 +1,7 @@
+package inbound
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "Proxyman", "Inbound")
+}

+ 5 - 4
app/proxyman/inbound/inbound.go

@@ -1,11 +1,12 @@
 package inbound
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg inbound -path App,Proxyman,Inbound
+
 import (
 	"context"
 
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 )
 
 type DefaultInboundHandlerManager struct {
@@ -26,7 +27,7 @@ func (m *DefaultInboundHandlerManager) AddHandler(ctx context.Context, config *p
 	}
 	receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
 	if !ok {
-		return errors.New("not a ReceiverConfig").Path("App", "Proxyman", "Inbound", "DefaultInboundHandlerManager")
+		return newError("not a ReceiverConfig")
 	}
 	proxySettings, err := config.ProxySettings.GetInstance()
 	if err != nil {
@@ -50,7 +51,7 @@ func (m *DefaultInboundHandlerManager) AddHandler(ctx context.Context, config *p
 	}
 
 	if handler == nil {
-		return errors.New("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).Path("App", "Proxyman", "Inbound", "DefaultInboundHandlerManager")
+		return newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type)
 	}
 
 	m.handlers = append(m.handlers, handler)
@@ -63,7 +64,7 @@ func (m *DefaultInboundHandlerManager) AddHandler(ctx context.Context, config *p
 func (m *DefaultInboundHandlerManager) GetHandler(ctx context.Context, tag string) (proxyman.InboundHandler, error) {
 	handler, found := m.taggedHandlers[tag]
 	if !found {
-		return nil, errors.New("handler not found: ", tag).Path("App", "Proxyman", "Inbound", "DefaultInboundHandlerManager")
+		return nil, newError("handler not found: ", tag)
 	}
 	return handler, nil
 }

+ 2 - 3
app/proxyman/inbound/worker.go

@@ -11,7 +11,6 @@ import (
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/internet"
@@ -54,7 +53,7 @@ func (w *tcpWorker) callback(conn internet.Connection) {
 	ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.TCPDestination(w.address, w.port))
 	ctx = proxy.ContextWithSource(ctx, v2net.DestinationFromAddr(conn.RemoteAddr()))
 	if err := w.proxy.Process(ctx, v2net.Network_TCP, conn, w.dispatcher); err != nil {
-		log.Trace(errors.New("connection ends").Base(err).Path("App", "Proxyman", "Inbound", "TCPWorker"))
+		log.Trace(newError("connection ends").Base(err))
 	}
 	cancel()
 	conn.Close()
@@ -231,7 +230,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source v2net.Destination, originalDe
 			ctx = proxy.ContextWithSource(ctx, source)
 			ctx = proxy.ContextWithInboundEntryPoint(ctx, v2net.UDPDestination(w.address, w.port))
 			if err := w.proxy.Process(ctx, v2net.Network_UDP, conn, w.dispatcher); err != nil {
-				log.Trace(errors.New("connection ends").Base(err).Path("App", "Proxymann", "Inbound", "UDPWorker"))
+				log.Trace(newError("connection ends").Base(err))
 			}
 			w.removeConn(source)
 			cancel()

+ 7 - 0
app/proxyman/mux/errors.generated.go

@@ -0,0 +1,7 @@
+package mux
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "Proxyman", "Mux")
+}

+ 3 - 4
app/proxyman/mux/frame.go

@@ -2,7 +2,6 @@ package mux
 
 import (
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/serial"
 )
@@ -114,7 +113,7 @@ func (f FrameMetadata) AsSupplier() buf.Supplier {
 
 func ReadFrameFrom(b []byte) (*FrameMetadata, error) {
 	if len(b) < 4 {
-		return nil, errors.New("insufficient buffer: ", len(b)).Path("App", "Proxyman", "Mux", "Frame")
+		return nil, newError("insufficient buffer: ", len(b))
 	}
 
 	f := &FrameMetadata{
@@ -144,7 +143,7 @@ func ReadFrameFrom(b []byte) (*FrameMetadata, error) {
 			addr = net.DomainAddress(string(b[1 : 1+nDomain]))
 			b = b[nDomain+1:]
 		default:
-			return nil, errors.New("unknown address type: ", addrType).Path("App", "Proxyman", "Mux", "Frame")
+			return nil, newError("unknown address type: ", addrType)
 		}
 		switch network {
 		case TargetNetworkTCP:
@@ -152,7 +151,7 @@ func ReadFrameFrom(b []byte) (*FrameMetadata, error) {
 		case TargetNetworkUDP:
 			f.Target = net.UDPDestination(addr, port)
 		default:
-			return nil, errors.New("unknown network type: ", network).Path("App", "Proxyman", "Mux", "Frame")
+			return nil, newError("unknown network type: ", network)
 		}
 	}
 

+ 14 - 13
app/proxyman/mux/mux.go

@@ -1,5 +1,7 @@
 package mux
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg mux -path App,Proxyman,Mux
+
 import (
 	"context"
 	"sync"
@@ -9,7 +11,6 @@ import (
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/signal"
 	"v2ray.com/core/proxy"
@@ -83,7 +84,7 @@ func (m *ClientManager) Dispatch(ctx context.Context, outboundRay ray.OutboundRa
 
 	client, err := NewClient(m.proxy, m.dialer, m)
 	if err != nil {
-		return errors.New("failed to create client").Base(err).Path("App", "Proxyman", "Mux", "ClientManager")
+		return newError("failed to create client").Base(err)
 	}
 	m.clients = append(m.clients, client)
 	client.Dispatch(ctx, outboundRay)
@@ -200,16 +201,16 @@ func fetchInput(ctx context.Context, s *session, output buf.Writer) {
 	defer writer.Close()
 	defer s.closeUplink()
 
-	log.Trace(errors.New("dispatching request to ", dest).Path("Proxyman", "Mux", "Client"))
+	log.Trace(newError("dispatching request to ", dest))
 	data, _ := s.input.ReadTimeout(time.Millisecond * 500)
 	if data != nil {
 		if err := writer.Write(data); err != nil {
-			log.Trace(errors.New("failed to write first payload").Base(err).Path("Proxyman", "Mux", "Client"))
+			log.Trace(newError("failed to write first payload").Base(err))
 			return
 		}
 	}
 	if err := buf.PipeUntilEOF(signal.BackgroundTimer(), s.input, writer); err != nil {
-		log.Trace(errors.New("failed to fetch all input").Base(err).Path("Proxyman", "Mux", "Client"))
+		log.Trace(newError("failed to fetch all input").Base(err))
 	}
 }
 
@@ -287,7 +288,7 @@ func (m *Client) fetchOutput() {
 	for {
 		meta, err := reader.ReadMetadata()
 		if err != nil {
-			log.Trace(errors.New("failed to read metadata").Base(err).Path("Proxyman", "Mux", "Client"))
+			log.Trace(newError("failed to read metadata").Base(err))
 			break
 		}
 		m.access.RLock()
@@ -308,7 +309,7 @@ func (m *Client) fetchOutput() {
 		}
 
 		if err != nil {
-			log.Trace(errors.New("failed to read data").Base(err).Path("Proxyman", "Mux", "Client"))
+			log.Trace(newError("failed to read data").Base(err))
 			break
 		}
 	}
@@ -324,7 +325,7 @@ func NewServer(ctx context.Context) *Server {
 	space.OnInitialize(func() error {
 		d := dispatcher.FromSpace(space)
 		if d == nil {
-			return errors.New("no dispatcher in space").Path("Proxyman", "Mux", "Server")
+			return newError("no dispatcher in space")
 		}
 		s.dispatcher = d
 		return nil
@@ -363,7 +364,7 @@ func (w *ServerWorker) remove(id uint16) {
 func handle(ctx context.Context, s *session, output buf.Writer) {
 	writer := NewResponseWriter(s.id, output)
 	if err := buf.PipeUntilEOF(signal.BackgroundTimer(), s.input, writer); err != nil {
-		log.Trace(errors.New("session ", s.id, " ends: ").Base(err).Path("Proxyman", "Mux", "ServerWorker"))
+		log.Trace(newError("session ", s.id, " ends: ").Base(err))
 	}
 	writer.Close()
 	s.closeDownlink()
@@ -381,7 +382,7 @@ func (w *ServerWorker) run(ctx context.Context) {
 
 		meta, err := reader.ReadMetadata()
 		if err != nil {
-			log.Trace(errors.New("failed to read metadata").Base(err).Path("Proxyman", "Mux", "ServerWorker"))
+			log.Trace(newError("failed to read metadata").Base(err))
 			return
 		}
 
@@ -395,10 +396,10 @@ func (w *ServerWorker) run(ctx context.Context) {
 		}
 
 		if meta.SessionStatus == SessionStatusNew {
-			log.Trace(errors.New("received request for ", meta.Target).Path("Proxyman", "Mux", "ServerWorker"))
+			log.Trace(newError("received request for ", meta.Target))
 			inboundRay, err := w.dispatcher.Dispatch(ctx, meta.Target)
 			if err != nil {
-				log.Trace(errors.New("failed to dispatch request.").Base(err).Path("Proxymann", "Mux", "ServerWorker"))
+				log.Trace(newError("failed to dispatch request.").Base(err))
 				continue
 			}
 			s = &session{
@@ -424,7 +425,7 @@ func (w *ServerWorker) run(ctx context.Context) {
 		}
 
 		if err != nil {
-			log.Trace(errors.New("failed to read data").Base(err).Path("Proxymann", "Mux", "ServerWorker"))
+			log.Trace(newError("failed to read data").Base(err))
 			break
 		}
 	}

+ 1 - 2
app/proxyman/mux/reader.go

@@ -4,7 +4,6 @@ import (
 	"io"
 
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 )
 
@@ -30,7 +29,7 @@ func (r *Reader) ReadMetadata() (*FrameMetadata, error) {
 	}
 	metaLen := serial.BytesToUint16(b.Bytes())
 	if metaLen > 512 {
-		return nil, errors.New("invalid metalen ", metaLen).Path("App", "Proxyman", "Mux", "Reader")
+		return nil, newError("invalid metalen ", metaLen)
 	}
 	b.Clear()
 	if err := b.AppendSupplier(buf.ReadFullFrom(r.reader, int(metaLen))); err != nil {

+ 7 - 0
app/proxyman/outbound/errors.generated.go

@@ -0,0 +1,7 @@
+package outbound
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("App", "Proxyman", "Outbound")
+}

+ 7 - 7
app/proxyman/outbound/handler.go

@@ -32,12 +32,12 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
 	}
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("App", "Proxyman", "Outbound", "Handler")
+		return nil, newError("no space in context")
 	}
 	space.OnInitialize(func() error {
 		ohm := proxyman.OutboundHandlerManagerFromSpace(space)
 		if ohm == nil {
-			return errors.New("no OutboundManager in space").Path("App", "Proxyman", "Outbound", "Handler")
+			return newError("no OutboundManager in space")
 		}
 		h.outboundManager = ohm
 		return nil
@@ -52,7 +52,7 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
 		case *proxyman.SenderConfig:
 			h.senderSettings = s
 		default:
-			return nil, errors.New("settings is not SenderConfig").Path("App", "Proxyman", "Outbound", "Handler")
+			return nil, newError("settings is not SenderConfig")
 		}
 	}
 
@@ -73,13 +73,13 @@ func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
 	if h.mux != nil {
 		err := h.mux.Dispatch(ctx, outboundRay)
 		if err != nil {
-			log.Trace(errors.New("failed to process outbound traffic").Base(err).Path("App", "Proxyman", "Outbound", "Handler"))
+			log.Trace(newError("failed to process outbound traffic").Base(err))
 		}
 	} else {
 		err := h.proxy.Process(ctx, outboundRay, h)
 		// Ensure outbound ray is properly closed.
 		if err != nil && errors.Cause(err) != io.EOF {
-			log.Trace(errors.New("failed to process outbound traffic").Base(err).Path("App", "Proxyman", "Outbound", "Handler"))
+			log.Trace(newError("failed to process outbound traffic").Base(err))
 			outboundRay.OutboundOutput().CloseError()
 		} else {
 			outboundRay.OutboundOutput().Close()
@@ -95,14 +95,14 @@ func (h *Handler) Dial(ctx context.Context, dest v2net.Destination) (internet.Co
 			tag := h.senderSettings.ProxySettings.Tag
 			handler := h.outboundManager.GetHandler(tag)
 			if handler != nil {
-				log.Trace(errors.New("proxying to ", tag).AtDebug().Path("App", "Proxyman", "Outbound", "Handler"))
+				log.Trace(newError("proxying to ", tag).AtDebug())
 				ctx = proxy.ContextWithTarget(ctx, dest)
 				stream := ray.NewRay(ctx)
 				go handler.Dispatch(ctx, stream)
 				return NewConnection(stream), nil
 			}
 
-			log.Trace(errors.New("failed to get outbound handler with tag: ", tag).AtWarning().Path("App", "Proxyman", "Outbound", "Handler"))
+			log.Trace(newError("failed to get outbound handler with tag: ", tag).AtWarning())
 		}
 
 		if h.senderSettings.Via != nil {

+ 2 - 0
app/proxyman/outbound/outbound.go

@@ -1,5 +1,7 @@
 package outbound
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg outbound -path App,Proxyman,Outbound
+
 import (
 	"context"
 	"sync"

+ 2 - 0
app/proxyman/proxyman.go

@@ -1,6 +1,8 @@
 // Package proxyman defines applications for manageing inbound and outbound proxies.
 package proxyman
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg proxyman -path App,Proxyman
+
 import (
 	"context"
 

+ 3 - 4
app/router/config.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"net"
 
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 )
 
@@ -53,7 +52,7 @@ func (v *RoutingRule) BuildCondition() (Condition, error) {
 				}
 				ipv6Cond.Add(matcher)
 			default:
-				return nil, errors.New("Router: Invalid IP length.")
+				return nil, newError("Router: Invalid IP length.")
 			}
 		}
 
@@ -94,7 +93,7 @@ func (v *RoutingRule) BuildCondition() (Condition, error) {
 				}
 				ipv6Cond.Add(matcher)
 			default:
-				return nil, errors.New("Router: Invalid IP length.")
+				return nil, newError("Router: Invalid IP length.")
 			}
 		}
 
@@ -119,7 +118,7 @@ func (v *RoutingRule) BuildCondition() (Condition, error) {
 	}
 
 	if conds.Len() == 0 {
-		return nil, errors.New("Router: This rule has no effective fields.")
+		return nil, newError("Router: This rule has no effective fields.")
 	}
 
 	return conds, nil

+ 5 - 0
app/router/errors.generated.go

@@ -0,0 +1,5 @@
+package router
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App", "Router") }

+ 6 - 5
app/router/router.go

@@ -1,5 +1,7 @@
 package router
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg router -path App,Router
+
 import (
 	"context"
 
@@ -7,13 +9,12 @@ import (
 	"v2ray.com/core/app/dns"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
 )
 
 var (
-	ErrNoRuleApplicable = errors.New("No rule applicable")
+	ErrNoRuleApplicable = newError("No rule applicable")
 )
 
 type Router struct {
@@ -25,7 +26,7 @@ type Router struct {
 func NewRouter(ctx context.Context, config *Config) (*Router, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("Router: No space in context.")
+		return nil, newError("Router: No space in context.")
 	}
 	r := &Router{
 		domainStrategy: config.DomainStrategy,
@@ -44,7 +45,7 @@ func NewRouter(ctx context.Context, config *Config) (*Router, error) {
 
 		r.dnsServer = dns.FromSpace(space)
 		if r.dnsServer == nil {
-			return errors.New("Router: DNS is not found in the space.")
+			return newError("Router: DNS is not found in the space.")
 		}
 		return nil
 	})
@@ -76,7 +77,7 @@ func (v *Router) TakeDetour(ctx context.Context) (string, error) {
 	}
 
 	if v.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() {
-		log.Trace(errors.New("looking up IP for ", dest).Path("App", "Router"))
+		log.Trace(newError("looking up IP for ", dest))
 		ipDests := v.resolveIP(dest)
 		if ipDests != nil {
 			ctx = proxy.ContextWithResolveIPs(ctx, ipDests)

+ 3 - 4
app/space.go

@@ -5,7 +5,6 @@ import (
 	"reflect"
 
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 )
 
 type Application interface {
@@ -25,7 +24,7 @@ func CreateAppFromConfig(ctx context.Context, config interface{}) (Application,
 	case Application:
 		return a, nil
 	default:
-		return nil, errors.New("App: Not an application.")
+		return nil, newError("App: Not an application.")
 	}
 }
 
@@ -82,7 +81,7 @@ func (v *spaceImpl) GetApplication(appInterface interface{}) Application {
 
 func (v *spaceImpl) AddApplication(app Application) error {
 	if v == nil {
-		return errors.New("App: Nil space.")
+		return newError("App: Nil space.")
 	}
 	appType := reflect.TypeOf(app.Interface())
 	v.cache[appType] = app
@@ -113,7 +112,7 @@ const (
 func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
 	space := SpaceFromContext(ctx)
 	if space == nil {
-		return errors.New("App: No space in context.")
+		return newError("App: No space in context.")
 	}
 	application, err := CreateAppFromConfig(ctx, appConfig)
 	if err != nil {

+ 3 - 0
common/buf/buf.go

@@ -0,0 +1,3 @@
+package buf
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg buf -path Buf

+ 5 - 0
common/buf/errors.generated.go

@@ -0,0 +1,5 @@
+package buf
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Buf") }

+ 1 - 1
common/buf/io.go

@@ -14,7 +14,7 @@ type Reader interface {
 	Read() (*Buffer, error)
 }
 
-var ErrReadTimeout = errors.New("Buf: IO timeout.")
+var ErrReadTimeout = newError("Buf: IO timeout.")
 
 type TimeoutReader interface {
 	ReadTimeout(time.Duration) (*Buffer, error)

+ 2 - 0
common/common.go

@@ -2,6 +2,8 @@
 // See each sub-package for detail.
 package common
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg common -path Common
+
 // Must panics if err is not nil.
 func Must(err error) {
 	if err != nil {

+ 5 - 6
common/crypto/auth.go

@@ -8,12 +8,11 @@ import (
 
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 )
 
 var (
-	errInsufficientBuffer = errors.New("insufficient buffer")
+	errInsufficientBuffer = newError("insufficient buffer")
 )
 
 type BytesGenerator interface {
@@ -52,7 +51,7 @@ type AEADAuthenticator struct {
 func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
 	iv := v.NonceGenerator.Next()
 	if len(iv) != v.AEAD.NonceSize() {
-		return nil, errors.New("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
+		return nil, newError("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
 	}
 
 	additionalData := v.AdditionalDataGenerator.Next()
@@ -62,7 +61,7 @@ func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
 func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
 	iv := v.NonceGenerator.Next()
 	if len(iv) != v.AEAD.NonceSize() {
-		return nil, errors.New("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
+		return nil, newError("Crypto:AEADAuthenticator: Invalid nonce size: ", len(iv))
 	}
 
 	additionalData := v.AdditionalDataGenerator.Next()
@@ -128,13 +127,13 @@ func (v *AuthenticationReader) nextChunk(mask uint16) error {
 		return errInsufficientBuffer
 	}
 	if size > readerBufferSize-2 {
-		return errors.New("size too large: ", size).Path("Common", "Crypto", "AuthenticationReader")
+		return newError("size too large: ", size)
 	}
 	if size == v.auth.Overhead() {
 		return io.EOF
 	}
 	if size < v.auth.Overhead() {
-		return errors.New("invalid packet size: ", size).Path("Common", "Crypto", "AuthenticationReader")
+		return newError("invalid packet size: ", size)
 	}
 	cipherChunk := v.buffer.BytesRange(2, size+2)
 	plainChunk, err := v.auth.Open(cipherChunk[:0], cipherChunk)

+ 2 - 0
common/crypto/crypto.go

@@ -1,2 +1,4 @@
 // Package crypto provides common crypto libraries for V2Ray.
 package crypto
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg crypto -path Crypto

+ 5 - 0
common/crypto/errors.generated.go

@@ -0,0 +1,5 @@
+package crypto
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Crypto") }

+ 0 - 1
common/crypto/internal/chacha_core.generated.go

@@ -1,4 +1,3 @@
-// GENERATED CODE. DO NOT MODIFY!
 package internal
 
 import "encoding/binary"

+ 5 - 0
common/errors.generated.go

@@ -0,0 +1,5 @@
+package common
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Common") }

+ 1 - 2
common/net/address.go

@@ -4,7 +4,6 @@ import (
 	"net"
 
 	"v2ray.com/core/app/log"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/predicate"
 )
 
@@ -95,7 +94,7 @@ func IPAddress(ip []byte) Address {
 		}
 		return addr
 	default:
-		log.Trace(errors.New("Net: Invalid IP format: ", ip).AtError())
+		log.Trace(newError("Net: Invalid IP format: ", ip).AtError())
 		return nil
 	}
 }

+ 5 - 0
common/net/errors.generated.go

@@ -0,0 +1,5 @@
+package net
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Net") }

+ 2 - 0
common/net/net.go

@@ -1,2 +1,4 @@
 // Package net contains common network utilities.
 package net
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg net -path Net

+ 2 - 3
common/net/port.go

@@ -3,7 +3,6 @@ package net
 import (
 	"strconv"
 
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 )
 
@@ -20,7 +19,7 @@ func PortFromBytes(port []byte) Port {
 // @error when the integer is not positive or larger then 65535
 func PortFromInt(val uint32) (Port, error) {
 	if val > 65535 {
-		return Port(0), errors.New("Net: Invalid port range: ", val)
+		return Port(0), newError("Net: Invalid port range: ", val)
 	}
 	return Port(val), nil
 }
@@ -30,7 +29,7 @@ func PortFromInt(val uint32) (Port, error) {
 func PortFromString(s string) (Port, error) {
 	val, err := strconv.ParseUint(s, 10, 32)
 	if err != nil {
-		return Port(0), errors.New("Net: Invalid port range: ", s)
+		return Port(0), newError("Net: Invalid port range: ", s)
 	}
 	return PortFromInt(uint32(val))
 }

+ 5 - 0
common/protocol/errors.generated.go

@@ -0,0 +1,5 @@
+package protocol
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Protocol") }

+ 3 - 0
common/protocol/protocol.go

@@ -0,0 +1,3 @@
+package protocol
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg protocol -path Protocol

+ 5 - 9
common/protocol/user.go

@@ -1,15 +1,11 @@
 package protocol
 
-import (
-	"time"
-
-	"v2ray.com/core/common/errors"
-)
+import "time"
 
 var (
-	ErrAccountMissing     = errors.New("Account is not specified.")
-	ErrNonMessageType     = errors.New("Not a protobuf message.")
-	ErrUnknownAccountType = errors.New("Unknown account type.")
+	ErrAccountMissing     = newError("Account is not specified.")
+	ErrNonMessageType     = newError("Not a protobuf message.")
+	ErrUnknownAccountType = newError("Unknown account type.")
 )
 
 func (v *User) GetTypedAccount() (Account, error) {
@@ -27,7 +23,7 @@ func (v *User) GetTypedAccount() (Account, error) {
 	if account, ok := rawAccount.(Account); ok {
 		return account, nil
 	}
-	return nil, errors.New("Unknown account type: ", v.Account.Type)
+	return nil, newError("Unknown account type: ", v.Account.Type)
 }
 
 func (v *User) GetSettings() UserSettings {

+ 5 - 0
common/retry/errors.generated.go

@@ -0,0 +1,5 @@
+package retry
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Retry") }

+ 4 - 4
common/retry/retry.go

@@ -1,13 +1,13 @@
 package retry
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg retry -path Retry
+
 import (
 	"time"
-
-	"v2ray.com/core/common/errors"
 )
 
 var (
-	ErrRetryFailed = errors.New("Retry: All retry attempts failed.")
+	ErrRetryFailed = newError("Retry: All retry attempts failed.")
 )
 
 // Strategy is a way to retry on a specific function.
@@ -38,7 +38,7 @@ func (r *retryer) On(method func() error) error {
 		<-time.After(time.Duration(delay) * time.Millisecond)
 		attempt++
 	}
-	return errors.New(accumulatedError).Base(ErrRetryFailed)
+	return newError(accumulatedError).Base(ErrRetryFailed)
 }
 
 // Timed returns a retry strategy with fixed interval.

+ 2 - 3
common/type.go

@@ -2,7 +2,6 @@ package common
 
 import (
 	"context"
-	"errors"
 	"reflect"
 )
 
@@ -17,7 +16,7 @@ var (
 func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
 	configType := reflect.TypeOf(config)
 	if _, found := typeCreatorRegistry[configType]; found {
-		return errors.New("Common: " + configType.Name() + " is already registered.")
+		return newError("Common: " + configType.Name() + " is already registered.")
 	}
 	typeCreatorRegistry[configType] = configCreator
 	return nil
@@ -28,7 +27,7 @@ func CreateObject(ctx context.Context, config interface{}) (interface{}, error)
 	configType := reflect.TypeOf(config)
 	creator, found := typeCreatorRegistry[configType]
 	if !found {
-		return nil, errors.New("Common: " + configType.String() + " is not registered.")
+		return nil, newError("Common: " + configType.String() + " is not registered.")
 	}
 	return creator(ctx, config)
 }

+ 2 - 2
common/uuid/uuid.go

@@ -70,7 +70,7 @@ func New() *UUID {
 // ParseBytes converts an UUID in byte form to object.
 func ParseBytes(b []byte) (*UUID, error) {
 	if len(b) != 16 {
-		return nil, errors.New("Invalid UUID: ", b)
+		return nil, errors.New("invalid UUID: ", b)
 	}
 	uuid := new(UUID)
 	copy(uuid[:], b)
@@ -81,7 +81,7 @@ func ParseBytes(b []byte) (*UUID, error) {
 func ParseString(str string) (*UUID, error) {
 	text := []byte(str)
 	if len(text) < 32 {
-		return nil, errors.New("Invalid UUID: ", str)
+		return nil, errors.New("invalid UUID: ", str)
 	}
 
 	uuid := new(UUID)

+ 2 - 0
core.go

@@ -9,6 +9,8 @@
 // connections.
 package core
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg core -path Core
+
 import (
 	"fmt"
 

+ 5 - 0
errors.generated.go

@@ -0,0 +1,5 @@
+package core
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Core") }

+ 1 - 2
loader.go

@@ -6,7 +6,6 @@ import (
 
 	"github.com/golang/protobuf/proto"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 )
 
 // ConfigLoader is an utility to load V2Ray config from external source.
@@ -24,7 +23,7 @@ func RegisterConfigLoader(format ConfigFormat, loader ConfigLoader) error {
 func LoadConfig(format ConfigFormat, input io.Reader) (*Config, error) {
 	loader, found := configLoaderCache[format]
 	if !found {
-		return nil, errors.New("Core: ", ConfigFormat_name[int32(format)], " is not loadable.")
+		return nil, newError("Core: ", ConfigFormat_name[int32(format)], " is not loadable.")
 	}
 	return loader(input)
 }

+ 5 - 0
main/errors.generated.go

@@ -0,0 +1,5 @@
+package main
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Main") }

+ 6 - 5
main/main.go

@@ -1,5 +1,7 @@
 package main
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg main -path Main
+
 import (
 	"flag"
 	"fmt"
@@ -11,7 +13,6 @@ import (
 	"syscall"
 
 	"v2ray.com/core"
-	"v2ray.com/core/common/errors"
 
 	_ "v2ray.com/core/main/distro/all"
 )
@@ -45,7 +46,7 @@ func GetConfigFormat() core.ConfigFormat {
 
 func startV2Ray() (core.Server, error) {
 	if len(configFile) == 0 {
-		return nil, errors.New("config file is not set").Path("Core")
+		return nil, newError("config file is not set")
 	}
 	var configInput io.Reader
 	if configFile == "stdin:" {
@@ -54,19 +55,19 @@ func startV2Ray() (core.Server, error) {
 		fixedFile := os.ExpandEnv(configFile)
 		file, err := os.Open(fixedFile)
 		if err != nil {
-			return nil, errors.New("config file not readable").Path("Core").Base(err)
+			return nil, newError("config file not readable").Base(err)
 		}
 		defer file.Close()
 		configInput = file
 	}
 	config, err := core.LoadConfig(GetConfigFormat(), configInput)
 	if err != nil {
-		return nil, errors.New("failed to read config file: ", configFile).Base(err).Path("Core")
+		return nil, newError("failed to read config file: ", configFile).Base(err)
 	}
 
 	server, err := core.New(config)
 	if err != nil {
-		return nil, errors.New("failed to create initialize").Base(err).Path("Core")
+		return nil, newError("failed to create initialize").Base(err)
 	}
 
 	return server, nil

+ 2 - 0
proxy/blackhole/blackhole.go

@@ -1,6 +1,8 @@
 // Package blackhole is an outbound handler that blocks all connections.
 package blackhole
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg blackhole -path Proxy,Blackhole
+
 import (
 	"context"
 	"time"

+ 7 - 0
proxy/blackhole/errors.generated.go

@@ -0,0 +1,7 @@
+package blackhole
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "Blackhole")
+}

+ 9 - 8
proxy/dokodemo/dokodemo.go

@@ -1,5 +1,7 @@
 package dokodemo
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg dokodemo -path Proxy,Dokodemo
+
 import (
 	"context"
 	"runtime"
@@ -10,7 +12,6 @@ import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/signal"
 	"v2ray.com/core/proxy"
@@ -26,10 +27,10 @@ type DokodemoDoor struct {
 func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("Dokodemo: No space in context.")
+		return nil, newError("Dokodemo: No space in context.")
 	}
 	if config.NetworkList == nil || config.NetworkList.Size() == 0 {
-		return nil, errors.New("DokodemoDoor: No network specified.")
+		return nil, newError("DokodemoDoor: No network specified.")
 	}
 	d := &DokodemoDoor{
 		config:  config,
@@ -44,7 +45,7 @@ func (d *DokodemoDoor) Network() net.NetworkList {
 }
 
 func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error {
-	log.Trace(errors.New("Dokodemo: processing connection from: ", conn.RemoteAddr()).AtDebug())
+	log.Trace(newError("Dokodemo: processing connection from: ", conn.RemoteAddr()).AtDebug())
 	dest := net.Destination{
 		Network: network,
 		Address: d.address,
@@ -56,7 +57,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 		}
 	}
 	if !dest.IsValid() || dest.Address == nil {
-		return errors.New("unable to get destination").Path("Proxy", "Dokodemo")
+		return newError("unable to get destination")
 	}
 
 	timeout := time.Second * time.Duration(d.config.Timeout)
@@ -76,7 +77,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 		chunkReader := buf.NewReader(conn)
 
 		if err := buf.PipeUntilEOF(timer, chunkReader, inboundRay.InboundInput()); err != nil {
-			return errors.New("failed to transport request").Base(err).Path("Proxy", "Dokodemo")
+			return newError("failed to transport request").Base(err)
 		}
 
 		return nil
@@ -86,7 +87,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 		v2writer := buf.NewWriter(conn)
 
 		if err := buf.PipeUntilEOF(timer, inboundRay.InboundOutput(), v2writer); err != nil {
-			return errors.New("failed to transport response").Base(err).Path("Proxy", "Dokodemo")
+			return newError("failed to transport response").Base(err)
 		}
 		return nil
 	})
@@ -94,7 +95,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		inboundRay.InboundInput().CloseError()
 		inboundRay.InboundOutput().CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "Dokodemo")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)

+ 7 - 0
proxy/dokodemo/errors.generated.go

@@ -0,0 +1,7 @@
+package dokodemo
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "Dokodemo")
+}

+ 5 - 0
proxy/errors.generated.go

@@ -0,0 +1,5 @@
+package proxy
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Proxy") }

+ 7 - 0
proxy/freedom/errors.generated.go

@@ -0,0 +1,7 @@
+package freedom
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "Freedom")
+}

+ 10 - 10
proxy/freedom/freedom.go

@@ -1,10 +1,11 @@
 package freedom
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg freedom -path Proxy,Freedom
+
 import (
 	"context"
-	"time"
-
 	"runtime"
+	"time"
 
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dns"
@@ -12,7 +13,6 @@ import (
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/retry"
 	"v2ray.com/core/common/signal"
@@ -31,7 +31,7 @@ type Handler struct {
 func New(ctx context.Context, config *Config) (*Handler, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("Proxy", "Freedom")
+		return nil, newError("no space in context")
 	}
 	f := &Handler{
 		domainStrategy: config.DomainStrategy,
@@ -42,7 +42,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
 		if config.DomainStrategy == Config_USE_IP {
 			f.dns = dns.FromSpace(space)
 			if f.dns == nil {
-				return errors.New("DNS server is not found in the space").Path("Proxy", "Freedom")
+				return newError("DNS server is not found in the space")
 			}
 		}
 		return nil
@@ -57,7 +57,7 @@ func (v *Handler) ResolveIP(destination net.Destination) net.Destination {
 
 	ips := v.dns.Get(destination.Address.Domain())
 	if len(ips) == 0 {
-		log.Trace(errors.New("DNS returns nil answer. Keep domain as is.").Path("Proxy", "Freedom"))
+		log.Trace(newError("DNS returns nil answer. Keep domain as is."))
 		return destination
 	}
 
@@ -68,7 +68,7 @@ func (v *Handler) ResolveIP(destination net.Destination) net.Destination {
 	} else {
 		newDest = net.UDPDestination(net.IPAddress(ip), destination.Port)
 	}
-	log.Trace(errors.New("changing destination from ", destination, " to ", newDest).Path("Proxy", "Freedom"))
+	log.Trace(newError("changing destination from ", destination, " to ", newDest))
 	return newDest
 }
 
@@ -82,7 +82,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 			Port:    net.Port(server.Port),
 		}
 	}
-	log.Trace(errors.New("opening connection to ", destination).Path("Proxy", "Freedom"))
+	log.Trace(newError("opening connection to ", destination))
 
 	input := outboundRay.OutboundInput()
 	output := outboundRay.OutboundOutput()
@@ -101,7 +101,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 		return nil
 	})
 	if err != nil {
-		return errors.New("failed to open connection to ", destination).Base(err).Path("Proxy", "Freedom")
+		return newError("failed to open connection to ", destination).Base(err)
 	}
 	defer conn.Close()
 
@@ -132,7 +132,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		input.CloseError()
 		output.CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "Freedom")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)

+ 2 - 3
proxy/handler_cache.go

@@ -4,7 +4,6 @@ import (
 	"context"
 
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 )
 
 func CreateInboundHandler(ctx context.Context, config interface{}) (Inbound, error) {
@@ -16,7 +15,7 @@ func CreateInboundHandler(ctx context.Context, config interface{}) (Inbound, err
 	case Inbound:
 		return h, nil
 	default:
-		return nil, errors.New("Proxy: Not a InboundHandler.")
+		return nil, newError("Proxy: Not a InboundHandler.")
 	}
 }
 
@@ -29,6 +28,6 @@ func CreateOutboundHandler(ctx context.Context, config interface{}) (Outbound, e
 	case Outbound:
 		return h, nil
 	default:
-		return nil, errors.New("Proxy: Not a OutboundHandler.")
+		return nil, newError("Proxy: Not a OutboundHandler.")
 	}
 }

+ 5 - 0
proxy/http/errors.generated.go

@@ -0,0 +1,5 @@
+package http
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Proxy", "HTTP") }

+ 3 - 0
proxy/http/http.go

@@ -0,0 +1,3 @@
+package http
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg http -path Proxy,HTTP

+ 8 - 8
proxy/http/server.go

@@ -31,7 +31,7 @@ type Server struct {
 func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context.").Path("Proxy", "HTTP", "Server")
+		return nil, newError("no space in context.")
 	}
 	s := &Server{
 		config: config,
@@ -75,11 +75,11 @@ func (s *Server) Process(ctx context.Context, network v2net.Network, conn intern
 	request, err := http.ReadRequest(reader)
 	if err != nil {
 		if errors.Cause(err) != io.EOF {
-			log.Trace(errors.New("failed to read http request").Base(err).AtWarning().Path("Proxy", "HTTP", "Server"))
+			log.Trace(newError("failed to read http request").Base(err).AtWarning())
 		}
 		return err
 	}
-	log.Trace(errors.New("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]").Path("Proxy", "HTTP", "Server"))
+	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
 	conn.SetReadDeadline(time.Time{})
 
 	defaultPort := v2net.Port(80)
@@ -92,7 +92,7 @@ func (s *Server) Process(ctx context.Context, network v2net.Network, conn intern
 	}
 	dest, err := parseHost(host, defaultPort)
 	if err != nil {
-		return errors.New("malformed proxy host: ", host).AtWarning().Base(err).Path("Proxy", "HTTP", "Server")
+		return newError("malformed proxy host: ", host).AtWarning().Base(err)
 	}
 	log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")
 
@@ -116,7 +116,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
 		Close:         false,
 	}
 	if err := response.Write(writer); err != nil {
-		return errors.New("failed to write back OK response").Base(err).Path("Proxy", "HTTP", "Server")
+		return newError("failed to write back OK response").Base(err)
 	}
 
 	timeout := time.Second * time.Duration(s.config.Timeout)
@@ -150,7 +150,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		ray.InboundInput().CloseError()
 		ray.InboundOutput().CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "HTTP", "Server")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)
@@ -232,7 +232,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, rea
 		responseReader := bufio.NewReader(buf.ToBytesReader(ray.InboundOutput()))
 		response, err := http.ReadResponse(responseReader, request)
 		if err != nil {
-			log.Trace(errors.New("failed to read response").Base(err).AtWarning().Path("Proxy", "HTTP", "Server"))
+			log.Trace(newError("failed to read response").Base(err).AtWarning())
 			response = generateResponse(503, "Service Unavailable")
 		}
 		responseWriter := buf.NewBufferedWriter(writer)
@@ -249,7 +249,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, rea
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		input.CloseError()
 		output.CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "HTTP", "Server")
+		return newError("connection ends").Base(err)
 	}
 
 	return nil

+ 2 - 0
proxy/proxy.go

@@ -5,6 +5,8 @@
 // 2. Register a config creator through common.RegisterConfig.
 package proxy
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg proxy -path Proxy
+
 import (
 	"context"
 

+ 2 - 3
proxy/shadowsocks/config.go

@@ -6,7 +6,6 @@ import (
 	"crypto/md5"
 
 	"v2ray.com/core/common/crypto"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/protocol"
 )
 
@@ -34,14 +33,14 @@ func (v *Account) GetCipher() (Cipher, error) {
 	case CipherType_CHACHA20_IETF:
 		return &ChaCha20{IVBytes: 12}, nil
 	default:
-		return nil, errors.New("Unsupported cipher.")
+		return nil, newError("Unsupported cipher.")
 	}
 }
 
 func (v *Account) AsAccount() (protocol.Account, error) {
 	cipher, err := v.GetCipher()
 	if err != nil {
-		return nil, errors.New("failed to get cipher").Base(err).Path("Shadowsocks", "Account")
+		return nil, newError("failed to get cipher").Base(err)
 	}
 	return &ShadowsocksAccount{
 		Cipher:      cipher,

+ 1 - 2
proxy/shadowsocks/ota.go

@@ -7,7 +7,6 @@ import (
 	"io"
 
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 )
 
@@ -97,7 +96,7 @@ func (v *ChunkReader) Read() (*buf.Buffer, error) {
 	v.auth.Authenticate(payload)(actualAuthBytes)
 	if !bytes.Equal(authBytes, actualAuthBytes) {
 		buffer.Release()
-		return nil, errors.New("invalid auth").Path("Proxy", "Shadowsocks", "ChunkReader")
+		return nil, newError("invalid auth")
 	}
 	buffer.SliceFrom(AuthSize)
 

+ 34 - 35
proxy/shadowsocks/protocol.go

@@ -7,7 +7,6 @@ import (
 
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/crypto"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -25,7 +24,7 @@ const (
 func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, nil, errors.New("failed to parse account").Path("Shadowsocks", "TCP").Base(err)
+		return nil, nil, newError("failed to parse account").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -35,14 +34,14 @@ func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHea
 	ivLen := account.Cipher.IVSize()
 	err = buffer.AppendSupplier(buf.ReadFullFrom(reader, ivLen))
 	if err != nil {
-		return nil, nil, errors.New("failed to read IV").Path("Shadowsocks", "TCP").Base(err)
+		return nil, nil, newError("failed to read IV").Base(err)
 	}
 
 	iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
 
 	stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
 	if err != nil {
-		return nil, nil, errors.New("failed to initialize decoding stream").Path("Shadowsocks", "TCP").Base(err)
+		return nil, nil, newError("failed to initialize decoding stream").Base(err)
 	}
 	reader = crypto.NewCryptionReader(stream, reader)
 
@@ -56,7 +55,7 @@ func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHea
 	buffer.Clear()
 	err = buffer.AppendSupplier(buf.ReadFullFrom(reader, 1))
 	if err != nil {
-		return nil, nil, errors.New("failed to read address type").Path("Shadowsocks", "TCP").Base(err)
+		return nil, nil, newError("failed to read address type").Base(err)
 	}
 
 	addrType := (buffer.Byte(0) & 0x0F)
@@ -65,35 +64,35 @@ func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHea
 	}
 
 	if request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Disabled {
-		return nil, nil, errors.New("rejecting connection with OTA enabled, while server disables OTA").Path("Shadowsocks", "TCP")
+		return nil, nil, newError("rejecting connection with OTA enabled, while server disables OTA")
 	}
 
 	if !request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Enabled {
-		return nil, nil, errors.New("rejecting connection with OTA disabled, while server enables OTA").Path("Shadowsocks", "TCP")
+		return nil, nil, newError("rejecting connection with OTA disabled, while server enables OTA")
 	}
 
 	switch addrType {
 	case AddrTypeIPv4:
 		err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 4))
 		if err != nil {
-			return nil, nil, errors.New("failed to read IPv4 address").Path("Shadowsocks", "TCP").Base(err)
+			return nil, nil, newError("failed to read IPv4 address").Base(err)
 		}
 		request.Address = v2net.IPAddress(buffer.BytesFrom(-4))
 	case AddrTypeIPv6:
 		err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 16))
 		if err != nil {
-			return nil, nil, errors.New("failed to read IPv6 address").Path("Shadowsocks", "TCP").Base(err)
+			return nil, nil, newError("failed to read IPv6 address").Base(err)
 		}
 		request.Address = v2net.IPAddress(buffer.BytesFrom(-16))
 	case AddrTypeDomain:
 		err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 1))
 		if err != nil {
-			return nil, nil, errors.New("failed to read domain lenth.").Path("Shadowsocks", "TCP").Base(err)
+			return nil, nil, newError("failed to read domain lenth.").Base(err)
 		}
 		domainLength := int(buffer.BytesFrom(-1)[0])
 		err = buffer.AppendSupplier(buf.ReadFullFrom(reader, domainLength))
 		if err != nil {
-			return nil, nil, errors.New("failed to read domain").Path("Shadowsocks", "TCP").Base(err)
+			return nil, nil, newError("failed to read domain").Base(err)
 		}
 		request.Address = v2net.DomainAddress(string(buffer.BytesFrom(-domainLength)))
 	default:
@@ -102,7 +101,7 @@ func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHea
 
 	err = buffer.AppendSupplier(buf.ReadFullFrom(reader, 2))
 	if err != nil {
-		return nil, nil, errors.New("failed to read port").Path("Shadowsocks", "TCP").Base(err)
+		return nil, nil, newError("failed to read port").Base(err)
 	}
 	request.Port = v2net.PortFromBytes(buffer.BytesFrom(-2))
 
@@ -112,16 +111,16 @@ func ReadTCPSession(user *protocol.User, reader io.Reader) (*protocol.RequestHea
 
 		err := buffer.AppendSupplier(buf.ReadFullFrom(reader, AuthSize))
 		if err != nil {
-			return nil, nil, errors.New("Failed to read OTA").Path("Shadowsocks", "TCP").Base(err)
+			return nil, nil, newError("Failed to read OTA").Base(err)
 		}
 
 		if !bytes.Equal(actualAuth, buffer.BytesFrom(-AuthSize)) {
-			return nil, nil, errors.New("invalid OTA").Path("Shadowsocks", "TCP")
+			return nil, nil, newError("invalid OTA")
 		}
 	}
 
 	if request.Address == nil {
-		return nil, nil, errors.New("invalid remote address.").Path("Shadowsocks", "TCP")
+		return nil, nil, newError("invalid remote address.")
 	}
 
 	var chunkReader buf.Reader
@@ -138,7 +137,7 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
 	user := request.User
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("failed to parse account").Path("Shadowsocks", "TCP").Base(err)
+		return nil, newError("failed to parse account").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -146,12 +145,12 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
 	rand.Read(iv)
 	_, err = writer.Write(iv)
 	if err != nil {
-		return nil, errors.New("failed to write IV").Path("Shadowsocks", "TCP")
+		return nil, newError("failed to write IV")
 	}
 
 	stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
 	if err != nil {
-		return nil, errors.New("failed to create encoding stream").Path("Shadowsocks", "TCP").Base(err)
+		return nil, newError("failed to create encoding stream").Base(err)
 	}
 
 	writer = crypto.NewCryptionWriter(stream, writer)
@@ -169,7 +168,7 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
 		header.AppendBytes(AddrTypeDomain, byte(len(request.Address.Domain())))
 		header.Append([]byte(request.Address.Domain()))
 	default:
-		return nil, errors.New("Shadowsocks|TCP: Unsupported address type: ", request.Address.Family())
+		return nil, newError("Shadowsocks|TCP: Unsupported address type: ", request.Address.Family())
 	}
 
 	header.AppendSupplier(serial.WriteUint16(uint16(request.Port)))
@@ -183,7 +182,7 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
 
 	_, err = writer.Write(header.Bytes())
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to write header.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to write header.").Base(err)
 	}
 
 	var chunkWriter buf.Writer
@@ -199,19 +198,19 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
 func ReadTCPResponse(user *protocol.User, reader io.Reader) (buf.Reader, error) {
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to parse account.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to parse account.").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
 	iv := make([]byte, account.Cipher.IVSize())
 	_, err = io.ReadFull(reader, iv)
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to read IV.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to read IV.").Base(err)
 	}
 
 	stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to initialize decoding stream.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to initialize decoding stream.").Base(err)
 	}
 	return buf.NewReader(crypto.NewCryptionReader(stream, reader)), nil
 }
@@ -220,7 +219,7 @@ func WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (buf.Wr
 	user := request.User
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to parse account.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to parse account.").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -228,12 +227,12 @@ func WriteTCPResponse(request *protocol.RequestHeader, writer io.Writer) (buf.Wr
 	rand.Read(iv)
 	_, err = writer.Write(iv)
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to write IV.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to write IV.").Base(err)
 	}
 
 	stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to create encoding stream.").Base(err)
 	}
 
 	return buf.NewWriter(crypto.NewCryptionWriter(stream, writer)), nil
@@ -243,7 +242,7 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload *buf.Buffer) (*buf
 	user := request.User
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("Shadowsocks|UDP: Failed to parse account.").Base(err)
+		return nil, newError("Shadowsocks|UDP: Failed to parse account.").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -263,7 +262,7 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload *buf.Buffer) (*buf
 		buffer.AppendBytes(AddrTypeDomain, byte(len(request.Address.Domain())))
 		buffer.Append([]byte(request.Address.Domain()))
 	default:
-		return nil, errors.New("Shadowsocks|UDP: Unsupported address type: ", request.Address.Family())
+		return nil, newError("Shadowsocks|UDP: Unsupported address type: ", request.Address.Family())
 	}
 
 	buffer.AppendSupplier(serial.WriteUint16(uint16(request.Port)))
@@ -278,7 +277,7 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload *buf.Buffer) (*buf
 
 	stream, err := account.Cipher.NewEncodingStream(account.Key, iv)
 	if err != nil {
-		return nil, errors.New("Shadowsocks|TCP: Failed to create encoding stream.").Base(err)
+		return nil, newError("Shadowsocks|TCP: Failed to create encoding stream.").Base(err)
 	}
 
 	stream.XORKeyStream(buffer.BytesFrom(ivLen), buffer.BytesFrom(ivLen))
@@ -288,7 +287,7 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload *buf.Buffer) (*buf
 func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
 	rawAccount, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, nil, errors.New("Shadowsocks|UDP: Failed to parse account.").Base(err)
+		return nil, nil, newError("Shadowsocks|UDP: Failed to parse account.").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -298,7 +297,7 @@ func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.Reques
 
 	stream, err := account.Cipher.NewDecodingStream(account.Key, iv)
 	if err != nil {
-		return nil, nil, errors.New("Shadowsocks|UDP: Failed to initialize decoding stream.").Base(err)
+		return nil, nil, newError("Shadowsocks|UDP: Failed to initialize decoding stream.").Base(err)
 	}
 	stream.XORKeyStream(payload.Bytes(), payload.Bytes())
 
@@ -315,11 +314,11 @@ func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.Reques
 	}
 
 	if request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Disabled {
-		return nil, nil, errors.New("Shadowsocks|UDP: Rejecting packet with OTA enabled, while server disables OTA.")
+		return nil, nil, newError("Shadowsocks|UDP: Rejecting packet with OTA enabled, while server disables OTA.")
 	}
 
 	if !request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Enabled {
-		return nil, nil, errors.New("Shadowsocks|UDP: Rejecting packet with OTA disabled, while server enables OTA.")
+		return nil, nil, newError("Shadowsocks|UDP: Rejecting packet with OTA disabled, while server enables OTA.")
 	}
 
 	if request.Option.Has(RequestOptionOneTimeAuth) {
@@ -329,7 +328,7 @@ func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.Reques
 		actualAuth := make([]byte, AuthSize)
 		authenticator.Authenticate(payload.BytesTo(payloadLen))(actualAuth)
 		if !bytes.Equal(actualAuth, authBytes) {
-			return nil, nil, errors.New("Shadowsocks|UDP: Invalid OTA.")
+			return nil, nil, newError("Shadowsocks|UDP: Invalid OTA.")
 		}
 
 		payload.Slice(0, payloadLen)
@@ -349,7 +348,7 @@ func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.Reques
 		request.Address = v2net.DomainAddress(string(payload.BytesRange(1, 1+domainLength)))
 		payload.SliceFrom(1 + domainLength)
 	default:
-		return nil, nil, errors.New("Shadowsocks|UDP: Unknown address type: ", addrType)
+		return nil, nil, newError("Shadowsocks|UDP: Unknown address type: ", addrType)
 	}
 
 	request.Port = v2net.PortFromBytes(payload.BytesTo(2))

+ 15 - 16
proxy/shadowsocks/server.go

@@ -10,7 +10,6 @@ import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/signal"
@@ -29,15 +28,15 @@ type Server struct {
 func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("Proxy", "Shadowsocks", "Server")
+		return nil, newError("no space in context")
 	}
 	if config.GetUser() == nil {
-		return nil, errors.New("user is not specified").Path("Proxy", "Shadowsocks", "Server")
+		return nil, newError("user is not specified")
 	}
 
 	rawAccount, err := config.User.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("failed to get user account").Base(err).Path("Proxy", "Shadowsocks", "Server")
+		return nil, newError("failed to get user account").Base(err)
 	}
 	account := rawAccount.(*ShadowsocksAccount)
 
@@ -67,7 +66,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
 	case net.Network_UDP:
 		return s.handlerUDPPayload(ctx, conn, dispatcher)
 	default:
-		return errors.New("unknown network: ", network).Path("Proxy", "Shadowsocks", "Server")
+		return newError("unknown network: ", network)
 	}
 }
 
@@ -84,7 +83,7 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 		request, data, err := DecodeUDPPacket(v.user, payload)
 		if err != nil {
 			if source, ok := proxy.SourceFromContext(ctx); ok {
-				log.Trace(errors.New("dropping invalid UDP packet from: ", source).Base(err).Path("Proxy", "Shadowsocks", "Server"))
+				log.Trace(newError("dropping invalid UDP packet from: ", source).Base(err))
 				log.Access(source, "", log.AccessRejected, err)
 			}
 			payload.Release()
@@ -92,13 +91,13 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 		}
 
 		if request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Disabled {
-			log.Trace(errors.New("client payload enables OTA but server doesn't allow it").Path("Proxy", "Shadowsocks", "Server"))
+			log.Trace(newError("client payload enables OTA but server doesn't allow it"))
 			payload.Release()
 			continue
 		}
 
 		if !request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Enabled {
-			log.Trace(errors.New("client payload disables OTA but server forces it").Path("Proxy", "Shadowsocks", "Server"))
+			log.Trace(newError("client payload disables OTA but server forces it"))
 			payload.Release()
 			continue
 		}
@@ -107,7 +106,7 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 		if source, ok := proxy.SourceFromContext(ctx); ok {
 			log.Access(source, dest, log.AccessAccepted, "")
 		}
-		log.Trace(errors.New("tunnelling request to ", dest).Path("Proxy", "Shadowsocks", "Server"))
+		log.Trace(newError("tunnelling request to ", dest))
 
 		ctx = protocol.ContextWithUser(ctx, request.User)
 		udpServer.Dispatch(ctx, dest, data, func(payload *buf.Buffer) {
@@ -115,7 +114,7 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 
 			data, err := EncodeUDPPacket(request, payload)
 			if err != nil {
-				log.Trace(errors.New("failed to encode UDP packet").Base(err).Path("Proxy", "Shadowsocks", "Server").AtWarning())
+				log.Trace(newError("failed to encode UDP packet").Base(err).AtWarning())
 				return
 			}
 			defer data.Release()
@@ -133,7 +132,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 	request, bodyReader, err := ReadTCPSession(s.user, bufferedReader)
 	if err != nil {
 		log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
-		return errors.New("failed to create request from: ", conn.RemoteAddr()).Base(err).Path("Proxy", "Shadowsocks", "Server")
+		return newError("failed to create request from: ", conn.RemoteAddr()).Base(err)
 	}
 	conn.SetReadDeadline(time.Time{})
 
@@ -141,7 +140,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 
 	dest := request.Destination()
 	log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "")
-	log.Trace(errors.New("tunnelling request to ", dest).Path("Proxy", "Shadowsocks", "Server"))
+	log.Trace(newError("tunnelling request to ", dest))
 
 	ctx = protocol.ContextWithUser(ctx, request.User)
 
@@ -156,7 +155,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 		bufferedWriter := buf.NewBufferedWriter(conn)
 		responseWriter, err := WriteTCPResponse(request, bufferedWriter)
 		if err != nil {
-			return errors.New("failed to write response").Base(err).Path("Proxy", "Shadowsocks", "Server")
+			return newError("failed to write response").Base(err)
 		}
 
 		mergeReader := buf.NewMergingReader(ray.InboundOutput())
@@ -174,7 +173,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 		}
 
 		if err := buf.PipeUntilEOF(timer, mergeReader, responseWriter); err != nil {
-			return errors.New("failed to transport all TCP response").Base(err).Path("Proxy", "Shadowsocks", "Server")
+			return newError("failed to transport all TCP response").Base(err)
 		}
 
 		return nil
@@ -184,7 +183,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 		defer ray.InboundInput().Close()
 
 		if err := buf.PipeUntilEOF(timer, bodyReader, ray.InboundInput()); err != nil {
-			return errors.New("failed to transport all TCP request").Base(err).Path("Proxy", "Shadowsocks", "Server")
+			return newError("failed to transport all TCP request").Base(err)
 		}
 		return nil
 	})
@@ -192,7 +191,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		ray.InboundInput().CloseError()
 		ray.InboundOutput().CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "Shadowsocks", "Server")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)

+ 5 - 6
proxy/socks/client.go

@@ -7,7 +7,6 @@ import (
 
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/retry"
@@ -36,7 +35,7 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
 func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.Dialer) error {
 	destination, ok := proxy.TargetFromContext(ctx)
 	if !ok {
-		return errors.New("target not specified.").Path("Proxy", "Socks", "Client")
+		return newError("target not specified.")
 	}
 
 	var server *protocol.ServerSpec
@@ -55,7 +54,7 @@ func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.
 	})
 
 	if err != nil {
-		return errors.New("failed to find an available destination").Base(err).Path("Proxy", "Socks", "Client")
+		return newError("failed to find an available destination").Base(err)
 	}
 
 	defer conn.Close()
@@ -77,7 +76,7 @@ func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.
 
 	udpRequest, err := ClientHandshake(request, conn, conn)
 	if err != nil {
-		return errors.New("failed to establish connection to server").AtWarning().Base(err).Path("Proxy", "Socks", "Client")
+		return newError("failed to establish connection to server").AtWarning().Base(err)
 	}
 
 	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*2)
@@ -95,7 +94,7 @@ func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.
 	} else if request.Command == protocol.RequestCommandUDP {
 		udpConn, err := dialer.Dial(ctx, udpRequest.Destination())
 		if err != nil {
-			return errors.New("failed to create UDP connection").Base(err).Path("Proxy", "Socks", "Client")
+			return newError("failed to create UDP connection").Base(err)
 		}
 		defer udpConn.Close()
 		requestFunc = func() error {
@@ -111,7 +110,7 @@ func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.
 	requestDone := signal.ExecuteAsync(requestFunc)
 	responseDone := signal.ExecuteAsync(responseFunc)
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
-		return errors.New("connection ends").Base(err).Path("Proxy", "Socks", "Client")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)

+ 7 - 0
proxy/socks/errors.generated.go

@@ -0,0 +1,7 @@
+package socks
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "Socks")
+}

+ 26 - 27
proxy/socks/protocol.go

@@ -4,7 +4,6 @@ import (
 	"io"
 
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -44,13 +43,13 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 	request := new(protocol.RequestHeader)
 
 	if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {
-		return nil, errors.New("insufficient header").Base(err).Path("Socks", "Server")
+		return nil, newError("insufficient header").Base(err)
 	}
 
 	version := buffer.Byte(0)
 	if version == socks4Version {
 		if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 6)); err != nil {
-			return nil, errors.New("insufficient header").Base(err).Path("Socks", "Server")
+			return nil, newError("insufficient header").Base(err)
 		}
 		port := v2net.PortFromBytes(buffer.BytesRange(2, 4))
 		address := v2net.IPAddress(buffer.BytesRange(4, 8))
@@ -61,7 +60,7 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 		if address.IP()[0] == 0x00 {
 			domain, err := readUntilNull(reader)
 			if err != nil {
-				return nil, errors.New("failed to read domain for socks 4a").Base(err).Path("Socks", "Server")
+				return nil, newError("failed to read domain for socks 4a").Base(err)
 			}
 			address = v2net.DomainAddress(domain)
 		}
@@ -78,14 +77,14 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 			return request, nil
 		default:
 			writeSocks4Response(writer, socks4RequestRejected, v2net.AnyIP, v2net.Port(0))
-			return nil, errors.New("Socks|Server: Unsupported command: ", buffer.Byte(1))
+			return nil, newError("Socks|Server: Unsupported command: ", buffer.Byte(1))
 		}
 	}
 
 	if version == socks5Version {
 		nMethod := int(buffer.Byte(1))
 		if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, nMethod)); err != nil {
-			return nil, errors.New("failed to read auth methods").Base(err).Path("Socks", "Server")
+			return nil, newError("failed to read auth methods").Base(err)
 		}
 
 		var expectedAuth byte = authNotRequired
@@ -95,37 +94,37 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 
 		if !hasAuthMethod(expectedAuth, buffer.BytesRange(2, 2+nMethod)) {
 			writeSocks5AuthenticationResponse(writer, socks5Version, authNoMatchingMethod)
-			return nil, errors.New("no matching auth method").Path("Socks", "Server")
+			return nil, newError("no matching auth method")
 		}
 
 		if err := writeSocks5AuthenticationResponse(writer, socks5Version, expectedAuth); err != nil {
-			return nil, errors.New("failed to write auth response").Base(err).Path("Socks", "Server")
+			return nil, newError("failed to write auth response").Base(err)
 		}
 
 		if expectedAuth == authPassword {
 			username, password, err := readUsernamePassword(reader)
 			if err != nil {
-				return nil, errors.New("failed to read username and password for authentication").Base(err).Path("Socks", "Server")
+				return nil, newError("failed to read username and password for authentication").Base(err)
 			}
 
 			if !s.config.HasAccount(username, password) {
 				writeSocks5AuthenticationResponse(writer, 0x01, 0xFF)
-				return nil, errors.New("invalid username or password").Path("Socks", "Server")
+				return nil, newError("invalid username or password")
 			}
 
 			if err := writeSocks5AuthenticationResponse(writer, 0x01, 0x00); err != nil {
-				return nil, errors.New("failed to write auth response").Base(err).Path("Socks", "Server")
+				return nil, newError("failed to write auth response").Base(err)
 			}
 		}
 		buffer.Clear()
 		if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 4)); err != nil {
-			return nil, errors.New("failed to read request").Base(err).Path("Socks", "Server")
+			return nil, newError("failed to read request").Base(err)
 		}
 
 		cmd := buffer.Byte(1)
 		if cmd == cmdTCPBind || (cmd == cmdUDPPort && !s.config.UdpEnabled) {
 			writeSocks5Response(writer, statusCmdNotSupport, v2net.AnyIP, v2net.Port(0))
-			return nil, errors.New("unsupported command: ", cmd).Path("Socks", "Server")
+			return nil, newError("unsupported command: ", cmd)
 		}
 
 		switch cmd {
@@ -161,7 +160,7 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 			}
 			request.Address = v2net.ParseAddress(string(buffer.BytesFrom(-domainLength)))
 		default:
-			return nil, errors.New("Unknown address type: ", addrType).Path("Socks", "Server")
+			return nil, newError("Unknown address type: ", addrType)
 		}
 
 		if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {
@@ -186,7 +185,7 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 		return request, nil
 	}
 
-	return nil, errors.New("unknown Socks version: ", version).Path("Socks", "Server")
+	return nil, newError("unknown Socks version: ", version)
 }
 
 func readUsernamePassword(reader io.Reader) (string, string, error) {
@@ -230,7 +229,7 @@ func readUntilNull(reader io.Reader) (string, error) {
 		}
 		size++
 		if size == 256 {
-			return "", errors.New("buffer overrun").Path("Socks", "Server")
+			return "", newError("buffer overrun")
 		}
 	}
 }
@@ -284,7 +283,7 @@ func writeSocks4Response(writer io.Writer, errCode byte, address v2net.Address,
 
 func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 	if len(packet) < 5 {
-		return nil, nil, errors.New("Socks|UDP: Insufficient length of packet.")
+		return nil, nil, newError("Socks|UDP: Insufficient length of packet.")
 	}
 	request := &protocol.RequestHeader{
 		Version: socks5Version,
@@ -293,7 +292,7 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 
 	// packet[0] and packet[1] are reserved
 	if packet[2] != 0 /* fragments */ {
-		return nil, nil, errors.New("Socks|UDP: Fragmented payload.")
+		return nil, nil, newError("Socks|UDP: Fragmented payload.")
 	}
 
 	addrType := packet[3]
@@ -302,7 +301,7 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 	switch addrType {
 	case addrTypeIPv4:
 		if len(packet) < 10 {
-			return nil, nil, errors.New("Socks|UDP: Insufficient length of packet.")
+			return nil, nil, newError("Socks|UDP: Insufficient length of packet.")
 		}
 		ip := packet[4:8]
 		request.Port = v2net.PortFromBytes(packet[8:10])
@@ -310,7 +309,7 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 		dataBegin = 10
 	case addrTypeIPv6:
 		if len(packet) < 22 {
-			return nil, nil, errors.New("Socks|UDP: Insufficient length of packet.")
+			return nil, nil, newError("Socks|UDP: Insufficient length of packet.")
 		}
 		ip := packet[4:20]
 		request.Port = v2net.PortFromBytes(packet[20:22])
@@ -319,14 +318,14 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 	case addrTypeDomain:
 		domainLength := int(packet[4])
 		if len(packet) < 5+domainLength+2 {
-			return nil, nil, errors.New("Socks|UDP: Insufficient length of packet.")
+			return nil, nil, newError("Socks|UDP: Insufficient length of packet.")
 		}
 		domain := string(packet[5 : 5+domainLength])
 		request.Port = v2net.PortFromBytes(packet[5+domainLength : 5+domainLength+2])
 		request.Address = v2net.ParseAddress(domain)
 		dataBegin = 5 + domainLength + 2
 	default:
-		return nil, nil, errors.New("Socks|UDP: Unknown address type ", addrType)
+		return nil, nil, newError("Socks|UDP: Unknown address type ", addrType)
 	}
 
 	return request, packet[dataBegin:], nil
@@ -400,10 +399,10 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
 	}
 
 	if b.Byte(0) != socks5Version {
-		return nil, errors.New("Socks|Client: Unexpected server version: ", b.Byte(0)).AtWarning()
+		return nil, newError("Socks|Client: Unexpected server version: ", b.Byte(0)).AtWarning()
 	}
 	if b.Byte(1) != authByte {
-		return nil, errors.New("Socks|Client: auth method not supported.").AtWarning()
+		return nil, newError("Socks|Client: auth method not supported.").AtWarning()
 	}
 
 	if authByte == authPassword {
@@ -426,7 +425,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
 			return nil, err
 		}
 		if b.Byte(1) != 0x00 {
-			return nil, errors.New("Socks|Client: Server rejects account: ", b.Byte(1))
+			return nil, newError("Socks|Client: Server rejects account: ", b.Byte(1))
 		}
 	}
 
@@ -449,7 +448,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
 
 	resp := b.Byte(1)
 	if resp != 0x00 {
-		return nil, errors.New("Socks|Client: Server rejects request: ", resp)
+		return nil, newError("Socks|Client: Server rejects request: ", resp)
 	}
 
 	addrType := b.Byte(3)
@@ -478,7 +477,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
 		}
 		address = v2net.DomainAddress(string(b.BytesFrom(-domainLength)))
 	default:
-		return nil, errors.New("Socks|Server: Unknown address type: ", addrType)
+		return nil, newError("Socks|Server: Unknown address type: ", addrType)
 	}
 
 	if err := b.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {

+ 12 - 13
proxy/socks/server.go

@@ -11,7 +11,6 @@ import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/signal"
@@ -29,7 +28,7 @@ type Server struct {
 func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").AtWarning().Path("Proxy", "Socks", "Server")
+		return nil, newError("no space in context").AtWarning()
 	}
 	s := &Server{
 		config: config,
@@ -54,7 +53,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
 	case net.Network_UDP:
 		return s.handleUDPPayload(ctx, conn, dispatcher)
 	default:
-		return errors.New("unknown network: ", network).Path("Proxy", "Socks", "Server")
+		return newError("unknown network: ", network)
 	}
 }
 
@@ -64,7 +63,7 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
 
 	inboundDest, ok := proxy.InboundEntryPointFromContext(ctx)
 	if !ok {
-		return errors.New("inbound entry point not specified").Path("Proxy", "Socks", "Server")
+		return newError("inbound entry point not specified")
 	}
 	session := &ServerSession{
 		config: s.config,
@@ -76,14 +75,14 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
 		if source, ok := proxy.SourceFromContext(ctx); ok {
 			log.Access(source, "", log.AccessRejected, err)
 		}
-		log.Trace(errors.New("failed to read request").Base(err).Path("Proxy", "Socks", "Server"))
+		log.Trace(newError("failed to read request").Base(err))
 		return err
 	}
 	conn.SetReadDeadline(time.Time{})
 
 	if request.Command == protocol.RequestCommandTCP {
 		dest := request.Destination()
-		log.Trace(errors.New("TCP Connect request to ", dest).Path("Proxy", "Socks", "Server"))
+		log.Trace(newError("TCP Connect request to ", dest))
 		if source, ok := proxy.SourceFromContext(ctx); ok {
 			log.Access(source, dest, log.AccessAccepted, "")
 		}
@@ -127,7 +126,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
 
 		v2reader := buf.NewReader(reader)
 		if err := buf.PipeUntilEOF(timer, v2reader, input); err != nil {
-			return errors.New("failed to transport all TCP request").Base(err).Path("Proxy", "Socks", "Server")
+			return newError("failed to transport all TCP request").Base(err)
 		}
 		return nil
 	})
@@ -135,7 +134,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
 	responseDone := signal.ExecuteAsync(func() error {
 		v2writer := buf.NewWriter(writer)
 		if err := buf.PipeUntilEOF(timer, output, v2writer); err != nil {
-			return errors.New("failed to transport all TCP response").Base(err).Path("Proxy", "Socks", "Server")
+			return newError("failed to transport all TCP response").Base(err)
 		}
 		return nil
 	})
@@ -143,7 +142,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		input.CloseError()
 		output.CloseError()
-		return errors.New("connection ends").Base(err).Path("Proxy", "Socks", "Server")
+		return newError("connection ends").Base(err)
 	}
 
 	runtime.KeepAlive(timer)
@@ -155,7 +154,7 @@ func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
 	udpServer := udp.NewDispatcher(dispatcher)
 
 	if source, ok := proxy.SourceFromContext(ctx); ok {
-		log.Trace(errors.New("client UDP connection from ", source).Path("Proxy", "Socks", "Server"))
+		log.Trace(newError("client UDP connection from ", source))
 	}
 
 	reader := buf.NewReader(conn)
@@ -167,7 +166,7 @@ func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
 		request, data, err := DecodeUDPPacket(payload.Bytes())
 
 		if err != nil {
-			log.Trace(errors.New("failed to parse UDP request").Base(err).Path("Proxy", "Socks", "Server"))
+			log.Trace(newError("failed to parse UDP request").Base(err))
 			continue
 		}
 
@@ -175,7 +174,7 @@ func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
 			continue
 		}
 
-		log.Trace(errors.New("send packet to ", request.Destination(), " with ", len(data), " bytes").Path("Proxy", "Socks", "Server").AtDebug())
+		log.Trace(newError("send packet to ", request.Destination(), " with ", len(data), " bytes").AtDebug())
 		if source, ok := proxy.SourceFromContext(ctx); ok {
 			log.Access(source, request.Destination, log.AccessAccepted, "")
 		}
@@ -185,7 +184,7 @@ func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
 		udpServer.Dispatch(ctx, request.Destination(), dataBuf, func(payload *buf.Buffer) {
 			defer payload.Release()
 
-			log.Trace(errors.New("writing back UDP response with ", payload.Len(), " bytes").Path("Proxy", "Socks", "Server").AtDebug())
+			log.Trace(newError("writing back UDP response with ", payload.Len(), " bytes").AtDebug())
 
 			udpMessage := EncodeUDPPacket(request, payload.Bytes())
 			defer udpMessage.Release()

+ 2 - 0
proxy/socks/socks.go

@@ -1,2 +1,4 @@
 // Package socks provides implements of Socks protocol 4, 4a and 5.
 package socks
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg socks -path Proxy,Socks

+ 1 - 2
proxy/vmess/account.go

@@ -3,7 +3,6 @@ package vmess
 import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/uuid"
 )
@@ -33,7 +32,7 @@ func (v *InternalAccount) Equals(account protocol.Account) bool {
 func (v *Account) AsAccount() (protocol.Account, error) {
 	id, err := uuid.ParseString(v.Id)
 	if err != nil {
-		log.Trace(errors.New("failed to parse ID").Path("VMess", "Account").Base(err).AtError())
+		log.Trace(newError("failed to parse ID").Base(err).AtError())
 		return nil, err
 	}
 	protoID := protocol.NewID(id)

+ 1 - 2
proxy/vmess/encoding/auth.go

@@ -4,7 +4,6 @@ import (
 	"crypto/md5"
 	"hash/fnv"
 
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 )
 
@@ -58,7 +57,7 @@ func (v *FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []
 // Open implements AEAD.Open().
 func (v *FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
 	if serial.BytesToUint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) {
-		return dst, errors.New("invalid authentication").Path("Proxy", "VMess", "Encoding", "FnvAuthenticator")
+		return dst, newError("invalid authentication")
 	}
 	return append(dst, ciphertext[4:]...), nil
 }

+ 4 - 5
proxy/vmess/encoding/client.go

@@ -14,7 +14,6 @@ import (
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/crypto"
 	"v2ray.com/core/common/dice"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -63,7 +62,7 @@ func (v *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ
 	timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
 	account, err := header.User.GetTypedAccount()
 	if err != nil {
-		log.Trace(errors.New("failed to get user account: ", err).AtError().Path("Proxy", "VMess", "Encoding", "ClientSession"))
+		log.Trace(newError("failed to get user account: ", err).AtError())
 		return
 	}
 	idHash := v.idHash(account.(*vmess.InternalAccount).AnyValidID().Bytes())
@@ -186,12 +185,12 @@ func (v *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
 
 	_, err := io.ReadFull(v.responseReader, buffer[:4])
 	if err != nil {
-		log.Trace(errors.New("failed to read response header").Base(err).Path("Proxy", "VMess", "Encoding", "ClientSession"))
+		log.Trace(newError("failed to read response header").Base(err))
 		return nil, err
 	}
 
 	if buffer[0] != v.responseHeader {
-		return nil, errors.New("unexpected response header. Expecting ", int(v.responseHeader), " but actually ", int(buffer[0])).Path("Proxy", "VMess", "Encoding", "ClientSession")
+		return nil, newError("unexpected response header. Expecting ", int(v.responseHeader), " but actually ", int(buffer[0]))
 	}
 
 	header := &protocol.ResponseHeader{
@@ -203,7 +202,7 @@ func (v *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
 		dataLen := int(buffer[3])
 		_, err := io.ReadFull(v.responseReader, buffer[:dataLen])
 		if err != nil {
-			log.Trace(errors.New("failed to read response command").Base(err).Path("Proxy", "VMess", "Encoding", "ClientSession"))
+			log.Trace(newError("failed to read response command").Base(err))
 			return nil, err
 		}
 		data := buffer[:dataLen]

+ 12 - 13
proxy/vmess/encoding/commands.go

@@ -4,7 +4,6 @@ import (
 	"io"
 
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -12,9 +11,9 @@ import (
 )
 
 var (
-	ErrCommandTypeMismatch = errors.New("Command type mismatch.")
-	ErrUnknownCommand      = errors.New("Unknown command.")
-	ErrCommandTooLarge     = errors.New("Command too large.")
+	ErrCommandTypeMismatch = newError("Command type mismatch.")
+	ErrUnknownCommand      = newError("Unknown command.")
+	ErrCommandTooLarge     = newError("Command too large.")
 )
 
 func MarshalCommand(command interface{}, writer io.Writer) error {
@@ -53,12 +52,12 @@ func MarshalCommand(command interface{}, writer io.Writer) error {
 
 func UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error) {
 	if len(data) <= 4 {
-		return nil, errors.New("insufficient length").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length")
 	}
 	expectedAuth := Authenticate(data[4:])
 	actualAuth := serial.BytesToUint32(data[:4])
 	if expectedAuth != actualAuth {
-		return nil, errors.New("invalid auth").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("invalid auth")
 	}
 
 	var factory CommandFactory
@@ -110,38 +109,38 @@ func (v *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Wri
 func (v *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
 	cmd := new(protocol.CommandSwitchAccount)
 	if len(data) == 0 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	lenHost := int(data[0])
 	if len(data) < lenHost+1 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	if lenHost > 0 {
 		cmd.Host = net.ParseAddress(string(data[1 : 1+lenHost]))
 	}
 	portStart := 1 + lenHost
 	if len(data) < portStart+2 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	cmd.Port = net.PortFromBytes(data[portStart : portStart+2])
 	idStart := portStart + 2
 	if len(data) < idStart+16 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	cmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16])
 	alterIDStart := idStart + 16
 	if len(data) < alterIDStart+2 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	cmd.AlterIds = serial.BytesToUint16(data[alterIDStart : alterIDStart+2])
 	levelStart := alterIDStart + 2
 	if len(data) < levelStart+1 {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	cmd.Level = uint32(data[levelStart])
 	timeStart := levelStart + 1
 	if len(data) < timeStart {
-		return nil, errors.New("insufficient length.").Path("Proxy", "VMess", "Encoding", "Command")
+		return nil, newError("insufficient length.")
 	}
 	cmd.ValidMin = data[timeStart]
 	return cmd, nil

+ 3 - 0
proxy/vmess/encoding/encoding.go

@@ -0,0 +1,3 @@
+package encoding
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg encoding -path Proxy,VMess,Encoding

+ 7 - 0
proxy/vmess/encoding/errors.generated.go

@@ -0,0 +1,7 @@
+package encoding
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "VMess", "Encoding")
+}

+ 15 - 16
proxy/vmess/encoding/server.go

@@ -13,7 +13,6 @@ import (
 	"golang.org/x/crypto/chacha20poly1305"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/crypto"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -123,12 +122,12 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 
 	_, err := io.ReadFull(reader, buffer[:protocol.IDBytesLen])
 	if err != nil {
-		return nil, errors.New("failed to read request header").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("failed to read request header").Base(err)
 	}
 
 	user, timestamp, valid := v.userValidator.Get(buffer[:protocol.IDBytesLen])
 	if !valid {
-		return nil, errors.New("invalid user").Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("invalid user")
 	}
 
 	timestampHash := md5.New()
@@ -136,7 +135,7 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	iv := timestampHash.Sum(nil)
 	account, err := user.GetTypedAccount()
 	if err != nil {
-		return nil, errors.New("failed to get user account").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("failed to get user account").Base(err)
 	}
 	vmessAccount := account.(*vmess.InternalAccount)
 
@@ -145,7 +144,7 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 
 	nBytes, err := io.ReadFull(decryptor, buffer[:41])
 	if err != nil {
-		return nil, errors.New("failed to read request header").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("failed to read request header").Base(err)
 	}
 	bufferLen := nBytes
 
@@ -155,7 +154,7 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	}
 
 	if request.Version != Version {
-		return nil, errors.New("invalid protocol version ", request.Version).Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("invalid protocol version ", request.Version)
 	}
 
 	v.requestBodyIV = append([]byte(nil), buffer[1:17]...)   // 16 bytes
@@ -165,7 +164,7 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	copy(sid.key[:], v.requestBodyKey)
 	copy(sid.nonce[:], v.requestBodyIV)
 	if v.sessionHistory.has(sid) {
-		return nil, errors.New("duplicated session id, possibly under replay attack").Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("duplicated session id, possibly under replay attack")
 	}
 	v.sessionHistory.add(sid)
 
@@ -183,28 +182,28 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 		_, err = io.ReadFull(decryptor, buffer[41:45]) // 4 bytes
 		bufferLen += 4
 		if err != nil {
-			return nil, errors.New("failed to read IPv4 address").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("failed to read IPv4 address").Base(err)
 		}
 		request.Address = net.IPAddress(buffer[41:45])
 	case AddrTypeIPv6:
 		_, err = io.ReadFull(decryptor, buffer[41:57]) // 16 bytes
 		bufferLen += 16
 		if err != nil {
-			return nil, errors.New("failed to read IPv6 address").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("failed to read IPv6 address").Base(err)
 		}
 		request.Address = net.IPAddress(buffer[41:57])
 	case AddrTypeDomain:
 		_, err = io.ReadFull(decryptor, buffer[41:42])
 		if err != nil {
-			return nil, errors.New("failed to read domain address").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("failed to read domain address").Base(err)
 		}
 		domainLength := int(buffer[41])
 		if domainLength == 0 {
-			return nil, errors.New("zero length domain").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("zero length domain").Base(err)
 		}
 		_, err = io.ReadFull(decryptor, buffer[42:42+domainLength])
 		if err != nil {
-			return nil, errors.New("failed to read domain address").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("failed to read domain address").Base(err)
 		}
 		bufferLen += 1 + domainLength
 		request.Address = net.DomainAddress(string(buffer[42 : 42+domainLength]))
@@ -213,14 +212,14 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	if padingLen > 0 {
 		_, err = io.ReadFull(decryptor, buffer[bufferLen:bufferLen+padingLen])
 		if err != nil {
-			return nil, errors.New("failed to read padding").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+			return nil, newError("failed to read padding").Base(err)
 		}
 		bufferLen += padingLen
 	}
 
 	_, err = io.ReadFull(decryptor, buffer[bufferLen:bufferLen+4])
 	if err != nil {
-		return nil, errors.New("failed to read checksum").Base(err).Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("failed to read checksum").Base(err)
 	}
 
 	fnv1a := fnv.New32a()
@@ -229,11 +228,11 @@ func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	expectedHash := serial.BytesToUint32(buffer[bufferLen : bufferLen+4])
 
 	if actualHash != expectedHash {
-		return nil, errors.New("invalid auth").Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("invalid auth")
 	}
 
 	if request.Address == nil {
-		return nil, errors.New("invalid remote address").Path("Proxy", "VMess", "Encoding", "ServerSession")
+		return nil, newError("invalid remote address")
 	}
 
 	return request, nil

+ 7 - 0
proxy/vmess/errors.generated.go

@@ -0,0 +1,7 @@
+package vmess
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "VMess")
+}

+ 7 - 0
proxy/vmess/inbound/errors.generated.go

@@ -0,0 +1,7 @@
+package inbound
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "VMess", "Inbound")
+}

+ 10 - 8
proxy/vmess/inbound/inbound.go

@@ -1,5 +1,7 @@
 package inbound
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg inbound -path Proxy,VMess,Inbound
+
 import (
 	"context"
 	"io"
@@ -82,7 +84,7 @@ type Handler struct {
 func New(ctx context.Context, config *Config) (*Handler, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context").Path("Proxy", "VMess", "Inbound")
+		return nil, newError("no space in context")
 	}
 
 	allowedClients := vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash)
@@ -100,7 +102,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
 	space.OnInitialize(func() error {
 		handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space)
 		if handler.inboundHandlerManager == nil {
-			return errors.New("InboundHandlerManager is not found is space").Path("Proxy", "VMess", "Inbound")
+			return newError("InboundHandlerManager is not found is space")
 		}
 		return nil
 	})
@@ -180,12 +182,12 @@ func (v *Handler) Process(ctx context.Context, network net.Network, connection i
 	if err != nil {
 		if errors.Cause(err) != io.EOF {
 			log.Access(connection.RemoteAddr(), "", log.AccessRejected, err)
-			log.Trace(errors.New("invalid request from ", connection.RemoteAddr(), ": ", err).Path("Proxy", "VMess", "Inbound"))
+			log.Trace(newError("invalid request from ", connection.RemoteAddr(), ": ", err))
 		}
 		return err
 	}
 	log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "")
-	log.Trace(errors.New("received request for ", request.Destination()).Path("Proxy", "VMess", "Inbound"))
+	log.Trace(newError("received request for ", request.Destination()))
 
 	connection.SetReadDeadline(time.Time{})
 
@@ -220,11 +222,11 @@ func (v *Handler) Process(ctx context.Context, network net.Network, connection i
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
 		input.CloseError()
 		output.CloseError()
-		return errors.New("error during processing").Base(err).Path("Proxy", "VMess", "Inbound")
+		return newError("error during processing").Base(err)
 	}
 
 	if err := writer.Flush(); err != nil {
-		return errors.New("error during flushing remaining data").Base(err).Path("Proxy", "VMess", "Inbound")
+		return newError("error during flushing remaining data").Base(err)
 	}
 
 	runtime.KeepAlive(timer)
@@ -238,7 +240,7 @@ func (v *Handler) generateCommand(ctx context.Context, request *protocol.Request
 		if v.inboundHandlerManager != nil {
 			handler, err := v.inboundHandlerManager.GetHandler(ctx, tag)
 			if err != nil {
-				log.Trace(errors.New("failed to get detour handler: ", tag, err).AtWarning().Path("Proxy", "VMess", "Inbound"))
+				log.Trace(newError("failed to get detour handler: ", tag, err).AtWarning())
 				return nil
 			}
 			proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
@@ -248,7 +250,7 @@ func (v *Handler) generateCommand(ctx context.Context, request *protocol.Request
 					availableMin = 255
 				}
 
-				log.Trace(errors.New("pick detour handler for port ", port, " for ", availableMin, " minutes.").Path("Proxy", "VMess", "Inbound").AtDebug())
+				log.Trace(newError("pick detour handler for port ", port, " for ", availableMin, " minutes.").AtDebug())
 				user := inboundHandler.GetUser(request.User.Email)
 				if user == nil {
 					return nil

+ 7 - 0
proxy/vmess/outbound/errors.generated.go

@@ -0,0 +1,7 @@
+package outbound
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error {
+	return errors.New(values...).Path("Proxy", "VMess", "Outbound")
+}

+ 10 - 9
proxy/vmess/outbound/outbound.go

@@ -1,5 +1,7 @@
 package outbound
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg outbound -path Proxy,VMess,Outbound
+
 import (
 	"context"
 	"runtime"
@@ -9,7 +11,6 @@ import (
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/retry"
@@ -30,7 +31,7 @@ type Handler struct {
 func New(ctx context.Context, config *Config) (*Handler, error) {
 	space := app.SpaceFromContext(ctx)
 	if space == nil {
-		return nil, errors.New("no space in context.").Path("Proxy", "VMess", "Outbound")
+		return nil, newError("no space in context.")
 	}
 
 	serverList := protocol.NewServerList()
@@ -61,15 +62,15 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 		return nil
 	})
 	if err != nil {
-		return errors.New("failed to find an available destination").Base(err).AtWarning().Path("Proxy", "VMess", "Outbound")
+		return newError("failed to find an available destination").Base(err).AtWarning()
 	}
 	defer conn.Close()
 
 	target, ok := proxy.TargetFromContext(ctx)
 	if !ok {
-		return errors.New("target not specified").Path("Proxy", "VMess", "Outbound").AtError()
+		return newError("target not specified").AtError()
 	}
-	log.Trace(errors.New("tunneling request to ", target, " via ", rec.Destination()).Path("Proxy", "VMess", "Outbound"))
+	log.Trace(newError("tunneling request to ", target, " via ", rec.Destination()))
 
 	command := protocol.RequestCommandTCP
 	if target.Network == net.Network_UDP {
@@ -86,7 +87,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 
 	rawAccount, err := request.User.GetTypedAccount()
 	if err != nil {
-		return errors.New("failed to get user account").Base(err).AtWarning().Path("Proxy", "VMess", "Outbound")
+		return newError("failed to get user account").Base(err).AtWarning()
 	}
 	account := rawAccount.(*vmess.InternalAccount)
 	request.Security = account.Security
@@ -109,11 +110,11 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 		bodyWriter := session.EncodeRequestBody(request, writer)
 		firstPayload, err := input.ReadTimeout(time.Millisecond * 500)
 		if err != nil && err != buf.ErrReadTimeout {
-			return errors.New("failed to get first payload").Base(err).Path("Proxy", "VMess", "Outbound")
+			return newError("failed to get first payload").Base(err)
 		}
 		if !firstPayload.IsEmpty() {
 			if err := bodyWriter.Write(firstPayload); err != nil {
-				return errors.New("failed to write first payload").Base(err).Path("Proxy", "VMess", "Outbound")
+				return newError("failed to write first payload").Base(err)
 			}
 			firstPayload.Release()
 		}
@@ -159,7 +160,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 	})
 
 	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
-		return errors.New("connection ends").Base(err).Path("Proxy", "VMess", "Outbound")
+		return newError("connection ends").Base(err)
 	}
 	runtime.KeepAlive(timer)
 

+ 2 - 0
proxy/vmess/vmess.go

@@ -5,6 +5,8 @@
 // clients with 'socks' for proxying.
 package vmess
 
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg vmess -path Proxy,VMess
+
 import (
 	"context"
 	"sync"

+ 1 - 1
testing/scenarios/common.go

@@ -1,6 +1,7 @@
 package scenarios
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -16,7 +17,6 @@ import (
 	"v2ray.com/core"
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/retry"
 )

+ 1 - 2
tools/conf/blackhole.go

@@ -3,7 +3,6 @@ package conf
 import (
 	"encoding/json"
 
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy/blackhole"
 )
@@ -29,7 +28,7 @@ func (v *BlackholeConfig) Build() (*serial.TypedMessage, error) {
 	if v.Response != nil {
 		response, _, err := configLoader.Load(v.Response)
 		if err != nil {
-			return nil, errors.New("Config: Failed to parse Blackhole response config.").Base(err)
+			return nil, newError("Config: Failed to parse Blackhole response config.").Base(err)
 		}
 		responseSettings, err := response.(Buildable).Build()
 		if err != nil {

+ 5 - 6
tools/conf/common.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"strings"
 
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 )
@@ -33,7 +32,7 @@ func (v *StringList) UnmarshalJSON(data []byte) error {
 		*v = *NewStringList(strlist)
 		return nil
 	}
-	return errors.New("Config: Unknown format of a string list: " + string(data))
+	return newError("Config: Unknown format of a string list: " + string(data))
 }
 
 type Address struct {
@@ -80,7 +79,7 @@ func (v *NetworkList) UnmarshalJSON(data []byte) error {
 		*v = nl
 		return nil
 	}
-	return errors.New("Config: Unknown format of a string list: " + string(data))
+	return newError("Config: Unknown format of a string list: " + string(data))
 }
 
 func (v *NetworkList) Build() *v2net.NetworkList {
@@ -114,7 +113,7 @@ func parseStringPort(data []byte) (v2net.Port, v2net.Port, error) {
 	}
 	pair := strings.SplitN(s, "-", 2)
 	if len(pair) == 0 {
-		return v2net.Port(0), v2net.Port(0), errors.New("Config: Invalid port range: ", s)
+		return v2net.Port(0), v2net.Port(0), newError("Config: Invalid port range: ", s)
 	}
 	if len(pair) == 1 {
 		port, err := v2net.PortFromString(pair[0])
@@ -158,12 +157,12 @@ func (v *PortRange) UnmarshalJSON(data []byte) error {
 		v.From = uint32(from)
 		v.To = uint32(to)
 		if v.From > v.To {
-			return errors.New("Config: Invalid port range ", v.From, " -> ", v.To)
+			return newError("Config: Invalid port range ", v.From, " -> ", v.To)
 		}
 		return nil
 	}
 
-	return errors.New("Config: Invalid port range: ", string(data))
+	return newError("Config: Invalid port range: ", string(data))
 }
 
 type User struct {

+ 3 - 0
tools/conf/conf.go

@@ -0,0 +1,3 @@
+package conf
+
+//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg conf -path Tools,Conf

+ 5 - 0
tools/conf/errors.generated.go

@@ -0,0 +1,5 @@
+package conf
+
+import "v2ray.com/core/common/errors"
+
+func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("Tools", "Conf") }

+ 2 - 3
tools/conf/freedom.go

@@ -4,7 +4,6 @@ import (
 	"net"
 	"strings"
 
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
@@ -31,11 +30,11 @@ func (v *FreedomConfig) Build() (*serial.TypedMessage, error) {
 	if len(v.Redirect) > 0 {
 		host, portStr, err := net.SplitHostPort(v.Redirect)
 		if err != nil {
-			return nil, errors.New("Config: Invalid redirect address: ", v.Redirect, ": ", err).Base(err)
+			return nil, newError("Config: Invalid redirect address: ", v.Redirect, ": ", err).Base(err)
 		}
 		port, err := v2net.PortFromString(portStr)
 		if err != nil {
-			return nil, errors.New("Config: Invalid redirect port: ", v.Redirect, ": ", err).Base(err)
+			return nil, newError("Config: Invalid redirect port: ", v.Redirect, ": ", err).Base(err)
 		}
 		if len(host) == 0 {
 			host = "127.0.0.1"

+ 6 - 10
tools/conf/loader.go

@@ -1,10 +1,6 @@
 package conf
 
-import (
-	"encoding/json"
-
-	"v2ray.com/core/common/errors"
-)
+import "encoding/json"
 
 type ConfigCreator func() interface{}
 
@@ -12,7 +8,7 @@ type ConfigCreatorCache map[string]ConfigCreator
 
 func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
 	if _, found := v[id]; found {
-		return errors.New("Config: ", id, " already registered.")
+		return newError("Config: ", id, " already registered.")
 	}
 
 	v[id] = creator
@@ -22,7 +18,7 @@ func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) er
 func (v ConfigCreatorCache) CreateConfig(id string) (interface{}, error) {
 	creator, found := v[id]
 	if !found {
-		return nil, errors.New("Config: Unknown config id: ", id)
+		return nil, newError("Config: Unknown config id: ", id)
 	}
 	return creator(), nil
 }
@@ -44,7 +40,7 @@ func NewJSONConfigLoader(cache ConfigCreatorCache, idKey string, configKey strin
 func (v *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) {
 	creator, found := v.cache[id]
 	if !found {
-		return nil, errors.New("Config: Unknown config id: ", id)
+		return nil, newError("Config: Unknown config id: ", id)
 	}
 
 	config := creator()
@@ -61,7 +57,7 @@ func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
 	}
 	rawID, found := obj[v.idKey]
 	if !found {
-		return nil, "", errors.New("Config: ", v.idKey, " not found in JSON context.")
+		return nil, "", newError("Config: ", v.idKey, " not found in JSON context.")
 	}
 	var id string
 	if err := json.Unmarshal(rawID, &id); err != nil {
@@ -71,7 +67,7 @@ func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
 	if len(v.configKey) > 0 {
 		configValue, found := obj[v.configKey]
 		if !found {
-			return nil, "", errors.New("Config: ", v.configKey, " not found in JSON content.")
+			return nil, "", newError("Config: ", v.configKey, " not found in JSON content.")
 		}
 		rawConfig = configValue
 	}

+ 16 - 17
tools/conf/router.go

@@ -7,7 +7,6 @@ import (
 
 	"v2ray.com/core/app/log"
 	"v2ray.com/core/app/router"
-	"v2ray.com/core/common/errors"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/tools/geoip"
 
@@ -25,7 +24,7 @@ type RouterConfig struct {
 
 func (v *RouterConfig) Build() (*router.Config, error) {
 	if v.Settings == nil {
-		return nil, errors.New("Config: Router settings is not specified.")
+		return nil, newError("Config: Router settings is not specified.")
 	}
 	config := new(router.Config)
 
@@ -69,12 +68,12 @@ func parseIP(s string) (*router.CIDR, error) {
 		if len(mask) > 0 {
 			bits64, err := strconv.ParseUint(mask, 10, 32)
 			if err != nil {
-				return nil, errors.New("Config: invalid network mask for router: ", mask).Base(err)
+				return nil, newError("Config: invalid network mask for router: ", mask).Base(err)
 			}
 			bits = uint32(bits64)
 		}
 		if bits > 32 {
-			return nil, errors.New("Config: invalid network mask for router: ", bits)
+			return nil, newError("Config: invalid network mask for router: ", bits)
 		}
 		return &router.CIDR{
 			Ip:     []byte(ip.IP()),
@@ -85,19 +84,19 @@ func parseIP(s string) (*router.CIDR, error) {
 		if len(mask) > 0 {
 			bits64, err := strconv.ParseUint(mask, 10, 32)
 			if err != nil {
-				return nil, errors.New("Config: invalid network mask for router: ", mask).Base(err)
+				return nil, newError("Config: invalid network mask for router: ", mask).Base(err)
 			}
 			bits = uint32(bits64)
 		}
 		if bits > 128 {
-			return nil, errors.New("Config: invalid network mask for router: ", bits)
+			return nil, newError("Config: invalid network mask for router: ", bits)
 		}
 		return &router.CIDR{
 			Ip:     []byte(ip.IP()),
 			Prefix: bits,
 		}, nil
 	default:
-		return nil, errors.New("Config: unsupported address for router: ", s)
+		return nil, newError("Config: unsupported address for router: ", s)
 	}
 }
 
@@ -139,7 +138,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
 		for _, ip := range *rawFieldRule.IP {
 			ipRule, err := parseIP(ip)
 			if err != nil {
-				return nil, errors.New("Config: invalid IP: ", ip).Base(err)
+				return nil, newError("Config: invalid IP: ", ip).Base(err)
 			}
 			rule.Cidr = append(rule.Cidr, ipRule)
 		}
@@ -157,7 +156,7 @@ func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
 		for _, ip := range *rawFieldRule.SourceIP {
 			ipRule, err := parseIP(ip)
 			if err != nil {
-				return nil, errors.New("Config: invalid IP: ", ip).Base(err)
+				return nil, newError("Config: invalid IP: ", ip).Base(err)
 			}
 			rule.SourceCidr = append(rule.SourceCidr, ipRule)
 		}
@@ -182,41 +181,41 @@ func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
 	rawRule := new(RouterRule)
 	err := json.Unmarshal(msg, rawRule)
 	if err != nil {
-		return nil, errors.New("Config: Invalid router rule.").Base(err)
+		return nil, newError("Config: Invalid router rule.").Base(err)
 	}
 	if rawRule.Type == "field" {
 		fieldrule, err := parseFieldRule(msg)
 		if err != nil {
-			return nil, errors.New("Config: Invalid field rule.").Base(err)
+			return nil, newError("Config: Invalid field rule.").Base(err)
 		}
 		return fieldrule, nil
 	}
 	if rawRule.Type == "chinaip" {
 		chinaiprule, err := parseChinaIPRule(msg)
 		if err != nil {
-			return nil, errors.New("Config: Invalid chinaip rule.").Base(err)
+			return nil, newError("Config: Invalid chinaip rule.").Base(err)
 		}
 		return chinaiprule, nil
 	}
 	if rawRule.Type == "chinasites" {
 		chinasitesrule, err := parseChinaSitesRule(msg)
 		if err != nil {
-			return nil, errors.New("Config: Invalid chinasites rule.").Base(err)
+			return nil, newError("Config: Invalid chinasites rule.").Base(err)
 		}
 		return chinasitesrule, nil
 	}
-	return nil, errors.New("Config: Unknown router rule type: ", rawRule.Type)
+	return nil, newError("Config: Unknown router rule type: ", rawRule.Type)
 }
 
 func parseChinaIPRule(data []byte) (*router.RoutingRule, error) {
 	rawRule := new(RouterRule)
 	err := json.Unmarshal(data, rawRule)
 	if err != nil {
-		return nil, errors.New("Config: Invalid router rule.").Base(err)
+		return nil, newError("Config: Invalid router rule.").Base(err)
 	}
 	var chinaIPs geoip.CountryIPRange
 	if err := proto.Unmarshal(geoip.ChinaIPs, &chinaIPs); err != nil {
-		return nil, errors.New("Config: Invalid china ips.").Base(err)
+		return nil, newError("Config: Invalid china ips.").Base(err)
 	}
 	return &router.RoutingRule{
 		Tag:  rawRule.OutboundTag,
@@ -228,7 +227,7 @@ func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {
 	rawRule := new(RouterRule)
 	err := json.Unmarshal(data, rawRule)
 	if err != nil {
-		log.Trace(errors.New("Router: Invalid router rule: ", err).AtError())
+		log.Trace(newError("Router: Invalid router rule: ", err).AtError())
 		return nil, err
 	}
 	return &router.RoutingRule{

+ 7 - 8
tools/conf/shadowsocks.go

@@ -3,7 +3,6 @@ package conf
 import (
 	"strings"
 
-	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy/shadowsocks"
@@ -23,7 +22,7 @@ func (v *ShadowsocksServerConfig) Build() (*serial.TypedMessage, error) {
 	config.UdpEnabled = v.UDP
 
 	if len(v.Password) == 0 {
-		return nil, errors.New("Shadowsocks password is not specified.")
+		return nil, newError("Shadowsocks password is not specified.")
 	}
 	account := &shadowsocks.Account{
 		Password: v.Password,
@@ -47,7 +46,7 @@ func (v *ShadowsocksServerConfig) Build() (*serial.TypedMessage, error) {
 	case "chacha20-ietf":
 		account.CipherType = shadowsocks.CipherType_CHACHA20_IETF
 	default:
-		return nil, errors.New("Unknown cipher method: " + cipher)
+		return nil, newError("Unknown cipher method: " + cipher)
 	}
 
 	config.User = &protocol.User{
@@ -76,19 +75,19 @@ func (v *ShadowsocksClientConfig) Build() (*serial.TypedMessage, error) {
 	config := new(shadowsocks.ClientConfig)
 
 	if len(v.Servers) == 0 {
-		return nil, errors.New("0 Shadowsocks server configured.")
+		return nil, newError("0 Shadowsocks server configured.")
 	}
 
 	serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))
 	for idx, server := range v.Servers {
 		if server.Address == nil {
-			return nil, errors.New("Shadowsocks server address is not set.")
+			return nil, newError("Shadowsocks server address is not set.")
 		}
 		if server.Port == 0 {
-			return nil, errors.New("Invalid Shadowsocks port.")
+			return nil, newError("Invalid Shadowsocks port.")
 		}
 		if len(server.Password) == 0 {
-			return nil, errors.New("Shadowsocks password is not specified.")
+			return nil, newError("Shadowsocks password is not specified.")
 		}
 		account := &shadowsocks.Account{
 			Password: server.Password,
@@ -108,7 +107,7 @@ func (v *ShadowsocksClientConfig) Build() (*serial.TypedMessage, error) {
 		case "chacha20-ietf":
 			account.CipherType = shadowsocks.CipherType_CHACHA20_IETF
 		default:
-			return nil, errors.New("Unknown cipher method: " + cipher)
+			return nil, newError("Unknown cipher method: " + cipher)
 		}
 
 		ss := &protocol.ServerEndpoint{

Some files were not shown because too many files changed in this diff