github.com/vmware/transport-go@v1.3.4/plank/utils/logger.go (about) 1 // Copyright 2019-2021 VMware, Inc. 2 // SPDX-License-Identifier: BSD-2-Clause 3 4 package utils 5 6 import ( 7 "github.com/sirupsen/logrus" 8 "io" 9 "os" 10 "path" 11 ) 12 13 var Log *PlankLogger 14 15 type LogConfig struct { 16 AccessLog string `json:"access_log"` 17 ErrorLog string `json:"error_log"` 18 OutputLog string `json:"output_log"` 19 FormatOptions *LogFormatOption `json:"format_options"` 20 Root string `json:"root"` 21 accessLogFp io.Writer `json:"-"` 22 errorLogFp io.Writer `json:"-"` 23 outputLogFp io.Writer `json:"-"` 24 } 25 26 // LogFormatOption is merely a wrapper of logrus.TextFormatter because TextFormatter does not allow serializing 27 // its public members of the struct 28 type LogFormatOption struct { 29 // Set to true to bypass checking for a TTY before outputting colors. 30 ForceColors bool `json:"force_colors"` 31 32 // Force disabling colors. 33 DisableColors bool `json:"disable_colors"` 34 35 // Force quoting of all values 36 ForceQuote bool `json:"force_quote"` 37 38 // DisableQuote disables quoting for all values. 39 // DisableQuote will have a lower priority than ForceQuote. 40 // If both of them are set to true, quote will be forced on all values. 41 DisableQuote bool `json:"disable_quote"` 42 43 // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ 44 EnvironmentOverrideColors bool `json:"environment_override_colors"` 45 46 // Disable timestamp logging. useful when output is redirected to logging 47 // system that already adds timestamps. 48 DisableTimestamp bool `json:"disable_timestamp"` 49 50 // Enable logging the full timestamp when a TTY is attached instead of just 51 // the time passed since beginning of execution. 52 FullTimestamp bool `json:"full_timestamp"` 53 54 // TimestampFormat to use for display when a full timestamp is printed 55 TimestampFormat string `json:"timestamp_format"` 56 57 // The fields are sorted by default for a consistent output. For applications 58 // that log extremely frequently and don't use the JSON formatter this may not 59 // be desired. 60 DisableSorting bool `json:"disable_sorting"` 61 62 // Disables the truncation of the level text to 4 characters. 63 DisableLevelTruncation bool `json:"disable_level_truncation"` 64 65 // PadLevelText Adds padding the level text so that all the levels output at the same length 66 // PadLevelText is a superset of the DisableLevelTruncation option 67 PadLevelText bool `json:"pad_level_text"` 68 69 // QuoteEmptyFields will wrap empty fields in quotes if true 70 QuoteEmptyFields bool `json:"quote_empty_fields"` 71 72 // Whether the logger's out is to a terminal 73 isTerminal bool `json:"is_terminal"` 74 75 // FieldMap allows users to customize the names of keys for default fields. 76 // As an example: 77 // formatter := &TextFormatter{ 78 // FieldMap: FieldMap{ 79 // FieldKeyTime: "@timestamp", 80 // FieldKeyLevel: "@level", 81 // FieldKeyMsg: "@message"}} 82 FieldMap logrus.FieldMap 83 } 84 85 func (lc *LogConfig) PrepareLogFiles() error { 86 var fp io.Writer 87 var err error 88 if fp, err = lc.prepareLogFilePointer(lc.AccessLog); err != nil { 89 return err 90 } 91 lc.accessLogFp = fp 92 93 if fp, err = lc.prepareLogFilePointer(lc.ErrorLog); err != nil { 94 return err 95 } 96 lc.errorLogFp = fp 97 98 if fp, err = lc.prepareLogFilePointer(lc.OutputLog); err != nil { 99 return err 100 } 101 lc.outputLogFp = fp 102 103 return nil 104 } 105 106 func (lc *LogConfig) GetAccessLogFilePointer() io.Writer { 107 return lc.accessLogFp 108 } 109 110 func (lc *LogConfig) GetErrorLogFilePointer() io.Writer { 111 return lc.errorLogFp 112 } 113 114 func (lc *LogConfig) GetPlatformLogFilePointer() io.Writer { 115 return lc.outputLogFp 116 } 117 118 func (lc *LogConfig) prepareLogFilePointer(target string) (fp io.Writer, err error) { 119 if target == "stdout" { 120 fp = os.Stdout 121 } else if target == "stderr" { 122 fp = os.Stderr 123 } else if target == "null" { 124 fp = &noopWriter{} 125 } else { 126 logFilePath := JoinBasePathIfRelativeRegularFilePath(lc.Root, target) 127 fp, err = GetNewLogFilePointer(logFilePath) 128 } 129 return 130 } 131 132 type PlankLogger struct { 133 *logrus.Logger 134 } 135 136 func (l *PlankLogger) setCommonFields() *logrus.Entry { 137 fr := getFrame(2) 138 pkgName := path.Base(path.Dir(fr.File)) 139 fileName := path.Base(fr.File) 140 return l.WithFields(logrus.Fields{ 141 "goroutine": GetGoRoutineID(), 142 "package": pkgName, 143 "fileName": fileName, 144 }) 145 } 146 147 func (l *PlankLogger) Trace(args ...interface{}) { 148 l.setCommonFields().Trace(args...) 149 } 150 151 func (l *PlankLogger) Traceln(args ...interface{}) { 152 l.setCommonFields().Traceln(args...) 153 } 154 155 func (l *PlankLogger) Tracef(format string, args ...interface{}) { 156 l.setCommonFields().Tracef(format, args...) 157 } 158 159 func (l *PlankLogger) Debug(args ...interface{}) { 160 l.setCommonFields().Debug(args...) 161 } 162 163 func (l *PlankLogger) Debugln(args ...interface{}) { 164 l.setCommonFields().Debugln(args...) 165 } 166 167 func (l *PlankLogger) Debugf(format string, args ...interface{}) { 168 l.setCommonFields().Debugf(format, args...) 169 } 170 171 func (l *PlankLogger) Info(args ...interface{}) { 172 l.setCommonFields().Info(args...) 173 } 174 175 func (l *PlankLogger) Infoln(args ...interface{}) { 176 l.setCommonFields().Infoln(args...) 177 } 178 179 func (l *PlankLogger) Infof(format string, args ...interface{}) { 180 l.setCommonFields().Infof(format, args...) 181 } 182 183 func (l *PlankLogger) Warn(args ...interface{}) { 184 l.setCommonFields().Warn(args...) 185 } 186 187 func (l *PlankLogger) Warnln(args ...interface{}) { 188 l.setCommonFields().Warnln(args...) 189 } 190 191 func (l *PlankLogger) Warnf(format string, args ...interface{}) { 192 l.setCommonFields().Warnf(format, args...) 193 } 194 195 func (l *PlankLogger) Error(args ...interface{}) { 196 l.setCommonFields().Error(args...) 197 } 198 199 func (l *PlankLogger) Errorln(args ...interface{}) { 200 l.setCommonFields().Errorln(args...) 201 } 202 203 func (l *PlankLogger) Errorf(format string, args ...interface{}) { 204 l.setCommonFields().Errorf(format, args...) 205 } 206 207 func (l *PlankLogger) Panic(args ...interface{}) { 208 l.setCommonFields().Panic(args...) 209 } 210 211 func (l *PlankLogger) Panicln(args ...interface{}) { 212 l.setCommonFields().Panicln(args...) 213 } 214 215 func (l *PlankLogger) Panicf(format string, args ...interface{}) { 216 l.setCommonFields().Panicf(format, args...) 217 } 218 219 // noopWriter does absolutely nothing and return immediately. for references 220 // to those who wonder why this is here then in the first place, this is so 221 // this no-op writer instance can be passed as an access logger to not bother 222 // logging HTTP access logs which may not be necessary for some applications 223 // that want as lowest IO bottlenecks as possible. 224 type noopWriter struct{} 225 226 func (noopWriter *noopWriter) Write(p []byte) (n int, err error) { 227 return 0, nil 228 } 229 230 func init() { 231 Log = &PlankLogger{logrus.New()} 232 } 233 234 // CreateTextFormatterFromFormatOptions takes *server.LogFormatOption and returns 235 // the pointer to a new logrus.TextFormatter instance. 236 func CreateTextFormatterFromFormatOptions(opts *LogFormatOption) *logrus.TextFormatter { 237 return &logrus.TextFormatter{ 238 ForceColors: opts.ForceColors, 239 DisableColors: opts.DisableColors, 240 ForceQuote: opts.ForceQuote, 241 DisableQuote: opts.DisableQuote, 242 EnvironmentOverrideColors: opts.EnvironmentOverrideColors, 243 DisableTimestamp: opts.DisableTimestamp, 244 FullTimestamp: opts.FullTimestamp, 245 TimestampFormat: opts.TimestampFormat, 246 DisableSorting: opts.DisableSorting, 247 DisableLevelTruncation: opts.DisableLevelTruncation, 248 PadLevelText: opts.PadLevelText, 249 QuoteEmptyFields: opts.QuoteEmptyFields, 250 FieldMap: opts.FieldMap, 251 } 252 } 253 254 // GetNewLogFilePointer returns the pointer to a new os.File instance given the file name 255 func GetNewLogFilePointer(file string) (*os.File, error) { 256 return os.OpenFile(file, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600) 257 }