// setLogEntry populates the log entry with format, arguments, // and any available fields set in the context. func setLogEntry(ctx context.Context, format string, args []interface{}, entry *proto.LogEntry) { entry.Format, entry.Args = parseFormatWithArgs(format, args) if ctx != nil { for i := Field(0); i < maxField; i++ { if v := ctx.Value(i); v != nil { switch vTyp := v.(type) { case proto.NodeID: entry.NodeID = &vTyp case proto.StoreID: entry.StoreID = &vTyp case proto.RaftID: entry.RaftID = &vTyp case proto.Method: entry.Method = &vTyp case proto.Key: entry.Key = vTyp } } } } }
// outputLogEntry marshals a log entry proto into bytes, and writes // the data to the log files. If a trace location is set, stack traces // are added to the entry before marshaling. func (l *loggingT) outputLogEntry(s Severity, file string, line int, alsoToStderr bool, entry *proto.LogEntry) { l.mu.Lock() // Set additional details in log entry. now := time.Now() entry.Severity = int32(s) entry.Time = now.UnixNano() entry.ThreadID = int32(pid) // TODO: should be TID entry.File = file entry.Line = int32(line) // On fatal log, set all stacks. if s == FatalLog { entry.Stacks = stacks(true) logExitFunc = func(error) {} // If we get a write error, we'll still exit. } else if l.traceLocation.isSet() { if l.traceLocation.match(file, line) { entry.Stacks = stacks(false) } } if l.toStderr { _, _ = os.Stderr.Write(l.processForStderr(entry)) } else { if alsoToStderr || l.alsoToStderr || s >= l.stderrThreshold.get() { _, _ = os.Stderr.Write(l.processForStderr(entry)) } if l.file[s] == nil { if err := l.createFiles(s); err != nil { _, _ = os.Stderr.Write(l.processForStderr(entry)) // Make sure the message appears somewhere. l.exit(err) } } data := encodeLogEntry(entry) 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 stats := severityStats[s]; stats != nil { atomic.AddInt64(&stats.lines, 1) atomic.AddInt64(&stats.bytes, int64(len(data))) } } l.mu.Unlock() // Flush and exit on fatal logging. if s == FatalLog { // If we got here via Exit rather than Fatal, print no stacks. timeoutFlush(10 * time.Second) if atomic.LoadUint32(&fatalNoStacks) > 0 { osExitFunc(1) } else { osExitFunc(255) // C++ uses -1, which is silly because it's anded with 255 anyway. } } }