...

Source file src/k8s.io/client-go/rest/warnings.go

Documentation: k8s.io/client-go/rest

     1  /*
     2  Copyright 2020 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 rest
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"net/http"
    23  	"sync"
    24  
    25  	"k8s.io/klog/v2"
    26  
    27  	"k8s.io/apimachinery/pkg/util/net"
    28  )
    29  
    30  // WarningHandler is an interface for handling warning headers
    31  type WarningHandler interface {
    32  	// HandleWarningHeader is called with the warn code, agent, and text when a warning header is countered.
    33  	HandleWarningHeader(code int, agent string, text string)
    34  }
    35  
    36  var (
    37  	defaultWarningHandler     WarningHandler = WarningLogger{}
    38  	defaultWarningHandlerLock sync.RWMutex
    39  )
    40  
    41  // SetDefaultWarningHandler sets the default handler clients use when warning headers are encountered.
    42  // By default, warnings are logged. Several built-in implementations are provided:
    43  //   - NoWarnings suppresses warnings.
    44  //   - WarningLogger logs warnings.
    45  //   - NewWarningWriter() outputs warnings to the provided writer.
    46  func SetDefaultWarningHandler(l WarningHandler) {
    47  	defaultWarningHandlerLock.Lock()
    48  	defer defaultWarningHandlerLock.Unlock()
    49  	defaultWarningHandler = l
    50  }
    51  func getDefaultWarningHandler() WarningHandler {
    52  	defaultWarningHandlerLock.RLock()
    53  	defer defaultWarningHandlerLock.RUnlock()
    54  	l := defaultWarningHandler
    55  	return l
    56  }
    57  
    58  // NoWarnings is an implementation of WarningHandler that suppresses warnings.
    59  type NoWarnings struct{}
    60  
    61  func (NoWarnings) HandleWarningHeader(code int, agent string, message string) {}
    62  
    63  // WarningLogger is an implementation of WarningHandler that logs code 299 warnings
    64  type WarningLogger struct{}
    65  
    66  func (WarningLogger) HandleWarningHeader(code int, agent string, message string) {
    67  	if code != 299 || len(message) == 0 {
    68  		return
    69  	}
    70  	klog.Warning(message)
    71  }
    72  
    73  type warningWriter struct {
    74  	// out is the writer to output warnings to
    75  	out io.Writer
    76  	// opts contains options controlling warning output
    77  	opts WarningWriterOptions
    78  	// writtenLock guards written and writtenCount
    79  	writtenLock  sync.Mutex
    80  	writtenCount int
    81  	written      map[string]struct{}
    82  }
    83  
    84  // WarningWriterOptions controls the behavior of a WarningHandler constructed using NewWarningWriter()
    85  type WarningWriterOptions struct {
    86  	// Deduplicate indicates a given warning message should only be written once.
    87  	// Setting this to true in a long-running process handling many warnings can result in increased memory use.
    88  	Deduplicate bool
    89  	// Color indicates that warning output can include ANSI color codes
    90  	Color bool
    91  }
    92  
    93  // NewWarningWriter returns an implementation of WarningHandler that outputs code 299 warnings to the specified writer.
    94  func NewWarningWriter(out io.Writer, opts WarningWriterOptions) *warningWriter {
    95  	h := &warningWriter{out: out, opts: opts}
    96  	if opts.Deduplicate {
    97  		h.written = map[string]struct{}{}
    98  	}
    99  	return h
   100  }
   101  
   102  const (
   103  	yellowColor = "\u001b[33;1m"
   104  	resetColor  = "\u001b[0m"
   105  )
   106  
   107  // HandleWarningHeader prints warnings with code=299 to the configured writer.
   108  func (w *warningWriter) HandleWarningHeader(code int, agent string, message string) {
   109  	if code != 299 || len(message) == 0 {
   110  		return
   111  	}
   112  
   113  	w.writtenLock.Lock()
   114  	defer w.writtenLock.Unlock()
   115  
   116  	if w.opts.Deduplicate {
   117  		if _, alreadyWritten := w.written[message]; alreadyWritten {
   118  			return
   119  		}
   120  		w.written[message] = struct{}{}
   121  	}
   122  	w.writtenCount++
   123  
   124  	if w.opts.Color {
   125  		fmt.Fprintf(w.out, "%sWarning:%s %s\n", yellowColor, resetColor, message)
   126  	} else {
   127  		fmt.Fprintf(w.out, "Warning: %s\n", message)
   128  	}
   129  }
   130  
   131  func (w *warningWriter) WarningCount() int {
   132  	w.writtenLock.Lock()
   133  	defer w.writtenLock.Unlock()
   134  	return w.writtenCount
   135  }
   136  
   137  func handleWarnings(headers http.Header, handler WarningHandler) []net.WarningHeader {
   138  	if handler == nil {
   139  		handler = getDefaultWarningHandler()
   140  	}
   141  
   142  	warnings, _ := net.ParseWarningHeaders(headers["Warning"])
   143  	for _, warning := range warnings {
   144  		handler.HandleWarningHeader(warning.Code, warning.Agent, warning.Text)
   145  	}
   146  	return warnings
   147  }
   148  

View as plain text