loggerv2.go (8331B)
1 /* 2 * 3 * Copyright 2017 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package grpclog 20 21 import ( 22 "encoding/json" 23 "fmt" 24 "io" 25 "log" 26 "os" 27 "strconv" 28 "strings" 29 30 "google.golang.org/grpc/internal/grpclog" 31 ) 32 33 // LoggerV2 does underlying logging work for grpclog. 34 type LoggerV2 interface { 35 // Info logs to INFO log. Arguments are handled in the manner of fmt.Print. 36 Info(args ...interface{}) 37 // Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println. 38 Infoln(args ...interface{}) 39 // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. 40 Infof(format string, args ...interface{}) 41 // Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print. 42 Warning(args ...interface{}) 43 // Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println. 44 Warningln(args ...interface{}) 45 // Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. 46 Warningf(format string, args ...interface{}) 47 // Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. 48 Error(args ...interface{}) 49 // Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println. 50 Errorln(args ...interface{}) 51 // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. 52 Errorf(format string, args ...interface{}) 53 // Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print. 54 // gRPC ensures that all Fatal logs will exit with os.Exit(1). 55 // Implementations may also call os.Exit() with a non-zero exit code. 56 Fatal(args ...interface{}) 57 // Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println. 58 // gRPC ensures that all Fatal logs will exit with os.Exit(1). 59 // Implementations may also call os.Exit() with a non-zero exit code. 60 Fatalln(args ...interface{}) 61 // Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. 62 // gRPC ensures that all Fatal logs will exit with os.Exit(1). 63 // Implementations may also call os.Exit() with a non-zero exit code. 64 Fatalf(format string, args ...interface{}) 65 // V reports whether verbosity level l is at least the requested verbose level. 66 V(l int) bool 67 } 68 69 // SetLoggerV2 sets logger that is used in grpc to a V2 logger. 70 // Not mutex-protected, should be called before any gRPC functions. 71 func SetLoggerV2(l LoggerV2) { 72 if _, ok := l.(*componentData); ok { 73 panic("cannot use component logger as grpclog logger") 74 } 75 grpclog.Logger = l 76 grpclog.DepthLogger, _ = l.(grpclog.DepthLoggerV2) 77 } 78 79 const ( 80 // infoLog indicates Info severity. 81 infoLog int = iota 82 // warningLog indicates Warning severity. 83 warningLog 84 // errorLog indicates Error severity. 85 errorLog 86 // fatalLog indicates Fatal severity. 87 fatalLog 88 ) 89 90 // severityName contains the string representation of each severity. 91 var severityName = []string{ 92 infoLog: "INFO", 93 warningLog: "WARNING", 94 errorLog: "ERROR", 95 fatalLog: "FATAL", 96 } 97 98 // loggerT is the default logger used by grpclog. 99 type loggerT struct { 100 m []*log.Logger 101 v int 102 jsonFormat bool 103 } 104 105 // NewLoggerV2 creates a loggerV2 with the provided writers. 106 // Fatal logs will be written to errorW, warningW, infoW, followed by exit(1). 107 // Error logs will be written to errorW, warningW and infoW. 108 // Warning logs will be written to warningW and infoW. 109 // Info logs will be written to infoW. 110 func NewLoggerV2(infoW, warningW, errorW io.Writer) LoggerV2 { 111 return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{}) 112 } 113 114 // NewLoggerV2WithVerbosity creates a loggerV2 with the provided writers and 115 // verbosity level. 116 func NewLoggerV2WithVerbosity(infoW, warningW, errorW io.Writer, v int) LoggerV2 { 117 return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{verbose: v}) 118 } 119 120 type loggerV2Config struct { 121 verbose int 122 jsonFormat bool 123 } 124 125 func newLoggerV2WithConfig(infoW, warningW, errorW io.Writer, c loggerV2Config) LoggerV2 { 126 var m []*log.Logger 127 flag := log.LstdFlags 128 if c.jsonFormat { 129 flag = 0 130 } 131 m = append(m, log.New(infoW, "", flag)) 132 m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag)) 133 ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal. 134 m = append(m, log.New(ew, "", flag)) 135 m = append(m, log.New(ew, "", flag)) 136 return &loggerT{m: m, v: c.verbose, jsonFormat: c.jsonFormat} 137 } 138 139 // newLoggerV2 creates a loggerV2 to be used as default logger. 140 // All logs are written to stderr. 141 func newLoggerV2() LoggerV2 { 142 errorW := io.Discard 143 warningW := io.Discard 144 infoW := io.Discard 145 146 logLevel := os.Getenv("GRPC_GO_LOG_SEVERITY_LEVEL") 147 switch logLevel { 148 case "", "ERROR", "error": // If env is unset, set level to ERROR. 149 errorW = os.Stderr 150 case "WARNING", "warning": 151 warningW = os.Stderr 152 case "INFO", "info": 153 infoW = os.Stderr 154 } 155 156 var v int 157 vLevel := os.Getenv("GRPC_GO_LOG_VERBOSITY_LEVEL") 158 if vl, err := strconv.Atoi(vLevel); err == nil { 159 v = vl 160 } 161 162 jsonFormat := strings.EqualFold(os.Getenv("GRPC_GO_LOG_FORMATTER"), "json") 163 164 return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{ 165 verbose: v, 166 jsonFormat: jsonFormat, 167 }) 168 } 169 170 func (g *loggerT) output(severity int, s string) { 171 sevStr := severityName[severity] 172 if !g.jsonFormat { 173 g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s)) 174 return 175 } 176 // TODO: we can also include the logging component, but that needs more 177 // (API) changes. 178 b, _ := json.Marshal(map[string]string{ 179 "severity": sevStr, 180 "message": s, 181 }) 182 g.m[severity].Output(2, string(b)) 183 } 184 185 func (g *loggerT) Info(args ...interface{}) { 186 g.output(infoLog, fmt.Sprint(args...)) 187 } 188 189 func (g *loggerT) Infoln(args ...interface{}) { 190 g.output(infoLog, fmt.Sprintln(args...)) 191 } 192 193 func (g *loggerT) Infof(format string, args ...interface{}) { 194 g.output(infoLog, fmt.Sprintf(format, args...)) 195 } 196 197 func (g *loggerT) Warning(args ...interface{}) { 198 g.output(warningLog, fmt.Sprint(args...)) 199 } 200 201 func (g *loggerT) Warningln(args ...interface{}) { 202 g.output(warningLog, fmt.Sprintln(args...)) 203 } 204 205 func (g *loggerT) Warningf(format string, args ...interface{}) { 206 g.output(warningLog, fmt.Sprintf(format, args...)) 207 } 208 209 func (g *loggerT) Error(args ...interface{}) { 210 g.output(errorLog, fmt.Sprint(args...)) 211 } 212 213 func (g *loggerT) Errorln(args ...interface{}) { 214 g.output(errorLog, fmt.Sprintln(args...)) 215 } 216 217 func (g *loggerT) Errorf(format string, args ...interface{}) { 218 g.output(errorLog, fmt.Sprintf(format, args...)) 219 } 220 221 func (g *loggerT) Fatal(args ...interface{}) { 222 g.output(fatalLog, fmt.Sprint(args...)) 223 os.Exit(1) 224 } 225 226 func (g *loggerT) Fatalln(args ...interface{}) { 227 g.output(fatalLog, fmt.Sprintln(args...)) 228 os.Exit(1) 229 } 230 231 func (g *loggerT) Fatalf(format string, args ...interface{}) { 232 g.output(fatalLog, fmt.Sprintf(format, args...)) 233 os.Exit(1) 234 } 235 236 func (g *loggerT) V(l int) bool { 237 return l <= g.v 238 } 239 240 // DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements 241 // DepthLoggerV2, the below functions will be called with the appropriate stack 242 // depth set for trivial functions the logger may ignore. 243 // 244 // # Experimental 245 // 246 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 247 // later release. 248 type DepthLoggerV2 interface { 249 LoggerV2 250 // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. 251 InfoDepth(depth int, args ...interface{}) 252 // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. 253 WarningDepth(depth int, args ...interface{}) 254 // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. 255 ErrorDepth(depth int, args ...interface{}) 256 // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. 257 FatalDepth(depth int, args ...interface{}) 258 }