...

Source file src/k8s.io/kubernetes/test/e2e/framework/ginkgologger.go

Documentation: k8s.io/kubernetes/test/e2e/framework

     1  /*
     2  Copyright 2015 The Kubernetes 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  // Package framework contains provider-independent helper code for
    18  // building and running E2E tests with Ginkgo. The actual Ginkgo test
    19  // suites gets assembled by combining this framework, the optional
    20  // provider support code and specific tests via a separate .go file
    21  // like Kubernetes' test/e2e.go.
    22  package framework
    23  
    24  import (
    25  	"flag"
    26  	"fmt"
    27  	"os"
    28  	"strings"
    29  	"time"
    30  
    31  	"github.com/onsi/ginkgo/v2"
    32  	ginkgotypes "github.com/onsi/ginkgo/v2/types"
    33  
    34  	"k8s.io/klog/v2"
    35  	"k8s.io/klog/v2/textlogger"
    36  
    37  	_ "k8s.io/component-base/logs/testinit" // Ensure command line flags are registered.
    38  )
    39  
    40  var (
    41  	logConfig = textlogger.NewConfig(
    42  		textlogger.Output(ginkgo.GinkgoWriter),
    43  		textlogger.Backtrace(unwind),
    44  	)
    45  	ginkgoLogger = textlogger.NewLogger(logConfig)
    46  	TimeNow      = time.Now    // Can be stubbed out for testing.
    47  	Pid          = os.Getpid() // Can be stubbed out for testing.
    48  )
    49  
    50  func init() {
    51  	// ktesting and testinit already registered the -v and -vmodule
    52  	// command line flags. To configure the textlogger and klog
    53  	// consistently, we need to intercept the Set call. This
    54  	// can be done by swapping out the flag.Value for the -v and
    55  	// -vmodule flags with a wrapper which calls both.
    56  	var fs flag.FlagSet
    57  	logConfig.AddFlags(&fs)
    58  	fs.VisitAll(func(loggerFlag *flag.Flag) {
    59  		klogFlag := flag.CommandLine.Lookup(loggerFlag.Name)
    60  		if klogFlag != nil {
    61  			klogFlag.Value = &valueChain{Value: loggerFlag.Value, parentValue: klogFlag.Value}
    62  		}
    63  	})
    64  
    65  	// Now install the textlogger as the klog default logger.
    66  	// Calls like klog.Info then will write to ginkgo.GingoWriter
    67  	// through the textlogger.
    68  	//
    69  	// However, stack unwinding is then still being done by klog and thus
    70  	// ignores ginkgo.GingkoHelper. Tests should use framework.Logf or
    71  	// structured, contextual logging.
    72  	writer, _ := ginkgoLogger.GetSink().(textlogger.KlogBufferWriter)
    73  	opts := []klog.LoggerOption{
    74  		klog.ContextualLogger(true),
    75  		klog.WriteKlogBuffer(writer.WriteKlogBuffer),
    76  	}
    77  	klog.SetLoggerWithOptions(ginkgoLogger, opts...)
    78  }
    79  
    80  type valueChain struct {
    81  	flag.Value
    82  	parentValue flag.Value
    83  }
    84  
    85  func (v *valueChain) Set(value string) error {
    86  	if err := v.Value.Set(value); err != nil {
    87  		return err
    88  	}
    89  	if err := v.parentValue.Set(value); err != nil {
    90  		return err
    91  	}
    92  	return nil
    93  }
    94  
    95  func unwind(skip int) (string, int) {
    96  	location := ginkgotypes.NewCodeLocation(skip + 1)
    97  	return location.FileName, location.LineNumber
    98  }
    99  
   100  // log re-implements klog.Info: same header, but stack unwinding
   101  // with support for ginkgo.GinkgoWriter and skipping stack levels.
   102  func log(offset int, msg string) {
   103  	now := TimeNow()
   104  	file, line := unwind(offset + 1)
   105  	if file == "" {
   106  		file = "???"
   107  		line = 1
   108  	} else if slash := strings.LastIndex(file, "/"); slash >= 0 {
   109  		file = file[slash+1:]
   110  	}
   111  	_, month, day := now.Date()
   112  	hour, minute, second := now.Clock()
   113  	header := fmt.Sprintf("I%02d%02d %02d:%02d:%02d.%06d %d %s:%d]",
   114  		month, day, hour, minute, second, now.Nanosecond()/1000, Pid, file, line)
   115  
   116  	fmt.Fprintln(ginkgo.GinkgoWriter, header, msg)
   117  }
   118  

View as plain text