fix(v2): log redacted ffmpeg/ffprobe stderr on stream failure

The stream worker discarded ffmpeg stderr, so reconnect loops were opaque.
Capture stderr and log it with the RTSP URL/credentials redacted, so the
real cause (auth, timeout, option, URL parse) is diagnosable without
leaking the source address.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ila
2026-07-23 20:31:00 +08:00
co-authored by Claude Opus 4.8
parent f58728cddd
commit 99226c7479
+22 -2
View File
@@ -2,18 +2,32 @@
package source
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"os/exec"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
var rtspURLPattern = regexp.MustCompile(`rtsp://[^\s'"]+`)
// redact removes the resolved source URL (which may carry credentials) from any
// FFmpeg/FFprobe diagnostic text before it is logged.
func redact(text, sourceURL string) string {
if sourceURL != "" {
text = strings.ReplaceAll(text, sourceURL, "<source>")
}
return rtspURLPattern.ReplaceAllString(text, "rtsp://<redacted>")
}
type Status string
const (
@@ -195,8 +209,12 @@ func probe(ctx context.Context, config Config) (Metadata, error) {
args := []string{"-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height,r_frame_rate", "-of", "json"}
args = appendInputOptions(args, config)
args = append(args, "-i", config.SourceURL)
output, err := exec.CommandContext(ctx, config.FFprobePath, args...).Output()
command := exec.CommandContext(ctx, config.FFprobePath, args...)
var stderr bytes.Buffer
command.Stderr = &stderr
output, err := command.Output()
if err != nil {
log.Printf("ffprobe 探测失败:%s(%v)", strings.TrimSpace(redact(stderr.String(), config.SourceURL)), err)
return Metadata{}, errors.New("unable to probe video metadata")
}
var parsed struct {
@@ -230,7 +248,8 @@ func decode(ctx context.Context, config Config, metadata Metadata, publish func(
args := append([]string{"-hide_banner", "-loglevel", "error"}, appendInputOptions(nil, config)...)
args = append(args, "-i", config.SourceURL, "-an", "-sn", "-dn", "-f", "rawvideo", "-pix_fmt", "bgr24", "-")
command := exec.CommandContext(ctx, config.FFmpegPath, args...)
command.Stderr = io.Discard
var stderr bytes.Buffer
command.Stderr = &stderr
stdout, err := command.StdoutPipe()
if err != nil {
return errors.New("unable to read video frames")
@@ -247,6 +266,7 @@ func decode(ctx context.Context, config Config, metadata Metadata, publish func(
if ctx.Err() != nil {
return ctx.Err()
}
log.Printf("ffmpeg 解码停止:%s(%v)", strings.TrimSpace(redact(stderr.String(), config.SourceURL)), err)
return errors.New("video decoder stopped")
}
publish(frame)