Refactor log

This commit is contained in:
世界 2022-07-12 15:17:29 +08:00
parent b47f3adbb3
commit 4fc763cfa2
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
46 changed files with 760 additions and 457 deletions

View file

@ -4,7 +4,7 @@ PROJECTS=$(dirname "$0")/../..
go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD) go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD)
go get -x github.com/sagernet/sing-dns@$(git -C $PROJECTS/sing-dns rev-parse HEAD) go get -x github.com/sagernet/sing-dns@$(git -C $PROJECTS/sing-dns rev-parse HEAD)
go get -x github.com/sagernet/sing-tun@$(git -C $PROJECTS/sing-dns rev-parse HEAD) go get -x github.com/sagernet/sing-tun@$(git -C $PROJECTS/sing-tun rev-parse HEAD)
go get -x github.com/sagernet/sing-shadowsocks@$(git -C $PROJECTS/sing-shadowsocks rev-parse HEAD) go get -x github.com/sagernet/sing-shadowsocks@$(git -C $PROJECTS/sing-shadowsocks rev-parse HEAD)
go mod tidy go mod tidy
pushd test pushd test

84
box.go
View file

@ -2,6 +2,8 @@ package box
import ( import (
"context" "context"
"io"
"os"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -18,20 +20,54 @@ import (
var _ adapter.Service = (*Box)(nil) var _ adapter.Service = (*Box)(nil)
type Box struct { type Box struct {
createdAt time.Time
router adapter.Router router adapter.Router
logger log.Logger
inbounds []adapter.Inbound inbounds []adapter.Inbound
outbounds []adapter.Outbound outbounds []adapter.Outbound
createdAt time.Time logFactory log.Factory
logger log.ContextLogger
logFile *os.File
} }
func New(ctx context.Context, options option.Options) (*Box, error) { func New(ctx context.Context, options option.Options) (*Box, error) {
createdAt := time.Now() createdAt := time.Now()
logger, err := log.NewLogger(common.PtrValueOrDefault(options.Log)) logOptions := common.PtrValueOrDefault(options.Log)
var logFactory log.Factory
var logFile *os.File
if logOptions.Disabled {
logFactory = log.NewNOPFactory()
} else {
var logWriter io.Writer
switch logOptions.Output {
case "", "stderr":
logWriter = os.Stderr
case "stdout":
logWriter = os.Stdout
default:
var err error
logFile, err = os.OpenFile(logOptions.Output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil { if err != nil {
return nil, E.Cause(err, "parse log options") return nil, err
} }
router, err := route.NewRouter(ctx, logger, common.PtrValueOrDefault(options.Route), common.PtrValueOrDefault(options.DNS)) }
logFormatter := log.Formatter{
BaseTime: createdAt,
DisableColors: logOptions.DisableColor || logFile != nil,
DisableTimestamp: !logOptions.Timestamp && logFile != nil,
FullTimestamp: logOptions.Timestamp,
TimestampFormat: "-0700 2006-01-02 15:04:05",
}
logFactory = log.NewFactory(logFormatter, logWriter)
}
router, err := route.NewRouter(
ctx,
logFactory.NewLogger("router"),
logFactory.NewLogger("dns"),
common.PtrValueOrDefault(options.Route),
common.PtrValueOrDefault(options.DNS),
)
if err != nil { if err != nil {
return nil, E.Cause(err, "parse route options") return nil, E.Cause(err, "parse route options")
} }
@ -39,7 +75,18 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
outbounds := make([]adapter.Outbound, 0, len(options.Outbounds)) outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
for i, inboundOptions := range options.Inbounds { for i, inboundOptions := range options.Inbounds {
var in adapter.Inbound var in adapter.Inbound
in, err = inbound.New(ctx, router, logger, i, inboundOptions) var tag string
if inboundOptions.Tag != "" {
tag = inboundOptions.Tag
} else {
tag = F.ToString(i)
}
in, err = inbound.New(
ctx,
router,
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
inboundOptions,
)
if err != nil { if err != nil {
return nil, E.Cause(err, "parse inbound[", i, "]") return nil, E.Cause(err, "parse inbound[", i, "]")
} }
@ -47,14 +94,23 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
} }
for i, outboundOptions := range options.Outbounds { for i, outboundOptions := range options.Outbounds {
var out adapter.Outbound var out adapter.Outbound
out, err = outbound.New(router, logger, i, outboundOptions) var tag string
if outboundOptions.Tag != "" {
tag = outboundOptions.Tag
} else {
tag = F.ToString(i)
}
out, err = outbound.New(
router,
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
outboundOptions)
if err != nil { if err != nil {
return nil, E.Cause(err, "parse outbound[", i, "]") return nil, E.Cause(err, "parse outbound[", i, "]")
} }
outbounds = append(outbounds, out) outbounds = append(outbounds, out)
} }
err = router.Initialize(outbounds, func() adapter.Outbound { err = router.Initialize(outbounds, func() adapter.Outbound {
out, oErr := outbound.New(router, logger, 0, option.Outbound{Type: "direct", Tag: "default"}) out, oErr := outbound.New(router, logFactory.NewLogger("outbound/direct"), option.Outbound{Type: "direct", Tag: "default"})
common.Must(oErr) common.Must(oErr)
outbounds = append(outbounds, out) outbounds = append(outbounds, out)
return out return out
@ -64,19 +120,17 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
} }
return &Box{ return &Box{
router: router, router: router,
logger: logger,
inbounds: inbounds, inbounds: inbounds,
outbounds: outbounds, outbounds: outbounds,
createdAt: createdAt, createdAt: createdAt,
logFactory: logFactory,
logger: logFactory.NewLogger(""),
logFile: logFile,
}, nil }, nil
} }
func (s *Box) Start() error { func (s *Box) Start() error {
err := s.logger.Start() err := s.router.Start()
if err != nil {
return err
}
err = s.router.Start()
if err != nil { if err != nil {
return err return err
} }
@ -99,6 +153,6 @@ func (s *Box) Close() error {
} }
return common.Close( return common.Close(
s.router, s.router,
s.logger, common.PtrOrNil(s.logFile),
) )
} }

View file

@ -5,10 +5,10 @@ import (
"os" "os"
"github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -21,17 +21,17 @@ var commandCheck = &cobra.Command{
func checkConfiguration(cmd *cobra.Command, args []string) { func checkConfiguration(cmd *cobra.Command, args []string) {
configContent, err := os.ReadFile(configPath) configContent, err := os.ReadFile(configPath)
if err != nil { if err != nil {
logrus.Fatal("read config: ", err) log.Fatal("read config: ", err)
} }
var options option.Options var options option.Options
err = json.Unmarshal(configContent, &options) err = json.Unmarshal(configContent, &options)
if err != nil { if err != nil {
logrus.Fatal("decode config: ", err) log.Fatal("decode config: ", err)
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
_, err = box.New(ctx, options) _, err = box.New(ctx, options)
if err != nil { if err != nil {
logrus.Fatal("create service: ", err) log.Fatal("create service: ", err)
} }
cancel() cancel()
} }

View file

@ -5,10 +5,10 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -27,19 +27,19 @@ func init() {
func formatConfiguration(cmd *cobra.Command, args []string) { func formatConfiguration(cmd *cobra.Command, args []string) {
configContent, err := os.ReadFile(configPath) configContent, err := os.ReadFile(configPath)
if err != nil { if err != nil {
logrus.Fatal("read config: ", err) log.Fatal("read config: ", err)
} }
var options option.Options var options option.Options
err = json.Unmarshal(configContent, &options) err = json.Unmarshal(configContent, &options)
if err != nil { if err != nil {
logrus.Fatal("decode config: ", err) log.Fatal("decode config: ", err)
} }
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer) encoder := json.NewEncoder(buffer)
encoder.SetIndent("", " ") encoder.SetIndent("", " ")
err = encoder.Encode(options) err = encoder.Encode(options)
if err != nil { if err != nil {
logrus.Fatal("encode config: ", err) log.Fatal("encode config: ", err)
} }
if !commandFormatFlagWrite { if !commandFormatFlagWrite {
os.Stdout.WriteString(buffer.String() + "\n") os.Stdout.WriteString(buffer.String() + "\n")
@ -50,12 +50,12 @@ func formatConfiguration(cmd *cobra.Command, args []string) {
} }
output, err := os.Create(configPath) output, err := os.Create(configPath)
if err != nil { if err != nil {
logrus.Fatal("open output: ", err) log.Fatal("open output: ", err)
} }
_, err = output.Write(buffer.Bytes()) _, err = output.Write(buffer.Bytes())
output.Close() output.Close()
if err != nil { if err != nil {
logrus.Fatal("write output: ", err) log.Fatal("write output: ", err)
} }
outputPath, _ := filepath.Abs(configPath) outputPath, _ := filepath.Abs(configPath)
os.Stderr.WriteString(outputPath + "\n") os.Stderr.WriteString(outputPath + "\n")

View file

@ -7,10 +7,10 @@ import (
"syscall" "syscall"
"github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -23,12 +23,12 @@ var commandRun = &cobra.Command{
func run(cmd *cobra.Command, args []string) { func run(cmd *cobra.Command, args []string) {
configContent, err := os.ReadFile(configPath) configContent, err := os.ReadFile(configPath)
if err != nil { if err != nil {
logrus.Fatal("read config: ", err) log.Fatal("read config: ", err)
} }
var options option.Options var options option.Options
err = json.Unmarshal(configContent, &options) err = json.Unmarshal(configContent, &options)
if err != nil { if err != nil {
logrus.Fatal("decode config: ", err) log.Fatal("decode config: ", err)
} }
if disableColor { if disableColor {
if options.Log == nil { if options.Log == nil {
@ -39,11 +39,11 @@ func run(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
instance, err := box.New(ctx, options) instance, err := box.New(ctx, options)
if err != nil { if err != nil {
logrus.Fatal("create service: ", err) log.Fatal("create service: ", err)
} }
err = instance.Start() err = instance.Start()
if err != nil { if err != nil {
logrus.Fatal("start service: ", err) log.Fatal("start service: ", err)
} }
osSignals := make(chan os.Signal, 1) osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)

View file

@ -5,15 +5,9 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func init() {
logrus.StandardLogger().SetLevel(logrus.TraceLevel)
logrus.StandardLogger().SetFormatter(&log.LogrusTextFormatter{})
}
var ( var (
configPath string configPath string
workingDir string workingDir string
@ -38,17 +32,14 @@ func init() {
func main() { func main() {
if err := mainCommand.Execute(); err != nil { if err := mainCommand.Execute(); err != nil {
logrus.Fatal(err) log.Fatal(err)
} }
} }
func preRun(cmd *cobra.Command, args []string) { func preRun(cmd *cobra.Command, args []string) {
if disableColor {
logrus.StandardLogger().SetFormatter(&log.LogrusTextFormatter{DisableColors: true})
}
if workingDir != "" { if workingDir != "" {
if err := os.Chdir(workingDir); err != nil { if err := os.Chdir(workingDir); err != nil {
logrus.Fatal(err) log.Fatal(err)
} }
} }
} }

3
go.mod
View file

@ -7,11 +7,10 @@ require (
github.com/goccy/go-json v0.9.8 github.com/goccy/go-json v0.9.8
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/oschwald/maxminddb-golang v1.9.0 github.com/oschwald/maxminddb-golang v1.9.0
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61 github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96 github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netlink v1.1.0

8
go.sum
View file

@ -25,23 +25,20 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61 h1:sOx7t+MFssiCAY2afRHQSmkWZNpLQnjF0Hwv/TNVMvk= github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91 h1:fYsRChEViZHDvrOLp7fbswYCH3txaVyAl1zB0cnSNlc=
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY=
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k= github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw= github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96 h1:BPsCEEKmww4PCuL2qCKGpwuS/HllNz4/G7EjvSHlXXg= github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96 h1:BPsCEEKmww4PCuL2qCKGpwuS/HllNz4/G7EjvSHlXXg=
github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96/go.mod h1:OLQnVTGk8NMVdoegQvenGHsGEv3diSMWe9Uh02cel0E= github.com/sagernet/sing-tun v0.0.0-20220711091522-4f7247190c96/go.mod h1:OLQnVTGk8NMVdoegQvenGHsGEv3diSMWe9Uh02cel0E=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@ -55,7 +52,6 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d h1:/m5NbqQelATgoSPVC2Z23sR4kVNokFwDDyWh/3rGY+I= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d h1:/m5NbqQelATgoSPVC2Z23sR4kVNokFwDDyWh/3rGY+I=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -9,33 +9,25 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
) )
func New(ctx context.Context, router adapter.Router, logger log.Logger, index int, options option.Inbound) (adapter.Inbound, error) { func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.Inbound) (adapter.Inbound, error) {
if common.IsEmptyByEquals(options) { if common.IsEmptyByEquals(options) {
return nil, E.New("empty inbound config") return nil, E.New("empty inbound config")
} }
var tag string
if options.Tag != "" {
tag = options.Tag
} else {
tag = F.ToString(index)
}
inboundLogger := logger.WithPrefix(F.ToString("inbound/", options.Type, "[", tag, "]: "))
switch options.Type { switch options.Type {
case C.TypeDirect: case C.TypeDirect:
return NewDirect(ctx, router, inboundLogger, options.Tag, options.DirectOptions), nil return NewDirect(ctx, router, logger, options.Tag, options.DirectOptions), nil
case C.TypeSocks: case C.TypeSocks:
return NewSocks(ctx, router, inboundLogger, options.Tag, options.SocksOptions), nil return NewSocks(ctx, router, logger, options.Tag, options.SocksOptions), nil
case C.TypeHTTP: case C.TypeHTTP:
return NewHTTP(ctx, router, inboundLogger, options.Tag, options.HTTPOptions), nil return NewHTTP(ctx, router, logger, options.Tag, options.HTTPOptions), nil
case C.TypeMixed: case C.TypeMixed:
return NewMixed(ctx, router, inboundLogger, options.Tag, options.MixedOptions), nil return NewMixed(ctx, router, logger, options.Tag, options.MixedOptions), nil
case C.TypeShadowsocks: case C.TypeShadowsocks:
return NewShadowsocks(ctx, router, inboundLogger, options.Tag, options.ShadowsocksOptions) return NewShadowsocks(ctx, router, logger, options.Tag, options.ShadowsocksOptions)
case C.TypeTun: case C.TypeTun:
return NewTun(ctx, router, inboundLogger, options.Tag, options.TunOptions) return NewTun(ctx, router, logger, options.Tag, options.TunOptions)
default: default:
return nil, E.New("unknown inbound type: ", options.Type) return nil, E.New("unknown inbound type: ", options.Type)
} }

View file

@ -29,7 +29,7 @@ type myInboundAdapter struct {
network []string network []string
ctx context.Context ctx context.Context
router adapter.Router router adapter.Router
logger log.Logger logger log.ContextLogger
tag string tag string
listenOptions option.ListenOptions listenOptions option.ListenOptions
connHandler adapter.ConnectionHandler connHandler adapter.ConnectionHandler
@ -107,19 +107,19 @@ func (a *myInboundAdapter) upstreamContextHandler() adapter.UpstreamHandlerAdapt
} }
func (a *myInboundAdapter) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (a *myInboundAdapter) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
a.logger.WithContext(ctx).Info("inbound connection to ", metadata.Destination) a.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
return a.router.RouteConnection(ctx, conn, metadata) return a.router.RouteConnection(ctx, conn, metadata)
} }
func (a *myInboundAdapter) streamPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { func (a *myInboundAdapter) streamPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
a.logger.WithContext(ctx).Info("inbound packet connection to ", metadata.Destination) a.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
return a.router.RoutePacketConnection(ctx, conn, metadata) return a.router.RoutePacketConnection(ctx, conn, metadata)
} }
func (a *myInboundAdapter) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { func (a *myInboundAdapter) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
ctx = log.ContextWithID(ctx) ctx = log.ContextWithNewID(ctx)
a.logger.WithContext(ctx).Info("inbound packet connection from ", metadata.Source) a.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
a.logger.WithContext(ctx).Info("inbound packet connection to ", metadata.Destination) a.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
return a.router.RoutePacketConnection(ctx, conn, metadata) return a.router.RoutePacketConnection(ctx, conn, metadata)
} }
@ -131,7 +131,7 @@ func (a *myInboundAdapter) loopTCPIn() {
return return
} }
go func() { go func() {
ctx := log.ContextWithID(a.ctx) ctx := log.ContextWithNewID(a.ctx)
var metadata adapter.InboundContext var metadata adapter.InboundContext
metadata.Inbound = a.tag metadata.Inbound = a.tag
metadata.SniffEnabled = a.listenOptions.SniffEnabled metadata.SniffEnabled = a.listenOptions.SniffEnabled
@ -139,7 +139,7 @@ func (a *myInboundAdapter) loopTCPIn() {
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Network = C.NetworkTCP metadata.Network = C.NetworkTCP
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()) metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
a.logger.WithContext(ctx).Info("inbound connection from ", metadata.Source) a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
hErr := a.connHandler.NewConnection(ctx, conn, metadata) hErr := a.connHandler.NewConnection(ctx, conn, metadata)
if hErr != nil { if hErr != nil {
conn.Close() conn.Close()
@ -235,13 +235,13 @@ func (a *myInboundAdapter) NewError(ctx context.Context, err error) {
NewError(a.logger, ctx, err) NewError(a.logger, ctx, err)
} }
func NewError(logger log.Logger, ctx context.Context, err error) { func NewError(logger log.ContextLogger, ctx context.Context, err error) {
common.Close(err) common.Close(err)
if E.IsClosed(err) || E.IsCanceled(err) { if E.IsClosed(err) || E.IsCanceled(err) {
logger.WithContext(ctx).Debug("connection closed") logger.DebugContext(ctx, "connection closed")
return return
} }
logger.WithContext(ctx).Error(err) logger.ErrorContext(ctx, err)
} }
func (a *myInboundAdapter) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error { func (a *myInboundAdapter) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error {

View file

@ -24,7 +24,7 @@ type Direct struct {
overrideDestination M.Socksaddr overrideDestination M.Socksaddr
} }
func NewDirect(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.DirectInboundOptions) *Direct { func NewDirect(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectInboundOptions) *Direct {
inbound := &Direct{ inbound := &Direct{
myInboundAdapter: myInboundAdapter{ myInboundAdapter: myInboundAdapter{
protocol: C.TypeDirect, protocol: C.TypeDirect,
@ -64,7 +64,7 @@ func (d *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adap
case 3: case 3:
metadata.Destination.Port = d.overrideDestination.Port metadata.Destination.Port = d.overrideDestination.Port
} }
d.logger.WithContext(ctx).Info("inbound connection to ", metadata.Destination) d.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
return d.router.RouteConnection(ctx, conn, metadata) return d.router.RouteConnection(ctx, conn, metadata)
} }
@ -79,6 +79,6 @@ func (d *Direct) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.B
case 3: case 3:
metadata.Destination.Port = d.overrideDestination.Port metadata.Destination.Port = d.overrideDestination.Port
} }
d.udpNat.NewPacketDirect(adapter.WithContext(log.ContextWithID(ctx), &metadata), metadata.Source.AddrPort(), conn, buffer, adapter.UpstreamMetadata(metadata)) d.udpNat.NewPacketDirect(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), metadata.Source.AddrPort(), conn, buffer, adapter.UpstreamMetadata(metadata))
return nil return nil
} }

View file

@ -15,7 +15,7 @@ import (
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
) )
func NewDNSConnection(ctx context.Context, router adapter.Router, logger log.Logger, conn net.Conn, metadata adapter.InboundContext) error { func NewDNSConnection(ctx context.Context, router adapter.Router, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error {
ctx = adapter.WithContext(ctx, &metadata) ctx = adapter.WithContext(ctx, &metadata)
_buffer := buf.StackNewSize(1024) _buffer := buf.StackNewSize(1024)
defer common.KeepAlive(_buffer) defer common.KeepAlive(_buffer)
@ -43,7 +43,7 @@ func NewDNSConnection(ctx context.Context, router adapter.Router, logger log.Log
if len(message.Questions) > 0 { if len(message.Questions) > 0 {
question := message.Questions[0] question := message.Questions[0]
metadata.Domain = string(question.Name.Data[:question.Name.Length-1]) metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
logger.WithContext(ctx).Debug("inbound dns query ", formatDNSQuestion(question), " from ", metadata.Source) logger.DebugContext(ctx, "inbound dns query ", formatDNSQuestion(question), " from ", metadata.Source)
} }
go func() error { go func() error {
response, err := router.Exchange(ctx, &message) response, err := router.Exchange(ctx, &message)
@ -67,7 +67,7 @@ func NewDNSConnection(ctx context.Context, router adapter.Router, logger log.Log
} }
} }
func NewDNSPacketConnection(ctx context.Context, router adapter.Router, logger log.Logger, conn N.PacketConn, metadata adapter.InboundContext) error { func NewDNSPacketConnection(ctx context.Context, router adapter.Router, logger log.ContextLogger, conn N.PacketConn, metadata adapter.InboundContext) error {
ctx = adapter.WithContext(ctx, &metadata) ctx = adapter.WithContext(ctx, &metadata)
_buffer := buf.StackNewSize(1024) _buffer := buf.StackNewSize(1024)
defer common.KeepAlive(_buffer) defer common.KeepAlive(_buffer)
@ -87,7 +87,7 @@ func NewDNSPacketConnection(ctx context.Context, router adapter.Router, logger l
if len(message.Questions) > 0 { if len(message.Questions) > 0 {
question := message.Questions[0] question := message.Questions[0]
metadata.Domain = string(question.Name.Data[:question.Name.Length-1]) metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
logger.WithContext(ctx).Debug("inbound dns query ", formatDNSQuestion(question), " from ", metadata.Source) logger.DebugContext(ctx, "inbound dns query ", formatDNSQuestion(question), " from ", metadata.Source)
} }
go func() error { go func() error {
response, err := router.Exchange(ctx, &message) response, err := router.Exchange(ctx, &message)

View file

@ -21,7 +21,7 @@ type HTTP struct {
authenticator auth.Authenticator authenticator auth.Authenticator
} }
func NewHTTP(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *HTTP { func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *HTTP {
inbound := &HTTP{ inbound := &HTTP{
myInboundAdapter{ myInboundAdapter{
protocol: C.TypeHTTP, protocol: C.TypeHTTP,

View file

@ -27,7 +27,7 @@ type Mixed struct {
authenticator auth.Authenticator authenticator auth.Authenticator
} }
func NewMixed(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *Mixed { func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *Mixed {
inbound := &Mixed{ inbound := &Mixed{
myInboundAdapter{ myInboundAdapter{
protocol: C.TypeMixed, protocol: C.TypeMixed,

View file

@ -17,7 +17,7 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksInboundOptions) (adapter.Inbound, error) { func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (adapter.Inbound, error) {
if len(options.Users) > 0 && len(options.Destinations) > 0 { if len(options.Users) > 0 && len(options.Destinations) > 0 {
return nil, E.New("users and destinations options must not be combined") return nil, E.New("users and destinations options must not be combined")
} }
@ -37,7 +37,7 @@ type Shadowsocks struct {
service shadowsocks.Service service shadowsocks.Service
} }
func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksInboundOptions) (*Shadowsocks, error) { func newShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (*Shadowsocks, error) {
inbound := &Shadowsocks{ inbound := &Shadowsocks{
myInboundAdapter: myInboundAdapter{ myInboundAdapter: myInboundAdapter{
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
@ -73,9 +73,9 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Logge
} }
func (h *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return h.service.NewConnection(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *Shadowsocks) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error { func (h *Shadowsocks) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
return h.service.NewPacket(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }

View file

@ -24,7 +24,7 @@ type ShadowsocksMulti struct {
users []option.ShadowsocksUser users []option.ShadowsocksUser
} }
func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksInboundOptions) (*ShadowsocksMulti, error) { func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (*ShadowsocksMulti, error) {
inbound := &ShadowsocksMulti{ inbound := &ShadowsocksMulti{
myInboundAdapter: myInboundAdapter{ myInboundAdapter: myInboundAdapter{
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
@ -68,11 +68,11 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
} }
func (h *ShadowsocksMulti) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksMulti) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return h.service.NewConnection(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksMulti) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error { func (h *ShadowsocksMulti) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
return h.service.NewPacket(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
@ -81,7 +81,7 @@ func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, met
if user == "" { if user == "" {
user = F.ToString(userCtx.User) user = F.ToString(userCtx.User)
} }
h.logger.WithContext(ctx).Info("[", user, "] inbound connection to ", metadata.Destination) h.logger.InfoContext(ctx, "[", user, "] inbound connection to ", metadata.Destination)
return h.router.RouteConnection(ctx, conn, metadata) return h.router.RouteConnection(ctx, conn, metadata)
} }
@ -91,8 +91,8 @@ func (h *ShadowsocksMulti) newPacketConnection(ctx context.Context, conn N.Packe
if user == "" { if user == "" {
user = F.ToString(userCtx.User) user = F.ToString(userCtx.User)
} }
ctx = log.ContextWithID(ctx) ctx = log.ContextWithNewID(ctx)
h.logger.WithContext(ctx).Info("[", user, "] inbound packet connection from ", metadata.Source) h.logger.InfoContext(ctx, "[", user, "] inbound packet connection from ", metadata.Source)
h.logger.WithContext(ctx).Info("[", user, "] inbound packet connection to ", metadata.Destination) h.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination)
return h.router.RoutePacketConnection(ctx, conn, metadata) return h.router.RoutePacketConnection(ctx, conn, metadata)
} }

View file

@ -24,7 +24,7 @@ type ShadowsocksRelay struct {
destinations []option.ShadowsocksDestination destinations []option.ShadowsocksDestination
} }
func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksInboundOptions) (*ShadowsocksRelay, error) { func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (*ShadowsocksRelay, error) {
inbound := &ShadowsocksRelay{ inbound := &ShadowsocksRelay{
myInboundAdapter: myInboundAdapter{ myInboundAdapter: myInboundAdapter{
protocol: C.TypeShadowsocks, protocol: C.TypeShadowsocks,
@ -68,11 +68,11 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.
} }
func (h *ShadowsocksRelay) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksRelay) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return h.service.NewConnection(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksRelay) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error { func (h *ShadowsocksRelay) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
return h.service.NewPacket(adapter.WithContext(log.ContextWithID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
@ -81,7 +81,7 @@ func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, met
if destination == "" { if destination == "" {
destination = F.ToString(userCtx.User) destination = F.ToString(userCtx.User)
} }
h.logger.WithContext(ctx).Info("[", destination, "] inbound connection to ", metadata.Destination) h.logger.InfoContext(ctx, "[", destination, "] inbound connection to ", metadata.Destination)
return h.router.RouteConnection(ctx, conn, metadata) return h.router.RouteConnection(ctx, conn, metadata)
} }
@ -91,8 +91,8 @@ func (h *ShadowsocksRelay) newPacketConnection(ctx context.Context, conn N.Packe
if destination == "" { if destination == "" {
destination = F.ToString(userCtx.User) destination = F.ToString(userCtx.User)
} }
ctx = log.ContextWithID(ctx) ctx = log.ContextWithNewID(ctx)
h.logger.WithContext(ctx).Info("[", destination, "] inbound packet connection from ", metadata.Source) h.logger.InfoContext(ctx, "[", destination, "] inbound packet connection from ", metadata.Source)
h.logger.WithContext(ctx).Info("[", destination, "] inbound packet connection to ", metadata.Destination) h.logger.InfoContext(ctx, "[", destination, "] inbound packet connection to ", metadata.Destination)
return h.router.RoutePacketConnection(ctx, conn, metadata) return h.router.RoutePacketConnection(ctx, conn, metadata)
} }

View file

@ -20,7 +20,7 @@ type Socks struct {
authenticator auth.Authenticator authenticator auth.Authenticator
} }
func NewSocks(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *Socks { func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SimpleInboundOptions) *Socks {
inbound := &Socks{ inbound := &Socks{
myInboundAdapter{ myInboundAdapter{
protocol: C.TypeSocks, protocol: C.TypeSocks,

View file

@ -31,7 +31,7 @@ type Tun struct {
ctx context.Context ctx context.Context
router adapter.Router router adapter.Router
logger log.Logger logger log.ContextLogger
inboundOptions option.InboundOptions inboundOptions option.InboundOptions
tunName string tunName string
tunMTU uint32 tunMTU uint32
@ -44,7 +44,7 @@ type Tun struct {
tun *tun.GVisorTun tun *tun.GVisorTun
} }
func NewTun(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.TunInboundOptions) (*Tun, error) { func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions) (*Tun, error) {
tunName := options.InterfaceName tunName := options.InterfaceName
if tunName == "" { if tunName == "" {
tunName = mkInterfaceName() tunName = mkInterfaceName()
@ -107,7 +107,7 @@ func (t *Tun) Close() error {
} }
func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error { func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
ctx = log.ContextWithID(ctx) ctx = log.ContextWithNewID(ctx)
var metadata adapter.InboundContext var metadata adapter.InboundContext
metadata.Inbound = t.tag metadata.Inbound = t.tag
metadata.Network = C.NetworkTCP metadata.Network = C.NetworkTCP
@ -121,13 +121,13 @@ func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata
return NewDNSConnection(ctx, t.router, t.logger, conn, metadata) return NewDNSConnection(ctx, t.router, t.logger, conn, metadata)
}) })
} }
t.logger.WithContext(ctx).Info("inbound connection from ", metadata.Source) t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
t.logger.WithContext(ctx).Info("inbound connection to ", metadata.Destination) t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
return t.router.RouteConnection(ctx, conn, metadata) return t.router.RouteConnection(ctx, conn, metadata)
} }
func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error { func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error {
ctx = log.ContextWithID(ctx) ctx = log.ContextWithNewID(ctx)
var metadata adapter.InboundContext var metadata adapter.InboundContext
metadata.Inbound = t.tag metadata.Inbound = t.tag
metadata.Network = C.NetworkUDP metadata.Network = C.NetworkUDP
@ -141,8 +141,8 @@ func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstre
return NewDNSPacketConnection(ctx, t.router, t.logger, conn, metadata) return NewDNSPacketConnection(ctx, t.router, t.logger, conn, metadata)
}) })
} }
t.logger.WithContext(ctx).Info("inbound packet connection from ", metadata.Source) t.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
t.logger.WithContext(ctx).Info("inbound packet connection to ", metadata.Destination) t.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
return t.router.RoutePacketConnection(ctx, conn, metadata) return t.router.RoutePacketConnection(ctx, conn, metadata)
} }

View file

@ -11,6 +11,6 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
) )
func NewTun(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.TunInboundOptions) (adapter.Inbound, error) { func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions) (adapter.Inbound, error) {
return nil, E.New("tun disabled in this build") return nil, E.New("tun disabled in this build")
} }

119
log/default.go Normal file
View file

@ -0,0 +1,119 @@
package log
import (
"context"
"io"
"os"
"time"
F "github.com/sagernet/sing/common/format"
)
var _ Factory = (*simpleFactory)(nil)
type simpleFactory struct {
formatter Formatter
writer io.Writer
level Level
}
func NewFactory(formatter Formatter, writer io.Writer) Factory {
return &simpleFactory{
formatter: formatter,
writer: writer,
level: LevelTrace,
}
}
func (f *simpleFactory) Level() Level {
return f.level
}
func (f *simpleFactory) SetLevel(level Level) {
f.level = level
}
func (f *simpleFactory) Logger() ContextLogger {
return f.NewLogger("")
}
func (f *simpleFactory) NewLogger(tag string) ContextLogger {
return &simpleLogger{f, tag}
}
var _ ContextLogger = (*simpleLogger)(nil)
type simpleLogger struct {
*simpleFactory
tag string
}
func (l *simpleLogger) Log(ctx context.Context, level Level, args []any) {
if level > l.level {
return
}
message := l.formatter.Format(ctx, level, l.tag, F.ToString(args...), time.Now()) + "\n"
if level == LevelPanic {
panic(message)
}
l.writer.Write([]byte(message))
if level == LevelFatal {
os.Exit(1)
}
}
func (l *simpleLogger) Trace(args ...any) {
l.Log(nil, LevelTrace, args)
}
func (l *simpleLogger) Debug(args ...any) {
l.Log(nil, LevelDebug, args)
}
func (l *simpleLogger) Info(args ...any) {
l.Log(nil, LevelInfo, args)
}
func (l *simpleLogger) Warn(args ...any) {
l.Log(nil, LevelWarn, args)
}
func (l *simpleLogger) Error(args ...any) {
l.Log(nil, LevelError, args)
}
func (l *simpleLogger) Fatal(args ...any) {
l.Log(nil, LevelFatal, args)
}
func (l *simpleLogger) Panic(args ...any) {
l.Log(nil, LevelPanic, args)
}
func (l *simpleLogger) TraceContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelTrace, args)
}
func (l *simpleLogger) DebugContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelDebug, args)
}
func (l *simpleLogger) InfoContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelInfo, args)
}
func (l *simpleLogger) WarnContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelWarn, args)
}
func (l *simpleLogger) ErrorContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelError, args)
}
func (l *simpleLogger) FatalContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelFatal, args)
}
func (l *simpleLogger) PanicContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelPanic, args)
}

69
log/export.go Normal file
View file

@ -0,0 +1,69 @@
package log
import (
"context"
"os"
"time"
)
var std ContextLogger
func init() {
std = NewFactory(Formatter{BaseTime: time.Now()}, os.Stderr).Logger()
}
func Trace(args ...any) {
std.Trace(args...)
}
func Debug(args ...any) {
std.Debug(args...)
}
func Info(args ...any) {
std.Info(args...)
}
func Warn(args ...any) {
std.Warn(args...)
}
func Error(args ...any) {
std.Error(args...)
}
func Fatal(args ...any) {
std.Fatal(args...)
}
func Panic(args ...any) {
std.Panic(args...)
}
func TraceContext(ctx context.Context, args ...any) {
std.TraceContext(ctx, args...)
}
func DebugContext(ctx context.Context, args ...any) {
std.DebugContext(ctx, args...)
}
func InfoContext(ctx context.Context, args ...any) {
std.InfoContext(ctx, args...)
}
func WarnContext(ctx context.Context, args ...any) {
std.WarnContext(ctx, args...)
}
func ErrorContext(ctx context.Context, args ...any) {
std.ErrorContext(ctx, args...)
}
func FatalContext(ctx context.Context, args ...any) {
std.FatalContext(ctx, args...)
}
func PanicContext(ctx context.Context, args ...any) {
std.PanicContext(ctx, args...)
}

45
log/factory.go Normal file
View file

@ -0,0 +1,45 @@
package log
import (
"context"
"github.com/sagernet/sing/common/observable"
)
type Factory interface {
Level() Level
SetLevel(level Level)
Logger() ContextLogger
NewLogger(tag string) ContextLogger
}
type ObservableFactory interface {
Factory
observable.Observable[Entry]
}
type Entry struct {
Level Level
Message string
}
type Logger interface {
Trace(args ...any)
Debug(args ...any)
Info(args ...any)
Warn(args ...any)
Error(args ...any)
Fatal(args ...any)
Panic(args ...any)
}
type ContextLogger interface {
Logger
TraceContext(ctx context.Context, args ...any)
DebugContext(ctx context.Context, args ...any)
InfoContext(ctx context.Context, args ...any)
WarnContext(ctx context.Context, args ...any)
ErrorContext(ctx context.Context, args ...any)
FatalContext(ctx context.Context, args ...any)
PanicContext(ctx context.Context, args ...any)
}

83
log/format.go Normal file
View file

@ -0,0 +1,83 @@
package log
import (
"context"
"strconv"
"strings"
"time"
F "github.com/sagernet/sing/common/format"
"github.com/logrusorgru/aurora"
)
type Formatter struct {
BaseTime time.Time
DisableColors bool
DisableTimestamp bool
FullTimestamp bool
TimestampFormat string
}
func (f Formatter) Format(ctx context.Context, level Level, tag string, message string, timestamp time.Time) string {
levelString := strings.ToUpper(FormatLevel(level))
if !f.DisableColors {
switch level {
case LevelDebug, LevelTrace:
levelString = aurora.White(levelString).String()
case LevelInfo:
levelString = aurora.Cyan(levelString).String()
case LevelWarn:
levelString = aurora.Yellow(levelString).String()
case LevelError, LevelFatal, LevelPanic:
levelString = aurora.Red(levelString).String()
}
}
if tag != "" {
message = tag + ": " + message
}
var id uint32
var hasId bool
if ctx != nil {
id, hasId = IDFromContext(ctx)
}
if hasId {
var color aurora.Color
color = aurora.Color(uint8(id))
color %= 215
row := uint(color / 36)
column := uint(color % 36)
var r, g, b float32
r = float32(row * 51)
g = float32(column / 6 * 51)
b = float32((column % 6) * 51)
luma := 0.2126*r + 0.7152*g + 0.0722*b
if luma < 60 {
row = 5 - row
column = 35 - column
color = aurora.Color(row*36 + column)
}
color += 16
color = color << 16
color |= 1 << 14
message = F.ToString("[", aurora.Colorize(id, color).String(), "] ", message)
}
switch {
case f.DisableTimestamp:
message = levelString + " " + message
case f.FullTimestamp:
message = F.ToString(int(timestamp.Sub(f.BaseTime)/time.Second)) + " " + levelString + " " + message
default:
message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message
}
return message
}
func xd(value int, x int) string {
message := strconv.Itoa(value)
for len(message) < x {
message = "0" + message
}
return message
}

View file

@ -11,23 +11,13 @@ func init() {
random.InitializeSeed() random.InitializeSeed()
} }
var idType = (*idContext)(nil) type idKey struct{}
type idContext struct { func ContextWithNewID(ctx context.Context) context.Context {
context.Context return context.WithValue(ctx, (*idKey)(nil), rand.Uint32())
id uint32
} }
func (c *idContext) Value(key any) any { func IDFromContext(ctx context.Context) (uint32, bool) {
if key == idType { id, loaded := ctx.Value((*idKey)(nil)).(uint32)
return c return id, loaded
}
return c.Context.Value(key)
}
func ContextWithID(ctx context.Context) context.Context {
if ctx.Value(idType) != nil {
return ctx
}
return &idContext{ctx, rand.Uint32()}
} }

59
log/level.go Normal file
View file

@ -0,0 +1,59 @@
package log
import (
E "github.com/sagernet/sing/common/exceptions"
)
type Level = uint8
const (
LevelPanic Level = iota
LevelFatal
LevelError
LevelWarn
LevelInfo
LevelDebug
LevelTrace
)
func FormatLevel(level Level) string {
switch level {
case LevelTrace:
return "trace"
case LevelDebug:
return "debug"
case LevelInfo:
return "info"
case LevelWarn:
return "warn"
case LevelError:
return "error"
case LevelFatal:
return "fatal"
case LevelPanic:
return "panic"
default:
return "unknown"
}
}
func ParseLevel(level string) (Level, error) {
switch level {
case "trace":
return LevelTrace, nil
case "debug":
return LevelDebug, nil
case "info":
return LevelInfo, nil
case "warn", "warning":
return LevelWarn, nil
case "error":
return LevelError, nil
case "fatal":
return LevelFatal, nil
case "panic":
return LevelPanic, nil
default:
return LevelTrace, E.New("unknown log level: ", level)
}
}

View file

@ -1,30 +0,0 @@
package log
import (
"context"
"github.com/sagernet/sing-box/option"
)
type Logger interface {
Start() error
Close() error
Trace(args ...interface{})
Debug(args ...interface{})
Info(args ...interface{})
Print(args ...interface{})
Warn(args ...interface{})
Warning(args ...interface{})
Error(args ...interface{})
Fatal(args ...interface{})
Panic(args ...interface{})
WithContext(ctx context.Context) Logger
WithPrefix(prefix string) Logger
}
func NewLogger(options option.LogOption) (Logger, error) {
if options.Disabled {
return NewNopLogger(), nil
}
return NewLogrusLogger(options)
}

View file

@ -1,74 +0,0 @@
package log
import (
"context"
"os"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sirupsen/logrus"
)
var _ Logger = (*logrusLogger)(nil)
type logrusLogger struct {
abstractLogrusLogger
outputPath string
output *os.File
}
type abstractLogrusLogger interface {
logrus.Ext1FieldLogger
WithContext(ctx context.Context) *logrus.Entry
}
func NewLogrusLogger(options option.LogOption) (*logrusLogger, error) {
logger := logrus.New()
logger.SetLevel(logrus.TraceLevel)
logger.SetFormatter(&LogrusTextFormatter{
DisableColors: options.DisableColor || options.Output != "",
DisableTimestamp: !options.Timestamp && options.Output != "",
FullTimestamp: options.Timestamp,
})
logger.AddHook(new(logrusHook))
var err error
if options.Level != "" {
logger.Level, err = logrus.ParseLevel(options.Level)
if err != nil {
return nil, err
}
}
return &logrusLogger{logger, options.Output, nil}, nil
}
func (l *logrusLogger) Start() error {
if l.outputPath != "" {
output, err := os.OpenFile(l.outputPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return E.Cause(err, "open log output")
}
l.abstractLogrusLogger.(*logrus.Logger).SetOutput(output)
}
return nil
}
func (l *logrusLogger) Close() error {
return common.Close(common.PtrOrNil(l.output))
}
func (l *logrusLogger) WithContext(ctx context.Context) Logger {
return &logrusLogger{abstractLogrusLogger: l.abstractLogrusLogger.WithContext(ctx)}
}
func (l *logrusLogger) WithPrefix(prefix string) Logger {
if entry, isEntry := l.abstractLogrusLogger.(*logrus.Entry); isEntry {
loadedPrefix := entry.Data["prefix"]
if loadedPrefix != "" {
prefix = F.ToString(loadedPrefix, prefix)
}
}
return &logrusLogger{abstractLogrusLogger: l.WithField("prefix", prefix)}
}

View file

@ -1,49 +0,0 @@
package log
import (
F "github.com/sagernet/sing/common/format"
"github.com/logrusorgru/aurora"
"github.com/sirupsen/logrus"
)
type logrusHook struct{}
func (h *logrusHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (h *logrusHook) Fire(entry *logrus.Entry) error {
if prefix, loaded := entry.Data["prefix"]; loaded {
prefixStr := prefix.(string)
delete(entry.Data, "prefix")
entry.Message = prefixStr + entry.Message
}
var idCtx *idContext
if entry.Context != nil {
idCtx, _ = entry.Context.Value(idType).(*idContext)
}
if idCtx != nil {
var color aurora.Color
color = aurora.Color(uint8(idCtx.id))
color %= 215
row := uint(color / 36)
column := uint(color % 36)
var r, g, b float32
r = float32(row * 51)
g = float32(column / 6 * 51)
b = float32((column % 6) * 51)
luma := 0.2126*r + 0.7152*g + 0.0722*b
if luma < 60 {
row = 5 - row
column = 35 - column
color = aurora.Color(row*36 + column)
}
color += 16
color = color << 16
color |= 1 << 14
entry.Message = F.ToString("[", aurora.Colorize(idCtx.id, color).String(), "] ", entry.Message)
}
return nil
}

View file

@ -1,83 +0,0 @@
package log
import (
"bytes"
"fmt"
"strings"
"time"
"github.com/sirupsen/logrus"
)
const (
red = 31
yellow = 33
blue = 36
gray = 37
)
var baseTimestamp time.Time
func init() {
baseTimestamp = time.Now()
}
type LogrusTextFormatter struct {
DisableColors bool
DisableTimestamp bool
FullTimestamp bool
TimestampFormat string
}
func (f *LogrusTextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = "-0700 2006-01-02 15:04:05"
}
f.print(b, entry, timestampFormat)
b.WriteByte('\n')
return b.Bytes(), nil
}
func (f *LogrusTextFormatter) print(b *bytes.Buffer, entry *logrus.Entry, timestampFormat string) {
var levelColor int
switch entry.Level {
case logrus.DebugLevel, logrus.TraceLevel:
levelColor = gray
case logrus.WarnLevel:
levelColor = yellow
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
levelColor = red
case logrus.InfoLevel:
levelColor = blue
default:
levelColor = blue
}
levelText := strings.ToUpper(entry.Level.String())
if !f.DisableColors {
switch {
case f.DisableTimestamp:
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s", levelColor, levelText, entry.Message)
case !f.FullTimestamp:
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
default:
fmt.Fprintf(b, "%s \x1b[%dm%s\x1b[0m %-44s", entry.Time.Format(timestampFormat), levelColor, levelText, entry.Message)
}
} else {
switch {
case f.DisableTimestamp:
fmt.Fprintf(b, "%s %-44s", levelText, entry.Message)
case !f.FullTimestamp:
fmt.Fprintf(b, "%s[%04d] %-44s", levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
default:
fmt.Fprintf(b, "[%s] %s %-44s", entry.Time.Format(timestampFormat), levelText, entry.Message)
}
}
}

View file

@ -2,53 +2,67 @@ package log
import "context" import "context"
var _ Logger = (*nopLogger)(nil) var _ Factory = (*nopFactory)(nil)
type nopLogger struct{} type nopFactory struct{}
func NewNopLogger() Logger { func NewNOPFactory() Factory {
return (*nopLogger)(nil) return (*nopFactory)(nil)
} }
func (l *nopLogger) Start() error { func (f *nopFactory) Level() Level {
return nil return LevelTrace
} }
func (l *nopLogger) Close() error { func (f *nopFactory) SetLevel(level Level) {
return nil
} }
func (l *nopLogger) Trace(args ...interface{}) { func (f *nopFactory) Logger() ContextLogger {
return f
} }
func (l *nopLogger) Debug(args ...interface{}) { func (f *nopFactory) NewLogger(tag string) ContextLogger {
return f
} }
func (l *nopLogger) Info(args ...interface{}) { func (f *nopFactory) Trace(args ...any) {
} }
func (l *nopLogger) Print(args ...interface{}) { func (f *nopFactory) Debug(args ...any) {
} }
func (l *nopLogger) Warn(args ...interface{}) { func (f *nopFactory) Info(args ...any) {
} }
func (l *nopLogger) Warning(args ...interface{}) { func (f *nopFactory) Warn(args ...any) {
} }
func (l *nopLogger) Error(args ...interface{}) { func (f *nopFactory) Error(args ...any) {
} }
func (l *nopLogger) Fatal(args ...interface{}) { func (f *nopFactory) Fatal(args ...any) {
} }
func (l *nopLogger) Panic(args ...interface{}) { func (f *nopFactory) Panic(args ...any) {
} }
func (l *nopLogger) WithContext(ctx context.Context) Logger { func (f *nopFactory) TraceContext(ctx context.Context, args ...any) {
return l
} }
func (l *nopLogger) WithPrefix(prefix string) Logger { func (f *nopFactory) DebugContext(ctx context.Context, args ...any) {
return l }
func (f *nopFactory) InfoContext(ctx context.Context, args ...any) {
}
func (f *nopFactory) WarnContext(ctx context.Context, args ...any) {
}
func (f *nopFactory) ErrorContext(ctx context.Context, args ...any) {
}
func (f *nopFactory) FatalContext(ctx context.Context, args ...any) {
}
func (f *nopFactory) PanicContext(ctx context.Context, args ...any) {
} }

136
log/observable.go Normal file
View file

@ -0,0 +1,136 @@
package log
import (
"context"
"io"
"os"
"time"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/observable"
)
var _ Factory = (*observableFactory)(nil)
type observableFactory struct {
formatter Formatter
writer io.Writer
level Level
subscriber *observable.Subscriber[Entry]
observer *observable.Observer[Entry]
}
func NewObservableFactory(formatter Formatter, writer io.Writer) ObservableFactory {
factory := &observableFactory{
formatter: formatter,
writer: writer,
level: LevelTrace,
subscriber: observable.NewSubscriber[Entry](128),
}
factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
return factory
}
func (f *observableFactory) Level() Level {
return f.level
}
func (f *observableFactory) SetLevel(level Level) {
f.level = level
}
func (f *observableFactory) Logger() ContextLogger {
return f.NewLogger("")
}
func (f *observableFactory) NewLogger(tag string) ContextLogger {
return &observableLogger{f, tag}
}
func (f *observableFactory) Subscribe() (subscription observable.Subscription[Entry], done <-chan struct{}, err error) {
return f.observer.Subscribe()
}
func (f *observableFactory) UnSubscribe(sub observable.Subscription[Entry]) {
f.observer.UnSubscribe(sub)
}
var _ ContextLogger = (*observableLogger)(nil)
type observableLogger struct {
*observableFactory
tag string
}
func (l *observableLogger) Log(ctx context.Context, level Level, args []any) {
if level > l.level {
return
}
message := l.formatter.Format(ctx, level, l.tag, F.ToString(args...), time.Now()) + "\n"
if level == LevelPanic {
panic(message)
}
l.writer.Write([]byte(message))
if level == LevelFatal {
os.Exit(1)
}
if l.subscriber != nil {
l.subscriber.Emit(Entry{level, message})
}
}
func (l *observableLogger) Trace(args ...any) {
l.Log(nil, LevelTrace, args)
}
func (l *observableLogger) Debug(args ...any) {
l.Log(nil, LevelDebug, args)
}
func (l *observableLogger) Info(args ...any) {
l.Log(nil, LevelInfo, args)
}
func (l *observableLogger) Warn(args ...any) {
l.Log(nil, LevelWarn, args)
}
func (l *observableLogger) Error(args ...any) {
l.Log(nil, LevelError, args)
}
func (l *observableLogger) Fatal(args ...any) {
l.Log(nil, LevelFatal, args)
}
func (l *observableLogger) Panic(args ...any) {
l.Log(nil, LevelPanic, args)
}
func (l *observableLogger) TraceContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelTrace, args)
}
func (l *observableLogger) DebugContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelDebug, args)
}
func (l *observableLogger) InfoContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelInfo, args)
}
func (l *observableLogger) WarnContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelWarn, args)
}
func (l *observableLogger) ErrorContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelError, args)
}
func (l *observableLogger) FatalContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelFatal, args)
}
func (l *observableLogger) PanicContext(ctx context.Context, args ...any) {
l.Log(ctx, LevelPanic, args)
}

View file

@ -18,7 +18,7 @@ type Block struct {
myOutboundAdapter myOutboundAdapter
} }
func NewBlock(logger log.Logger, tag string) *Block { func NewBlock(logger log.ContextLogger, tag string) *Block {
return &Block{ return &Block{
myOutboundAdapter{ myOutboundAdapter{
protocol: C.TypeBlock, protocol: C.TypeBlock,
@ -30,23 +30,23 @@ func NewBlock(logger log.Logger, tag string) *Block {
} }
func (h *Block) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { func (h *Block) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
h.logger.WithContext(ctx).Info("blocked connection to ", destination) h.logger.InfoContext(ctx, "blocked connection to ", destination)
return nil, io.EOF return nil, io.EOF
} }
func (h *Block) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (h *Block) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
h.logger.WithContext(ctx).Info("blocked packet connection to ", destination) h.logger.InfoContext(ctx, "blocked packet connection to ", destination)
return nil, io.EOF return nil, io.EOF
} }
func (h *Block) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Block) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
conn.Close() conn.Close()
h.logger.WithContext(ctx).Info("blocked connection to ", metadata.Destination) h.logger.InfoContext(ctx, "blocked connection to ", metadata.Destination)
return nil return nil
} }
func (h *Block) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { func (h *Block) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
conn.Close() conn.Close()
h.logger.WithContext(ctx).Info("blocked packet connection to ", metadata.Destination) h.logger.InfoContext(ctx, "blocked packet connection to ", metadata.Destination)
return nil return nil
} }

View file

@ -7,31 +7,23 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
) )
func New(router adapter.Router, logger log.Logger, index int, options option.Outbound) (adapter.Outbound, error) { func New(router adapter.Router, logger log.ContextLogger, options option.Outbound) (adapter.Outbound, error) {
if common.IsEmpty(options) { if common.IsEmpty(options) {
return nil, E.New("empty outbound config") return nil, E.New("empty outbound config")
} }
var tag string
if options.Tag != "" {
tag = options.Tag
} else {
tag = F.ToString(index)
}
outboundLogger := logger.WithPrefix(F.ToString("outbound/", options.Type, "[", tag, "]: "))
switch options.Type { switch options.Type {
case C.TypeDirect: case C.TypeDirect:
return NewDirect(router, outboundLogger, options.Tag, options.DirectOptions), nil return NewDirect(router, logger, options.Tag, options.DirectOptions), nil
case C.TypeBlock: case C.TypeBlock:
return NewBlock(outboundLogger, options.Tag), nil return NewBlock(logger, options.Tag), nil
case C.TypeSocks: case C.TypeSocks:
return NewSocks(router, outboundLogger, options.Tag, options.SocksOptions) return NewSocks(router, logger, options.Tag, options.SocksOptions)
case C.TypeHTTP: case C.TypeHTTP:
return NewHTTP(router, outboundLogger, options.Tag, options.HTTPOptions), nil return NewHTTP(router, logger, options.Tag, options.HTTPOptions), nil
case C.TypeShadowsocks: case C.TypeShadowsocks:
return NewShadowsocks(router, outboundLogger, options.Tag, options.ShadowsocksOptions) return NewShadowsocks(router, logger, options.Tag, options.ShadowsocksOptions)
default: default:
return nil, E.New("unknown outbound type: ", options.Type) return nil, E.New("unknown outbound type: ", options.Type)
} }

View file

@ -18,7 +18,7 @@ import (
type myOutboundAdapter struct { type myOutboundAdapter struct {
protocol string protocol string
logger log.Logger logger log.ContextLogger
tag string tag string
network []string network []string
} }

View file

@ -23,7 +23,7 @@ type Direct struct {
overrideDestination M.Socksaddr overrideDestination M.Socksaddr
} }
func NewDirect(router adapter.Router, logger log.Logger, tag string, options option.DirectOutboundOptions) *Direct { func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) *Direct {
outbound := &Direct{ outbound := &Direct{
myOutboundAdapter: myOutboundAdapter{ myOutboundAdapter: myOutboundAdapter{
protocol: C.TypeDirect, protocol: C.TypeDirect,
@ -62,9 +62,9 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
} }
switch network { switch network {
case C.NetworkTCP: case C.NetworkTCP:
h.logger.WithContext(ctx).Info("outbound connection to ", destination) h.logger.InfoContext(ctx, "outbound connection to ", destination)
case C.NetworkUDP: case C.NetworkUDP:
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination) h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
} }
return h.dialer.DialContext(ctx, network, destination) return h.dialer.DialContext(ctx, network, destination)
} }
@ -73,7 +73,7 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag metadata.Outbound = h.tag
metadata.Destination = destination metadata.Destination = destination
h.logger.WithContext(ctx).Info("outbound packet connection") h.logger.InfoContext(ctx, "outbound packet connection")
return h.dialer.ListenPacket(ctx, destination) return h.dialer.ListenPacket(ctx, destination)
} }

View file

@ -22,7 +22,7 @@ type HTTP struct {
client *http.Client client *http.Client
} }
func NewHTTP(router adapter.Router, logger log.Logger, tag string, options option.HTTPOutboundOptions) *HTTP { func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) *HTTP {
return &HTTP{ return &HTTP{
myOutboundAdapter{ myOutboundAdapter{
protocol: C.TypeHTTP, protocol: C.TypeHTTP,
@ -38,7 +38,7 @@ func (h *HTTP) DialContext(ctx context.Context, network string, destination M.So
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag metadata.Outbound = h.tag
metadata.Destination = destination metadata.Destination = destination
h.logger.WithContext(ctx).Info("outbound connection to ", destination) h.logger.InfoContext(ctx, "outbound connection to ", destination)
return h.client.DialContext(ctx, network, destination) return h.client.DialContext(ctx, network, destination)
} }

View file

@ -25,7 +25,7 @@ type Shadowsocks struct {
serverAddr M.Socksaddr serverAddr M.Socksaddr
} }
func NewShadowsocks(router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) { func NewShadowsocks(router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
method, err := shadowimpl.FetchMethod(options.Method, options.Password) method, err := shadowimpl.FetchMethod(options.Method, options.Password)
if err != nil { if err != nil {
return nil, err return nil, err
@ -49,14 +49,14 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati
metadata.Destination = destination metadata.Destination = destination
switch network { switch network {
case C.NetworkTCP: case C.NetworkTCP:
h.logger.WithContext(ctx).Info("outbound connection to ", destination) h.logger.InfoContext(ctx, "outbound connection to ", destination)
outConn, err := h.dialer.DialContext(ctx, C.NetworkTCP, h.serverAddr) outConn, err := h.dialer.DialContext(ctx, C.NetworkTCP, h.serverAddr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return h.method.DialEarlyConn(outConn, destination), nil return h.method.DialEarlyConn(outConn, destination), nil
case C.NetworkUDP: case C.NetworkUDP:
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination) h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
outConn, err := h.dialer.DialContext(ctx, C.NetworkUDP, h.serverAddr) outConn, err := h.dialer.DialContext(ctx, C.NetworkUDP, h.serverAddr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -71,7 +71,7 @@ func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr)
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag metadata.Outbound = h.tag
metadata.Destination = destination metadata.Destination = destination
h.logger.WithContext(ctx).Info("outbound packet connection to ", h.serverAddr) h.logger.InfoContext(ctx, "outbound packet connection to ", h.serverAddr)
outConn, err := h.dialer.DialContext(ctx, "udp", h.serverAddr) outConn, err := h.dialer.DialContext(ctx, "udp", h.serverAddr)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -21,7 +21,7 @@ type Socks struct {
client *socks.Client client *socks.Client
} }
func NewSocks(router adapter.Router, logger log.Logger, tag string, options option.SocksOutboundOptions) (*Socks, error) { func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
detour := dialer.NewOutbound(router, options.OutboundDialerOptions) detour := dialer.NewOutbound(router, options.OutboundDialerOptions)
var version socks.Version var version socks.Version
var err error var err error
@ -50,9 +50,9 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
metadata.Destination = destination metadata.Destination = destination
switch network { switch network {
case C.NetworkTCP: case C.NetworkTCP:
h.logger.WithContext(ctx).Info("outbound connection to ", destination) h.logger.InfoContext(ctx, "outbound connection to ", destination)
case C.NetworkUDP: case C.NetworkUDP:
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination) h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
default: default:
panic("unknown network " + network) panic("unknown network " + network)
} }
@ -63,7 +63,7 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag metadata.Outbound = h.tag
metadata.Destination = destination metadata.Destination = destination
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination) h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
return h.client.ListenPacket(ctx, destination) return h.client.ListenPacket(ctx, destination)
} }

View file

@ -39,8 +39,8 @@ var _ adapter.Router = (*Router)(nil)
type Router struct { type Router struct {
ctx context.Context ctx context.Context
logger log.Logger logger log.ContextLogger
dnsLogger log.Logger dnsLogger log.ContextLogger
outboundByTag map[string]adapter.Outbound outboundByTag map[string]adapter.Outbound
rules []adapter.Rule rules []adapter.Rule
@ -68,11 +68,11 @@ type Router struct {
interfaceMonitor iffmonitor.InterfaceMonitor interfaceMonitor iffmonitor.InterfaceMonitor
} }
func NewRouter(ctx context.Context, logger log.Logger, options option.RouteOptions, dnsOptions option.DNSOptions) (*Router, error) { func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.ContextLogger, options option.RouteOptions, dnsOptions option.DNSOptions) (*Router, error) {
router := &Router{ router := &Router{
ctx: ctx, ctx: ctx,
logger: logger.WithPrefix("router: "), logger: logger,
dnsLogger: logger.WithPrefix("dns: "), dnsLogger: dnsLogger,
outboundByTag: make(map[string]adapter.Outbound), outboundByTag: make(map[string]adapter.Outbound),
rules: make([]adapter.Rule, 0, len(options.Rules)), rules: make([]adapter.Rule, 0, len(options.Rules)),
dnsRules: make([]adapter.Rule, 0, len(dnsOptions.Rules)), dnsRules: make([]adapter.Rule, 0, len(dnsOptions.Rules)),
@ -397,9 +397,9 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
metadata.Destination.Fqdn = metadata.Domain metadata.Destination.Fqdn = metadata.Domain
} }
if metadata.Domain != "" { if metadata.Domain != "" {
r.logger.WithContext(ctx).Debug("sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain) r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
} else { } else {
r.logger.WithContext(ctx).Debug("sniffed protocol: ", metadata.Protocol) r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
} }
} }
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
@ -412,7 +412,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
return err return err
} }
metadata.DestinationAddresses = addresses metadata.DestinationAddresses = addresses
r.dnsLogger.WithContext(ctx).Debug("resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]")
} }
detour := r.match(ctx, metadata, r.defaultOutboundForConnection) detour := r.match(ctx, metadata, r.defaultOutboundForConnection)
if !common.Contains(detour.Network(), C.NetworkTCP) { if !common.Contains(detour.Network(), C.NetworkTCP) {
@ -441,9 +441,9 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
metadata.Destination.Fqdn = metadata.Domain metadata.Destination.Fqdn = metadata.Domain
} }
if metadata.Domain != "" { if metadata.Domain != "" {
r.logger.WithContext(ctx).Debug("sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain) r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
} else { } else {
r.logger.WithContext(ctx).Debug("sniffed packet protocol: ", metadata.Protocol) r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
} }
} }
conn = bufio.NewCachedPacketConn(conn, buffer, originDestination) conn = bufio.NewCachedPacketConn(conn, buffer, originDestination)
@ -454,7 +454,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
return err return err
} }
metadata.DestinationAddresses = addresses metadata.DestinationAddresses = addresses
r.dnsLogger.WithContext(ctx).Debug("resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]")
} }
detour := r.match(ctx, metadata, r.defaultOutboundForPacketConnection) detour := r.match(ctx, metadata, r.defaultOutboundForPacketConnection)
if !common.Contains(detour.Network(), C.NetworkUDP) { if !common.Contains(detour.Network(), C.NetworkUDP) {
@ -480,11 +480,11 @@ func (r *Router) match(ctx context.Context, metadata adapter.InboundContext, def
for i, rule := range r.rules { for i, rule := range r.rules {
if rule.Match(&metadata) { if rule.Match(&metadata) {
detour := rule.Outbound() detour := rule.Outbound()
r.logger.WithContext(ctx).Debug("match[", i, "] ", rule.String(), " => ", detour) r.logger.DebugContext(ctx, "match[", i, "] ", rule.String(), " => ", detour)
if outbound, loaded := r.Outbound(detour); loaded { if outbound, loaded := r.Outbound(detour); loaded {
return outbound return outbound
} }
r.logger.WithContext(ctx).Error("outbound not found: ", detour) r.logger.ErrorContext(ctx, "outbound not found: ", detour)
} }
} }
return defaultOutbound return defaultOutbound
@ -493,17 +493,17 @@ func (r *Router) match(ctx context.Context, metadata adapter.InboundContext, def
func (r *Router) matchDNS(ctx context.Context) dns.Transport { func (r *Router) matchDNS(ctx context.Context) dns.Transport {
metadata := adapter.ContextFrom(ctx) metadata := adapter.ContextFrom(ctx)
if metadata == nil { if metadata == nil {
r.dnsLogger.WithContext(ctx).Warn("no context: ", reflect.TypeOf(ctx)) r.dnsLogger.WarnContext(ctx, "no context: ", reflect.TypeOf(ctx))
return r.defaultTransport return r.defaultTransport
} }
for i, rule := range r.dnsRules { for i, rule := range r.dnsRules {
if rule.Match(metadata) { if rule.Match(metadata) {
detour := rule.Outbound() detour := rule.Outbound()
r.dnsLogger.WithContext(ctx).Debug("match[", i, "] ", rule.String(), " => ", detour) r.dnsLogger.DebugContext(ctx, "match[", i, "] ", rule.String(), " => ", detour)
if transport, loaded := r.transportMap[detour]; loaded { if transport, loaded := r.transportMap[detour]; loaded {
return transport return transport
} }
r.dnsLogger.WithContext(ctx).Error("transport not found: ", detour) r.dnsLogger.ErrorContext(ctx, "transport not found: ", detour)
} }
} }
return r.defaultTransport return r.defaultTransport

View file

@ -12,7 +12,7 @@ import (
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
) )
func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (adapter.Rule, error) { func NewRule(router adapter.Router, logger log.ContextLogger, options option.Rule) (adapter.Rule, error) {
if common.IsEmptyByEquals(options) { if common.IsEmptyByEquals(options) {
return nil, E.New("empty rule config") return nil, E.New("empty rule config")
} }
@ -53,7 +53,7 @@ type RuleItem interface {
String() string String() string
} }
func NewDefaultRule(router adapter.Router, logger log.Logger, options option.DefaultRule) (*DefaultRule, error) { func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
rule := &DefaultRule{ rule := &DefaultRule{
outbound: options.Outbound, outbound: options.Outbound,
} }
@ -263,7 +263,7 @@ func (r *LogicalRule) Close() error {
return nil return nil
} }
func NewLogicalRule(router adapter.Router, logger log.Logger, options option.LogicalRule) (*LogicalRule, error) { func NewLogicalRule(router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
r := &LogicalRule{ r := &LogicalRule{
rules: make([]*DefaultRule, len(options.Rules)), rules: make([]*DefaultRule, len(options.Rules)),
outbound: options.Outbound, outbound: options.Outbound,

View file

@ -12,7 +12,7 @@ import (
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
) )
func NewDNSRule(router adapter.Router, logger log.Logger, options option.DNSRule) (adapter.Rule, error) { func NewDNSRule(router adapter.Router, logger log.ContextLogger, options option.DNSRule) (adapter.Rule, error) {
if common.IsEmptyByEquals(options) { if common.IsEmptyByEquals(options) {
return nil, E.New("empty rule config") return nil, E.New("empty rule config")
} }
@ -47,7 +47,7 @@ type DefaultDNSRule struct {
outbound string outbound string
} }
func NewDefaultDNSRule(router adapter.Router, logger log.Logger, options option.DefaultDNSRule) (*DefaultDNSRule, error) { func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
rule := &DefaultDNSRule{ rule := &DefaultDNSRule{
outbound: options.Server, outbound: options.Server,
} }
@ -224,7 +224,7 @@ func (r *LogicalDNSRule) Close() error {
return nil return nil
} }
func NewLogicalDNSRule(router adapter.Router, logger log.Logger, options option.LogicalDNSRule) (*LogicalDNSRule, error) { func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
r := &LogicalDNSRule{ r := &LogicalDNSRule{
rules: make([]*DefaultDNSRule, len(options.Rules)), rules: make([]*DefaultDNSRule, len(options.Rules)),
outbound: options.Server, outbound: options.Server,

View file

@ -11,13 +11,13 @@ var _ RuleItem = (*GeoIPItem)(nil)
type GeoIPItem struct { type GeoIPItem struct {
router adapter.Router router adapter.Router
logger log.Logger logger log.ContextLogger
isSource bool isSource bool
codes []string codes []string
codeMap map[string]bool codeMap map[string]bool
} }
func NewGeoIPItem(router adapter.Router, logger log.Logger, isSource bool, codes []string) *GeoIPItem { func NewGeoIPItem(router adapter.Router, logger log.ContextLogger, isSource bool, codes []string) *GeoIPItem {
codeMap := make(map[string]bool) codeMap := make(map[string]bool)
for _, code := range codes { for _, code := range codes {
codeMap[code] = true codeMap[code] = true

View file

@ -12,12 +12,12 @@ var _ RuleItem = (*GeositeItem)(nil)
type GeositeItem struct { type GeositeItem struct {
router adapter.Router router adapter.Router
logger log.Logger logger log.ContextLogger
codes []string codes []string
matchers []adapter.Rule matchers []adapter.Rule
} }
func NewGeositeItem(router adapter.Router, logger log.Logger, codes []string) *GeositeItem { func NewGeositeItem(router adapter.Router, logger log.ContextLogger, codes []string) *GeositeItem {
return &GeositeItem{ return &GeositeItem{
router: router, router: router,
logger: logger, logger: logger,

View file

@ -5,7 +5,7 @@ go 1.18
require ( require (
github.com/docker/docker v20.10.17+incompatible github.com/docker/docker v20.10.17+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61 github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91
github.com/sagernet/sing-box v0.0.0 github.com/sagernet/sing-box v0.0.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0

View file

@ -52,8 +52,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61 h1:sOx7t+MFssiCAY2afRHQSmkWZNpLQnjF0Hwv/TNVMvk= github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91 h1:fYsRChEViZHDvrOLp7fbswYCH3txaVyAl1zB0cnSNlc=
github.com/sagernet/sing v0.0.0-20220711103842-d3fb2260ef61/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= github.com/sagernet/sing v0.0.0-20220712060558-029ab1ce4f91/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619 h1:oHbOmq1WS0XaZmXp6WpxzyB2xeyRIA1/L8EJKuNntfY=
github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk= github.com/sagernet/sing-dns v0.0.0-20220711062726-c64e938e4619/go.mod h1:y2fpvoxukw3G7eApIZwkcpcG/NE4AB8pCQI0Qd8rMqk=
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k= github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=