knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/test/logging/logging.go (about) 1 /* 2 Copyright 2018 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // logging.go contains the logic to configure and interact with the 18 // logging and metrics libraries. 19 20 package logging 21 22 import ( 23 "context" 24 "flag" 25 "os" 26 "strconv" 27 "sync" 28 29 "go.opentelemetry.io/otel" 30 "go.opentelemetry.io/otel/trace" 31 "go.uber.org/zap" 32 "go.uber.org/zap/zapcore" 33 "k8s.io/klog/v2" 34 ) 35 36 var tracer = otel.GetTracerProvider().Tracer("knative.dev/pkg/test/logging") 37 38 // FormatLogger is a printf style function for logging in tests. 39 type FormatLogger func(template string, args ...interface{}) 40 41 // GetEmitableSpan starts and returns a trace.Span with a name that 42 // is used by the ExportSpan method to emit the span. 43 // 44 //nolint:spancheck 45 func GetEmitableSpan(ctx context.Context, metricName string) trace.Span { 46 _, span := tracer.Start(ctx, metricName) 47 return span 48 } 49 50 const ( 51 logrZapDebugLevel = 3 52 ) 53 54 func zapLevelFromLogrLevel(logrLevel int) zapcore.Level { 55 // Zap levels are -1, 0, 1, 2,... corresponding to DebugLevel, InfoLevel, WarnLevel, ErrorLevel,... 56 // zapr library just does zapLevel := -1*logrLevel; which means: 57 // 1. Info level is only active at 0 (versus 2 in klog being generally equivalent to Info) 58 // 2. Only verbosity of 0 and 1 map to valid Zap levels 59 // According to https://github.com/uber-go/zap/issues/713 custom levels (i.e. < -1) aren't guaranteed to work, so not using them (for now). 60 61 l := zap.InfoLevel 62 if logrLevel >= logrZapDebugLevel { 63 l = zap.DebugLevel 64 } 65 66 return l 67 } 68 69 func printFlags() { 70 var flagList []interface{} 71 flag.CommandLine.VisitAll(func(f *flag.Flag) { 72 flagList = append(flagList, f.Name, f.Value.String()) 73 }) 74 logger.Sugar().Debugw("Test Flags", flagList...) 75 } 76 77 var ( 78 zapCore zapcore.Core 79 logger *zap.Logger 80 verbosity int // Amount of log verbosity 81 loggerInitializeOnce = &sync.Once{} 82 ) 83 84 // InitializeLogger initializes logging for Knative tests. 85 // It should be called prior to executing tests but after command-line flags have been processed. 86 // It is recommended doing it in the TestMain() function. 87 func InitializeLogger() { 88 loggerInitializeOnce.Do(func() { 89 humanEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()) 90 91 // Output streams 92 // TODO(coryrc): also open a log file if in Prow? 93 stdOut := zapcore.Lock(os.Stdout) 94 95 // Level function helper 96 zapLevel := zapLevelFromLogrLevel(verbosity) 97 isPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 98 return lvl >= zapLevel 99 }) 100 101 // Assemble the output streams 102 zapCore = zapcore.NewTee( 103 // TODO(coryrc): log JSON output somewhere? 104 zapcore.NewCore(humanEncoder, stdOut, isPriority), 105 ) 106 107 logger = zap.New(zapCore) 108 zap.ReplaceGlobals(logger) // Gets used by klog/glog proxy libraries 109 110 // Set klog/glog verbosities (works with and without proxy libraries) 111 klogLevel := klog.Level(0) 112 klogLevel.Set(strconv.Itoa(verbosity)) 113 114 if verbosity > 2 { 115 printFlags() 116 } 117 }) 118 } 119 120 func init() { 121 flag.IntVar(&verbosity, "verbosity", 2, 122 "Amount of verbosity, 0-10. See https://github.com/go-logr/logr#how-do-i-choose-my-v-levels and https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md") 123 }