github.com/sagernet/sing-box@v1.2.7/log/log.go (about) 1 package log 2 3 import ( 4 "io" 5 "os" 6 "time" 7 8 C "github.com/sagernet/sing-box/constant" 9 "github.com/sagernet/sing-box/option" 10 "github.com/sagernet/sing/common" 11 E "github.com/sagernet/sing/common/exceptions" 12 ) 13 14 type factoryWithFile struct { 15 Factory 16 file *os.File 17 } 18 19 func (f *factoryWithFile) Close() error { 20 return common.Close( 21 f.Factory, 22 common.PtrOrNil(f.file), 23 ) 24 } 25 26 type observableFactoryWithFile struct { 27 ObservableFactory 28 file *os.File 29 } 30 31 func (f *observableFactoryWithFile) Close() error { 32 return common.Close( 33 f.ObservableFactory, 34 common.PtrOrNil(f.file), 35 ) 36 } 37 38 type Options struct { 39 Options option.LogOptions 40 Observable bool 41 DefaultWriter io.Writer 42 BaseTime time.Time 43 PlatformWriter io.Writer 44 } 45 46 func New(options Options) (Factory, error) { 47 logOptions := options.Options 48 49 if logOptions.Disabled { 50 return NewNOPFactory(), nil 51 } 52 53 var logFile *os.File 54 var logWriter io.Writer 55 56 switch logOptions.Output { 57 case "": 58 logWriter = options.DefaultWriter 59 if logWriter == nil { 60 logWriter = os.Stderr 61 } 62 case "stderr": 63 logWriter = os.Stderr 64 case "stdout": 65 logWriter = os.Stdout 66 default: 67 var err error 68 logFile, err = os.OpenFile(C.BasePath(logOptions.Output), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) 69 if err != nil { 70 return nil, err 71 } 72 logWriter = logFile 73 } 74 logFormatter := Formatter{ 75 BaseTime: options.BaseTime, 76 DisableColors: logOptions.DisableColor || logFile != nil, 77 DisableTimestamp: !logOptions.Timestamp && logFile != nil, 78 FullTimestamp: logOptions.Timestamp, 79 TimestampFormat: "-0700 2006-01-02 15:04:05", 80 } 81 var factory Factory 82 if options.Observable { 83 factory = NewObservableFactory(logFormatter, logWriter, options.PlatformWriter) 84 } else { 85 factory = NewFactory(logFormatter, logWriter, options.PlatformWriter) 86 } 87 if logOptions.Level != "" { 88 logLevel, err := ParseLevel(logOptions.Level) 89 if err != nil { 90 return nil, E.Cause(err, "parse log level") 91 } 92 factory.SetLevel(logLevel) 93 } else { 94 factory.SetLevel(LevelTrace) 95 } 96 if logFile != nil { 97 if options.Observable { 98 factory = &observableFactoryWithFile{ 99 ObservableFactory: factory.(ObservableFactory), 100 file: logFile, 101 } 102 } else { 103 factory = &factoryWithFile{ 104 Factory: factory, 105 file: logFile, 106 } 107 } 108 } 109 return factory, nil 110 }