github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/grpcutil/log.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package grpcutil
    12  
    13  import (
    14  	"context"
    15  	"math"
    16  	"regexp"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/util/log"
    21  	"github.com/cockroachdb/cockroach/pkg/util/syncutil"
    22  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    23  	"github.com/petermattis/goid"
    24  	"google.golang.org/grpc/grpclog"
    25  )
    26  
    27  func init() {
    28  	SetSeverity(log.Severity_ERROR)
    29  }
    30  
    31  // SetSeverity sets the severity level below which GRPC log messages are
    32  // suppressed.
    33  //
    34  // Must be called before GRPC is used.
    35  func SetSeverity(s log.Severity) {
    36  	grpclog.SetLoggerV2((*logger)(&s))
    37  }
    38  
    39  // NB: This interface is implemented by a pointer because using a value causes
    40  // a synthetic stack frame to be inserted on calls to the interface methods.
    41  // Specifically, we get a stack frame that appears as "<autogenerated>", which
    42  // is not useful in logs.
    43  //
    44  // Also NB: we pass a depth of 2 here because all logging calls originate from
    45  // the logging adapter file in grpc, which is an additional stack frame away
    46  // from the actual logging site.
    47  var _ grpclog.LoggerV2 = (*logger)(nil)
    48  
    49  type logger log.Severity
    50  
    51  func (severity *logger) Info(args ...interface{}) {
    52  	if log.Severity(*severity) > log.Severity_INFO {
    53  		return
    54  	}
    55  	log.InfofDepth(context.TODO(), 2, "", args...)
    56  }
    57  
    58  func (severity *logger) Infoln(args ...interface{}) {
    59  	if log.Severity(*severity) > log.Severity_INFO {
    60  		return
    61  	}
    62  	log.InfofDepth(context.TODO(), 2, "", args...)
    63  }
    64  
    65  func (severity *logger) Infof(format string, args ...interface{}) {
    66  	if log.Severity(*severity) > log.Severity_INFO {
    67  		return
    68  	}
    69  	log.InfofDepth(context.TODO(), 2, format, args...)
    70  }
    71  
    72  func (severity *logger) Warning(args ...interface{}) {
    73  	if log.Severity(*severity) > log.Severity_WARNING {
    74  		return
    75  	}
    76  	log.WarningfDepth(context.TODO(), 2, "", args...)
    77  }
    78  
    79  func (severity *logger) Warningln(args ...interface{}) {
    80  	if log.Severity(*severity) > log.Severity_WARNING {
    81  		return
    82  	}
    83  	log.WarningfDepth(context.TODO(), 2, "", args...)
    84  }
    85  
    86  func (severity *logger) Warningf(format string, args ...interface{}) {
    87  	if log.Severity(*severity) > log.Severity_WARNING {
    88  		return
    89  	}
    90  	if shouldPrint(transportFailedRe, connectionRefusedRe, time.Minute, format, args...) {
    91  		log.WarningfDepth(context.TODO(), 2, format, args...)
    92  	}
    93  }
    94  
    95  func (severity *logger) Error(args ...interface{}) {
    96  	if log.Severity(*severity) > log.Severity_ERROR {
    97  		return
    98  	}
    99  	log.ErrorfDepth(context.TODO(), 2, "", args...)
   100  }
   101  
   102  func (severity *logger) Errorln(args ...interface{}) {
   103  	if log.Severity(*severity) > log.Severity_ERROR {
   104  		return
   105  	}
   106  	log.ErrorfDepth(context.TODO(), 2, "", args...)
   107  }
   108  
   109  func (severity *logger) Errorf(format string, args ...interface{}) {
   110  	if log.Severity(*severity) > log.Severity_ERROR {
   111  		return
   112  	}
   113  	log.ErrorfDepth(context.TODO(), 2, format, args...)
   114  }
   115  
   116  func (severity *logger) Fatal(args ...interface{}) {
   117  	if log.Severity(*severity) > log.Severity_NONE {
   118  		return
   119  	}
   120  	log.FatalfDepth(context.TODO(), 2, "", args...)
   121  }
   122  
   123  func (severity *logger) Fatalln(args ...interface{}) {
   124  	if log.Severity(*severity) > log.Severity_NONE {
   125  		return
   126  	}
   127  	log.FatalfDepth(context.TODO(), 2, "", args...)
   128  }
   129  
   130  func (severity *logger) Fatalf(format string, args ...interface{}) {
   131  	if log.Severity(*severity) > log.Severity_NONE {
   132  		return
   133  	}
   134  	log.FatalfDepth(context.TODO(), 2, format, args...)
   135  }
   136  
   137  func (severity *logger) V(i int) bool {
   138  	if i < 0 {
   139  		i = 0
   140  	}
   141  	if i > math.MaxInt32 {
   142  		i = math.MaxInt32
   143  	}
   144  	return log.VDepth(log.Level(i) /* level */, 1 /* depth */)
   145  }
   146  
   147  // https://github.com/grpc/grpc-go/blob/v1.7.0/clientconn.go#L937
   148  var (
   149  	transportFailedRe   = regexp.MustCompile("^" + regexp.QuoteMeta("grpc: addrConn.resetTransport failed to create client transport:"))
   150  	connectionRefusedRe = regexp.MustCompile(
   151  		strings.Join([]string{
   152  			// *nix
   153  			regexp.QuoteMeta("connection refused"),
   154  			// Windows
   155  			regexp.QuoteMeta("No connection could be made because the target machine actively refused it"),
   156  			// Host removed from the network and no longer resolvable:
   157  			// https://github.com/golang/go/blob/go1.8.3/src/net/net.go#L566
   158  			regexp.QuoteMeta("no such host"),
   159  		}, "|"),
   160  	)
   161  )
   162  
   163  var spamMu = struct {
   164  	syncutil.Mutex
   165  	gids map[int64]time.Time
   166  }{
   167  	gids: make(map[int64]time.Time),
   168  }
   169  
   170  func shouldPrint(
   171  	formatRe, argsRe *regexp.Regexp, freq time.Duration, format string, args ...interface{},
   172  ) bool {
   173  	if formatRe.MatchString(format) {
   174  		for _, arg := range args {
   175  			if err, ok := arg.(error); ok {
   176  				if argsRe.MatchString(err.Error()) {
   177  					gid := goid.Get()
   178  					now := timeutil.Now()
   179  					spamMu.Lock()
   180  					t, ok := spamMu.gids[gid]
   181  					doPrint := !(ok && now.Sub(t) < freq)
   182  					if doPrint {
   183  						spamMu.gids[gid] = now
   184  					}
   185  					spamMu.Unlock()
   186  					return doPrint
   187  				}
   188  			}
   189  		}
   190  	}
   191  	return true
   192  }