...

Source file src/google.golang.org/grpc/grpclog/loggerv2.go

Documentation: google.golang.org/grpc/grpclog

     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 ...any)
    37  	// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
    38  	Infoln(args ...any)
    39  	// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
    40  	Infof(format string, args ...any)
    41  	// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
    42  	Warning(args ...any)
    43  	// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
    44  	Warningln(args ...any)
    45  	// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
    46  	Warningf(format string, args ...any)
    47  	// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
    48  	Error(args ...any)
    49  	// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
    50  	Errorln(args ...any)
    51  	// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
    52  	Errorf(format string, args ...any)
    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 ...any)
    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 ...any)
    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 ...any)
    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 ...any) {
   186  	g.output(infoLog, fmt.Sprint(args...))
   187  }
   188  
   189  func (g *loggerT) Infoln(args ...any) {
   190  	g.output(infoLog, fmt.Sprintln(args...))
   191  }
   192  
   193  func (g *loggerT) Infof(format string, args ...any) {
   194  	g.output(infoLog, fmt.Sprintf(format, args...))
   195  }
   196  
   197  func (g *loggerT) Warning(args ...any) {
   198  	g.output(warningLog, fmt.Sprint(args...))
   199  }
   200  
   201  func (g *loggerT) Warningln(args ...any) {
   202  	g.output(warningLog, fmt.Sprintln(args...))
   203  }
   204  
   205  func (g *loggerT) Warningf(format string, args ...any) {
   206  	g.output(warningLog, fmt.Sprintf(format, args...))
   207  }
   208  
   209  func (g *loggerT) Error(args ...any) {
   210  	g.output(errorLog, fmt.Sprint(args...))
   211  }
   212  
   213  func (g *loggerT) Errorln(args ...any) {
   214  	g.output(errorLog, fmt.Sprintln(args...))
   215  }
   216  
   217  func (g *loggerT) Errorf(format string, args ...any) {
   218  	g.output(errorLog, fmt.Sprintf(format, args...))
   219  }
   220  
   221  func (g *loggerT) Fatal(args ...any) {
   222  	g.output(fatalLog, fmt.Sprint(args...))
   223  	os.Exit(1)
   224  }
   225  
   226  func (g *loggerT) Fatalln(args ...any) {
   227  	g.output(fatalLog, fmt.Sprintln(args...))
   228  	os.Exit(1)
   229  }
   230  
   231  func (g *loggerT) Fatalf(format string, args ...any) {
   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 ...any)
   252  	// WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println.
   253  	WarningDepth(depth int, args ...any)
   254  	// ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println.
   255  	ErrorDepth(depth int, args ...any)
   256  	// FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println.
   257  	FatalDepth(depth int, args ...any)
   258  }
   259  

View as plain text