github.com/sagernet/sing-box@v1.9.0-rc.20/log/format.go (about) 1 package log 2 3 import ( 4 "context" 5 "strconv" 6 "strings" 7 "time" 8 9 F "github.com/sagernet/sing/common/format" 10 11 "github.com/logrusorgru/aurora" 12 ) 13 14 type Formatter struct { 15 BaseTime time.Time 16 DisableColors bool 17 DisableTimestamp bool 18 FullTimestamp bool 19 TimestampFormat string 20 DisableLineBreak bool 21 } 22 23 func (f Formatter) Format(ctx context.Context, level Level, tag string, message string, timestamp time.Time) string { 24 levelString := strings.ToUpper(FormatLevel(level)) 25 if !f.DisableColors { 26 switch level { 27 case LevelDebug, LevelTrace: 28 levelString = aurora.White(levelString).String() 29 case LevelInfo: 30 levelString = aurora.Cyan(levelString).String() 31 case LevelWarn: 32 levelString = aurora.Yellow(levelString).String() 33 case LevelError, LevelFatal, LevelPanic: 34 levelString = aurora.Red(levelString).String() 35 } 36 } 37 if tag != "" { 38 message = tag + ": " + message 39 } 40 var id ID 41 var hasId bool 42 if ctx != nil { 43 id, hasId = IDFromContext(ctx) 44 } 45 if hasId { 46 activeDuration := formatDuration(time.Since(id.CreatedAt)) 47 if !f.DisableColors { 48 var color aurora.Color 49 color = aurora.Color(uint8(id.ID)) 50 color %= 215 51 row := uint(color / 36) 52 column := uint(color % 36) 53 54 var r, g, b float32 55 r = float32(row * 51) 56 g = float32(column / 6 * 51) 57 b = float32((column % 6) * 51) 58 luma := 0.2126*r + 0.7152*g + 0.0722*b 59 if luma < 60 { 60 row = 5 - row 61 column = 35 - column 62 color = aurora.Color(row*36 + column) 63 } 64 color += 16 65 color = color << 16 66 color |= 1 << 14 67 message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message) 68 } else { 69 message = F.ToString("[", id.ID, " ", activeDuration, "] ", message) 70 } 71 } 72 switch { 73 case f.DisableTimestamp: 74 message = levelString + " " + message 75 case f.FullTimestamp: 76 message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message 77 default: 78 message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message 79 } 80 if f.DisableLineBreak { 81 if message[len(message)-1] == '\n' { 82 message = message[:len(message)-1] 83 } 84 } else { 85 if message[len(message)-1] != '\n' { 86 message += "\n" 87 } 88 } 89 return message 90 } 91 92 func (f Formatter) FormatWithSimple(ctx context.Context, level Level, tag string, message string, timestamp time.Time) (string, string) { 93 levelString := strings.ToUpper(FormatLevel(level)) 94 if !f.DisableColors { 95 switch level { 96 case LevelDebug, LevelTrace: 97 levelString = aurora.White(levelString).String() 98 case LevelInfo: 99 levelString = aurora.Cyan(levelString).String() 100 case LevelWarn: 101 levelString = aurora.Yellow(levelString).String() 102 case LevelError, LevelFatal, LevelPanic: 103 levelString = aurora.Red(levelString).String() 104 } 105 } 106 if tag != "" { 107 message = tag + ": " + message 108 } 109 messageSimple := message 110 var id ID 111 var hasId bool 112 if ctx != nil { 113 id, hasId = IDFromContext(ctx) 114 } 115 if hasId { 116 activeDuration := formatDuration(time.Since(id.CreatedAt)) 117 if !f.DisableColors { 118 var color aurora.Color 119 color = aurora.Color(uint8(id.ID)) 120 color %= 215 121 row := uint(color / 36) 122 column := uint(color % 36) 123 124 var r, g, b float32 125 r = float32(row * 51) 126 g = float32(column / 6 * 51) 127 b = float32((column % 6) * 51) 128 luma := 0.2126*r + 0.7152*g + 0.0722*b 129 if luma < 60 { 130 row = 5 - row 131 column = 35 - column 132 color = aurora.Color(row*36 + column) 133 } 134 color += 16 135 color = color << 16 136 color |= 1 << 14 137 message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message) 138 } else { 139 message = F.ToString("[", id.ID, " ", activeDuration, "] ", message) 140 } 141 messageSimple = F.ToString("[", id.ID, " ", activeDuration, "] ", messageSimple) 142 143 } 144 switch { 145 case f.DisableTimestamp: 146 message = levelString + " " + message 147 case f.FullTimestamp: 148 message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message 149 default: 150 message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message 151 } 152 if message[len(message)-1] != '\n' { 153 message += "\n" 154 } 155 return message, messageSimple 156 } 157 158 func xd(value int, x int) string { 159 message := strconv.Itoa(value) 160 for len(message) < x { 161 message = "0" + message 162 } 163 return message 164 } 165 166 func formatDuration(duration time.Duration) string { 167 if duration < time.Second { 168 return F.ToString(duration.Milliseconds(), "ms") 169 } else if duration < time.Minute { 170 return F.ToString(int64(duration.Seconds()), ".", int64(duration.Seconds()*100)%100, "s") 171 } else { 172 return F.ToString(int64(duration.Minutes()), "m", int64(duration.Seconds())%60, "s") 173 } 174 }