1// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
2//
3// Copyright 2013 Google Inc. All Rights Reserved.
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// Package klog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup.
18// It provides functions Info, Warning, Error, Fatal, plus formatting variants such as
19// Infof. It also provides V-style logging controlled by the -v and -vmodule=file=2 flags.
20//
21// Basic examples:
22//
23//	klog.Info("Prepare to repel boarders")
24//
25//	klog.Fatalf("Initialization failed: %s", err)
26//
27// See the documentation for the V function for an explanation of these examples:
28//
29//	if klog.V(2) {
30//		klog.Info("Starting transaction...")
31//	}
32//
33//	klog.V(2).Infoln("Processed", nItems, "elements")
34//
35// Log output is buffered and written periodically using Flush. Programs
36// should call Flush before exiting to guarantee all log output is written.
37//
38// By default, all log statements write to standard error.
39// This package provides several flags that modify this behavior.
40// As a result, flag.Parse must be called before any logging is done.
41//
42//	-logtostderr=true
43//		Logs are written to standard error instead of to files.
44//	-alsologtostderr=false
45//		Logs are written to standard error as well as to files.
46//	-stderrthreshold=ERROR
47//		Log events at or above this severity are logged to standard
48//		error as well as to files.
49//	-log_dir=""
50//		Log files will be written to this directory instead of the
51//		default temporary directory.
52//
53//	Other flags provide aids to debugging.
54//
55//	-log_backtrace_at=""
56//		When set to a file and line number holding a logging statement,
57//		such as
58//			-log_backtrace_at=gopherflakes.go:234
59//		a stack trace will be written to the Info log whenever execution
60//		hits that statement. (Unlike with -vmodule, the ".go" must be
61//		present.)
62//	-v=0
63//		Enable V-leveled logging at the specified level.
64//	-vmodule=""
65//		The syntax of the argument is a comma-separated list of pattern=N,
66//		where pattern is a literal file name (minus the ".go" suffix) or
67//		"glob" pattern and N is a V level. For instance,
68//			-vmodule=gopher*=3
69//		sets the V level to 3 in all Go files whose names begin "gopher".
70//
71package klog
72
73import (
74	"bufio"
75	"bytes"
76	"errors"
77	"flag"
78	"fmt"
79	"io"
80	stdLog "log"
81	"math"
82	"os"
83	"path/filepath"
84	"runtime"
85	"strconv"
86	"strings"
87	"sync"
88	"sync/atomic"
89	"time"
90
91	"github.com/go-logr/logr"
92)
93
94// severity identifies the sort of log: info, warning etc. It also implements
95// the flag.Value interface. The -stderrthreshold flag is of type severity and
96// should be modified only through the flag.Value interface. The values match
97// the corresponding constants in C++.
98type severity int32 // sync/atomic int32
99
100// These constants identify the log levels in order of increasing severity.
101// A message written to a high-severity log file is also written to each
102// lower-severity log file.
103const (
104	infoLog severity = iota
105	warningLog
106	errorLog
107	fatalLog
108	numSeverity = 4
109)
110
111const severityChar = "IWEF"
112
113var severityName = []string{
114	infoLog:    "INFO",
115	warningLog: "WARNING",
116	errorLog:   "ERROR",
117	fatalLog:   "FATAL",
118}
119
120// get returns the value of the severity.
121func (s *severity) get() severity {
122	return severity(atomic.LoadInt32((*int32)(s)))
123}
124
125// set sets the value of the severity.
126func (s *severity) set(val severity) {
127	atomic.StoreInt32((*int32)(s), int32(val))
128}
129
130// String is part of the flag.Value interface.
131func (s *severity) String() string {
132	return strconv.FormatInt(int64(*s), 10)
133}
134
135// Get is part of the flag.Getter interface.
136func (s *severity) Get() interface{} {
137	return *s
138}
139
140// Set is part of the flag.Value interface.
141func (s *severity) Set(value string) error {
142	var threshold severity
143	// Is it a known name?
144	if v, ok := severityByName(value); ok {
145		threshold = v
146	} else {
147		v, err := strconv.ParseInt(value, 10, 32)
148		if err != nil {
149			return err
150		}
151		threshold = severity(v)
152	}
153	logging.stderrThreshold.set(threshold)
154	return nil
155}
156
157func severityByName(s string) (severity, bool) {
158	s = strings.ToUpper(s)
159	for i, name := range severityName {
160		if name == s {
161			return severity(i), true
162		}
163	}
164	return 0, false
165}
166
167// OutputStats tracks the number of output lines and bytes written.
168type OutputStats struct {
169	lines int64
170	bytes int64
171}
172
173// Lines returns the number of lines written.
174func (s *OutputStats) Lines() int64 {
175	return atomic.LoadInt64(&s.lines)
176}
177
178// Bytes returns the number of bytes written.
179func (s *OutputStats) Bytes() int64 {
180	return atomic.LoadInt64(&s.bytes)
181}
182
183// Stats tracks the number of lines of output and number of bytes
184// per severity level. Values must be read with atomic.LoadInt64.
185var Stats struct {
186	Info, Warning, Error OutputStats
187}
188
189var severityStats = [numSeverity]*OutputStats{
190	infoLog:    &Stats.Info,
191	warningLog: &Stats.Warning,
192	errorLog:   &Stats.Error,
193}
194
195// Level is exported because it appears in the arguments to V and is
196// the type of the v flag, which can be set programmatically.
197// It's a distinct type because we want to discriminate it from logType.
198// Variables of type level are only changed under logging.mu.
199// The -v flag is read only with atomic ops, so the state of the logging
200// module is consistent.
201
202// Level is treated as a sync/atomic int32.
203
204// Level specifies a level of verbosity for V logs. *Level implements
205// flag.Value; the -v flag is of type Level and should be modified
206// only through the flag.Value interface.
207type Level int32
208
209// get returns the value of the Level.
210func (l *Level) get() Level {
211	return Level(atomic.LoadInt32((*int32)(l)))
212}
213
214// set sets the value of the Level.
215func (l *Level) set(val Level) {
216	atomic.StoreInt32((*int32)(l), int32(val))
217}
218
219// String is part of the flag.Value interface.
220func (l *Level) String() string {
221	return strconv.FormatInt(int64(*l), 10)
222}
223
224// Get is part of the flag.Getter interface.
225func (l *Level) Get() interface{} {
226	return *l
227}
228
229// Set is part of the flag.Value interface.
230func (l *Level) Set(value string) error {
231	v, err := strconv.ParseInt(value, 10, 32)
232	if err != nil {
233		return err
234	}
235	logging.mu.Lock()
236	defer logging.mu.Unlock()
237	logging.setVState(Level(v), logging.vmodule.filter, false)
238	return nil
239}
240
241// moduleSpec represents the setting of the -vmodule flag.
242type moduleSpec struct {
243	filter []modulePat
244}
245
246// modulePat contains a filter for the -vmodule flag.
247// It holds a verbosity level and a file pattern to match.
248type modulePat struct {
249	pattern string
250	literal bool // The pattern is a literal string
251	level   Level
252}
253
254// match reports whether the file matches the pattern. It uses a string
255// comparison if the pattern contains no metacharacters.
256func (m *modulePat) match(file string) bool {
257	if m.literal {
258		return file == m.pattern
259	}
260	match, _ := filepath.Match(m.pattern, file)
261	return match
262}
263
264func (m *moduleSpec) String() string {
265	// Lock because the type is not atomic. TODO: clean this up.
266	logging.mu.Lock()
267	defer logging.mu.Unlock()
268	var b bytes.Buffer
269	for i, f := range m.filter {
270		if i > 0 {
271			b.WriteRune(',')
272		}
273		fmt.Fprintf(&b, "%s=%d", f.pattern, f.level)
274	}
275	return b.String()
276}
277
278// Get is part of the (Go 1.2)  flag.Getter interface. It always returns nil for this flag type since the
279// struct is not exported.
280func (m *moduleSpec) Get() interface{} {
281	return nil
282}
283
284var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")
285
286// Syntax: -vmodule=recordio=2,file=1,gfs*=3
287func (m *moduleSpec) Set(value string) error {
288	var filter []modulePat
289	for _, pat := range strings.Split(value, ",") {
290		if len(pat) == 0 {
291			// Empty strings such as from a trailing comma can be ignored.
292			continue
293		}
294		patLev := strings.Split(pat, "=")
295		if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
296			return errVmoduleSyntax
297		}
298		pattern := patLev[0]
299		v, err := strconv.ParseInt(patLev[1], 10, 32)
300		if err != nil {
301			return errors.New("syntax error: expect comma-separated list of filename=N")
302		}
303		if v < 0 {
304			return errors.New("negative value for vmodule level")
305		}
306		if v == 0 {
307			continue // Ignore. It's harmless but no point in paying the overhead.
308		}
309		// TODO: check syntax of filter?
310		filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)})
311	}
312	logging.mu.Lock()
313	defer logging.mu.Unlock()
314	logging.setVState(logging.verbosity, filter, true)
315	return nil
316}
317
318// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
319// that require filepath.Match to be called to match the pattern.
320func isLiteral(pattern string) bool {
321	return !strings.ContainsAny(pattern, `\*?[]`)
322}
323
324// traceLocation represents the setting of the -log_backtrace_at flag.
325type traceLocation struct {
326	file string
327	line int
328}
329
330// isSet reports whether the trace location has been specified.
331// logging.mu is held.
332func (t *traceLocation) isSet() bool {
333	return t.line > 0
334}
335
336// match reports whether the specified file and line matches the trace location.
337// The argument file name is the full path, not the basename specified in the flag.
338// logging.mu is held.
339func (t *traceLocation) match(file string, line int) bool {
340	if t.line != line {
341		return false
342	}
343	if i := strings.LastIndex(file, "/"); i >= 0 {
344		file = file[i+1:]
345	}
346	return t.file == file
347}
348
349func (t *traceLocation) String() string {
350	// Lock because the type is not atomic. TODO: clean this up.
351	logging.mu.Lock()
352	defer logging.mu.Unlock()
353	return fmt.Sprintf("%s:%d", t.file, t.line)
354}
355
356// Get is part of the (Go 1.2) flag.Getter interface. It always returns nil for this flag type since the
357// struct is not exported
358func (t *traceLocation) Get() interface{} {
359	return nil
360}
361
362var errTraceSyntax = errors.New("syntax error: expect file.go:234")
363
364// Syntax: -log_backtrace_at=gopherflakes.go:234
365// Note that unlike vmodule the file extension is included here.
366func (t *traceLocation) Set(value string) error {
367	if value == "" {
368		// Unset.
369		logging.mu.Lock()
370		defer logging.mu.Unlock()
371		t.line = 0
372		t.file = ""
373		return nil
374	}
375	fields := strings.Split(value, ":")
376	if len(fields) != 2 {
377		return errTraceSyntax
378	}
379	file, line := fields[0], fields[1]
380	if !strings.Contains(file, ".") {
381		return errTraceSyntax
382	}
383	v, err := strconv.Atoi(line)
384	if err != nil {
385		return errTraceSyntax
386	}
387	if v <= 0 {
388		return errors.New("negative or zero value for level")
389	}
390	logging.mu.Lock()
391	defer logging.mu.Unlock()
392	t.line = v
393	t.file = file
394	return nil
395}
396
397// flushSyncWriter is the interface satisfied by logging destinations.
398type flushSyncWriter interface {
399	Flush() error
400	Sync() error
401	io.Writer
402}
403
404// init sets up the defaults and runs flushDaemon.
405func init() {
406	logging.stderrThreshold = errorLog // Default stderrThreshold is ERROR.
407	logging.setVState(0, nil, false)
408	logging.logDir = ""
409	logging.logFile = ""
410	logging.logFileMaxSizeMB = 1800
411	logging.toStderr = true
412	logging.alsoToStderr = false
413	logging.skipHeaders = false
414	logging.addDirHeader = false
415	logging.skipLogHeaders = false
416	go logging.flushDaemon()
417}
418
419// InitFlags is for explicitly initializing the flags.
420func InitFlags(flagset *flag.FlagSet) {
421	if flagset == nil {
422		flagset = flag.CommandLine
423	}
424
425	flagset.StringVar(&logging.logDir, "log_dir", logging.logDir, "If non-empty, write log files in this directory")
426	flagset.StringVar(&logging.logFile, "log_file", logging.logFile, "If non-empty, use this log file")
427	flagset.Uint64Var(&logging.logFileMaxSizeMB, "log_file_max_size", logging.logFileMaxSizeMB,
428		"Defines the maximum size a log file can grow to. Unit is megabytes. "+
429			"If the value is 0, the maximum file size is unlimited.")
430	flagset.BoolVar(&logging.toStderr, "logtostderr", logging.toStderr, "log to standard error instead of files")
431	flagset.BoolVar(&logging.alsoToStderr, "alsologtostderr", logging.alsoToStderr, "log to standard error as well as files")
432	flagset.Var(&logging.verbosity, "v", "number for the log level verbosity")
433	flagset.BoolVar(&logging.addDirHeader, "add_dir_header", logging.addDirHeader, "If true, adds the file directory to the header of the log messages")
434	flagset.BoolVar(&logging.skipHeaders, "skip_headers", logging.skipHeaders, "If true, avoid header prefixes in the log messages")
435	flagset.BoolVar(&logging.skipLogHeaders, "skip_log_headers", logging.skipLogHeaders, "If true, avoid headers when opening log files")
436	flagset.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
437	flagset.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
438	flagset.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
439}
440
441// Flush flushes all pending log I/O.
442func Flush() {
443	logging.lockAndFlushAll()
444}
445
446// loggingT collects all the global state of the logging setup.
447type loggingT struct {
448	// Boolean flags. Not handled atomically because the flag.Value interface
449	// does not let us avoid the =true, and that shorthand is necessary for
450	// compatibility. TODO: does this matter enough to fix? Seems unlikely.
451	toStderr     bool // The -logtostderr flag.
452	alsoToStderr bool // The -alsologtostderr flag.
453
454	// Level flag. Handled atomically.
455	stderrThreshold severity // The -stderrthreshold flag.
456
457	// freeList is a list of byte buffers, maintained under freeListMu.
458	freeList *buffer
459	// freeListMu maintains the free list. It is separate from the main mutex
460	// so buffers can be grabbed and printed to without holding the main lock,
461	// for better parallelization.
462	freeListMu sync.Mutex
463
464	// mu protects the remaining elements of this structure and is
465	// used to synchronize logging.
466	mu sync.Mutex
467	// file holds writer for each of the log types.
468	file [numSeverity]flushSyncWriter
469	// pcs is used in V to avoid an allocation when computing the caller's PC.
470	pcs [1]uintptr
471	// vmap is a cache of the V Level for each V() call site, identified by PC.
472	// It is wiped whenever the vmodule flag changes state.
473	vmap map[uintptr]Level
474	// filterLength stores the length of the vmodule filter chain. If greater
475	// than zero, it means vmodule is enabled. It may be read safely
476	// using sync.LoadInt32, but is only modified under mu.
477	filterLength int32
478	// traceLocation is the state of the -log_backtrace_at flag.
479	traceLocation traceLocation
480	// These flags are modified only under lock, although verbosity may be fetched
481	// safely using atomic.LoadInt32.
482	vmodule   moduleSpec // The state of the -vmodule flag.
483	verbosity Level      // V logging level, the value of the -v flag/
484
485	// If non-empty, overrides the choice of directory in which to write logs.
486	// See createLogDirs for the full list of possible destinations.
487	logDir string
488
489	// If non-empty, specifies the path of the file to write logs. mutually exclusive
490	// with the log_dir option.
491	logFile string
492
493	// When logFile is specified, this limiter makes sure the logFile won't exceeds a certain size. When exceeds, the
494	// logFile will be cleaned up. If this value is 0, no size limitation will be applied to logFile.
495	logFileMaxSizeMB uint64
496
497	// If true, do not add the prefix headers, useful when used with SetOutput
498	skipHeaders bool
499
500	// If true, do not add the headers to log files
501	skipLogHeaders bool
502
503	// If true, add the file directory to the header
504	addDirHeader bool
505
506	// If set, all output will be redirected unconditionally to the provided logr.Logger
507	logr logr.Logger
508}
509
510// buffer holds a byte Buffer for reuse. The zero value is ready for use.
511type buffer struct {
512	bytes.Buffer
513	tmp  [64]byte // temporary byte array for creating headers.
514	next *buffer
515}
516
517var logging loggingT
518
519// setVState sets a consistent state for V logging.
520// l.mu is held.
521func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) {
522	// Turn verbosity off so V will not fire while we are in transition.
523	l.verbosity.set(0)
524	// Ditto for filter length.
525	atomic.StoreInt32(&l.filterLength, 0)
526
527	// Set the new filters and wipe the pc->Level map if the filter has changed.
528	if setFilter {
529		l.vmodule.filter = filter
530		l.vmap = make(map[uintptr]Level)
531	}
532
533	// Things are consistent now, so enable filtering and verbosity.
534	// They are enabled in order opposite to that in V.
535	atomic.StoreInt32(&l.filterLength, int32(len(filter)))
536	l.verbosity.set(verbosity)
537}
538
539// getBuffer returns a new, ready-to-use buffer.
540func (l *loggingT) getBuffer() *buffer {
541	l.freeListMu.Lock()
542	b := l.freeList
543	if b != nil {
544		l.freeList = b.next
545	}
546	l.freeListMu.Unlock()
547	if b == nil {
548		b = new(buffer)
549	} else {
550		b.next = nil
551		b.Reset()
552	}
553	return b
554}
555
556// putBuffer returns a buffer to the free list.
557func (l *loggingT) putBuffer(b *buffer) {
558	if b.Len() >= 256 {
559		// Let big buffers die a natural death.
560		return
561	}
562	l.freeListMu.Lock()
563	b.next = l.freeList
564	l.freeList = b
565	l.freeListMu.Unlock()
566}
567
568var timeNow = time.Now // Stubbed out for testing.
569
570/*
571header formats a log header as defined by the C++ implementation.
572It returns a buffer containing the formatted header and the user's file and line number.
573The depth specifies how many stack frames above lives the source line to be identified in the log message.
574
575Log lines have this form:
576	Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
577where the fields are defined as follows:
578	L                A single character, representing the log level (eg 'I' for INFO)
579	mm               The month (zero padded; ie May is '05')
580	dd               The day (zero padded)
581	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
582	threadid         The space-padded thread ID as returned by GetTID()
583	file             The file name
584	line             The line number
585	msg              The user-supplied message
586*/
587func (l *loggingT) header(s severity, depth int) (*buffer, string, int) {
588	_, file, line, ok := runtime.Caller(3 + depth)
589	if !ok {
590		file = "???"
591		line = 1
592	} else {
593		if slash := strings.LastIndex(file, "/"); slash >= 0 {
594			path := file
595			file = path[slash+1:]
596			if l.addDirHeader {
597				if dirsep := strings.LastIndex(path[:slash], "/"); dirsep >= 0 {
598					file = path[dirsep+1:]
599				}
600			}
601		}
602	}
603	return l.formatHeader(s, file, line), file, line
604}
605
606// formatHeader formats a log header using the provided file name and line number.
607func (l *loggingT) formatHeader(s severity, file string, line int) *buffer {
608	now := timeNow()
609	if line < 0 {
610		line = 0 // not a real line number, but acceptable to someDigits
611	}
612	if s > fatalLog {
613		s = infoLog // for safety.
614	}
615	buf := l.getBuffer()
616	if l.skipHeaders {
617		return buf
618	}
619
620	// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
621	// It's worth about 3X. Fprintf is hard.
622	_, month, day := now.Date()
623	hour, minute, second := now.Clock()
624	// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
625	buf.tmp[0] = severityChar[s]
626	buf.twoDigits(1, int(month))
627	buf.twoDigits(3, day)
628	buf.tmp[5] = ' '
629	buf.twoDigits(6, hour)
630	buf.tmp[8] = ':'
631	buf.twoDigits(9, minute)
632	buf.tmp[11] = ':'
633	buf.twoDigits(12, second)
634	buf.tmp[14] = '.'
635	buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
636	buf.tmp[21] = ' '
637	buf.nDigits(7, 22, pid, ' ') // TODO: should be TID
638	buf.tmp[29] = ' '
639	buf.Write(buf.tmp[:30])
640	buf.WriteString(file)
641	buf.tmp[0] = ':'
642	n := buf.someDigits(1, line)
643	buf.tmp[n+1] = ']'
644	buf.tmp[n+2] = ' '
645	buf.Write(buf.tmp[:n+3])
646	return buf
647}
648
649// Some custom tiny helper functions to print the log header efficiently.
650
651const digits = "0123456789"
652
653// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i].
654func (buf *buffer) twoDigits(i, d int) {
655	buf.tmp[i+1] = digits[d%10]
656	d /= 10
657	buf.tmp[i] = digits[d%10]
658}
659
660// nDigits formats an n-digit integer at buf.tmp[i],
661// padding with pad on the left.
662// It assumes d >= 0.
663func (buf *buffer) nDigits(n, i, d int, pad byte) {
664	j := n - 1
665	for ; j >= 0 && d > 0; j-- {
666		buf.tmp[i+j] = digits[d%10]
667		d /= 10
668	}
669	for ; j >= 0; j-- {
670		buf.tmp[i+j] = pad
671	}
672}
673
674// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
675func (buf *buffer) someDigits(i, d int) int {
676	// Print into the top, then copy down. We know there's space for at least
677	// a 10-digit number.
678	j := len(buf.tmp)
679	for {
680		j--
681		buf.tmp[j] = digits[d%10]
682		d /= 10
683		if d == 0 {
684			break
685		}
686	}
687	return copy(buf.tmp[i:], buf.tmp[j:])
688}
689
690func (l *loggingT) println(s severity, logr logr.Logger, args ...interface{}) {
691	buf, file, line := l.header(s, 0)
692	// if logr is set, we clear the generated header as we rely on the backing
693	// logr implementation to print headers
694	if logr != nil {
695		l.putBuffer(buf)
696		buf = l.getBuffer()
697	}
698	fmt.Fprintln(buf, args...)
699	l.output(s, logr, buf, file, line, false)
700}
701
702func (l *loggingT) print(s severity, logr logr.Logger, args ...interface{}) {
703	l.printDepth(s, logr, 1, args...)
704}
705
706func (l *loggingT) printDepth(s severity, logr logr.Logger, depth int, args ...interface{}) {
707	buf, file, line := l.header(s, depth)
708	// if logr is set, we clear the generated header as we rely on the backing
709	// logr implementation to print headers
710	if logr != nil {
711		l.putBuffer(buf)
712		buf = l.getBuffer()
713	}
714	fmt.Fprint(buf, args...)
715	if buf.Bytes()[buf.Len()-1] != '\n' {
716		buf.WriteByte('\n')
717	}
718	l.output(s, logr, buf, file, line, false)
719}
720
721func (l *loggingT) printf(s severity, logr logr.Logger, format string, args ...interface{}) {
722	buf, file, line := l.header(s, 0)
723	// if logr is set, we clear the generated header as we rely on the backing
724	// logr implementation to print headers
725	if logr != nil {
726		l.putBuffer(buf)
727		buf = l.getBuffer()
728	}
729	fmt.Fprintf(buf, format, args...)
730	if buf.Bytes()[buf.Len()-1] != '\n' {
731		buf.WriteByte('\n')
732	}
733	l.output(s, logr, buf, file, line, false)
734}
735
736// printWithFileLine behaves like print but uses the provided file and line number.  If
737// alsoLogToStderr is true, the log message always appears on standard error; it
738// will also appear in the log file unless --logtostderr is set.
739func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, file string, line int, alsoToStderr bool, args ...interface{}) {
740	buf := l.formatHeader(s, file, line)
741	// if logr is set, we clear the generated header as we rely on the backing
742	// logr implementation to print headers
743	if logr != nil {
744		l.putBuffer(buf)
745		buf = l.getBuffer()
746	}
747	fmt.Fprint(buf, args...)
748	if buf.Bytes()[buf.Len()-1] != '\n' {
749		buf.WriteByte('\n')
750	}
751	l.output(s, logr, buf, file, line, alsoToStderr)
752}
753
754// if loggr is specified, will call loggr.Error, otherwise output with logging module.
755func (l *loggingT) errorS(err error, loggr logr.Logger, msg string, keysAndValues ...interface{}) {
756	if loggr != nil {
757		loggr.Error(err, msg, keysAndValues)
758		return
759	}
760	l.printS(err, msg, keysAndValues...)
761}
762
763// if loggr is specified, will call loggr.Info, otherwise output with logging module.
764func (l *loggingT) infoS(loggr logr.Logger, msg string, keysAndValues ...interface{}) {
765	if loggr != nil {
766		loggr.Info(msg, keysAndValues)
767		return
768	}
769	l.printS(nil, msg, keysAndValues...)
770}
771
772// printS is called from infoS and errorS if loggr is not specified.
773// if err arguments is specified, will output to errorLog severity
774func (l *loggingT) printS(err error, msg string, keysAndValues ...interface{}) {
775	b := &bytes.Buffer{}
776	b.WriteString(fmt.Sprintf("%q", msg))
777	if err != nil {
778		b.WriteByte(' ')
779		b.WriteString(fmt.Sprintf("err=%q", err.Error()))
780	}
781	kvListFormat(b, keysAndValues...)
782	var s severity
783	if err == nil {
784		s = infoLog
785	} else {
786		s = errorLog
787	}
788	l.printDepth(s, logging.logr, 2, b)
789}
790
791const missingValue = "(MISSING)"
792
793func kvListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
794	for i := 0; i < len(keysAndValues); i += 2 {
795		var v interface{}
796		k := keysAndValues[i]
797		if i+1 < len(keysAndValues) {
798			v = keysAndValues[i+1]
799		} else {
800			v = missingValue
801		}
802		b.WriteByte(' ')
803
804		switch v.(type) {
805		case string, error:
806			b.WriteString(fmt.Sprintf("%s=%q", k, v))
807		default:
808			if _, ok := v.(fmt.Stringer); ok {
809				b.WriteString(fmt.Sprintf("%s=%q", k, v))
810			} else {
811				b.WriteString(fmt.Sprintf("%s=%+v", k, v))
812			}
813		}
814	}
815}
816
817// redirectBuffer is used to set an alternate destination for the logs
818type redirectBuffer struct {
819	w io.Writer
820}
821
822func (rb *redirectBuffer) Sync() error {
823	return nil
824}
825
826func (rb *redirectBuffer) Flush() error {
827	return nil
828}
829
830func (rb *redirectBuffer) Write(bytes []byte) (n int, err error) {
831	return rb.w.Write(bytes)
832}
833
834// SetLogger will set the backing logr implementation for klog.
835// If set, all log lines will be suppressed from the regular Output, and
836// redirected to the logr implementation.
837// All log lines include the 'severity', 'file' and 'line' values attached as
838// structured logging values.
839// Use as:
840//   ...
841//   klog.SetLogger(zapr.NewLogger(zapLog))
842func SetLogger(logr logr.Logger) {
843	logging.logr = logr
844}
845
846// SetOutput sets the output destination for all severities
847func SetOutput(w io.Writer) {
848	logging.mu.Lock()
849	defer logging.mu.Unlock()
850	for s := fatalLog; s >= infoLog; s-- {
851		rb := &redirectBuffer{
852			w: w,
853		}
854		logging.file[s] = rb
855	}
856}
857
858// SetOutputBySeverity sets the output destination for specific severity
859func SetOutputBySeverity(name string, w io.Writer) {
860	logging.mu.Lock()
861	defer logging.mu.Unlock()
862	sev, ok := severityByName(name)
863	if !ok {
864		panic(fmt.Sprintf("SetOutputBySeverity(%q): unrecognized severity name", name))
865	}
866	rb := &redirectBuffer{
867		w: w,
868	}
869	logging.file[sev] = rb
870}
871
872// LogToStderr sets whether to log exclusively to stderr, bypassing outputs
873func LogToStderr(stderr bool) {
874	logging.mu.Lock()
875	defer logging.mu.Unlock()
876
877	logging.toStderr = stderr
878}
879
880// output writes the data to the log files and releases the buffer.
881func (l *loggingT) output(s severity, log logr.Logger, buf *buffer, file string, line int, alsoToStderr bool) {
882	l.mu.Lock()
883	if l.traceLocation.isSet() {
884		if l.traceLocation.match(file, line) {
885			buf.Write(stacks(false))
886		}
887	}
888	data := buf.Bytes()
889	if log != nil {
890		// TODO: set 'severity' and caller information as structured log info
891		// keysAndValues := []interface{}{"severity", severityName[s], "file", file, "line", line}
892		if s == errorLog {
893			l.logr.Error(nil, string(data))
894		} else {
895			log.Info(string(data))
896		}
897	} else if l.toStderr {
898		os.Stderr.Write(data)
899	} else {
900		if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
901			os.Stderr.Write(data)
902		}
903
904		if logging.logFile != "" {
905			// Since we are using a single log file, all of the items in l.file array
906			// will point to the same file, so just use one of them to write data.
907			if l.file[infoLog] == nil {
908				if err := l.createFiles(infoLog); err != nil {
909					os.Stderr.Write(data) // Make sure the message appears somewhere.
910					l.exit(err)
911				}
912			}
913			l.file[infoLog].Write(data)
914		} else {
915			if l.file[s] == nil {
916				if err := l.createFiles(s); err != nil {
917					os.Stderr.Write(data) // Make sure the message appears somewhere.
918					l.exit(err)
919				}
920			}
921
922			switch s {
923			case fatalLog:
924				l.file[fatalLog].Write(data)
925				fallthrough
926			case errorLog:
927				l.file[errorLog].Write(data)
928				fallthrough
929			case warningLog:
930				l.file[warningLog].Write(data)
931				fallthrough
932			case infoLog:
933				l.file[infoLog].Write(data)
934			}
935		}
936	}
937	if s == fatalLog {
938		// If we got here via Exit rather than Fatal, print no stacks.
939		if atomic.LoadUint32(&fatalNoStacks) > 0 {
940			l.mu.Unlock()
941			timeoutFlush(10 * time.Second)
942			os.Exit(1)
943		}
944		// Dump all goroutine stacks before exiting.
945		trace := stacks(true)
946		// Write the stack trace for all goroutines to the stderr.
947		if l.toStderr || l.alsoToStderr || s >= l.stderrThreshold.get() || alsoToStderr {
948			os.Stderr.Write(trace)
949		}
950		// Write the stack trace for all goroutines to the files.
951		logExitFunc = func(error) {} // If we get a write error, we'll still exit below.
952		for log := fatalLog; log >= infoLog; log-- {
953			if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set.
954				f.Write(trace)
955			}
956		}
957		l.mu.Unlock()
958		timeoutFlush(10 * time.Second)
959		os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
960	}
961	l.putBuffer(buf)
962	l.mu.Unlock()
963	if stats := severityStats[s]; stats != nil {
964		atomic.AddInt64(&stats.lines, 1)
965		atomic.AddInt64(&stats.bytes, int64(len(data)))
966	}
967}
968
969// timeoutFlush calls Flush and returns when it completes or after timeout
970// elapses, whichever happens first.  This is needed because the hooks invoked
971// by Flush may deadlock when klog.Fatal is called from a hook that holds
972// a lock.
973func timeoutFlush(timeout time.Duration) {
974	done := make(chan bool, 1)
975	go func() {
976		Flush() // calls logging.lockAndFlushAll()
977		done <- true
978	}()
979	select {
980	case <-done:
981	case <-time.After(timeout):
982		fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout)
983	}
984}
985
986// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines.
987func stacks(all bool) []byte {
988	// We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
989	n := 10000
990	if all {
991		n = 100000
992	}
993	var trace []byte
994	for i := 0; i < 5; i++ {
995		trace = make([]byte, n)
996		nbytes := runtime.Stack(trace, all)
997		if nbytes < len(trace) {
998			return trace[:nbytes]
999		}
1000		n *= 2
1001	}
1002	return trace
1003}
1004
1005// logExitFunc provides a simple mechanism to override the default behavior
1006// of exiting on error. Used in testing and to guarantee we reach a required exit
1007// for fatal logs. Instead, exit could be a function rather than a method but that
1008// would make its use clumsier.
1009var logExitFunc func(error)
1010
1011// exit is called if there is trouble creating or writing log files.
1012// It flushes the logs and exits the program; there's no point in hanging around.
1013// l.mu is held.
1014func (l *loggingT) exit(err error) {
1015	fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err)
1016	// If logExitFunc is set, we do that instead of exiting.
1017	if logExitFunc != nil {
1018		logExitFunc(err)
1019		return
1020	}
1021	l.flushAll()
1022	os.Exit(2)
1023}
1024
1025// syncBuffer joins a bufio.Writer to its underlying file, providing access to the
1026// file's Sync method and providing a wrapper for the Write method that provides log
1027// file rotation. There are conflicting methods, so the file cannot be embedded.
1028// l.mu is held for all its methods.
1029type syncBuffer struct {
1030	logger *loggingT
1031	*bufio.Writer
1032	file     *os.File
1033	sev      severity
1034	nbytes   uint64 // The number of bytes written to this file
1035	maxbytes uint64 // The max number of bytes this syncBuffer.file can hold before cleaning up.
1036}
1037
1038func (sb *syncBuffer) Sync() error {
1039	return sb.file.Sync()
1040}
1041
1042// CalculateMaxSize returns the real max size in bytes after considering the default max size and the flag options.
1043func CalculateMaxSize() uint64 {
1044	if logging.logFile != "" {
1045		if logging.logFileMaxSizeMB == 0 {
1046			// If logFileMaxSizeMB is zero, we don't have limitations on the log size.
1047			return math.MaxUint64
1048		}
1049		// Flag logFileMaxSizeMB is in MB for user convenience.
1050		return logging.logFileMaxSizeMB * 1024 * 1024
1051	}
1052	// If "log_file" flag is not specified, the target file (sb.file) will be cleaned up when reaches a fixed size.
1053	return MaxSize
1054}
1055
1056func (sb *syncBuffer) Write(p []byte) (n int, err error) {
1057	if sb.nbytes+uint64(len(p)) >= sb.maxbytes {
1058		if err := sb.rotateFile(time.Now(), false); err != nil {
1059			sb.logger.exit(err)
1060		}
1061	}
1062	n, err = sb.Writer.Write(p)
1063	sb.nbytes += uint64(n)
1064	if err != nil {
1065		sb.logger.exit(err)
1066	}
1067	return
1068}
1069
1070// rotateFile closes the syncBuffer's file and starts a new one.
1071// The startup argument indicates whether this is the initial startup of klog.
1072// If startup is true, existing files are opened for appending instead of truncated.
1073func (sb *syncBuffer) rotateFile(now time.Time, startup bool) error {
1074	if sb.file != nil {
1075		sb.Flush()
1076		sb.file.Close()
1077	}
1078	var err error
1079	sb.file, _, err = create(severityName[sb.sev], now, startup)
1080	sb.nbytes = 0
1081	if err != nil {
1082		return err
1083	}
1084
1085	sb.Writer = bufio.NewWriterSize(sb.file, bufferSize)
1086
1087	if sb.logger.skipLogHeaders {
1088		return nil
1089	}
1090
1091	// Write header.
1092	var buf bytes.Buffer
1093	fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05"))
1094	fmt.Fprintf(&buf, "Running on machine: %s\n", host)
1095	fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
1096	fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n")
1097	n, err := sb.file.Write(buf.Bytes())
1098	sb.nbytes += uint64(n)
1099	return err
1100}
1101
1102// bufferSize sizes the buffer associated with each log file. It's large
1103// so that log records can accumulate without the logging thread blocking
1104// on disk I/O. The flushDaemon will block instead.
1105const bufferSize = 256 * 1024
1106
1107// createFiles creates all the log files for severity from sev down to infoLog.
1108// l.mu is held.
1109func (l *loggingT) createFiles(sev severity) error {
1110	now := time.Now()
1111	// Files are created in decreasing severity order, so as soon as we find one
1112	// has already been created, we can stop.
1113	for s := sev; s >= infoLog && l.file[s] == nil; s-- {
1114		sb := &syncBuffer{
1115			logger:   l,
1116			sev:      s,
1117			maxbytes: CalculateMaxSize(),
1118		}
1119		if err := sb.rotateFile(now, true); err != nil {
1120			return err
1121		}
1122		l.file[s] = sb
1123	}
1124	return nil
1125}
1126
1127const flushInterval = 5 * time.Second
1128
1129// flushDaemon periodically flushes the log file buffers.
1130func (l *loggingT) flushDaemon() {
1131	for range time.NewTicker(flushInterval).C {
1132		l.lockAndFlushAll()
1133	}
1134}
1135
1136// lockAndFlushAll is like flushAll but locks l.mu first.
1137func (l *loggingT) lockAndFlushAll() {
1138	l.mu.Lock()
1139	l.flushAll()
1140	l.mu.Unlock()
1141}
1142
1143// flushAll flushes all the logs and attempts to "sync" their data to disk.
1144// l.mu is held.
1145func (l *loggingT) flushAll() {
1146	// Flush from fatal down, in case there's trouble flushing.
1147	for s := fatalLog; s >= infoLog; s-- {
1148		file := l.file[s]
1149		if file != nil {
1150			file.Flush() // ignore error
1151			file.Sync()  // ignore error
1152		}
1153	}
1154}
1155
1156// CopyStandardLogTo arranges for messages written to the Go "log" package's
1157// default logs to also appear in the Google logs for the named and lower
1158// severities.  Subsequent changes to the standard log's default output location
1159// or format may break this behavior.
1160//
1161// Valid names are "INFO", "WARNING", "ERROR", and "FATAL".  If the name is not
1162// recognized, CopyStandardLogTo panics.
1163func CopyStandardLogTo(name string) {
1164	sev, ok := severityByName(name)
1165	if !ok {
1166		panic(fmt.Sprintf("log.CopyStandardLogTo(%q): unrecognized severity name", name))
1167	}
1168	// Set a log format that captures the user's file and line:
1169	//   d.go:23: message
1170	stdLog.SetFlags(stdLog.Lshortfile)
1171	stdLog.SetOutput(logBridge(sev))
1172}
1173
1174// logBridge provides the Write method that enables CopyStandardLogTo to connect
1175// Go's standard logs to the logs provided by this package.
1176type logBridge severity
1177
1178// Write parses the standard logging line and passes its components to the
1179// logger for severity(lb).
1180func (lb logBridge) Write(b []byte) (n int, err error) {
1181	var (
1182		file = "???"
1183		line = 1
1184		text string
1185	)
1186	// Split "d.go:23: message" into "d.go", "23", and "message".
1187	if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 {
1188		text = fmt.Sprintf("bad log format: %s", b)
1189	} else {
1190		file = string(parts[0])
1191		text = string(parts[2][1:]) // skip leading space
1192		line, err = strconv.Atoi(string(parts[1]))
1193		if err != nil {
1194			text = fmt.Sprintf("bad line number: %s", b)
1195			line = 1
1196		}
1197	}
1198	// printWithFileLine with alsoToStderr=true, so standard log messages
1199	// always appear on standard error.
1200	logging.printWithFileLine(severity(lb), logging.logr, file, line, true, text)
1201	return len(b), nil
1202}
1203
1204// setV computes and remembers the V level for a given PC
1205// when vmodule is enabled.
1206// File pattern matching takes the basename of the file, stripped
1207// of its .go suffix, and uses filepath.Match, which is a little more
1208// general than the *? matching used in C++.
1209// l.mu is held.
1210func (l *loggingT) setV(pc uintptr) Level {
1211	fn := runtime.FuncForPC(pc)
1212	file, _ := fn.FileLine(pc)
1213	// The file is something like /a/b/c/d.go. We want just the d.
1214	if strings.HasSuffix(file, ".go") {
1215		file = file[:len(file)-3]
1216	}
1217	if slash := strings.LastIndex(file, "/"); slash >= 0 {
1218		file = file[slash+1:]
1219	}
1220	for _, filter := range l.vmodule.filter {
1221		if filter.match(file) {
1222			l.vmap[pc] = filter.level
1223			return filter.level
1224		}
1225	}
1226	l.vmap[pc] = 0
1227	return 0
1228}
1229
1230// Verbose is a boolean type that implements Infof (like Printf) etc.
1231// See the documentation of V for more information.
1232type Verbose struct {
1233	enabled bool
1234	logr    logr.Logger
1235}
1236
1237func newVerbose(level Level, b bool) Verbose {
1238	if logging.logr == nil {
1239		return Verbose{b, nil}
1240	}
1241	return Verbose{b, logging.logr.V(int(level))}
1242}
1243
1244// V reports whether verbosity at the call site is at least the requested level.
1245// The returned value is a struct of type Verbose, which implements Info, Infoln
1246// and Infof. These methods will write to the Info log if called.
1247// Thus, one may write either
1248//	if glog.V(2).Enabled() { klog.Info("log this") }
1249// or
1250//	klog.V(2).Info("log this")
1251// The second form is shorter but the first is cheaper if logging is off because it does
1252// not evaluate its arguments.
1253//
1254// Whether an individual call to V generates a log record depends on the setting of
1255// the -v and -vmodule flags; both are off by default. The V call will log if its level
1256// is less than or equal to the value of the -v flag, or alternatively if its level is
1257// less than or equal to the value of the -vmodule pattern matching the source file
1258// containing the call.
1259func V(level Level) Verbose {
1260	// This function tries hard to be cheap unless there's work to do.
1261	// The fast path is two atomic loads and compares.
1262
1263	// Here is a cheap but safe test to see if V logging is enabled globally.
1264	if logging.verbosity.get() >= level {
1265		return newVerbose(level, true)
1266	}
1267
1268	// It's off globally but it vmodule may still be set.
1269	// Here is another cheap but safe test to see if vmodule is enabled.
1270	if atomic.LoadInt32(&logging.filterLength) > 0 {
1271		// Now we need a proper lock to use the logging structure. The pcs field
1272		// is shared so we must lock before accessing it. This is fairly expensive,
1273		// but if V logging is enabled we're slow anyway.
1274		logging.mu.Lock()
1275		defer logging.mu.Unlock()
1276		if runtime.Callers(2, logging.pcs[:]) == 0 {
1277			return newVerbose(level, false)
1278		}
1279		v, ok := logging.vmap[logging.pcs[0]]
1280		if !ok {
1281			v = logging.setV(logging.pcs[0])
1282		}
1283		return newVerbose(level, v >= level)
1284	}
1285	return newVerbose(level, false)
1286}
1287
1288// Enabled will return true if this log level is enabled, guarded by the value
1289// of v.
1290// See the documentation of V for usage.
1291func (v Verbose) Enabled() bool {
1292	return v.enabled
1293}
1294
1295// Info is equivalent to the global Info function, guarded by the value of v.
1296// See the documentation of V for usage.
1297func (v Verbose) Info(args ...interface{}) {
1298	if v.enabled {
1299		logging.print(infoLog, v.logr, args...)
1300	}
1301}
1302
1303// Infoln is equivalent to the global Infoln function, guarded by the value of v.
1304// See the documentation of V for usage.
1305func (v Verbose) Infoln(args ...interface{}) {
1306	if v.enabled {
1307		logging.println(infoLog, v.logr, args...)
1308	}
1309}
1310
1311// Infof is equivalent to the global Infof function, guarded by the value of v.
1312// See the documentation of V for usage.
1313func (v Verbose) Infof(format string, args ...interface{}) {
1314	if v.enabled {
1315		logging.printf(infoLog, v.logr, format, args...)
1316	}
1317}
1318
1319// InfoS is equivalent to the global InfoS function, guarded by the value of v.
1320// See the documentation of V for usage.
1321func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
1322	if v.enabled {
1323		logging.infoS(v.logr, msg, keysAndValues...)
1324	}
1325}
1326
1327// Error is equivalent to the global Error function, guarded by the value of v.
1328// See the documentation of V for usage.
1329func (v Verbose) Error(err error, msg string, args ...interface{}) {
1330	if v.enabled {
1331		logging.errorS(err, v.logr, msg, args...)
1332	}
1333}
1334
1335// Info logs to the INFO log.
1336// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
1337func Info(args ...interface{}) {
1338	logging.print(infoLog, logging.logr, args...)
1339}
1340
1341// InfoDepth acts as Info but uses depth to determine which call frame to log.
1342// InfoDepth(0, "msg") is the same as Info("msg").
1343func InfoDepth(depth int, args ...interface{}) {
1344	logging.printDepth(infoLog, logging.logr, depth, args...)
1345}
1346
1347// Infoln logs to the INFO log.
1348// Arguments are handled in the manner of fmt.Println; a newline is always appended.
1349func Infoln(args ...interface{}) {
1350	logging.println(infoLog, logging.logr, args...)
1351}
1352
1353// Infof logs to the INFO log.
1354// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
1355func Infof(format string, args ...interface{}) {
1356	logging.printf(infoLog, logging.logr, format, args...)
1357}
1358
1359// InfoS structured logs to the INFO log.
1360// The msg argument used to add constant description to the log line.
1361// The key/value pairs would be join by "=" ; a newline is always appended.
1362//
1363// Basic examples:
1364// >> klog.InfoS("Pod status updated", "pod", "kubedns", "status", "ready")
1365// output:
1366// >> I1025 00:15:15.525108       1 controller_utils.go:116] "Pod status updated" pod="kubedns" status="ready"
1367func InfoS(msg string, keysAndValues ...interface{}) {
1368	logging.infoS(logging.logr, msg, keysAndValues...)
1369}
1370
1371// Warning logs to the WARNING and INFO logs.
1372// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
1373func Warning(args ...interface{}) {
1374	logging.print(warningLog, logging.logr, args...)
1375}
1376
1377// WarningDepth acts as Warning but uses depth to determine which call frame to log.
1378// WarningDepth(0, "msg") is the same as Warning("msg").
1379func WarningDepth(depth int, args ...interface{}) {
1380	logging.printDepth(warningLog, logging.logr, depth, args...)
1381}
1382
1383// Warningln logs to the WARNING and INFO logs.
1384// Arguments are handled in the manner of fmt.Println; a newline is always appended.
1385func Warningln(args ...interface{}) {
1386	logging.println(warningLog, logging.logr, args...)
1387}
1388
1389// Warningf logs to the WARNING and INFO logs.
1390// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
1391func Warningf(format string, args ...interface{}) {
1392	logging.printf(warningLog, logging.logr, format, args...)
1393}
1394
1395// Error logs to the ERROR, WARNING, and INFO logs.
1396// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
1397func Error(args ...interface{}) {
1398	logging.print(errorLog, logging.logr, args...)
1399}
1400
1401// ErrorDepth acts as Error but uses depth to determine which call frame to log.
1402// ErrorDepth(0, "msg") is the same as Error("msg").
1403func ErrorDepth(depth int, args ...interface{}) {
1404	logging.printDepth(errorLog, logging.logr, depth, args...)
1405}
1406
1407// Errorln logs to the ERROR, WARNING, and INFO logs.
1408// Arguments are handled in the manner of fmt.Println; a newline is always appended.
1409func Errorln(args ...interface{}) {
1410	logging.println(errorLog, logging.logr, args...)
1411}
1412
1413// Errorf logs to the ERROR, WARNING, and INFO logs.
1414// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
1415func Errorf(format string, args ...interface{}) {
1416	logging.printf(errorLog, logging.logr, format, args...)
1417}
1418
1419// ErrorS structured logs to the ERROR, WARNING, and INFO logs.
1420// the err argument used as "err" field of log line.
1421// The msg argument used to add constant description to the log line.
1422// The key/value pairs would be join by "=" ; a newline is always appended.
1423//
1424// Basic examples:
1425// >> klog.ErrorS(err, "Failed to update pod status")
1426// output:
1427// >> E1025 00:15:15.525108       1 controller_utils.go:114] "Failed to update pod status" err="timeout"
1428func ErrorS(err error, msg string, keysAndValues ...interface{}) {
1429	logging.errorS(err, logging.logr, msg, keysAndValues...)
1430}
1431
1432// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
1433// including a stack trace of all running goroutines, then calls os.Exit(255).
1434// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
1435func Fatal(args ...interface{}) {
1436	logging.print(fatalLog, logging.logr, args...)
1437}
1438
1439// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
1440// FatalDepth(0, "msg") is the same as Fatal("msg").
1441func FatalDepth(depth int, args ...interface{}) {
1442	logging.printDepth(fatalLog, logging.logr, depth, args...)
1443}
1444
1445// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
1446// including a stack trace of all running goroutines, then calls os.Exit(255).
1447// Arguments are handled in the manner of fmt.Println; a newline is always appended.
1448func Fatalln(args ...interface{}) {
1449	logging.println(fatalLog, logging.logr, args...)
1450}
1451
1452// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
1453// including a stack trace of all running goroutines, then calls os.Exit(255).
1454// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
1455func Fatalf(format string, args ...interface{}) {
1456	logging.printf(fatalLog, logging.logr, format, args...)
1457}
1458
1459// fatalNoStacks is non-zero if we are to exit without dumping goroutine stacks.
1460// It allows Exit and relatives to use the Fatal logs.
1461var fatalNoStacks uint32
1462
1463// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
1464// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
1465func Exit(args ...interface{}) {
1466	atomic.StoreUint32(&fatalNoStacks, 1)
1467	logging.print(fatalLog, logging.logr, args...)
1468}
1469
1470// ExitDepth acts as Exit but uses depth to determine which call frame to log.
1471// ExitDepth(0, "msg") is the same as Exit("msg").
1472func ExitDepth(depth int, args ...interface{}) {
1473	atomic.StoreUint32(&fatalNoStacks, 1)
1474	logging.printDepth(fatalLog, logging.logr, depth, args...)
1475}
1476
1477// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
1478func Exitln(args ...interface{}) {
1479	atomic.StoreUint32(&fatalNoStacks, 1)
1480	logging.println(fatalLog, logging.logr, args...)
1481}
1482
1483// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
1484// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
1485func Exitf(format string, args ...interface{}) {
1486	atomic.StoreUint32(&fatalNoStacks, 1)
1487	logging.printf(fatalLog, logging.logr, format, args...)
1488}
1489
1490// ObjectRef references a kubernetes object
1491type ObjectRef struct {
1492	Name      string `json:"name"`
1493	Namespace string `json:"namespace,omitempty"`
1494}
1495
1496func (ref ObjectRef) String() string {
1497	if ref.Namespace != "" {
1498		return fmt.Sprintf("%s/%s", ref.Namespace, ref.Name)
1499	}
1500	return ref.Name
1501}
1502
1503// KMetadata is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
1504// this interface may expand in the future, but will always be a subset of the
1505// kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
1506type KMetadata interface {
1507	GetName() string
1508	GetNamespace() string
1509}
1510
1511// KObj returns ObjectRef from ObjectMeta
1512func KObj(obj KMetadata) ObjectRef {
1513	return ObjectRef{
1514		Name:      obj.GetName(),
1515		Namespace: obj.GetNamespace(),
1516	}
1517}
1518
1519// KRef returns ObjectRef from name and namespace
1520func KRef(namespace, name string) ObjectRef {
1521	return ObjectRef{
1522		Name:      name,
1523		Namespace: namespace,
1524	}
1525}
1526