github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/logger/console.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package logger 19 20 import ( 21 "encoding/json" 22 "fmt" 23 "os" 24 "strings" 25 "time" 26 27 "github.com/minio/minio/internal/color" 28 c "github.com/minio/pkg/v2/console" 29 "github.com/minio/pkg/v2/logger/message/log" 30 ) 31 32 // ConsoleLoggerTgt is a stringified value to represent console logging 33 const ConsoleLoggerTgt = "console+http" 34 35 // ExitFunc is called by Fatal() class functions, by default it calls os.Exit() 36 var ExitFunc = os.Exit 37 38 // Logger interface describes the methods that need to be implemented to satisfy the interface requirements. 39 type Logger interface { 40 json(msg string, args ...interface{}) 41 quiet(msg string, args ...interface{}) 42 pretty(msg string, args ...interface{}) 43 } 44 45 func consoleLog(console Logger, msg string, args ...interface{}) { 46 switch { 47 case jsonFlag: 48 // Strip escape control characters from json message 49 msg = ansiRE.ReplaceAllLiteralString(msg, "") 50 console.json(msg, args...) 51 case quietFlag: 52 if len(msg) != 0 && len(args) == 0 { 53 args = append(args, msg) 54 msg = "%s" 55 } 56 console.quiet(msg+"\n", args...) 57 default: 58 if len(msg) != 0 && len(args) == 0 { 59 args = append(args, msg) 60 msg = "%s" 61 } 62 console.pretty(msg+"\n", args...) 63 } 64 } 65 66 // Fatal prints only fatal error message with no stack trace 67 // it will be called for input validation failures 68 func Fatal(err error, msg string, data ...interface{}) { 69 fatal(err, msg, data...) 70 } 71 72 func fatal(err error, msg string, data ...interface{}) { 73 var errMsg string 74 if msg != "" { 75 errMsg = errorFmtFunc(fmt.Sprintf(msg, data...), err, jsonFlag) 76 } else { 77 errMsg = err.Error() 78 } 79 consoleLog(fatalMessage, errMsg) 80 } 81 82 var fatalMessage fatalMsg 83 84 type fatalMsg struct{} 85 86 func (f fatalMsg) json(msg string, args ...interface{}) { 87 var message string 88 if msg != "" { 89 message = fmt.Sprintf(msg, args...) 90 } else { 91 message = fmt.Sprint(args...) 92 } 93 logJSON, err := json.Marshal(&log.Entry{ 94 Level: FatalKind, 95 Message: message, 96 Time: time.Now().UTC(), 97 Trace: &log.Trace{Message: message, Source: []string{getSource(6)}}, 98 }) 99 if err != nil { 100 panic(err) 101 } 102 fmt.Println(string(logJSON)) 103 104 ExitFunc(1) 105 } 106 107 func (f fatalMsg) quiet(msg string, args ...interface{}) { 108 f.pretty(msg, args...) 109 } 110 111 var ( 112 logTag = "ERROR" 113 logBanner = color.BgRed(color.FgWhite(color.Bold(logTag))) + " " 114 emptyBanner = color.BgRed(strings.Repeat(" ", len(logTag))) + " " 115 bannerWidth = len(logTag) + 1 116 ) 117 118 func (f fatalMsg) pretty(msg string, args ...interface{}) { 119 // Build the passed error message 120 errMsg := fmt.Sprintf(msg, args...) 121 122 tagPrinted := false 123 124 // Print the error message: the following code takes care 125 // of splitting error text and always pretty printing the 126 // red banner along with the error message. Since the error 127 // message itself contains some colored text, we needed 128 // to use some ANSI control escapes to cursor color state 129 // and freely move in the screen. 130 for _, line := range strings.Split(errMsg, "\n") { 131 if len(line) == 0 { 132 // No more text to print, just quit. 133 break 134 } 135 136 for { 137 // Save the attributes of the current cursor helps 138 // us save the text color of the passed error message 139 ansiSaveAttributes() 140 // Print banner with or without the log tag 141 if !tagPrinted { 142 c.Print(logBanner) 143 tagPrinted = true 144 } else { 145 c.Print(emptyBanner) 146 } 147 // Restore the text color of the error message 148 ansiRestoreAttributes() 149 ansiMoveRight(bannerWidth) 150 // Continue error message printing 151 c.Println(line) 152 break 153 } 154 } 155 156 // Exit because this is a fatal error message 157 ExitFunc(1) 158 } 159 160 type infoMsg struct{} 161 162 var info infoMsg 163 164 func (i infoMsg) json(msg string, args ...interface{}) { 165 var message string 166 if msg != "" { 167 message = fmt.Sprintf(msg, args...) 168 } else { 169 message = fmt.Sprint(args...) 170 } 171 logJSON, err := json.Marshal(&log.Entry{ 172 Level: InfoKind, 173 Message: message, 174 Time: time.Now().UTC(), 175 }) 176 if err != nil { 177 panic(err) 178 } 179 fmt.Println(string(logJSON)) 180 } 181 182 func (i infoMsg) quiet(msg string, args ...interface{}) { 183 } 184 185 func (i infoMsg) pretty(msg string, args ...interface{}) { 186 if msg == "" { 187 c.Println(args...) 188 } 189 c.Printf(msg, args...) 190 } 191 192 type errorMsg struct{} 193 194 var errorm errorMsg 195 196 func (i errorMsg) json(msg string, args ...interface{}) { 197 var message string 198 if msg != "" { 199 message = fmt.Sprintf(msg, args...) 200 } else { 201 message = fmt.Sprint(args...) 202 } 203 logJSON, err := json.Marshal(&log.Entry{ 204 Level: ErrorKind, 205 Message: message, 206 Time: time.Now().UTC(), 207 Trace: &log.Trace{Message: message, Source: []string{getSource(6)}}, 208 }) 209 if err != nil { 210 panic(err) 211 } 212 fmt.Println(string(logJSON)) 213 } 214 215 func (i errorMsg) quiet(msg string, args ...interface{}) { 216 i.pretty(msg, args...) 217 } 218 219 func (i errorMsg) pretty(msg string, args ...interface{}) { 220 if msg == "" { 221 c.Println(args...) 222 } 223 c.Printf(msg, args...) 224 } 225 226 // Error : 227 func Error(msg string, data ...interface{}) { 228 if DisableErrorLog { 229 return 230 } 231 consoleLog(errorm, msg, data...) 232 } 233 234 // Info : 235 func Info(msg string, data ...interface{}) { 236 if DisableErrorLog { 237 return 238 } 239 consoleLog(info, msg, data...) 240 }