github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/logger/logger.go (about) 1 // Copyright 2021 The TrueBlocks Authors. All rights reserved. 2 // Use of this source code is governed by a license that can 3 // be found in the LICENSE file. 4 5 package logger 6 7 import ( 8 "fmt" 9 "io" 10 "math" 11 "os" 12 "strings" 13 "time" 14 15 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors" 16 "golang.org/x/term" 17 ) 18 19 type severity int 20 21 const ( 22 progress severity = iota 23 infoC // colored table 24 info 25 test 26 warning 27 err 28 ) 29 30 var severityToLabel = map[severity]string{ 31 progress: "PROG", 32 infoC: "INFO", 33 info: "INFO", 34 test: "TEST", 35 warning: "WARN", 36 err: "EROR", 37 } 38 39 var ( 40 testModeSet = false 41 testMode = false 42 ) 43 44 func SetTestMode(onOff bool) { 45 testMode = onOff 46 testModeSet = true 47 } 48 49 // TestLog is used to print log lines during testing only 50 func TestLog(notDefault bool, a ...interface{}) { 51 if !testModeSet { 52 testModeSet = true 53 testMode = os.Getenv("TEST_MODE") == "true" 54 } 55 56 if !testMode { 57 return 58 } 59 60 if notDefault { 61 toLog(test, a...) 62 } 63 } 64 65 var ( 66 isTestMode = false 67 timingModeSet = false 68 timingMode = true 69 decorationOff = false 70 ) 71 72 func LogTimerOn() bool { 73 return timingMode 74 } 75 76 func ToggleDecoration() { 77 decorationOff = !decorationOff 78 } 79 80 var loggerWriter io.Writer = nil 81 82 func init() { 83 if !timingModeSet { 84 on := os.Getenv("TB_LOGTIMER_OFF") == "" 85 isTestMode = os.Getenv("TEST_MODE") == "true" 86 timingMode = on && !isTestMode 87 timingModeSet = true 88 } 89 loggerWriter = os.Stderr 90 } 91 92 // SetLoggerWriter sets the writer to which log messages are written. Do not send 93 // nil as a writer if you wish to disable logging. Instead, use 94 // 95 // w := logger.GetLoggerWriter() 96 // defer logger.SetLoggerWriter(w) 97 // logger.SetLoggerWriter(io.Discard) 98 // 99 // Setting to `nil` will core dump. 100 func SetLoggerWriter(w io.Writer) { 101 loggerWriter = w 102 } 103 104 func GetLoggerWriter() io.Writer { 105 return loggerWriter 106 } 107 108 // toLog prints `a` to stderr with a label corresponding to the severity level 109 // prepended (e.g. <INFO>, <EROR>, etc.) 110 func toLog(sev severity, a ...interface{}) { 111 if loggerWriter == nil { 112 return 113 } 114 115 timeDatePart := "DATE|TIME" 116 if timingMode { 117 now := time.Now() 118 timeDatePart = now.Format("02-01|15:04:05.000") 119 } 120 121 if !decorationOff { 122 fmt.Fprintf(loggerWriter, "%s[%s] ", severityToLabel[sev], timeDatePart) 123 } 124 if sev == progress { 125 for index, aa := range a { 126 if index > 0 { 127 fmt.Fprint(loggerWriter, " ") 128 } 129 fmt.Fprint(loggerWriter, aa) 130 } 131 fmt.Fprint(loggerWriter, "\r") 132 133 } else if sev == infoC { 134 fmt.Fprintf(loggerWriter, "%s%s%s ", colors.Green, a[0], colors.Off) 135 for _, aa := range a[1:] { 136 fmt.Fprintf(loggerWriter, "%s", aa) 137 } 138 fmt.Fprintln(loggerWriter, "") 139 140 } else if sev == warning { 141 defer fmt.Fprint(loggerWriter, colors.Off) 142 fmt.Fprint(loggerWriter, colors.Yellow) 143 fmt.Fprintln(loggerWriter, a...) 144 145 } else if sev == err { 146 defer fmt.Fprint(loggerWriter, colors.Off) 147 fmt.Fprint(loggerWriter, colors.Red) 148 fmt.Fprintln(loggerWriter, a...) 149 150 } else { 151 fmt.Fprintln(loggerWriter, a...) 152 } 153 } 154 155 func InfoTable(v ...any) { 156 toLog(infoC, v...) 157 } 158 159 func Info(v ...any) { 160 toLog(info, v...) 161 } 162 163 func Warn(v ...any) { 164 toLog(warning, v...) 165 } 166 167 func Error(v ...any) { 168 toLog(err, v...) 169 } 170 171 func Fatal(v ...any) { 172 toLog(err, v...) 173 os.Exit(1) 174 } 175 176 func Panic(v ...any) { 177 s := fmt.Sprint(v...) 178 toLog(err, s) 179 panic(s) 180 } 181 182 func CleanLine() { 183 // \033[K is escape sequence meaning "erase to end of line" 184 fmt.Print("\r\033[K") 185 } 186 187 func PctProgress(done int32, total int, tick int32) { 188 if done%tick != 0 { 189 return 190 } 191 192 percentage := math.Round(float64(done) / float64(total) * 100) 193 toLog(progress, fmt.Sprintf("\r\t\t\t Processing: %.f%% (%d of %d)%s", percentage, done, total, strings.Repeat(" ", 40))) 194 } 195 196 func Progress(tick bool, v ...any) { 197 if isTestMode || !tick { 198 return 199 } 200 toLog(progress, v...) 201 } 202 203 func IsTerminal() bool { 204 return term.IsTerminal(int(os.Stdout.Fd())) 205 }