mirror of https://github.com/docker/cli.git
vendor: k8s.io/klog v1.0.0-2-g4ad0115
Temporarily vendoring tip of the release-1.x branch, to address
docker context inspect being slow on Windows because this package
performs user lookup through `os.Current()` during `init()`.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 466c50f939
)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
bef0d567ac
commit
62a9babca6
|
@ -94,7 +94,7 @@ gotest.tools/v3 ab4a870b92ce57a83881fbeb535a
|
||||||
k8s.io/api 40a48860b5abbba9aa891b02b32da429b08d96a0 # kubernetes-1.14.0
|
k8s.io/api 40a48860b5abbba9aa891b02b32da429b08d96a0 # kubernetes-1.14.0
|
||||||
k8s.io/apimachinery d7deff9243b165ee192f5551710ea4285dcfd615 # kubernetes-1.14.0
|
k8s.io/apimachinery d7deff9243b165ee192f5551710ea4285dcfd615 # kubernetes-1.14.0
|
||||||
k8s.io/client-go 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f # kubernetes-1.14.0
|
k8s.io/client-go 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f # kubernetes-1.14.0
|
||||||
k8s.io/klog 71442cd4037d612096940ceb0f3fec3f7fff66e0 # v0.2.0
|
k8s.io/klog 4ad0115ba9e45c096d06a31d8dfb0e5bd945ec5f # v1.0.0-2-g4ad0115 pending v1.0.1 release to fix https://github.com/docker/cli/issues/2420
|
||||||
k8s.io/kube-openapi 5e45bb682580c9be5ffa4d27d367f0eeba125c7b
|
k8s.io/kube-openapi 5e45bb682580c9be5ffa4d27d367f0eeba125c7b
|
||||||
k8s.io/kubernetes 641856db18352033a0d96dbc99153fa3b27298e5 # v1.14.0
|
k8s.io/kubernetes 641856db18352033a0d96dbc99153fa3b27298e5 # v1.14.0
|
||||||
k8s.io/utils 21c4ce38f2a793ec01e925ddc31216500183b773
|
k8s.io/utils 21c4ce38f2a793ec01e925ddc31216500183b773
|
||||||
|
|
|
@ -1,7 +1,27 @@
|
||||||
klog
|
klog
|
||||||
====
|
====
|
||||||
|
|
||||||
klog is a permanant fork of https://github.com/golang/glog. original README from glog is below
|
klog is a permanent fork of https://github.com/golang/glog.
|
||||||
|
|
||||||
|
## Why was klog created?
|
||||||
|
|
||||||
|
The decision to create klog was one that wasn't made lightly, but it was necessary due to some
|
||||||
|
drawbacks that are present in [glog](https://github.com/golang/glog). Ultimately, the fork was created due to glog not being under active development; this can be seen in the glog README:
|
||||||
|
|
||||||
|
> The code in this repo [...] is not itself under development
|
||||||
|
|
||||||
|
This makes us unable to solve many use cases without a fork. The factors that contributed to needing feature development are listed below:
|
||||||
|
|
||||||
|
* `glog` [presents a lot "gotchas"](https://github.com/kubernetes/kubernetes/issues/61006) and introduces challenges in containerized environments, all of which aren't well documented.
|
||||||
|
* `glog` doesn't provide an easy way to test logs, which detracts from the stability of software using it
|
||||||
|
* A long term goal is to implement a logging interface that allows us to add context, change output format, etc.
|
||||||
|
|
||||||
|
Historical context is available here:
|
||||||
|
|
||||||
|
* https://github.com/kubernetes/kubernetes/issues/61006
|
||||||
|
* https://github.com/kubernetes/kubernetes/issues/70264
|
||||||
|
* https://groups.google.com/forum/#!msg/kubernetes-sig-architecture/wCWiWf3Juzs/hXRVBH90CgAJ
|
||||||
|
* https://groups.google.com/forum/#!msg/kubernetes-dev/7vnijOMhLS0/1oRiNtigBgAJ
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -11,7 +31,7 @@ How to use klog
|
||||||
- Use `klog.InitFlags(nil)` explicitly for initializing global flags as we no longer use `init()` method to register the flags
|
- Use `klog.InitFlags(nil)` explicitly for initializing global flags as we no longer use `init()` method to register the flags
|
||||||
- You can now use `log-file` instead of `log-dir` for logging to a single file (See `examples/log_file/usage_log_file.go`)
|
- You can now use `log-file` instead of `log-dir` for logging to a single file (See `examples/log_file/usage_log_file.go`)
|
||||||
- If you want to redirect everything logged using klog somewhere else (say syslog!), you can use `klog.SetOutput()` method and supply a `io.Writer`. (See `examples/set_output/usage_set_output.go`)
|
- If you want to redirect everything logged using klog somewhere else (say syslog!), you can use `klog.SetOutput()` method and supply a `io.Writer`. (See `examples/set_output/usage_set_output.go`)
|
||||||
- For more logging conventions (See [Logging Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/logging.md))
|
- For more logging conventions (See [Logging Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md))
|
||||||
|
|
||||||
### Coexisting with glog
|
### Coexisting with glog
|
||||||
This package can be used side by side with glog. [This example](examples/coexist_glog/coexist_glog.go) shows how to initialize and syncronize flags from the global `flag.CommandLine` FlagSet. In addition, the example makes use of stderr as combined output by setting `alsologtostderr` (or `logtostderr`) to `true`.
|
This package can be used side by side with glog. [This example](examples/coexist_glog/coexist_glog.go) shows how to initialize and syncronize flags from the global `flag.CommandLine` FlagSet. In addition, the example makes use of stderr as combined output by setting `alsologtostderr` (or `logtostderr`) to `true`.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module k8s.io/klog
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require github.com/go-logr/logr v0.1.0
|
|
@ -20,30 +20,30 @@
|
||||||
//
|
//
|
||||||
// Basic examples:
|
// Basic examples:
|
||||||
//
|
//
|
||||||
// glog.Info("Prepare to repel boarders")
|
// klog.Info("Prepare to repel boarders")
|
||||||
//
|
//
|
||||||
// glog.Fatalf("Initialization failed: %s", err)
|
// klog.Fatalf("Initialization failed: %s", err)
|
||||||
//
|
//
|
||||||
// See the documentation for the V function for an explanation of these examples:
|
// See the documentation for the V function for an explanation of these examples:
|
||||||
//
|
//
|
||||||
// if glog.V(2) {
|
// if klog.V(2) {
|
||||||
// glog.Info("Starting transaction...")
|
// klog.Info("Starting transaction...")
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// glog.V(2).Infoln("Processed", nItems, "elements")
|
// klog.V(2).Infoln("Processed", nItems, "elements")
|
||||||
//
|
//
|
||||||
// Log output is buffered and written periodically using Flush. Programs
|
// Log output is buffered and written periodically using Flush. Programs
|
||||||
// should call Flush before exiting to guarantee all log output is written.
|
// should call Flush before exiting to guarantee all log output is written.
|
||||||
//
|
//
|
||||||
// By default, all log statements write to files in a temporary directory.
|
// By default, all log statements write to standard error.
|
||||||
// This package provides several flags that modify this behavior.
|
// This package provides several flags that modify this behavior.
|
||||||
// As a result, flag.Parse must be called before any logging is done.
|
// As a result, flag.Parse must be called before any logging is done.
|
||||||
//
|
//
|
||||||
// -logtostderr=false
|
// -logtostderr=true
|
||||||
// Logs are written to standard error instead of to files.
|
// Logs are written to standard error instead of to files.
|
||||||
// -alsologtostderr=false
|
// -alsologtostderr=false
|
||||||
// Logs are written to standard error as well as to files.
|
// Logs are written to standard error as well as to files.
|
||||||
// -stderrthreshold=INFO
|
// -stderrthreshold=ERROR
|
||||||
// Log events at or above this severity are logged to standard
|
// Log events at or above this severity are logged to standard
|
||||||
// error as well as to files.
|
// error as well as to files.
|
||||||
// -log_dir=""
|
// -log_dir=""
|
||||||
|
@ -78,6 +78,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
stdLog "log"
|
stdLog "log"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -141,7 +142,7 @@ func (s *severity) Set(value string) error {
|
||||||
if v, ok := severityByName(value); ok {
|
if v, ok := severityByName(value); ok {
|
||||||
threshold = v
|
threshold = v
|
||||||
} else {
|
} else {
|
||||||
v, err := strconv.Atoi(value)
|
v, err := strconv.ParseInt(value, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -225,7 +226,7 @@ func (l *Level) Get() interface{} {
|
||||||
|
|
||||||
// Set is part of the flag.Value interface.
|
// Set is part of the flag.Value interface.
|
||||||
func (l *Level) Set(value string) error {
|
func (l *Level) Set(value string) error {
|
||||||
v, err := strconv.Atoi(value)
|
v, err := strconv.ParseInt(value, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -293,7 +294,7 @@ func (m *moduleSpec) Set(value string) error {
|
||||||
return errVmoduleSyntax
|
return errVmoduleSyntax
|
||||||
}
|
}
|
||||||
pattern := patLev[0]
|
pattern := patLev[0]
|
||||||
v, err := strconv.Atoi(patLev[1])
|
v, err := strconv.ParseInt(patLev[1], 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("syntax error: expect comma-separated list of filename=N")
|
return errors.New("syntax error: expect comma-separated list of filename=N")
|
||||||
}
|
}
|
||||||
|
@ -395,25 +396,38 @@ type flushSyncWriter interface {
|
||||||
io.Writer
|
io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init sets up the defaults and runs flushDaemon.
|
||||||
func init() {
|
func init() {
|
||||||
// Default stderrThreshold is INFO.
|
logging.stderrThreshold = errorLog // Default stderrThreshold is ERROR.
|
||||||
logging.stderrThreshold = infoLog
|
|
||||||
|
|
||||||
logging.setVState(0, nil, false)
|
logging.setVState(0, nil, false)
|
||||||
|
logging.logDir = ""
|
||||||
|
logging.logFile = ""
|
||||||
|
logging.logFileMaxSizeMB = 1800
|
||||||
|
logging.toStderr = true
|
||||||
|
logging.alsoToStderr = false
|
||||||
|
logging.skipHeaders = false
|
||||||
|
logging.addDirHeader = false
|
||||||
|
logging.skipLogHeaders = false
|
||||||
go logging.flushDaemon()
|
go logging.flushDaemon()
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitFlags is for explicitly initializing the flags
|
// InitFlags is for explicitly initializing the flags.
|
||||||
func InitFlags(flagset *flag.FlagSet) {
|
func InitFlags(flagset *flag.FlagSet) {
|
||||||
if flagset == nil {
|
if flagset == nil {
|
||||||
flagset = flag.CommandLine
|
flagset = flag.CommandLine
|
||||||
}
|
}
|
||||||
flagset.StringVar(&logging.logDir, "log_dir", "", "If non-empty, write log files in this directory")
|
|
||||||
flagset.StringVar(&logging.logFile, "log_file", "", "If non-empty, use this log file")
|
flagset.StringVar(&logging.logDir, "log_dir", logging.logDir, "If non-empty, write log files in this directory")
|
||||||
flagset.BoolVar(&logging.toStderr, "logtostderr", true, "log to standard error instead of files")
|
flagset.StringVar(&logging.logFile, "log_file", logging.logFile, "If non-empty, use this log file")
|
||||||
flagset.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files")
|
flagset.Uint64Var(&logging.logFileMaxSizeMB, "log_file_max_size", logging.logFileMaxSizeMB,
|
||||||
|
"Defines the maximum size a log file can grow to. Unit is megabytes. "+
|
||||||
|
"If the value is 0, the maximum file size is unlimited.")
|
||||||
|
flagset.BoolVar(&logging.toStderr, "logtostderr", logging.toStderr, "log to standard error instead of files")
|
||||||
|
flagset.BoolVar(&logging.alsoToStderr, "alsologtostderr", logging.alsoToStderr, "log to standard error as well as files")
|
||||||
flagset.Var(&logging.verbosity, "v", "number for the log level verbosity")
|
flagset.Var(&logging.verbosity, "v", "number for the log level verbosity")
|
||||||
flagset.BoolVar(&logging.skipHeaders, "skip_headers", false, "If true, avoid header prefixes in the log messages")
|
flagset.BoolVar(&logging.skipHeaders, "add_dir_header", logging.addDirHeader, "If true, adds the file directory to the header")
|
||||||
|
flagset.BoolVar(&logging.skipHeaders, "skip_headers", logging.skipHeaders, "If true, avoid header prefixes in the log messages")
|
||||||
|
flagset.BoolVar(&logging.skipLogHeaders, "skip_log_headers", logging.skipLogHeaders, "If true, avoid headers when opening log files")
|
||||||
flagset.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
|
flagset.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
|
||||||
flagset.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
|
flagset.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
|
||||||
flagset.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
|
flagset.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
|
||||||
|
@ -471,8 +485,18 @@ type loggingT struct {
|
||||||
// with the log-dir option.
|
// with the log-dir option.
|
||||||
logFile string
|
logFile string
|
||||||
|
|
||||||
|
// When logFile is specified, this limiter makes sure the logFile won't exceeds a certain size. When exceeds, the
|
||||||
|
// logFile will be cleaned up. If this value is 0, no size limitation will be applied to logFile.
|
||||||
|
logFileMaxSizeMB uint64
|
||||||
|
|
||||||
// If true, do not add the prefix headers, useful when used with SetOutput
|
// If true, do not add the prefix headers, useful when used with SetOutput
|
||||||
skipHeaders bool
|
skipHeaders bool
|
||||||
|
|
||||||
|
// If true, do not add the headers to log files
|
||||||
|
skipLogHeaders bool
|
||||||
|
|
||||||
|
// If true, add the file directory to the header
|
||||||
|
addDirHeader bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer holds a byte Buffer for reuse. The zero value is ready for use.
|
// buffer holds a byte Buffer for reuse. The zero value is ready for use.
|
||||||
|
@ -558,9 +582,14 @@ func (l *loggingT) header(s severity, depth int) (*buffer, string, int) {
|
||||||
file = "???"
|
file = "???"
|
||||||
line = 1
|
line = 1
|
||||||
} else {
|
} else {
|
||||||
slash := strings.LastIndex(file, "/")
|
if slash := strings.LastIndex(file, "/"); slash >= 0 {
|
||||||
if slash >= 0 {
|
path := file
|
||||||
file = file[slash+1:]
|
file = path[slash+1:]
|
||||||
|
if l.addDirHeader {
|
||||||
|
if dirsep := strings.LastIndex(path[:slash], "/"); dirsep >= 0 {
|
||||||
|
file = path[dirsep+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return l.formatHeader(s, file, line), file, line
|
return l.formatHeader(s, file, line), file, line
|
||||||
|
@ -709,6 +738,8 @@ func (rb *redirectBuffer) Write(bytes []byte) (n int, err error) {
|
||||||
|
|
||||||
// SetOutput sets the output destination for all severities
|
// SetOutput sets the output destination for all severities
|
||||||
func SetOutput(w io.Writer) {
|
func SetOutput(w io.Writer) {
|
||||||
|
logging.mu.Lock()
|
||||||
|
defer logging.mu.Unlock()
|
||||||
for s := fatalLog; s >= infoLog; s-- {
|
for s := fatalLog; s >= infoLog; s-- {
|
||||||
rb := &redirectBuffer{
|
rb := &redirectBuffer{
|
||||||
w: w,
|
w: w,
|
||||||
|
@ -719,6 +750,8 @@ func SetOutput(w io.Writer) {
|
||||||
|
|
||||||
// SetOutputBySeverity sets the output destination for specific severity
|
// SetOutputBySeverity sets the output destination for specific severity
|
||||||
func SetOutputBySeverity(name string, w io.Writer) {
|
func SetOutputBySeverity(name string, w io.Writer) {
|
||||||
|
logging.mu.Lock()
|
||||||
|
defer logging.mu.Unlock()
|
||||||
sev, ok := severityByName(name)
|
sev, ok := severityByName(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("SetOutputBySeverity(%q): unrecognized severity name", name))
|
panic(fmt.Sprintf("SetOutputBySeverity(%q): unrecognized severity name", name))
|
||||||
|
@ -739,31 +772,43 @@ func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoTo
|
||||||
}
|
}
|
||||||
data := buf.Bytes()
|
data := buf.Bytes()
|
||||||
if l.toStderr {
|
if l.toStderr {
|
||||||
if s >= l.stderrThreshold.get() {
|
os.Stderr.Write(data)
|
||||||
os.Stderr.Write(data)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
|
if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
|
||||||
os.Stderr.Write(data)
|
os.Stderr.Write(data)
|
||||||
}
|
}
|
||||||
if l.file[s] == nil {
|
|
||||||
if err := l.createFiles(s); err != nil {
|
if logging.logFile != "" {
|
||||||
os.Stderr.Write(data) // Make sure the message appears somewhere.
|
// Since we are using a single log file, all of the items in l.file array
|
||||||
l.exit(err)
|
// will point to the same file, so just use one of them to write data.
|
||||||
|
if l.file[infoLog] == nil {
|
||||||
|
if err := l.createFiles(infoLog); err != nil {
|
||||||
|
os.Stderr.Write(data) // Make sure the message appears somewhere.
|
||||||
|
l.exit(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
switch s {
|
|
||||||
case fatalLog:
|
|
||||||
l.file[fatalLog].Write(data)
|
|
||||||
fallthrough
|
|
||||||
case errorLog:
|
|
||||||
l.file[errorLog].Write(data)
|
|
||||||
fallthrough
|
|
||||||
case warningLog:
|
|
||||||
l.file[warningLog].Write(data)
|
|
||||||
fallthrough
|
|
||||||
case infoLog:
|
|
||||||
l.file[infoLog].Write(data)
|
l.file[infoLog].Write(data)
|
||||||
|
} else {
|
||||||
|
if l.file[s] == nil {
|
||||||
|
if err := l.createFiles(s); err != nil {
|
||||||
|
os.Stderr.Write(data) // Make sure the message appears somewhere.
|
||||||
|
l.exit(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case fatalLog:
|
||||||
|
l.file[fatalLog].Write(data)
|
||||||
|
fallthrough
|
||||||
|
case errorLog:
|
||||||
|
l.file[errorLog].Write(data)
|
||||||
|
fallthrough
|
||||||
|
case warningLog:
|
||||||
|
l.file[warningLog].Write(data)
|
||||||
|
fallthrough
|
||||||
|
case infoLog:
|
||||||
|
l.file[infoLog].Write(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s == fatalLog {
|
if s == fatalLog {
|
||||||
|
@ -802,7 +847,7 @@ func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoTo
|
||||||
|
|
||||||
// timeoutFlush calls Flush and returns when it completes or after timeout
|
// timeoutFlush calls Flush and returns when it completes or after timeout
|
||||||
// elapses, whichever happens first. This is needed because the hooks invoked
|
// elapses, whichever happens first. This is needed because the hooks invoked
|
||||||
// by Flush may deadlock when glog.Fatal is called from a hook that holds
|
// by Flush may deadlock when klog.Fatal is called from a hook that holds
|
||||||
// a lock.
|
// a lock.
|
||||||
func timeoutFlush(timeout time.Duration) {
|
func timeoutFlush(timeout time.Duration) {
|
||||||
done := make(chan bool, 1)
|
done := make(chan bool, 1)
|
||||||
|
@ -813,7 +858,7 @@ func timeoutFlush(timeout time.Duration) {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout)
|
fmt.Fprintln(os.Stderr, "klog: Flush took longer than", timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,18 +908,33 @@ func (l *loggingT) exit(err error) {
|
||||||
type syncBuffer struct {
|
type syncBuffer struct {
|
||||||
logger *loggingT
|
logger *loggingT
|
||||||
*bufio.Writer
|
*bufio.Writer
|
||||||
file *os.File
|
file *os.File
|
||||||
sev severity
|
sev severity
|
||||||
nbytes uint64 // The number of bytes written to this file
|
nbytes uint64 // The number of bytes written to this file
|
||||||
|
maxbytes uint64 // The max number of bytes this syncBuffer.file can hold before cleaning up.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *syncBuffer) Sync() error {
|
func (sb *syncBuffer) Sync() error {
|
||||||
return sb.file.Sync()
|
return sb.file.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateMaxSize returns the real max size in bytes after considering the default max size and the flag options.
|
||||||
|
func CalculateMaxSize() uint64 {
|
||||||
|
if logging.logFile != "" {
|
||||||
|
if logging.logFileMaxSizeMB == 0 {
|
||||||
|
// If logFileMaxSizeMB is zero, we don't have limitations on the log size.
|
||||||
|
return math.MaxUint64
|
||||||
|
}
|
||||||
|
// Flag logFileMaxSizeMB is in MB for user convenience.
|
||||||
|
return logging.logFileMaxSizeMB * 1024 * 1024
|
||||||
|
}
|
||||||
|
// If "log_file" flag is not specified, the target file (sb.file) will be cleaned up when reaches a fixed size.
|
||||||
|
return MaxSize
|
||||||
|
}
|
||||||
|
|
||||||
func (sb *syncBuffer) Write(p []byte) (n int, err error) {
|
func (sb *syncBuffer) Write(p []byte) (n int, err error) {
|
||||||
if sb.nbytes+uint64(len(p)) >= MaxSize {
|
if sb.nbytes+uint64(len(p)) >= sb.maxbytes {
|
||||||
if err := sb.rotateFile(time.Now()); err != nil {
|
if err := sb.rotateFile(time.Now(), false); err != nil {
|
||||||
sb.logger.exit(err)
|
sb.logger.exit(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,13 +947,15 @@ func (sb *syncBuffer) Write(p []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotateFile closes the syncBuffer's file and starts a new one.
|
// rotateFile closes the syncBuffer's file and starts a new one.
|
||||||
func (sb *syncBuffer) rotateFile(now time.Time) error {
|
// The startup argument indicates whether this is the initial startup of klog.
|
||||||
|
// If startup is true, existing files are opened for appending instead of truncated.
|
||||||
|
func (sb *syncBuffer) rotateFile(now time.Time, startup bool) error {
|
||||||
if sb.file != nil {
|
if sb.file != nil {
|
||||||
sb.Flush()
|
sb.Flush()
|
||||||
sb.file.Close()
|
sb.file.Close()
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
sb.file, _, err = create(severityName[sb.sev], now)
|
sb.file, _, err = create(severityName[sb.sev], now, startup)
|
||||||
sb.nbytes = 0
|
sb.nbytes = 0
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -901,6 +963,10 @@ func (sb *syncBuffer) rotateFile(now time.Time) error {
|
||||||
|
|
||||||
sb.Writer = bufio.NewWriterSize(sb.file, bufferSize)
|
sb.Writer = bufio.NewWriterSize(sb.file, bufferSize)
|
||||||
|
|
||||||
|
if sb.logger.skipLogHeaders {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Write header.
|
// Write header.
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05"))
|
fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05"))
|
||||||
|
@ -925,10 +991,11 @@ func (l *loggingT) createFiles(sev severity) error {
|
||||||
// has already been created, we can stop.
|
// has already been created, we can stop.
|
||||||
for s := sev; s >= infoLog && l.file[s] == nil; s-- {
|
for s := sev; s >= infoLog && l.file[s] == nil; s-- {
|
||||||
sb := &syncBuffer{
|
sb := &syncBuffer{
|
||||||
logger: l,
|
logger: l,
|
||||||
sev: s,
|
sev: s,
|
||||||
|
maxbytes: CalculateMaxSize(),
|
||||||
}
|
}
|
||||||
if err := sb.rotateFile(now); err != nil {
|
if err := sb.rotateFile(now, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.file[s] = sb
|
l.file[s] = sb
|
||||||
|
@ -1047,9 +1114,9 @@ type Verbose bool
|
||||||
// The returned value is a boolean of type Verbose, which implements Info, Infoln
|
// The returned value is a boolean of type Verbose, which implements Info, Infoln
|
||||||
// and Infof. These methods will write to the Info log if called.
|
// and Infof. These methods will write to the Info log if called.
|
||||||
// Thus, one may write either
|
// Thus, one may write either
|
||||||
// if glog.V(2) { glog.Info("log this") }
|
// if klog.V(2) { klog.Info("log this") }
|
||||||
// or
|
// or
|
||||||
// glog.V(2).Info("log this")
|
// klog.V(2).Info("log this")
|
||||||
// The second form is shorter but the first is cheaper if logging is off because it does
|
// The second form is shorter but the first is cheaper if logging is off because it does
|
||||||
// not evaluate its arguments.
|
// not evaluate its arguments.
|
||||||
//
|
//
|
||||||
|
@ -1123,7 +1190,7 @@ func InfoDepth(depth int, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infoln logs to the INFO log.
|
// Infoln logs to the INFO log.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||||
func Infoln(args ...interface{}) {
|
func Infoln(args ...interface{}) {
|
||||||
logging.println(infoLog, args...)
|
logging.println(infoLog, args...)
|
||||||
}
|
}
|
||||||
|
@ -1147,7 +1214,7 @@ func WarningDepth(depth int, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warningln logs to the WARNING and INFO logs.
|
// Warningln logs to the WARNING and INFO logs.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||||
func Warningln(args ...interface{}) {
|
func Warningln(args ...interface{}) {
|
||||||
logging.println(warningLog, args...)
|
logging.println(warningLog, args...)
|
||||||
}
|
}
|
||||||
|
@ -1171,7 +1238,7 @@ func ErrorDepth(depth int, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||||
func Errorln(args ...interface{}) {
|
func Errorln(args ...interface{}) {
|
||||||
logging.println(errorLog, args...)
|
logging.println(errorLog, args...)
|
||||||
}
|
}
|
||||||
|
@ -1197,7 +1264,7 @@ func FatalDepth(depth int, args ...interface{}) {
|
||||||
|
|
||||||
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
||||||
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
// including a stack trace of all running goroutines, then calls os.Exit(255).
|
||||||
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
// Arguments are handled in the manner of fmt.Println; a newline is always appended.
|
||||||
func Fatalln(args ...interface{}) {
|
func Fatalln(args ...interface{}) {
|
||||||
logging.println(fatalLog, args...)
|
logging.println(fatalLog, args...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -55,13 +56,31 @@ func init() {
|
||||||
host = shortHostname(h)
|
host = shortHostname(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
current, err := user.Current()
|
// On Windows, the Go 'user' package requires netapi32.dll.
|
||||||
if err == nil {
|
// This affects Windows Nano Server:
|
||||||
userName = current.Username
|
// https://github.com/golang/go/issues/21867
|
||||||
}
|
// Fallback to using environment variables.
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
u := os.Getenv("USERNAME")
|
||||||
|
if len(u) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Sanitize the USERNAME since it may contain filepath separators.
|
||||||
|
u = strings.Replace(u, `\`, "_", -1)
|
||||||
|
|
||||||
// Sanitize userName since it may contain filepath separators on Windows.
|
// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
|
||||||
userName = strings.Replace(userName, `\`, "_", -1)
|
d := os.Getenv("USERDOMAIN")
|
||||||
|
if len(d) != 0 {
|
||||||
|
userName = d + "_" + u
|
||||||
|
} else {
|
||||||
|
userName = u
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current, err := user.Current()
|
||||||
|
if err == nil {
|
||||||
|
userName = current.Username
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shortHostname returns its argument, truncating at the first period.
|
// shortHostname returns its argument, truncating at the first period.
|
||||||
|
@ -97,9 +116,11 @@ var onceLogDirs sync.Once
|
||||||
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
||||||
// successfully, create also attempts to update the symlink for that tag, ignoring
|
// successfully, create also attempts to update the symlink for that tag, ignoring
|
||||||
// errors.
|
// errors.
|
||||||
func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
// The startup argument indicates whether this is the initial startup of klog.
|
||||||
|
// If startup is true, existing files are opened for appending instead of truncated.
|
||||||
|
func create(tag string, t time.Time, startup bool) (f *os.File, filename string, err error) {
|
||||||
if logging.logFile != "" {
|
if logging.logFile != "" {
|
||||||
f, err := os.Create(logging.logFile)
|
f, err := openOrCreate(logging.logFile, startup)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f, logging.logFile, nil
|
return f, logging.logFile, nil
|
||||||
}
|
}
|
||||||
|
@ -113,7 +134,7 @@ func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for _, dir := range logDirs {
|
for _, dir := range logDirs {
|
||||||
fname := filepath.Join(dir, name)
|
fname := filepath.Join(dir, name)
|
||||||
f, err := os.Create(fname)
|
f, err := openOrCreate(fname, startup)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
symlink := filepath.Join(dir, link)
|
symlink := filepath.Join(dir, link)
|
||||||
os.Remove(symlink) // ignore err
|
os.Remove(symlink) // ignore err
|
||||||
|
@ -124,3 +145,14 @@ func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
||||||
}
|
}
|
||||||
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The startup argument indicates whether this is the initial startup of klog.
|
||||||
|
// If startup is true, existing files are opened for appending instead of truncated.
|
||||||
|
func openOrCreate(name string, startup bool) (*os.File, error) {
|
||||||
|
if startup {
|
||||||
|
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
return f, err
|
||||||
|
}
|
||||||
|
f, err := os.Create(name)
|
||||||
|
return f, err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue