Skip to content

Commit 941d47b

Browse files
committed
Revert "Fix the log duplication issue for --log-file."
This reverts commit 7eb35e2.
1 parent 78315d9 commit 941d47b

File tree

2 files changed

+55
-170
lines changed

2 files changed

+55
-170
lines changed

klog.go

+54-107
Original file line numberDiff line numberDiff line change
@@ -414,16 +414,6 @@ func InitFlags(flagset *flag.FlagSet) {
414414
logging.logDir = ""
415415
logging.logFile = ""
416416
logging.logFileMaxSizeMB = 1800
417-
// TODO: The default value of toStderr should be false.
418-
// Ideally, toStderr can be deprecated.
419-
// If --log-file is set, only log to the dedicated log-file.
420-
// If --alsoToStderr is true, whether or not --log-file is set, we will
421-
// log to stderr.
422-
// Since kubernetes/kubernetes are currently using klog with
423-
// default --toStderr to be true, we can't change this default value
424-
// directly.
425-
// As a compromise, when --log-file is set, the toStdErr is reset to
426-
// be false. e.g. See function `IsSingleMode`.
427417
logging.toStderr = true
428418
logging.alsoToStderr = false
429419
logging.skipHeaders = false
@@ -477,8 +467,6 @@ type loggingT struct {
477467
mu sync.Mutex
478468
// file holds writer for each of the log types.
479469
file [numSeverity]flushSyncWriter
480-
// file holds writer for the dedicated file when --log-file is set.
481-
singleModeFile flushSyncWriter
482470
// pcs is used in V to avoid an allocation when computing the caller's PC.
483471
pcs [1]uintptr
484472
// vmap is a cache of the V Level for each V() call site, identified by PC.
@@ -523,16 +511,6 @@ type buffer struct {
523511

524512
var logging loggingT
525513

526-
func (l *loggingT) IsSingleMode() bool {
527-
if l.logFile != "" {
528-
// TODO: Remove the toStdErr reset when switching the logging.toStderr
529-
// default value to be false.
530-
l.toStderr = false
531-
return true
532-
}
533-
return false
534-
}
535-
536514
// setVState sets a consistent state for V logging.
537515
// l.mu is held.
538516
func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) {
@@ -758,40 +736,24 @@ func (rb *redirectBuffer) Write(bytes []byte) (n int, err error) {
758736

759737
// SetOutput sets the output destination for all severities
760738
func SetOutput(w io.Writer) {
761-
// In single-mode, all severity logs are tracked in a single dedicated file.
762-
if logging.IsSingleMode() {
739+
for s := fatalLog; s >= infoLog; s-- {
763740
rb := &redirectBuffer{
764741
w: w,
765742
}
766-
logging.singleModeFile = rb
767-
} else {
768-
for s := fatalLog; s >= infoLog; s-- {
769-
rb := &redirectBuffer{
770-
w: w,
771-
}
772-
logging.file[s] = rb
773-
}
743+
logging.file[s] = rb
774744
}
775745
}
776746

777747
// SetOutputBySeverity sets the output destination for specific severity
778748
func SetOutputBySeverity(name string, w io.Writer) {
779-
// In single-mode, all severity logs are tracked in a single dedicated file.
780-
// Guarantee this buffer exists whatever severity output is trying to be set.
781-
if logging.IsSingleMode() {
782-
if logging.singleModeFile == nil {
783-
logging.singleModeFile = &redirectBuffer{w: w}
784-
}
785-
} else {
786-
sev, ok := severityByName(name)
787-
if !ok {
788-
panic(fmt.Sprintf("SetOutputBySeverity(%q): unrecognized severity name", name))
789-
}
790-
rb := &redirectBuffer{
791-
w: w,
792-
}
793-
logging.file[sev] = rb
749+
sev, ok := severityByName(name)
750+
if !ok {
751+
panic(fmt.Sprintf("SetOutputBySeverity(%q): unrecognized severity name", name))
794752
}
753+
rb := &redirectBuffer{
754+
w: w,
755+
}
756+
logging.file[sev] = rb
795757
}
796758

797759
// output writes the data to the log files and releases the buffer.
@@ -803,73 +765,66 @@ func (l *loggingT) output(s severity, buf *buffer, file string, line int, alsoTo
803765
}
804766
}
805767
data := buf.Bytes()
806-
l.writeLogData(s, data)
768+
if l.toStderr {
769+
os.Stderr.Write(data)
770+
} else {
771+
if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() {
772+
os.Stderr.Write(data)
773+
}
774+
if l.file[s] == nil {
775+
if err := l.createFiles(s); err != nil {
776+
os.Stderr.Write(data) // Make sure the message appears somewhere.
777+
l.exit(err)
778+
}
779+
}
780+
switch s {
781+
case fatalLog:
782+
l.file[fatalLog].Write(data)
783+
fallthrough
784+
case errorLog:
785+
l.file[errorLog].Write(data)
786+
fallthrough
787+
case warningLog:
788+
l.file[warningLog].Write(data)
789+
fallthrough
790+
case infoLog:
791+
l.file[infoLog].Write(data)
792+
}
793+
}
807794
if s == fatalLog {
808795
// If we got here via Exit rather than Fatal, print no stacks.
809796
if atomic.LoadUint32(&fatalNoStacks) > 0 {
810797
l.mu.Unlock()
811798
timeoutFlush(10 * time.Second)
812799
os.Exit(1)
813800
}
801+
// Dump all goroutine stacks before exiting.
802+
// First, make sure we see the trace for the current goroutine on standard error.
803+
// If -logtostderr has been specified, the loop below will do that anyway
804+
// as the first stack in the full dump.
805+
if !l.toStderr {
806+
os.Stderr.Write(stacks(false))
807+
}
808+
// Write the stack trace for all goroutines to the files.
809+
trace := stacks(true)
814810
logExitFunc = func(error) {} // If we get a write error, we'll still exit below.
815-
l.writeLogData(fatalLog, stacks(true))
811+
for log := fatalLog; log >= infoLog; log-- {
812+
if f := l.file[log]; f != nil { // Can be nil if -logtostderr is set.
813+
f.Write(trace)
814+
}
815+
}
816816
l.mu.Unlock()
817817
timeoutFlush(10 * time.Second)
818818
os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
819819
}
820820
l.putBuffer(buf)
821821
l.mu.Unlock()
822-
// Note: The stats estimate logs for each severity level individually,
823-
// even in the situation that log-file is specified and
824-
// all severity-level logs are tracked only in the infoLog file.
825822
if stats := severityStats[s]; stats != nil {
826823
atomic.AddInt64(&stats.lines, 1)
827824
atomic.AddInt64(&stats.bytes, int64(len(data)))
828825
}
829826
}
830827

831-
// writeLogData writes |data| to the `s` and lower severity files.
832-
// e.g. If Severity level is Error, the data will be written to all the Error,
833-
// Warning, and Info log file. However, if --log_file flag is provided, klog
834-
// no longer tracks logs separately due to their severity level, but rather
835-
// only write to the singleModeFile which later on will be flushed to the
836-
// dedicated log_file.
837-
func (l *loggingT) writeLogData(s severity, data []byte) {
838-
shouldAlsoToStderr := l.alsoToStderr && s >= l.stderrThreshold.get()
839-
if l.IsSingleMode() {
840-
if shouldAlsoToStderr {
841-
os.Stderr.Write(data)
842-
}
843-
if l.singleModeFile == nil {
844-
now := time.Now()
845-
sb := &syncBuffer{
846-
logger: l,
847-
maxbytes: CalculateMaxSize(),
848-
}
849-
if err := sb.rotateFile(now, true); err != nil {
850-
l.exit(err)
851-
}
852-
l.singleModeFile = sb
853-
}
854-
l.singleModeFile.Write(data)
855-
} else {
856-
if l.toStderr || shouldAlsoToStderr {
857-
os.Stderr.Write(data)
858-
}
859-
for currSeverity := s; currSeverity >= infoLog; currSeverity-- {
860-
if l.file[currSeverity] == nil {
861-
if err := l.createFiles(currSeverity); err != nil {
862-
os.Stderr.Write(data) // Make sure the message appears somewhere.
863-
l.exit(err)
864-
}
865-
}
866-
if f := l.file[currSeverity]; f != nil { // Can be nil if -logtostderr is set.
867-
f.Write(data)
868-
}
869-
}
870-
}
871-
}
872-
873828
// timeoutFlush calls Flush and returns when it completes or after timeout
874829
// elapses, whichever happens first. This is needed because the hooks invoked
875830
// by Flush may deadlock when glog.Fatal is called from a hook that holds
@@ -1047,21 +1002,13 @@ func (l *loggingT) lockAndFlushAll() {
10471002
// flushAll flushes all the logs and attempts to "sync" their data to disk.
10481003
// l.mu is held.
10491004
func (l *loggingT) flushAll() {
1050-
if l.IsSingleMode() {
1051-
file := l.singleModeFile
1005+
// Flush from fatal down, in case there's trouble flushing.
1006+
for s := fatalLog; s >= infoLog; s-- {
1007+
file := l.file[s]
10521008
if file != nil {
10531009
file.Flush() // ignore error
10541010
file.Sync() // ignore error
10551011
}
1056-
} else {
1057-
// Flush from fatal down, in case there's trouble flushing.
1058-
for s := fatalLog; s >= infoLog; s-- {
1059-
file := l.file[s]
1060-
if file != nil {
1061-
file.Flush() // ignore error
1062-
file.Sync() // ignore error
1063-
}
1064-
}
10651012
}
10661013
}
10671014

@@ -1147,9 +1094,9 @@ type Verbose bool
11471094
// The returned value is a boolean of type Verbose, which implements Info, Infoln
11481095
// and Infof. These methods will write to the Info log if called.
11491096
// Thus, one may write either
1150-
// if glog.V(2) { glog.Info("log this") }
1097+
// if glog.V(2) { glog.Info("log this") }
11511098
// or
1152-
// glog.V(2).Info("log this")
1099+
// glog.V(2).Info("log this")
11531100
// The second form is shorter but the first is cheaper if logging is off because it does
11541101
// not evaluate its arguments.
11551102
//

klog_test.go

+1-63
Original file line numberDiff line numberDiff line change
@@ -22,63 +22,14 @@ import (
2222
"fmt"
2323
"io/ioutil"
2424
stdLog "log"
25-
"os"
2625
"path/filepath"
27-
"regexp"
2826
"runtime"
2927
"strconv"
3028
"strings"
3129
"testing"
3230
"time"
3331
)
3432

35-
// Test that no duplicated logs are written to logfile.
36-
func TestDedupLogsInSingleLogFileMode(t *testing.T) {
37-
setFlags()
38-
39-
tmpLogFile := "tmp-klog"
40-
errMsg := "Test. This is an error"
41-
tmpFile, err := ioutil.TempFile("", tmpLogFile)
42-
defer deleteFile(tmpFile.Name())
43-
44-
if err != nil {
45-
t.Fatalf("unexpected error: %v", err)
46-
}
47-
logging.logFile = tmpFile.Name()
48-
logging.toStderr = false
49-
logging.alsoToStderr = false
50-
logging.skipLogHeaders = true
51-
Error(errMsg)
52-
logging.flushAll()
53-
54-
f, err := os.Open(tmpFile.Name())
55-
if err != nil {
56-
t.Fatalf("error %v", err)
57-
}
58-
content := make([]byte, 1000)
59-
f.Read(content)
60-
tmpFile.Close()
61-
62-
// the log message is of format (w/ header): Lmmdd hh:mm:ss.uuuuuu threadid file:line] %v
63-
expectedRegx := fmt.Sprintf(
64-
`E[0-9]{4}\s+[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}\s+[0-9]+\s+klog_test.go:[0-9]+]\s+%v`, errMsg)
65-
re := regexp.MustCompile(expectedRegx)
66-
actual := string(content)
67-
// Verify the logFile doesn't have duplicated log items. If log-file not specified, Error log will also show
68-
// up in Warning and Info log.
69-
if !re.MatchString(actual) {
70-
t.Fatalf("Was expecting Error and Fatal logs both show up and show up only once, result equals\n %v",
71-
actual)
72-
}
73-
}
74-
75-
func deleteFile(path string) {
76-
var err = os.Remove(path)
77-
if err != nil {
78-
fmt.Println(err.Error())
79-
}
80-
}
81-
8233
// TODO: This test package should be refactored so that tests cannot
8334
// interfere with each-other.
8435

@@ -137,18 +88,6 @@ func contains(s severity, str string, t *testing.T) bool {
13788
// setFlags configures the logging flags how the test expects them.
13889
func setFlags() {
13990
logging.toStderr = false
140-
logging.logFile = ""
141-
logging.alsoToStderr = false
142-
logging.skipLogHeaders = false
143-
144-
for s := fatalLog; s >= infoLog; s-- {
145-
if logging.file[s] != nil {
146-
os.Remove(logging.file[s].(*syncBuffer).file.Name())
147-
logging.file[s] = nil
148-
}
149-
}
150-
logging.singleModeFile = nil
151-
15291
}
15392

15493
// Test that Info works as advertised.
@@ -462,7 +401,7 @@ func TestOpenAppendOnStart(t *testing.T) {
462401

463402
// Logging creates the file
464403
Info(x)
465-
_, ok := logging.singleModeFile.(*syncBuffer)
404+
_, ok := logging.file[infoLog].(*syncBuffer)
466405
if !ok {
467406
t.Fatal("info wasn't created")
468407
}
@@ -472,7 +411,6 @@ func TestOpenAppendOnStart(t *testing.T) {
472411
// ensure we wrote what we expected
473412
logging.flushAll()
474413
b, err := ioutil.ReadFile(logging.logFile)
475-
476414
if err != nil {
477415
t.Fatalf("unexpected error: %v", err)
478416
}

0 commit comments

Comments
 (0)