github.com/yaling888/clash@v1.53.0/log/log.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "os" 6 "sync" 7 "time" 8 _ "unsafe" 9 10 logger "github.com/phuslu/log" 11 12 "github.com/yaling888/clash/common/observable" 13 ) 14 15 var ( 16 textCh = make(chan Event) 17 jsonCh = make(chan Event) 18 textSource = observable.NewObservable[Event](textCh) 19 jsonSource = observable.NewObservable[Event](jsonCh) 20 21 level = INFO 22 tracing = false 23 enabledText = false 24 enabledJson = false 25 26 bbPool = sync.Pool{ 27 New: func() any { 28 return new(bb) 29 }, 30 } 31 ) 32 33 func init() { 34 var ( 35 timeFormat = time.RFC3339 36 colorOutput = false 37 ) 38 if logger.IsTerminal(os.Stdout.Fd()) { 39 timeFormat = "15:04:05" 40 colorOutput = true 41 } 42 43 logger.DefaultLogger = logger.Logger{ 44 Level: logger.DebugLevel, 45 TimeFormat: timeFormat, 46 // Caller: 1, 47 Writer: &multiWriter{ 48 textWriter: &logger.IOWriter{Writer: &apiWriter{isJson: false}}, 49 jsonWriter: &logger.IOWriter{Writer: &apiWriter{isJson: true}}, 50 consoleWriter: &logger.ConsoleWriter{ColorOutput: colorOutput, Writer: os.Stdout}, 51 consoleLevel: logger.InfoLevel, 52 }, 53 } 54 } 55 56 func SubscribeText() observable.Subscription[Event] { 57 sub, _ := textSource.Subscribe() 58 enabledText = true 59 logger.DefaultLogger.SetLevel(logger.DebugLevel) 60 return sub 61 } 62 63 func UnSubscribeText(sub observable.Subscription[Event]) { 64 textSource.UnSubscribe(sub) 65 if !textSource.HasSubscriber() { 66 enabledText = false 67 if !jsonSource.HasSubscriber() { 68 logger.DefaultLogger.SetLevel(logger.DefaultLogger.Writer.(*multiWriter).consoleLevel) 69 } 70 } 71 } 72 73 func SubscribeJson() observable.Subscription[Event] { 74 sub, _ := jsonSource.Subscribe() 75 enabledJson = true 76 logger.DefaultLogger.SetLevel(logger.DebugLevel) 77 return sub 78 } 79 80 func UnSubscribeJson(sub observable.Subscription[Event]) { 81 jsonSource.UnSubscribe(sub) 82 if !jsonSource.HasSubscriber() { 83 enabledJson = false 84 if !textSource.HasSubscriber() { 85 logger.DefaultLogger.SetLevel(logger.DefaultLogger.Writer.(*multiWriter).consoleLevel) 86 } 87 } 88 } 89 90 func Level() LogLevel { 91 return level 92 } 93 94 func SetTracing(t bool) { 95 tracing = t 96 } 97 98 type Event struct { 99 LogLevel LogLevel 100 Payload string 101 } 102 103 func (e *Event) Type() string { 104 return e.LogLevel.String() 105 } 106 107 type bb struct { 108 B []byte 109 } 110 111 type apiWriter struct { 112 isJson bool 113 } 114 115 func (aw *apiWriter) Write(p []byte) (n int, err error) { 116 b := bbPool.Get().(*bb) 117 b.B = b.B[:0] 118 defer bbPool.Put(b) 119 120 b.B = append(b.B, p...) 121 122 var ( 123 args logger.FormatterArgs 124 logLevel LogLevel 125 ) 126 127 parseFormatterArgs(b.B, &args) 128 129 switch args.Level { 130 case "debug": 131 logLevel = DEBUG 132 case "info": 133 logLevel = INFO 134 case "warn": 135 logLevel = WARNING 136 case "error": 137 logLevel = ERROR 138 case "fatal": 139 logLevel = FATAL 140 default: 141 logLevel = SILENT 142 } 143 144 if aw.isJson { 145 formatJson(logLevel, p) 146 } else { 147 formatText(logLevel, &args) 148 } 149 return 150 } 151 152 type multiWriter struct { 153 textWriter *logger.IOWriter 154 jsonWriter *logger.IOWriter 155 consoleWriter *logger.ConsoleWriter 156 consoleLevel logger.Level 157 } 158 159 func (mw *multiWriter) Close() (err error) { 160 return mw.consoleWriter.Close() 161 } 162 163 func (mw *multiWriter) WriteEntry(entry *logger.Entry) (n int, err error) { 164 if tracing { 165 if enabledText { 166 _, _ = mw.textWriter.WriteEntry(entry) 167 } 168 if enabledJson { 169 _, _ = mw.jsonWriter.WriteEntry(entry) 170 } 171 } 172 173 if entry.Level >= mw.consoleLevel { 174 _, _ = mw.consoleWriter.WriteEntry(entry) 175 } 176 return 177 } 178 179 func formatText(logLevel LogLevel, args *logger.FormatterArgs) { 180 b := bbPool.Get().(*bb) 181 b.B = b.B[:0] 182 defer bbPool.Put(b) 183 184 b.B = fmt.Appendf(b.B, " %s", args.Message) 185 186 for _, kv := range args.KeyValues { 187 b.B = fmt.Appendf(b.B, " %s=%s", kv.Key, kv.Value) 188 } 189 190 event := Event{ 191 LogLevel: logLevel, 192 Payload: string(b.B), 193 } 194 195 textCh <- event 196 } 197 198 func formatJson(logLevel LogLevel, p []byte) { 199 event := Event{ 200 LogLevel: logLevel, 201 Payload: string(p), 202 } 203 204 jsonCh <- event 205 } 206 207 //go:linkname parseFormatterArgs github.com/phuslu/log.parseFormatterArgs 208 func parseFormatterArgs(_ []byte, _ *logger.FormatterArgs)