diff --git a/common/observable/iterable.go b/common/observable/iterable.go deleted file mode 100644 index 2ac38b40..00000000 --- a/common/observable/iterable.go +++ /dev/null @@ -1,3 +0,0 @@ -package observable - -type Iterable <-chan any diff --git a/common/observable/observable.go b/common/observable/observable.go deleted file mode 100644 index 5caaf690..00000000 --- a/common/observable/observable.go +++ /dev/null @@ -1,65 +0,0 @@ -package observable - -import ( - "errors" - "sync" -) - -type Observable struct { - iterable Iterable - listener map[Subscription]*Subscriber - mux sync.Mutex - done bool -} - -func (o *Observable) process() { - for item := range o.iterable { - o.mux.Lock() - for _, sub := range o.listener { - sub.Emit(item) - } - o.mux.Unlock() - } - o.close() -} - -func (o *Observable) close() { - o.mux.Lock() - defer o.mux.Unlock() - - o.done = true - for _, sub := range o.listener { - sub.Close() - } -} - -func (o *Observable) Subscribe() (Subscription, error) { - o.mux.Lock() - defer o.mux.Unlock() - if o.done { - return nil, errors.New("observable is closed") - } - subscriber := newSubscriber() - o.listener[subscriber.Out()] = subscriber - return subscriber.Out(), nil -} - -func (o *Observable) UnSubscribe(sub Subscription) { - o.mux.Lock() - defer o.mux.Unlock() - subscriber, exist := o.listener[sub] - if !exist { - return - } - delete(o.listener, sub) - subscriber.Close() -} - -func NewObservable(any Iterable) *Observable { - observable := &Observable{ - iterable: any, - listener: map[Subscription]*Subscriber{}, - } - go observable.process() - return observable -} diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go deleted file mode 100644 index f34b81fc..00000000 --- a/common/observable/observable_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package observable - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "go.uber.org/atomic" -) - -func iterator(item []any) chan any { - ch := make(chan any) - go func() { - time.Sleep(100 * time.Millisecond) - for _, elm := range item { - ch <- elm - } - close(ch) - }() - return ch -} - -func TestObservable(t *testing.T) { - iter := iterator([]any{1, 2, 3, 4, 5}) - src := NewObservable(iter) - data, err := src.Subscribe() - assert.Nil(t, err) - count := 0 - for range data { - count++ - } - assert.Equal(t, count, 5) -} - -func TestObservable_MultiSubscribe(t *testing.T) { - iter := iterator([]any{1, 2, 3, 4, 5}) - src := NewObservable(iter) - ch1, _ := src.Subscribe() - ch2, _ := src.Subscribe() - count := atomic.NewInt32(0) - - var wg sync.WaitGroup - wg.Add(2) - waitCh := func(ch <-chan any) { - for range ch { - count.Inc() - } - wg.Done() - } - go waitCh(ch1) - go waitCh(ch2) - wg.Wait() - assert.Equal(t, int32(10), count.Load()) -} - -func TestObservable_UnSubscribe(t *testing.T) { - iter := iterator([]any{1, 2, 3, 4, 5}) - src := NewObservable(iter) - data, err := src.Subscribe() - assert.Nil(t, err) - src.UnSubscribe(data) - _, open := <-data - assert.False(t, open) -} - -func TestObservable_SubscribeClosedSource(t *testing.T) { - iter := iterator([]any{1}) - src := NewObservable(iter) - data, _ := src.Subscribe() - <-data - - _, closed := src.Subscribe() - assert.NotNil(t, closed) -} - -func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) { - sub := Subscription(make(chan any)) - iter := iterator([]any{1}) - src := NewObservable(iter) - src.UnSubscribe(sub) -} - -func TestObservable_SubscribeGoroutineLeak(t *testing.T) { - iter := iterator([]any{1, 2, 3, 4, 5}) - src := NewObservable(iter) - max := 100 - - var list []Subscription - for i := 0; i < max; i++ { - ch, _ := src.Subscribe() - list = append(list, ch) - } - - var wg sync.WaitGroup - wg.Add(max) - waitCh := func(ch <-chan any) { - for range ch { - } - wg.Done() - } - - for _, ch := range list { - go waitCh(ch) - } - wg.Wait() - - for _, sub := range list { - _, more := <-sub - assert.False(t, more) - } - - if len(list) > 0 { - _, more := <-list[0] - assert.False(t, more) - } -} - -func Benchmark_Observable_1000(b *testing.B) { - ch := make(chan any) - o := NewObservable(ch) - num := 1000 - - var subs []Subscription - for i := 0; i < num; i++ { - sub, _ := o.Subscribe() - subs = append(subs, sub) - } - - wg := sync.WaitGroup{} - wg.Add(num) - - b.ResetTimer() - for _, sub := range subs { - go func(s Subscription) { - for range s { - } - wg.Done() - }(sub) - } - - for i := 0; i < b.N; i++ { - ch <- i - } - - close(ch) - wg.Wait() -} diff --git a/common/observable/subscriber.go b/common/observable/subscriber.go deleted file mode 100644 index 0d8559bc..00000000 --- a/common/observable/subscriber.go +++ /dev/null @@ -1,33 +0,0 @@ -package observable - -import ( - "sync" -) - -type Subscription <-chan any - -type Subscriber struct { - buffer chan any - once sync.Once -} - -func (s *Subscriber) Emit(item any) { - s.buffer <- item -} - -func (s *Subscriber) Out() Subscription { - return s.buffer -} - -func (s *Subscriber) Close() { - s.once.Do(func() { - close(s.buffer) - }) -} - -func newSubscriber() *Subscriber { - sub := &Subscriber{ - buffer: make(chan any, 200), - } - return sub -} diff --git a/engine/engine.go b/engine/engine.go index efabc870..f513fac3 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -109,7 +109,7 @@ func general(k *Key) error { if err != nil { return err } - log.SetLevel(level) + log.SetLogger(log.Must(log.NewLeveled(level))) if k.Interface != "" { iface, err := net.InterfaceByName(k.Interface) @@ -156,7 +156,7 @@ func restAPI(k *Key) error { go func() { if err := restapi.Start(host, token); err != nil { - log.Warnf("[RESTAPI] failed to start: %v", err) + log.Errorf("[RESTAPI] failed to start: %v", err) } }() log.Infof("[RESTAPI] serve at: %s", u) @@ -175,7 +175,7 @@ func netstack(k *Key) (err error) { if k.TUNPreUp != "" { log.Infof("[TUN] pre-execute command: `%s`", k.TUNPreUp) if preUpErr := execCommand(k.TUNPreUp); preUpErr != nil { - log.Warnf("[TUN] failed to pre-execute: %s: %v", k.TUNPreUp, preUpErr) + log.Errorf("[TUN] failed to pre-execute: %s: %v", k.TUNPreUp, preUpErr) } } @@ -185,7 +185,7 @@ func netstack(k *Key) (err error) { } log.Infof("[TUN] post-execute command: `%s`", k.TUNPostUp) if postUpErr := execCommand(k.TUNPostUp); postUpErr != nil { - log.Warnf("[TUN] failed to post-execute: %s: %v", k.TUNPostUp, postUpErr) + log.Errorf("[TUN] failed to post-execute: %s: %v", k.TUNPostUp, postUpErr) } }() diff --git a/go.mod b/go.mod index 56ab338a..c5cd0263 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,10 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/schema v1.4.1 github.com/gorilla/websocket v1.5.3 - github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 go.uber.org/atomic v1.11.0 go.uber.org/automaxprocs v1.5.3 + go.uber.org/zap v1.27.0 golang.org/x/crypto v0.25.0 golang.org/x/sys v0.22.0 golang.org/x/time v0.5.0 @@ -30,8 +30,8 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/btree v1.1.2 // indirect - github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.27.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect ) diff --git a/go.sum b/go.sum index f60ab0d1..3d3f523c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -32,21 +30,22 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -58,7 +57,6 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQX gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gvisor.dev/gvisor v0.0.0-20240713103206-39d6c232e61d h1:dFTIljP/5ReqgM7nMR4DauApFatUaSP8r9btX0sd8a8= diff --git a/log/doc.go b/log/doc.go new file mode 100644 index 00000000..bf4c305c --- /dev/null +++ b/log/doc.go @@ -0,0 +1,2 @@ +// Package log is a thin wrapper based on "go.uber.org/zap". +package log diff --git a/log/emitter.go b/log/emitter.go index bf10587e..8312edb1 100644 --- a/log/emitter.go +++ b/log/emitter.go @@ -1,7 +1,6 @@ package log import ( - "io" "runtime" "strings" "time" @@ -9,26 +8,30 @@ import ( glog "gvisor.dev/gvisor/pkg/log" ) +var _globalE = &emitter{} + func init() { - EnableStackLog(true) + glog.SetTarget(_globalE) } -func EnableStackLog(v bool) { - if v { - glog.SetTarget(&emitter{}) // built-in logger - } else { - glog.SetTarget(&glog.Writer{Next: io.Discard}) - } +type emitter struct { + logger *SugaredLogger } -type emitter struct{} +func (e *emitter) setLogger(logger *SugaredLogger) { + e.logger = logger.WithOptions(pkgCallerSkip) +} + +func (e *emitter) logf(level glog.Level, format string, args ...any) { + e.logger.Logf(1-Level(level), "[STACK] "+format, args...) +} -func (emitter) Emit(depth int, level glog.Level, _ time.Time, format string, args ...any) { +func (e *emitter) Emit(depth int, level glog.Level, _ time.Time, format string, args ...any) { if _, file, line, ok := runtime.Caller(depth + 1); ok { - // Ignore (*gonet.TCPConn).RemoteAddr() warning: `ep.GetRemoteAddress() failed`. - if line == 457 && strings.HasSuffix(file, "/pkg/tcpip/adapters/gonet/gonet.go") { + // Ignore: gvisor.dev/gvisor/pkg/tcpip/adapters/gonet/gonet.go:457 + if line == 457 && strings.HasSuffix(file, "gonet/gonet.go") { return } } - logf(Level(level)+2, "[STACK] "+format, args...) + e.logf(level, format, args...) } diff --git a/log/event.go b/log/event.go deleted file mode 100644 index d3fb68aa..00000000 --- a/log/event.go +++ /dev/null @@ -1,39 +0,0 @@ -package log - -import ( - "fmt" - "time" - - "github.com/xjasonlyu/tun2socks/v2/common/observable" -) - -var ( - _logCh = make(chan any) - _source = observable.NewObservable(_logCh) -) - -type Event struct { - Level Level `json:"level"` - Message string `json:"msg"` - Time time.Time `json:"time"` -} - -func newEvent(level Level, format string, args ...any) *Event { - event := &Event{ - Level: level, - Time: time.Now(), - Message: fmt.Sprintf(format, args...), - } - _logCh <- event /* send all events to logCh */ - - return event -} - -func Subscribe() observable.Subscription { - sub, _ := _source.Subscribe() - return sub -} - -func UnSubscribe(sub observable.Subscription) { - _source.UnSubscribe(sub) -} diff --git a/log/level.go b/log/level.go index 0b30949e..0123cdad 100644 --- a/log/level.go +++ b/log/level.go @@ -1,72 +1,31 @@ package log import ( - "encoding/json" - "fmt" - "strings" + "go.uber.org/zap/zapcore" ) -type Level uint32 +// Level is an alias for zapcore.Level. +type Level = zapcore.Level +// Levels are aliases for Level. const ( - SilentLevel Level = iota - ErrorLevel - WarnLevel - InfoLevel - DebugLevel + DebugLevel = zapcore.DebugLevel + InfoLevel = zapcore.InfoLevel + WarnLevel = zapcore.WarnLevel + ErrorLevel = zapcore.ErrorLevel + DPanicLevel = zapcore.DPanicLevel + PanicLevel = zapcore.PanicLevel + FatalLevel = zapcore.FatalLevel + InvalidLevel = zapcore.InvalidLevel + SilentLevel = InvalidLevel + 1 ) -// UnmarshalJSON deserialize Level with json -func (level *Level) UnmarshalJSON(data []byte) error { - var lvl string - if err := json.Unmarshal(data, &lvl); err != nil { - return err - } - - l, err := ParseLevel(lvl) - if err != nil { - return err - } - - *level = l - return nil -} - -// MarshalJSON serialize Level with json -func (level Level) MarshalJSON() ([]byte, error) { - return json.Marshal(level.String()) -} - -func (level Level) String() string { - switch level { - case DebugLevel: - return "debug" - case InfoLevel: - return "info" - case WarnLevel: - return "warning" - case ErrorLevel: - return "error" - case SilentLevel: - return "silent" - default: - return fmt.Sprintf("not a valid level %d", level) - } -} - -func ParseLevel(lvl string) (Level, error) { - switch strings.ToLower(lvl) { - case "silent": +// ParseLevel is a thin wrapper for zapcore.ParseLevel. +func ParseLevel(text string) (Level, error) { + switch text { + case "silent", "SILENT": return SilentLevel, nil - case "error": - return ErrorLevel, nil - case "warning": - return WarnLevel, nil - case "info": - return InfoLevel, nil - case "debug": - return DebugLevel, nil default: - return Level(0), fmt.Errorf("not a valid logrus Level: %q", lvl) + return zapcore.ParseLevel(text) } } diff --git a/log/log.go b/log/log.go index f1336328..9b44fa31 100644 --- a/log/log.go +++ b/log/log.go @@ -1,63 +1,71 @@ package log import ( - "io" - "os" + "fmt" + "sync" - "github.com/sirupsen/logrus" - "go.uber.org/atomic" + "go.uber.org/zap" ) -// _defaultLevel is package default logging level. -var _defaultLevel = atomic.NewUint32(uint32(InfoLevel)) +// global Logger and SugaredLogger. +var ( + _globalMu sync.RWMutex + _globalL *Logger + _globalS *SugaredLogger +) func init() { - logrus.SetOutput(os.Stdout) - logrus.SetLevel(logrus.DebugLevel) + SetLogger(zap.Must(zap.NewProduction())) } -func SetOutput(out io.Writer) { - logrus.SetOutput(out) +func NewLeveled(l Level, options ...Option) (*Logger, error) { + switch l { + case SilentLevel: + return zap.NewNop(), nil + case DebugLevel: + return zap.NewDevelopment(options...) + case InfoLevel, WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, FatalLevel: + cfg := zap.NewProductionConfig() + cfg.Level.SetLevel(l) + return cfg.Build(options...) + default: + return nil, fmt.Errorf("invalid level: %s", l) + } } -func SetLevel(level Level) { - _defaultLevel.Store(uint32(level)) +// SetLogger sets the global Logger and SugaredLogger. +func SetLogger(logger *Logger) { + _globalMu.Lock() + defer _globalMu.Unlock() + // apply pkgCallerSkip to global loggers. + _globalL = logger.WithOptions(pkgCallerSkip) + _globalS = _globalL.Sugar() + _globalE.setLogger(_globalS) } -func Debugf(format string, args ...any) { - logf(DebugLevel, format, args...) +func logf(lvl Level, template string, args ...any) { + _globalMu.RLock() + s := _globalS + _globalMu.RUnlock() + s.Logf(lvl, template, args...) } -func Infof(format string, args ...any) { - logf(InfoLevel, format, args...) +func Debugf(template string, args ...any) { + logf(DebugLevel, template, args...) } -func Warnf(format string, args ...any) { - logf(WarnLevel, format, args...) +func Infof(template string, args ...any) { + logf(InfoLevel, template, args...) } -func Errorf(format string, args ...any) { - logf(ErrorLevel, format, args...) +func Warnf(template string, args ...any) { + logf(WarnLevel, template, args...) } -func Fatalf(format string, args ...any) { - logrus.Fatalf(format, args...) +func Errorf(template string, args ...any) { + logf(ErrorLevel, template, args...) } -func logf(level Level, format string, args ...any) { - event := newEvent(level, format, args...) - if uint32(event.Level) > _defaultLevel.Load() { - return - } - - switch level { - case DebugLevel: - logrus.WithTime(event.Time).Debugln(event.Message) - case InfoLevel: - logrus.WithTime(event.Time).Infoln(event.Message) - case WarnLevel: - logrus.WithTime(event.Time).Warnln(event.Message) - case ErrorLevel: - logrus.WithTime(event.Time).Errorln(event.Message) - } +func Fatalf(template string, args ...any) { + logf(FatalLevel, template, args...) } diff --git a/log/zap.go b/log/zap.go new file mode 100644 index 00000000..efab1b6e --- /dev/null +++ b/log/zap.go @@ -0,0 +1,22 @@ +package log + +import ( + "go.uber.org/zap" +) + +// Must is an alias for zap.Must. +var Must = zap.Must + +// logger aliases for zap.Logger and zap.SugaredLogger. +type ( + Logger = zap.Logger + SugaredLogger = zap.SugaredLogger +) + +type ( + // Option is an alias for zap.Option. + Option = zap.Option +) + +// pkgCallerSkip skips the pkg wrapper code as the caller. +var pkgCallerSkip = zap.AddCallerSkip(2) diff --git a/main.go b/main.go index a7c08e4c..201c396d 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ func init() { flag.StringVar(&configFile, "config", "", "YAML format configuration file") flag.StringVar(&key.Device, "device", "", "Use this device [driver://]name") flag.StringVar(&key.Interface, "interface", "", "Use network INTERFACE (Linux/MacOS only)") - flag.StringVar(&key.LogLevel, "loglevel", "info", "Log level [debug|info|warning|error|silent]") + flag.StringVar(&key.LogLevel, "loglevel", "info", "Log level [debug|info|warn|error|silent]") flag.StringVar(&key.Proxy, "proxy", "", "Use this proxy [protocol://]host[:port]") flag.StringVar(&key.RestAPI, "restapi", "", "HTTP statistic server listen address") flag.StringVar(&key.TCPSendBufferSize, "tcp-sndbuf", "", "Set TCP send buffer size for netstack") diff --git a/restapi/connections.go b/restapi/connections.go index b8c9c336..6e98215f 100644 --- a/restapi/connections.go +++ b/restapi/connections.go @@ -17,7 +17,7 @@ import ( const defaultInterval = 1000 func init() { - registerMountPoint("/connections", connectionRouter()) + registerEndpoint("/connections", connectionRouter()) } func connectionRouter() http.Handler { diff --git a/restapi/debug.go b/restapi/debug.go index 8a3e780a..7ac02858 100644 --- a/restapi/debug.go +++ b/restapi/debug.go @@ -10,7 +10,7 @@ import ( ) func init() { - registerMountPoint("/debug/pprof/", pprofRouter()) + registerEndpoint("/debug/pprof/", pprofRouter()) } func pprofRouter() http.Handler { diff --git a/restapi/netstats.go b/restapi/netstats.go index e62d9bf8..13dd6870 100644 --- a/restapi/netstats.go +++ b/restapi/netstats.go @@ -19,7 +19,7 @@ func SetStatsFunc(s func() tcpip.Stats) { } func init() { - registerMountPoint("/netstats", http.HandlerFunc(getNetStats)) + registerEndpoint("/netstats", http.HandlerFunc(getNetStats)) } func getNetStats(w http.ResponseWriter, r *http.Request) { diff --git a/restapi/server.go b/restapi/server.go index b55462a4..fdd9b41c 100644 --- a/restapi/server.go +++ b/restapi/server.go @@ -14,7 +14,6 @@ import ( "github.com/gorilla/websocket" V "github.com/xjasonlyu/tun2socks/v2/internal/version" - "github.com/xjasonlyu/tun2socks/v2/log" "github.com/xjasonlyu/tun2socks/v2/tunnel/statistic" ) @@ -25,11 +24,11 @@ var ( }, } - _mountPoints = make(map[string]http.Handler) + _endpoints = make(map[string]http.Handler) ) -func registerMountPoint(pattern string, handler http.Handler) { - _mountPoints[pattern] = handler +func registerEndpoint(pattern string, handler http.Handler) { + _endpoints[pattern] = handler } func Start(addr, token string) error { @@ -46,11 +45,10 @@ func Start(addr, token string) error { r.Group(func(r chi.Router) { r.Use(authenticator(token)) r.Get("/", hello) - r.Get("/logs", getLogs) r.Get("/traffic", traffic) r.Get("/version", version) // attach HTTP handlers - for pattern, handler := range _mountPoints { + for pattern, handler := range _endpoints { r.Mount(pattern, handler) } }) @@ -103,61 +101,6 @@ func authenticator(token string) func(http.Handler) http.Handler { } } -func getLogs(w http.ResponseWriter, r *http.Request) { - lvl := r.URL.Query().Get("level") - if lvl == "" { - lvl = "info" /* default */ - } - - level, err := log.ParseLevel(lvl) - if err != nil { - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, ErrBadRequest) - return - } - - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { - wsConn, err = _upgrader.Upgrade(w, r, nil) - if err != nil { - return - } - } - - if wsConn == nil { - w.Header().Set("Content-Type", "application/json") - render.Status(r, http.StatusOK) - } - - sub := log.Subscribe() - defer log.UnSubscribe(sub) - - buf := &bytes.Buffer{} - for elm := range sub { - buf.Reset() - - e := elm.(*log.Event) - if e.Level > level { - continue - } - - if err = json.NewEncoder(buf).Encode(e); err != nil { - break - } - - if wsConn == nil { - _, err = w.Write(buf.Bytes()) - w.(http.Flusher).Flush() - } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) - } - - if err != nil { - break - } - } -} - func traffic(w http.ResponseWriter, r *http.Request) { var ( err error