diff --git a/internal/agent/runner/runner.go b/internal/agent/runner/runner.go index 62c17f4..e7b1e0b 100644 --- a/internal/agent/runner/runner.go +++ b/internal/agent/runner/runner.go @@ -74,19 +74,26 @@ func (r *Runner) RunBackup(ctx context.Context, jobID string, paths, excludes, t lastProgress := time.Now() handle := func(stream string, line string, ev any) { - // Forward every line to the server as log.stream. - now := time.Now().UTC() - logEnv, _ := api.Marshal(api.MsgLogStream, "", api.LogStreamLine{ - JobID: jobID, - Seq: seq.Add(1), - TS: now, - Stream: api.LogStream(stream), - Payload: line, - }) - _ = r.tx.Send(logEnv) + // Throttled progress events come from restic's `status` JSON. + // We deliberately do NOT forward the raw status line to + // log.stream — it's emitted ~every 16ms by restic --json and + // would drown the live log in dupes for any short backup. The + // progress widget already covers the same information at a + // sane sample rate. + status, isStatus := ev.(restic.BackupStatus) + if !isStatus { + now := time.Now().UTC() + logEnv, _ := api.Marshal(api.MsgLogStream, "", api.LogStreamLine{ + JobID: jobID, + Seq: seq.Add(1), + TS: now, + Stream: api.LogStream(stream), + Payload: line, + }) + _ = r.tx.Send(logEnv) + } - // Throttled progress events. - if status, ok := ev.(restic.BackupStatus); ok { + if isStatus { if time.Since(lastProgress) < r.progressMinPeriod { return }