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