// Tail returns the last log entry for a given log stream.
507405
func (s *server) Tail(c context.Context, req *logdog.TailRequest) (*logdog.GetResponse, error) {
	r := logdog.GetRequest{
		Project: req.Project,
		Path:    req.Path,
		State:   req.State,
	}
	return s.getImpl(c, &r, true)
}
733444
func (l *Log) truncate(index uint64, term uint64) error {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	debugln("log.truncate: ", index)

	// Do not allow committed entries to be truncated.
	if index < l.commitIndex {
		debugln("log.truncate.before")
		return fmt.Errorf("raft.Log: Index is already committed (%v): (IDX=%v, TERM=%v)", l.commitIndex, index, term)
	}

	// Do not truncate past end of entries.
	if index > l.startIndex+uint64(len(l.entries)) {
		debugln("log.truncate.after")
		return fmt.Errorf("raft.Log: Entry index does not exist (MAX=%v): (IDX=%v, TERM=%v)", len(l.entries), index, term)
	}

	// If we're truncating everything then just clear the entries.
	if index == l.startIndex {
		debugln("log.truncate.clear")
		l.file.Truncate(0)
		l.file.Seek(0, os.SEEK_SET)

		// notify clients if this node is the previous leader
		for _, entry := range l.entries {
			if entry.event != nil {
				entry.event.c <- errors.New("command failed to be committed due to node failure")
			}
		}

		l.entries = []*LogEntry{}
	} else {
		// Do not truncate if the entry at index does not have the matching term.
		entry := l.entries[index-l.startIndex-1]
		if len(l.entries) > 0 && entry.Term() != term {
			debugln("log.truncate.termMismatch")
			return fmt.Errorf("raft.Log: Entry at index does not have matching term (%v): (IDX=%v, TERM=%v)", entry.Term(), index, term)
		}

		// Otherwise truncate up to the desired entry.
		if index < l.startIndex+uint64(len(l.entries)) {
			debugln("log.truncate.finish")
			position := l.entries[index-l.startIndex].Position
			l.file.Truncate(position)
			l.file.Seek(position, os.SEEK_SET)

			// notify clients if this node is the previous leader
			for i := index - l.startIndex; i < uint64(len(l.entries)); i++ {
				entry := l.entries[i]
				if entry.event != nil {
					entry.event.c <- errors.New("command failed to be committed due to node failure")
				}
			}

			l.entries = l.entries[0 : index-l.startIndex]
		}
	}

	return nil
}
899153
func (ts *traceState) Log() {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	gLogger.Println()

	// Special case: we require at least one span.
	if len(ts.spans) == 0 {
		return
	}

	// Print a banner for this trace.
	const bannerHalfLength = 45

	gLogger.Println()
	gLogger.Printf(
		"%s %s %s",
		strings.Repeat("=", bannerHalfLength),
		ts.spans[0].desc,
		strings.Repeat("=", bannerHalfLength))
	gLogger.Printf("Start time: %v", ts.spans[0].start.Format(time.RFC3339Nano))
	gLogger.Println()

	// Find the minimum start time and maximum end time of all durations.
	var minStart time.Time
	var maxEnd time.Time
	for _, s := range ts.spans {
		if !s.finished {
			continue
		}

		if minStart.IsZero() || s.start.Before(minStart) {
			minStart = s.start
		}

		if maxEnd.Before(s.end) {
			maxEnd = s.end
		}
	}

	// Bail out if something weird happened.
	//
	// TODO(jacobsa): Be more graceful.
	totalDuration := maxEnd.Sub(minStart)
	if minStart.IsZero() || maxEnd.IsZero() || totalDuration <= 0 {
		gLogger.Println("(Weird trace)")
		return
	}

	// Calculate the number of nanoseconds elapsed, as a floating point number.
	totalNs := float64(totalDuration / time.Nanosecond)

	// Log each span with some ASCII art showing its length relative to the
	// total.
	const totalNumCols float64 = 120
	for _, s := range ts.spans {
		if !s.finished {
			gLogger.Printf("(Unfinished: %s)", s.desc)
			gLogger.Println()
			continue
		}

		// Calculate the duration of the span, and its width relative to the
		// longest span.
		d := s.end.Sub(s.start)
		if d <= 0 {
			gLogger.Println("(Weird duration)")
			gLogger.Println()
			continue
		}

		durationRatio := float64(d/time.Nanosecond) / totalNs

		// We will offset the label and banner proportional to the time since the
		// start of the earliest span.
		offsetRatio := float64(s.start.Sub(minStart)/time.Nanosecond) / totalNs
		offsetChars := int(round(offsetRatio * totalNumCols))
		offsetStr := strings.Repeat(" ", offsetChars)

		// Print the description and duration.
		gLogger.Printf("%s%v", offsetStr, s.desc)
		gLogger.Printf("%s%v", offsetStr, d)

		// Print a banner showing the duration graphically.
		bannerChars := int(round(durationRatio * totalNumCols))
		var dashes string
		if bannerChars > 2 {
			dashes = strings.Repeat("-", bannerChars-2)
		}

		gLogger.Printf("%s|%s|", offsetStr, dashes)
		gLogger.Println()
	}
}
332740
func (handler *Handler) Last() *event.Event {
	handler.mutex.Lock()
	defer handler.mutex.Unlock()

	l := len(handler.events)
	if l == 0 {
		return nil
	}

	logEvent := handler.events[l-1]
	return logEvent
}
716794
func (l *IoLogger) Log(data Data) error {
	line := fmt.Sprintf("%s\n", BuildLog(data, l.AddTime))
	_, err := l.stream.Write([]byte(line))
	return err
}
639812
func (l *Logger) log(level Level, e *Entry, msg string) {
	if level < l.Level {
		return
	}

	if err := l.Handler.HandleLog(e.finalize(level, msg)); err != nil {
		stdlog.Printf("error logging: %s", err)
	}
}
194422
func (l *LogSendContext) LogSend(statusJSON, feedback string, sendLogs bool, numBytes int, uid keybase1.UID, installID InstallID, mergeExtendedStatus bool) (string, error) {
	mctx := NewMetaContextBackground(l.G()).WithLogTag("LOGSEND")
	logs := l.Logs
	var kbfsLog string
	var svcLog string
	var ekLog string
	var desktopLog string
	var updaterLog string
	var startLog string
	var installLog string
	var systemLog string
	var gitLog string
	var traceBundle []byte
	var cpuProfileBundle []byte
	var watchdogLog string
	var processesLog string

	if sendLogs {
		svcLog = tail(l.G().Log, "service", logs.Service, numBytes)
		ekLog = tail(l.G().Log, "ek", logs.EK, numBytes)
		kbfsLog = tail(l.G().Log, "kbfs", logs.Kbfs, numBytes)
		desktopLog = tail(l.G().Log, "desktop", logs.Desktop, numBytes)
		updaterLog = tail(l.G().Log, "updater", logs.Updater, numBytes)
		// We don't use the systemd journal to store regular logs, since on
		// some systems (e.g. Ubuntu 16.04) it's not persisted across boots.
		// However we do use it for startup logs, since that's the only place
		// to get them in systemd mode.
		if l.G().Env.WantsSystemd() {
			startLog = tailSystemdJournal(l.G().Log, []string{"keybase.service", "keybase.ek", "kbfs.service", "keybase.gui.service", "keybase-redirector.service"}, numBytes)
		} else {
			startLog = tail(l.G().Log, "start", logs.Start, numBytes)
		}
		installLog = tail(l.G().Log, "install", logs.Install, numBytes)
		systemLog = tail(l.G().Log, "system", logs.System, numBytes)
		gitLog = tail(l.G().Log, "git", logs.Git, numBytes)
		watchdogLog = tail(l.G().Log, "watchdog", logs.Watchdog, numBytes)
		if logs.Trace != "" {
			traceBundle = getTraceBundle(l.G().Log, logs.Trace)
		}
		if logs.CPUProfile != "" {
			cpuProfileBundle = getCPUProfileBundle(l.G().Log, logs.CPUProfile)
		}
		// Only add extended status if we're sending logs
		if mergeExtendedStatus {
			statusJSON = l.mergeExtendedStatus(statusJSON)
		}
		processesLog = keybaseProcessList()
	}

	return l.post(mctx, statusJSON, feedback, kbfsLog, svcLog, ekLog, desktopLog, updaterLog, startLog, installLog, systemLog, gitLog, watchdogLog, traceBundle, cpuProfileBundle, uid, installID, processesLog)
}
871660
func (s *stream) Shout(format string, args ...interface{}) {
	s.log.output(s.quiet, &line{"", s.log.format(s.timestamps, shout, format, args), s})
}
490707
func TailTables(g Grouping, n int) Grouping {
	return headTailTables(g, n, true)
}
394159
func Trace(e *logrus.Entry, args ...interface{}) {
	level := logrus.Level(atomic.LoadUint32((*uint32)(&e.Logger.Level)))
	if level >= TraceLevel {
		e.Debug(args...)
	}
}
57789
func (st stateAdapter) NewLastSentTracker(tag names.ModelTag, sink string) LastSentTracker {
	return state.NewLastSentLogTracker(st, tag.Id(), sink)
}
1162364
func (t *topicInfo) getFifoTail() *topicEntry {
	for t.entries[t.fifoTail] == nil {
		t.fifoTail++
	}
	tail := t.entries[t.fifoTail]
	t.fifoTail++
	return tail
}
711969
func (t *SecondaryTree) SeekLast() (e *SecondaryEnumerator, err error) {
	q := t.last
	if q == nil {
		return nil, io.EOF
	}

	return btEPool2.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, atomic.LoadUint64(&t.ver)), nil
}
613591
func (t *Tail) UnmarshalTOML(data interface{}) error {
	dataOK, ok := data.(map[string]interface{})
	if !ok {
		return errors.New("bad files for tail input plugin")
	}
	files, ok := dataOK["files"].([]interface{})
	if !ok {
		return errors.New("not an array for tail input plugin")
	}
	for _, fi := range files {
		t.Files = append(t.Files, fi.(string))
	}
	return nil
}
69651
func FallbackFormater(sl *Slog) ([]byte, error) {
	buf := Pool.Get().([]byte)
	buf = append(buf, sl.Log.Domain...)
	buf = append(buf, sep...)
	FormatTime(&buf, sl.Log.Timestamp)
	buf = append(buf, sep...)
	buf = append(buf, sl.Log.Priority.Byte()...)
	buf = append(buf, sep...)
	if len(*sl.Log.Tags) > 0 {
		buf = append(buf, []byte(sl.Log.Tags.String())...)
		buf = append(buf, sepTags...)
	}
	if sl.Log.DoDi {
		buf = append(buf, []byte(sl.Log.file)...)
		buf = append(buf, sep...)
	}
	buf = append(buf, []byte(sl.Log.FormatMessage())...)
	return buf, nil
}
279383
func (c *cursor) Last() (key, value []byte) {
	return (*bbolt.Cursor)(c).Last()
}
1144411
func Trace(tag interface{}, message interface{}) {
	Logger.Trace(fmt.Sprintf("[%s] %s", tag, message))
	EmitterLogs.Emit(newLogLine(fmt.Sprintf("%s", tag), TraceLogTypeId, fmt.Sprintf("%s", message), nil))
}