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 // Copyright 2022 The Kubernetes Authors. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package klog 19 20 import ( 21 "fmt" 22 "os" 23 "time" 24 ) 25 26 var ( 27 28 // ExitFlushTimeout is the timeout that klog has traditionally used during 29 // calls like Fatal or Exit when flushing log data right before exiting. 30 // Applications that replace those calls and do not have some specific 31 // requirements like "exit immediately" can use this value as parameter 32 // for FlushAndExit. 33 // 34 // Can be set for testing purpose or to change the application's 35 // default. 36 ExitFlushTimeout = 10 * time.Second 37 38 // OsExit is the function called by FlushAndExit to terminate the program. 39 // 40 // Can be set for testing purpose or to change the application's 41 // default behavior. Note that the function should not simply return 42 // because callers of functions like Fatal will not expect that. 43 OsExit = os.Exit 44 ) 45 46 // FlushAndExit flushes log data for a certain amount of time and then calls 47 // os.Exit. Combined with some logging call it provides a replacement for 48 // traditional calls like Fatal or Exit. 49 func FlushAndExit(flushTimeout time.Duration, exitCode int) { 50 timeoutFlush(flushTimeout) 51 OsExit(exitCode) 52 } 53 54 // timeoutFlush calls Flush and returns when it completes or after timeout 55 // elapses, whichever happens first. This is needed because the hooks invoked 56 // by Flush may deadlock when klog.Fatal is called from a hook that holds 57 // a lock. Flushing also might take too long. 58 func timeoutFlush(timeout time.Duration) { 59 done := make(chan bool, 1) 60 go func() { 61 Flush() // calls logging.lockAndFlushAll() 62 done <- true 63 }() 64 select { 65 case <-done: 66 case <-time.After(timeout): 67 fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout) 68 } 69 } 70