Forráskód Böngészése

Refine log output

世界 3 éve
szülő
commit
13f41f59d6
5 módosított fájl, 159 hozzáadás és 55 törlés
  1. 53 0
      cmd/sing-box/cmd_run.go
  2. 13 51
      cmd/sing-box/main.go
  3. 5 1
      log/logrus.go
  4. 83 0
      log/logrus_text_formatter.go
  5. 5 3
      option/config.go

+ 53 - 0
cmd/sing-box/cmd_run.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"context"
+	"os"
+	"os/signal"
+	"syscall"
+
+	"github.com/goccy/go-json"
+	"github.com/sagernet/sing-box"
+	"github.com/sagernet/sing-box/option"
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+)
+
+var commandRun = &cobra.Command{
+	Use:   "run",
+	Short: "run service",
+	Run:   run,
+}
+
+func run(cmd *cobra.Command, args []string) {
+	configContent, err := os.ReadFile(configPath)
+	if err != nil {
+		logrus.Fatal("read config: ", err)
+	}
+	var options option.Options
+	err = json.Unmarshal(configContent, &options)
+	if err != nil {
+		logrus.Fatal("decode config: ", err)
+	}
+	if disableColor {
+		if options.Log == nil {
+			options.Log = &option.LogOption{}
+		}
+		options.Log.DisableColor = true
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	service, err := box.NewService(ctx, options)
+	if err != nil {
+		logrus.Fatal("create service: ", err)
+	}
+	err = service.Start()
+	if err != nil {
+		logrus.Fatal("start service: ", err)
+	}
+	osSignals := make(chan os.Signal, 1)
+	signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)
+	<-osSignals
+	cancel()
+	service.Close()
+}

+ 13 - 51
cmd/sing-box/main.go

@@ -1,83 +1,45 @@
 package main
 
 import (
-	"context"
 	"os"
-	"os/signal"
-	"syscall"
 
-	"github.com/goccy/go-json"
-	"github.com/sagernet/sing-box"
-	"github.com/sagernet/sing-box/option"
+	"github.com/sagernet/sing-box/log"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 )
 
 func init() {
 	logrus.StandardLogger().SetLevel(logrus.TraceLevel)
-	logrus.StandardLogger().Formatter.(*logrus.TextFormatter).ForceColors = true
+	logrus.StandardLogger().SetFormatter(&log.LogrusTextFormatter{})
 }
 
 var (
 	configPath   string
 	workingDir   string
-	formatConfig bool
+	disableColor bool
 )
 
 func main() {
 	command := &cobra.Command{
-		Use: "sing-box",
-		Run: run,
+		Use:              "sing-box",
+		PersistentPreRun: preRun,
 	}
-	command.Flags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path")
-	command.Flags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
-	command.Flags().BoolVarP(&formatConfig, "format", "f", false, "print formatted configuration file")
+	command.PersistentFlags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path")
+	command.PersistentFlags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
+	command.PersistentFlags().BoolVarP(&disableColor, "disable-color", "", false, "disable color output")
+	command.AddCommand(commandRun)
 	if err := command.Execute(); err != nil {
 		logrus.Fatal(err)
 	}
 }
 
-func run(cmd *cobra.Command, args []string) {
+func preRun(cmd *cobra.Command, args []string) {
+	if disableColor {
+		logrus.StandardLogger().SetFormatter(&log.LogrusTextFormatter{DisableColors: true})
+	}
 	if workingDir != "" {
 		if err := os.Chdir(workingDir); err != nil {
 			logrus.Fatal(err)
 		}
 	}
-
-	configContent, err := os.ReadFile(configPath)
-	if err != nil {
-		logrus.Fatal("read config: ", err)
-	}
-	var options option.Options
-	err = json.Unmarshal(configContent, &options)
-	if err != nil {
-		logrus.Fatal("decode config: ", err)
-	}
-
-	ctx, cancel := context.WithCancel(context.Background())
-	service, err := box.NewService(ctx, options)
-	if err != nil {
-		logrus.Fatal("create service: ", err)
-	}
-
-	if formatConfig {
-		cancel()
-		encoder := json.NewEncoder(os.Stdout)
-		encoder.SetIndent("", "  ")
-		err = encoder.Encode(options)
-		if err != nil {
-			logrus.Fatal("encode config: ", err)
-		}
-		return
-	}
-
-	err = service.Start()
-	if err != nil {
-		logrus.Fatal("start service: ", err)
-	}
-	osSignals := make(chan os.Signal, 1)
-	signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)
-	<-osSignals
-	cancel()
-	service.Close()
 }

+ 5 - 1
log/logrus.go

@@ -27,7 +27,11 @@ type abstractLogrusLogger interface {
 func NewLogrusLogger(options option.LogOption) (*logrusLogger, error) {
 	logger := logrus.New()
 	logger.SetLevel(logrus.TraceLevel)
-	logger.Formatter.(*logrus.TextFormatter).ForceColors = true
+	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 != "" {

+ 83 - 0
log/logrus_text_formatter.go

@@ -0,0 +1,83 @@
+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)
+		}
+	}
+}

+ 5 - 3
option/config.go

@@ -30,7 +30,9 @@ func (o Options) Equals(other Options) bool {
 }
 
 type LogOption struct {
-	Disabled bool   `json:"disabled,omitempty"`
-	Level    string `json:"level,omitempty"`
-	Output   string `json:"output,omitempty"`
+	Disabled     bool   `json:"disabled,omitempty"`
+	Level        string `json:"level,omitempty"`
+	Output       string `json:"output,omitempty"`
+	Timestamp    bool   `json:"timestamp,omitempty"`
+	DisableColor bool   `json:"-"`
 }