Keep run logs opaque and streamline transfers

This commit is contained in:
npc0-hue
2026-09-03 16:40:05 +08:00
parent 48dd540253
commit 330b1c0130
27 changed files with 429 additions and 673 deletions
+45 -45
View File
@@ -326,7 +326,7 @@ func (worker *Worker) registerUnlocked(ctx context.Context) error {
Capacity: worker.capacityReportFor(state),
})
if err != nil {
log.Printf("RUN phase=register status=failed endpoint=%s error=%s", worker.cfg.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=register status=failed endpoint=%s error=%s", worker.cfg.RunEndpointID, err.Error())
return err
}
if !response.Accepted || response.SessionToken == "" {
@@ -399,10 +399,10 @@ func (worker *Worker) HeartbeatOnce(ctx context.Context) error {
})
if err != nil {
if sessionInvalidError(err) {
log.Printf("RUN phase=heartbeat status=session_invalid endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=heartbeat status=session_invalid endpoint=%s error=%s", state.RunEndpointID, err.Error())
return worker.reregisterAndReconcile(ctx, "heartbeat_session_invalid", state.SessionToken)
}
log.Printf("RUN phase=heartbeat status=failed endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=heartbeat status=failed endpoint=%s error=%s", state.RunEndpointID, err.Error())
return err
}
if !response.Accepted {
@@ -452,10 +452,10 @@ func (worker *Worker) claimAndRunOnce(ctx context.Context, waitSeconds int) (boo
})
if err != nil {
if sessionInvalidError(err) {
log.Printf("RUN phase=claim status=session_invalid endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=claim status=session_invalid endpoint=%s error=%s", state.RunEndpointID, err.Error())
return false, worker.reregisterAndReconcile(ctx, "claim_session_invalid", state.SessionToken)
}
log.Printf("RUN phase=claim status=failed endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=claim status=failed endpoint=%s error=%s", state.RunEndpointID, err.Error())
return false, err
}
if !claim.Accepted || !claim.HasJob || claim.Job == nil {
@@ -482,7 +482,7 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
}
log.Printf("RUN phase=job status=journal_store job=%s capability=%s attempt=%d", assignment.JobID, assignment.Capability, assignment.Attempt)
if err := worker.journal.Store(assignment); err != nil {
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
log.Printf("RUN phase=job status=ack_start job=%s capability=%s", assignment.JobID, assignment.Capability)
@@ -495,7 +495,7 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
Message: "job accepted by run worker",
})
if err != nil {
log.Printf("RUN phase=job status=ack_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=ack_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
assignment = ack.Job
@@ -505,7 +505,7 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
}
log.Printf("RUN phase=job status=ack_accepted job=%s attempt=%d", assignment.JobID, assignment.Attempt)
if err := worker.journal.Store(assignment); err != nil {
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
progressSequence := worker.nextProgressSequence(assignment.ProgressSequence)
@@ -524,7 +524,7 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
Sequence: progressSequence,
})
if err != nil {
log.Printf("RUN phase=job status=progress_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=progress_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
if !progress.Accepted {
@@ -534,13 +534,13 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
assignment = progress.Job
log.Printf("RUN phase=job status=progress_accepted job=%s percent=%d", assignment.JobID, assignment.Progress.Percent)
if err := worker.journal.Store(assignment); err != nil {
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=journal_store_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
log.Printf("RUN phase=job status=execute_start job=%s capability=%s", assignment.JobID, assignment.Capability)
execution, assignment, cancelledByPlatform, err := worker.executeWithJobPolling(ctx, assignment)
if err != nil {
log.Printf("RUN phase=job status=execute_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=execute_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
log.Printf("RUN phase=job status=execute_done job=%s state=%s errorCode=%s message=%s cancelledByPlatform=%t", assignment.JobID, execution.State, safeOptional(execution.ErrorCode), safeOptional(execution.Message), cancelledByPlatform)
@@ -559,13 +559,13 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
resultRequest := LifecycleResultRequest(assignment, state.SessionToken, execution)
log.Printf("RUN phase=job status=result_store job=%s state=%s", assignment.JobID, resultRequest.State)
if err := worker.journal.StorePendingResult(resultRequest, execution.ActivationManifest); err != nil {
log.Printf("RUN phase=job status=result_store_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=result_store_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
log.Printf("RUN phase=job status=result_submit job=%s state=%s", assignment.JobID, resultRequest.State)
result, err := worker.client.CompleteJob(ctx, resultRequest)
if err != nil {
log.Printf("RUN phase=job status=result_submit_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=result_submit_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
if !result.Accepted {
@@ -574,14 +574,14 @@ func (worker *Worker) runAssignment(ctx context.Context, assignment protocol.Run
}
log.Printf("RUN phase=job status=result_accepted job=%s state=%s", assignment.JobID, resultRequest.State)
if err := worker.journal.Delete(assignment.JobID); err != nil {
log.Printf("RUN phase=job status=journal_delete_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job status=journal_delete_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
log.Printf("RUN phase=job status=complete job=%s state=%s", assignment.JobID, resultRequest.State)
if execution.ActivationManifest != "" {
log.Printf("RUN phase=self_update status=activate_start job=%s", assignment.JobID)
if err := worker.executor.selfUpdateActivator.Activate(execution.ActivationManifest); err != nil {
log.Printf("RUN phase=self_update status=activate_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=self_update status=activate_failed job=%s error=%s", assignment.JobID, err.Error())
return fmt.Errorf("launch self-update helper: %w", err)
}
worker.restartMu.Lock()
@@ -598,7 +598,7 @@ func (worker *Worker) executeWithJobPolling(ctx context.Context, assignment prot
pollCancel := func() {
state, err := worker.registeredState()
if err != nil {
log.Printf("RUN phase=job.cancel_poll status=skipped_unregistered job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job.cancel_poll status=skipped_unregistered job=%s error=%s", assignment.JobID, err.Error())
return
}
log.Printf("RUN phase=job.cancel_poll status=starting job=%s", assignment.JobID)
@@ -610,7 +610,7 @@ func (worker *Worker) executeWithJobPolling(ctx context.Context, assignment prot
Attempt: assignment.Attempt,
})
if err != nil {
log.Printf("RUN phase=job.cancel_poll status=failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job.cancel_poll status=failed job=%s error=%s", assignment.JobID, err.Error())
return
}
if err == nil && response.HasCancel {
@@ -637,7 +637,7 @@ func (worker *Worker) executeWithJobPolling(ctx context.Context, assignment prot
log.Printf("RUN phase=job.execute status=worker_finished job=%s state=%s", assignment.JobID, execution.State)
return execution, assignment, cancelledByPlatform, nil
case <-ctx.Done():
log.Printf("RUN phase=job.execute status=context_done job=%s error=%s", assignment.JobID, RedactText(ctx.Err().Error()))
log.Printf("RUN phase=job.execute status=context_done job=%s error=%s", assignment.JobID, ctx.Err().Error())
cancel()
execution := <-executionCh
return execution, assignment, cancelledByPlatform, ctx.Err()
@@ -652,7 +652,7 @@ func (worker *Worker) executeWithJobPolling(ctx context.Context, assignment prot
state, err := worker.registeredState()
if err != nil {
cancel()
log.Printf("RUN phase=job.execute status=lease_renew_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job.execute status=lease_renew_failed job=%s error=%s", assignment.JobID, err.Error())
return LifecycleExecutionResult{}, assignment, cancelledByPlatform, err
}
progress, err := worker.client.UpdateJobProgress(ctx, protocol.RunJobProgressRequest{
@@ -669,14 +669,14 @@ func (worker *Worker) executeWithJobPolling(ctx context.Context, assignment prot
if err == nil {
err = fmt.Errorf("job lease renewal was not accepted")
}
log.Printf("RUN phase=job.execute status=lease_renew_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job.execute status=lease_renew_failed job=%s error=%s", assignment.JobID, err.Error())
return LifecycleExecutionResult{}, assignment, cancelledByPlatform, err
}
assignment = progress.Job
log.Printf("RUN phase=job.execute status=lease_renewed job=%s percent=%d", assignment.JobID, assignment.Progress.Percent)
if err := worker.journal.Store(assignment); err != nil {
cancel()
log.Printf("RUN phase=job.execute status=journal_store_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=job.execute status=journal_store_failed job=%s error=%s", assignment.JobID, err.Error())
return LifecycleExecutionResult{}, assignment, cancelledByPlatform, err
}
}
@@ -880,7 +880,7 @@ func (worker *Worker) ReconcileOnce(ctx context.Context) error {
ActiveJobs: worker.journal.ReconcileEntries(),
})
if err != nil {
log.Printf("RUN phase=reconcile status=failed endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=reconcile status=failed endpoint=%s error=%s", state.RunEndpointID, err.Error())
return err
}
if !response.Accepted {
@@ -928,7 +928,7 @@ func (worker *Worker) RecoverActiveJobs(ctx context.Context) error {
pending.SessionToken = state.SessionToken
result, err := worker.client.CompleteJob(ctx, pending)
if err != nil {
log.Printf("RUN phase=recover status=result_submit_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=recover status=result_submit_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
if !result.Accepted {
@@ -950,7 +950,7 @@ func (worker *Worker) RecoverActiveJobs(ctx context.Context) error {
}
log.Printf("RUN phase=recover status=rerun_active_job job=%s capability=%s", assignment.JobID, assignment.Capability)
if err := worker.runAssignment(ctx, assignment); err != nil {
log.Printf("RUN phase=recover status=rerun_failed job=%s error=%s", assignment.JobID, RedactText(err.Error()))
log.Printf("RUN phase=recover status=rerun_failed job=%s error=%s", assignment.JobID, err.Error())
return err
}
}
@@ -973,11 +973,11 @@ func (worker *Worker) Run(ctx context.Context) error {
return err
}
if err := worker.reportAutonomousProcessObservations(ctx); err != nil {
log.Printf("RUN phase=autonomous_lifecycle.observation status=degraded error=%s", RedactText(err.Error()))
log.Printf("RUN phase=autonomous_lifecycle.observation status=degraded error=%s", err.Error())
}
worker.reportMetricsDegraded(ctx, "startup")
if err := MarkSelfUpdateHealthy(worker.cfg.UpdateHealthFile); err != nil {
log.Printf("RUN phase=self_update_health status=mark_failed error=%s", RedactText(err.Error()))
log.Printf("RUN phase=self_update_health status=mark_failed error=%s", err.Error())
return err
}
if err := worker.reportRunUpdateHealth(ctx); err != nil {
@@ -1004,7 +1004,7 @@ func (worker *Worker) Run(ctx context.Context) error {
for {
select {
case <-ctx.Done():
log.Printf("RUN phase=run status=context_done error=%s", RedactText(ctx.Err().Error()))
log.Printf("RUN phase=run status=context_done error=%s", ctx.Err().Error())
return ctx.Err()
case err := <-jobDone:
log.Printf("RUN phase=run status=job_loop_done error=%s", errorSummary(err))
@@ -1022,7 +1022,7 @@ func (worker *Worker) Run(ctx context.Context) error {
continue
}
if err := worker.reportAutonomousProcessObservations(ctx); err != nil {
log.Printf("RUN phase=autonomous_lifecycle.observation status=degraded error=%s", RedactText(err.Error()))
log.Printf("RUN phase=autonomous_lifecycle.observation status=degraded error=%s", err.Error())
}
worker.reportMetricsDegraded(ctx, "heartbeat")
heartbeatTicker.Reset(heartbeatInterval)
@@ -1054,7 +1054,7 @@ func (worker *Worker) reportRunUpdateHealth(ctx context.Context) error {
Version: worker.cfg.Version,
})
if err != nil {
log.Printf("RUN phase=self_update_health status=failed job=%s error=%s", worker.cfg.UpdateJobID, RedactText(err.Error()))
log.Printf("RUN phase=self_update_health status=failed job=%s error=%s", worker.cfg.UpdateJobID, err.Error())
return err
}
if !response.Accepted || response.JobID != worker.cfg.UpdateJobID {
@@ -1088,19 +1088,19 @@ func (worker *Worker) runControlStreamLoop(ctx context.Context, wake chan<- stru
return nil
})
if ctx.Err() != nil {
log.Printf("RUN phase=control_stream status=context_done error=%s", RedactText(ctx.Err().Error()))
log.Printf("RUN phase=control_stream status=context_done error=%s", ctx.Err().Error())
return ctx.Err()
}
if err != nil {
if sessionInvalidError(err) {
log.Printf("RUN phase=control_stream status=session_invalid endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=control_stream status=session_invalid endpoint=%s error=%s", state.RunEndpointID, err.Error())
if refreshErr := worker.reregisterAndReconcile(ctx, "control_stream_session_invalid", state.SessionToken); refreshErr != nil {
log.Printf("RUN phase=control_stream status=reregister_failed endpoint=%s error=%s", state.RunEndpointID, RedactText(refreshErr.Error()))
log.Printf("RUN phase=control_stream status=reregister_failed endpoint=%s error=%s", state.RunEndpointID, refreshErr.Error())
}
lastSeq = 0
signalControlWake(wake)
} else {
log.Printf("RUN phase=control_stream status=failed endpoint=%s error=%s", state.RunEndpointID, RedactText(err.Error()))
log.Printf("RUN phase=control_stream status=failed endpoint=%s error=%s", state.RunEndpointID, err.Error())
}
}
if waitErr := waitWorkerLoop(ctx, boundedRetryBackoff(worker.cfg.RetryBackoff)); waitErr != nil {
@@ -1121,21 +1121,21 @@ func (worker *Worker) runJobLoop(ctx context.Context, interval time.Duration, wa
for {
select {
case <-ctx.Done():
log.Printf("RUN phase=job_loop status=context_done error=%s", RedactText(ctx.Err().Error()))
log.Printf("RUN phase=job_loop status=context_done error=%s", ctx.Err().Error())
return ctx.Err()
default:
}
if worker.journal.ActiveCount() > 0 {
log.Printf("RUN phase=job_loop status=active_jobs activeJobs=%d", worker.journal.ActiveCount())
if err := worker.ReconcileOnce(ctx); err != nil {
log.Printf("RUN phase=job_loop status=reconcile_failed error=%s", RedactText(err.Error()))
log.Printf("RUN phase=job_loop status=reconcile_failed error=%s", err.Error())
if err := waitWorkerLoop(ctx, boundedRetryBackoff(worker.cfg.RetryBackoff)); err != nil {
return err
}
continue
}
if err := worker.RecoverActiveJobs(ctx); err != nil {
log.Printf("RUN phase=job_loop status=recover_failed error=%s", RedactText(err.Error()))
log.Printf("RUN phase=job_loop status=recover_failed error=%s", err.Error())
if err := waitWorkerLoop(ctx, boundedRetryBackoff(worker.cfg.RetryBackoff)); err != nil {
return err
}
@@ -1145,7 +1145,7 @@ func (worker *Worker) runJobLoop(ctx context.Context, interval time.Duration, wa
claimStartedAt := time.Now()
handled, err := worker.claimAndRunOnce(ctx, 0)
if err != nil {
log.Printf("RUN phase=job_loop status=claim_failed error=%s", RedactText(err.Error()))
log.Printf("RUN phase=job_loop status=claim_failed error=%s", err.Error())
if err := waitWorkerLoop(ctx, boundedRetryBackoff(worker.cfg.RetryBackoff)); err != nil {
return err
}
@@ -1248,7 +1248,7 @@ func (client sessionLogBatchClient) IngestLogBatch(ctx context.Context, batch pr
}
response, err := client.client.IngestLogBatch(ctx, batch)
if err != nil && logBatchNotFoundError(err) {
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=platform_not_found error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=platform_not_found error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, err.Error())
return protocol.LogBatchIngestResponse{}, spool.PermanentLogBatchRejection("platform_not_found", err)
}
if err != nil && (logBatchSequenceGapError(err) || logBatchAcknowledgedRangeConflict(err)) {
@@ -1256,15 +1256,15 @@ func (client sessionLogBatchClient) IngestLogBatch(ctx context.Context, batch pr
if logBatchAcknowledgedRangeConflict(err) {
reason = "platform_acknowledged_range_conflict"
}
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=%s error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, reason, RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=%s error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, reason, err.Error())
return protocol.LogBatchIngestResponse{}, spool.PermanentLogBatchRejection(reason, err)
}
if err != nil && logBatchLegacySessionMetadataError(err) && strings.TrimSpace(batch.LogSessionID) == "" && !batch.SessionStartedAt.IsZero() {
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=legacy_session_metadata error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=legacy_session_metadata error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, err.Error())
return protocol.LogBatchIngestResponse{}, spool.PermanentLogBatchRejection("legacy_session_metadata", err)
}
if err != nil && logBatchSessionMetadataMismatchError(err) {
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=session_metadata_mismatch error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.logs status=spool_quarantine stream=%s firstSeq=%d lastSeq=%d reason=session_metadata_mismatch error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, batch.LastSeq, err.Error())
return protocol.LogBatchIngestResponse{}, spool.PermanentLogBatchRejection("session_metadata_mismatch", err)
}
return response, err
@@ -1362,7 +1362,7 @@ func (worker *Worker) runDurableUploaders(ctx context.Context, done chan<- struc
case <-ticker.C:
state, err := worker.registeredState()
if err != nil {
log.Printf("RUN phase=durable_uploaders status=skipped_unregistered error=%s", RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders status=skipped_unregistered error=%s", err.Error())
continue
}
if hasLogSink && hasLogClient {
@@ -1372,7 +1372,7 @@ func (worker *Worker) runDurableUploaders(ctx context.Context, done chan<- struc
client := sessionLogBatchClient{client: logClient, progressClient: progressClient, runEndpointID: state.RunEndpointID, sessionToken: state.SessionToken}
flushed, err := logSink.Spool.Flush(flushCtx, client)
if err != nil {
log.Printf("RUN phase=durable_uploaders.logs status=flush_failed flushed=%d durationMs=%d error=%s", flushed, time.Since(startedAt).Milliseconds(), RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.logs status=flush_failed flushed=%d durationMs=%d error=%s", flushed, time.Since(startedAt).Milliseconds(), err.Error())
} else if flushed > 0 {
log.Printf("RUN phase=durable_uploaders.logs status=flushed count=%d durationMs=%d", flushed, time.Since(startedAt).Milliseconds())
}
@@ -1385,7 +1385,7 @@ func (worker *Worker) runDurableUploaders(ctx context.Context, done chan<- struc
client := sessionArtifactChunkClient{client: artifactClient, runEndpointID: state.RunEndpointID, sessionToken: state.SessionToken}
flushed, err := artifactHook.Queue.Flush(flushCtx, client)
if err != nil {
log.Printf("RUN phase=durable_uploaders.artifacts status=flush_failed flushed=%d durationMs=%d error=%s", flushed, time.Since(startedAt).Milliseconds(), RedactText(err.Error()))
log.Printf("RUN phase=durable_uploaders.artifacts status=flush_failed flushed=%d durationMs=%d error=%s", flushed, time.Since(startedAt).Milliseconds(), err.Error())
} else if flushed > 0 {
log.Printf("RUN phase=durable_uploaders.artifacts status=flushed count=%d durationMs=%d", flushed, time.Since(startedAt).Milliseconds())
}
@@ -1542,7 +1542,7 @@ func (sink *LiveLogSink) dispatch() {
_, err := sink.Client.RelayLiveLogBatch(ctx, batch)
cancel()
if err != nil {
log.Printf("RUN phase=live_log_relay status=dropped stream=%s sequence=%d error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, RedactText(err.Error()))
log.Printf("RUN phase=live_log_relay status=dropped stream=%s sequence=%d error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, err.Error())
}
}
}