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