@@ -23,7 +23,6 @@ const (
23
23
24
24
var (
25
25
colorKeyRegex = regexp .MustCompile (`"(?:\\["\\/bfnrt]|[^\x00-\x1f"\\]|\\u[0-9a-fA-F]{4})*"\s*:|[^\x00-\x20"=&?]+=` ) // handles JSON, logfmt, and query params
26
- ansiRegex = regexp .MustCompile ("\x1b (?:\\ [[=?]?[0-9;]*[@-~]|].*?(?:\x1b \\ \\ |\x07 |$)|[@-Z\\ \\ ^_])" )
27
26
)
28
27
29
28
// ParseTimeOrDuration parses a time string or duration string (e.g. 1h30m) and returns a time.Time.
@@ -129,27 +128,38 @@ func Tail(ctx context.Context, client defangv1connect.FabricControllerClient, se
129
128
// Reconnect on Error: internal: stream error: stream ID 5; INTERNAL_ERROR; received from peer
130
129
if code == connect .CodeUnavailable || (code == connect .CodeInternal && ! connect .IsWireError (tailClient .Err ())) {
131
130
Debug (" - Disconnected:" , tailClient .Err ())
132
- Warn (" ! Reconnecting..." )
131
+ if ! raw {
132
+ Fprint (os .Stderr , WarnColor , " ! Reconnecting...\r " ) // overwritten below
133
+ }
133
134
time .Sleep (time .Second )
134
135
tailClient , err = client .Tail (ctx , connect .NewRequest (& pb.TailRequest {Service : service , Etag : etag , Since : timestamppb .New (since )}))
135
- if err == nil {
136
- skipDuplicate = true
137
- continue
136
+ if err != nil {
137
+ Debug (" - Reconnect failed:" , err )
138
+ return err
139
+ }
140
+ if ! raw {
141
+ Fprintln (os .Stderr , WarnColor , " ! Reconnected! " )
138
142
}
139
- Debug ( " - Reconnect failed:" , err )
140
- return err
143
+ skipDuplicate = true
144
+ continue
141
145
}
142
146
143
147
return tailClient .Err () // returns nil on EOF
144
148
}
145
149
msg := tailClient .Msg ()
146
150
147
- if DoColor && ! DoVerbose && ! raw {
151
+ // Show a spinner if we're not in raw mode and have a TTY
152
+ if ! raw && DoColor {
148
153
fmt .Printf ("%c\r " , spinner [spinMe % len (spinner )])
149
154
spinMe ++
155
+ // Replace service progress messages with our own spinner
156
+ if isProgressMsg (msg .Entries ) {
157
+ println ("asf" )
158
+ continue
159
+ }
150
160
}
151
161
152
- isInternal := ! strings .HasPrefix (msg .Host , "ip-" )
162
+ isInternal := ! strings .HasPrefix (msg .Host , "ip-" ) // FIXME: not true for BYOC
153
163
for _ , e := range msg .Entries {
154
164
if ! DoVerbose && ! e .Stderr && isInternal {
155
165
// HACK: skip noisy CI/CD logs (except errors)
@@ -201,13 +211,21 @@ func Tail(ctx context.Context, client defangv1connect.FabricControllerClient, se
201
211
}
202
212
if DoColor {
203
213
if ! strings .Contains (line , "\033 [" ) {
204
- line = colorKeyRegex .ReplaceAllString (line , replaceString )
214
+ line = colorKeyRegex .ReplaceAllString (line , replaceString ) // add some color
205
215
}
206
216
} else {
207
- line = ansiRegex . ReplaceAllLiteralString (line , "" )
217
+ line = StripAnsi (line )
208
218
}
209
219
Println (Reset , line )
210
220
}
211
221
}
212
222
}
213
223
}
224
+
225
+ func isProgressDot (line string ) bool {
226
+ return len (line ) <= 1 || len (StripAnsi (line )) <= 1
227
+ }
228
+
229
+ func isProgressMsg (entries []* pb.LogEntry ) bool {
230
+ return len (entries ) == 0 || (len (entries ) == 1 && isProgressDot (entries [0 ].Message ))
231
+ }
0 commit comments