github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/pkg/model/logstore/logline.go (about) 1 package logstore 2 3 import ( 4 "strings" 5 "time" 6 7 "github.com/tilt-dev/tilt/pkg/logger" 8 ) 9 10 type LogLine struct { 11 Text string 12 SpanID SpanID 13 ProgressID string 14 15 // Most progress lines are optional. For example, if a bunch 16 // of little upload updates come in, it's ok to skip some. 17 // 18 // ProgressMustPrint indicates that this line must appear in the 19 // output - e.g., a line that communicates that the upload finished. 20 ProgressMustPrint bool 21 22 Time time.Time 23 } 24 25 type logLineBuilder struct { 26 span *Span 27 segments []LogSegment 28 isFirstLine bool 29 30 needsTrailingNewline bool 31 } 32 33 func newLogLineBuilder(span *Span, segment LogSegment, isFirstLine bool) *logLineBuilder { 34 return &logLineBuilder{ 35 span: span, 36 segments: []LogSegment{segment}, 37 isFirstLine: isFirstLine, 38 } 39 } 40 41 func (b *logLineBuilder) addSegment(segment LogSegment) { 42 b.segments = append(b.segments, segment) 43 } 44 45 func (b *logLineBuilder) lastSegment() LogSegment { 46 return b.segments[len(b.segments)-1] 47 } 48 49 func (b *logLineBuilder) isComplete() bool { 50 return b.lastSegment().IsComplete() 51 } 52 53 func (b *logLineBuilder) build(options logOptions) []LogLine { 54 result := []LogLine{} 55 56 segment := b.segments[0] 57 buildEvent := segment.Fields[logger.FieldNameBuildEvent] 58 if buildEvent == "init" { 59 result = append(result, b.buildSpaceLine(options)) 60 } 61 62 result = append(result, b.buildMainLine(options)) 63 return result 64 } 65 66 func (b *logLineBuilder) buildSpaceLine(options logOptions) LogLine { 67 sb := strings.Builder{} 68 span := b.span 69 segment := b.segments[0] 70 spanID := segment.SpanID 71 time := segment.Time 72 if options.showManifestPrefix && span.ManifestName != "" { 73 shouldSkip := options.skipFirstLineManifestPrefix && b.isFirstLine 74 if !shouldSkip { 75 sb.WriteString(SourcePrefix(span.ManifestName)) 76 } 77 } 78 sb.WriteString("\n") 79 80 return LogLine{ 81 Text: sb.String(), 82 SpanID: spanID, 83 Time: time, 84 } 85 } 86 87 func (b *logLineBuilder) buildMainLine(options logOptions) LogLine { 88 segment := b.segments[0] 89 span := b.span 90 spanID := segment.SpanID 91 time := segment.Time 92 progressID := segment.Fields[logger.FieldNameProgressID] 93 progressMustPrint := segment.Fields[logger.FieldNameProgressMustPrint] == "1" 94 95 sb := strings.Builder{} 96 if options.showManifestPrefix && span.ManifestName != "" { 97 shouldSkip := options.skipFirstLineManifestPrefix && b.isFirstLine 98 if !shouldSkip { 99 sb.WriteString(SourcePrefix(span.ManifestName)) 100 } 101 } 102 103 if segment.Anchor { 104 // TODO(nick): Add Terminal colors when supported. 105 if segment.Level == logger.WarnLvl { 106 sb.WriteString("WARNING: ") 107 } else if segment.Level == logger.ErrorLvl { 108 sb.WriteString("ERROR: ") 109 } 110 } 111 112 for _, segment := range b.segments { 113 sb.Write(segment.Text) 114 } 115 116 if !b.isComplete() && b.needsTrailingNewline { 117 sb.WriteString("\n") 118 } 119 120 return LogLine{ 121 Text: sb.String(), 122 SpanID: spanID, 123 ProgressID: progressID, 124 ProgressMustPrint: progressMustPrint, 125 Time: time, 126 } 127 }