Merge branch 'master' into feat-log-terminal-check
This commit is contained in:
+9
-1
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/shell"
|
||||
"github.com/AlexxIT/go2rtc/pkg/yaml"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -117,9 +118,16 @@ func Init() {
|
||||
Mod map[string]string `yaml:"log"`
|
||||
}
|
||||
|
||||
cfg.Mod = map[string]string{
|
||||
"format": "color",
|
||||
"level": "info",
|
||||
"output": "stdout", // TODO: change to stderr someday
|
||||
"time": zerolog.TimeFormatUnixMs,
|
||||
}
|
||||
|
||||
LoadConfig(&cfg)
|
||||
|
||||
log.Logger = NewLogger(cfg.Mod["format"], cfg.Mod["level"])
|
||||
log.Logger = NewLogger(cfg.Mod)
|
||||
|
||||
modules = cfg.Mod
|
||||
|
||||
|
||||
+44
-15
@@ -9,29 +9,58 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var MemoryLog *circularBuffer
|
||||
var MemoryLog = newBuffer(16)
|
||||
|
||||
func NewLogger(format string, level string) zerolog.Logger {
|
||||
var writer io.Writer = os.Stdout
|
||||
func NewLogger(config map[string]string) zerolog.Logger {
|
||||
var writer io.Writer
|
||||
|
||||
if format != "json" {
|
||||
writer = zerolog.ConsoleWriter{
|
||||
Out: writer, TimeFormat: "15:04:05.000", NoColor: (format == "text" || !shell.IsInteractive(os.Stdout.Fd())),
|
||||
// support output only to memory
|
||||
switch config["output"] {
|
||||
case "stderr":
|
||||
writer = os.Stderr
|
||||
case "stdout":
|
||||
writer = os.Stdout
|
||||
}
|
||||
|
||||
timeFormat := config["time"]
|
||||
|
||||
if writer != nil {
|
||||
switch format := config["format"]; format {
|
||||
case "color", "text":
|
||||
if timeFormat != "" {
|
||||
writer = &zerolog.ConsoleWriter{
|
||||
Out: writer,
|
||||
NoColor: format == "text" || !shell.IsInteractive(os.Stdout.Fd()),
|
||||
TimeFormat: "15:04:05.000",
|
||||
}
|
||||
} else {
|
||||
writer = &zerolog.ConsoleWriter{
|
||||
Out: writer,
|
||||
NoColor: format == "text" || !shell.IsInteractive(os.Stdout.Fd()),
|
||||
PartsOrder: []string{
|
||||
zerolog.LevelFieldName,
|
||||
zerolog.CallerFieldName,
|
||||
zerolog.MessageFieldName,
|
||||
},
|
||||
}
|
||||
}
|
||||
case "json": // none
|
||||
}
|
||||
|
||||
writer = zerolog.MultiLevelWriter(writer, MemoryLog)
|
||||
} else {
|
||||
writer = MemoryLog
|
||||
}
|
||||
|
||||
MemoryLog = newBuffer(16)
|
||||
logger := zerolog.New(writer)
|
||||
|
||||
writer = zerolog.MultiLevelWriter(writer, MemoryLog)
|
||||
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
|
||||
|
||||
lvl, err := zerolog.ParseLevel(level)
|
||||
if err != nil || lvl == zerolog.NoLevel {
|
||||
lvl = zerolog.InfoLevel
|
||||
if timeFormat != "" {
|
||||
zerolog.TimeFieldFormat = timeFormat
|
||||
logger = logger.With().Timestamp().Logger()
|
||||
}
|
||||
|
||||
return zerolog.New(writer).With().Timestamp().Logger().Level(lvl)
|
||||
lvl, _ := zerolog.ParseLevel(config["level"])
|
||||
return logger.Level(lvl)
|
||||
}
|
||||
|
||||
func GetLogger(module string) zerolog.Logger {
|
||||
|
||||
+39
-20
@@ -4,7 +4,7 @@ import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -68,8 +68,9 @@ func execHandle(rawURL string) (core.Producer, error) {
|
||||
|
||||
args := shell.QuoteSplit(rawURL[5:]) // remove `exec:`
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
if log.Debug().Enabled() {
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stderr = &logWriter{
|
||||
buf: make([]byte, 512),
|
||||
debug: log.Debug().Enabled(),
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
@@ -104,18 +105,10 @@ func handlePipe(_ string, cmd *exec.Cmd, query url.Values) (core.Producer, error
|
||||
|
||||
log.Debug().Stringer("launch", time.Since(ts)).Msg("[exec] run pipe")
|
||||
|
||||
return prod, err
|
||||
return prod, fmt.Errorf("exec/pipe: %w\n%s", err, cmd.Stderr)
|
||||
}
|
||||
|
||||
func handleRTSP(url string, cmd *exec.Cmd, path string) (core.Producer, error) {
|
||||
stderr := limitBuffer{buf: make([]byte, 512)}
|
||||
|
||||
if cmd.Stderr != nil {
|
||||
cmd.Stderr = io.MultiWriter(cmd.Stderr, &stderr)
|
||||
} else {
|
||||
cmd.Stderr = &stderr
|
||||
}
|
||||
|
||||
if log.Trace().Enabled() {
|
||||
cmd.Stdout = os.Stdout
|
||||
}
|
||||
@@ -150,10 +143,10 @@ func handleRTSP(url string, cmd *exec.Cmd, path string) (core.Producer, error) {
|
||||
case <-time.After(time.Second * 60):
|
||||
_ = cmd.Process.Kill()
|
||||
log.Error().Str("url", url).Msg("[exec] timeout")
|
||||
return nil, errors.New("timeout")
|
||||
return nil, errors.New("exec: timeout")
|
||||
case <-done:
|
||||
// limit message size
|
||||
return nil, errors.New("exec: " + stderr.String())
|
||||
return nil, fmt.Errorf("exec/rtsp\n%s", cmd.Stderr)
|
||||
case prod := <-waiter:
|
||||
log.Debug().Stringer("launch", time.Since(ts)).Msg("[exec] run rtsp")
|
||||
return prod, nil
|
||||
@@ -168,21 +161,47 @@ var (
|
||||
waitersMu sync.Mutex
|
||||
)
|
||||
|
||||
type limitBuffer struct {
|
||||
buf []byte
|
||||
n int
|
||||
type logWriter struct {
|
||||
buf []byte
|
||||
debug bool
|
||||
n int
|
||||
}
|
||||
|
||||
func (l *limitBuffer) String() string {
|
||||
func (l *logWriter) String() string {
|
||||
if l.n == len(l.buf) {
|
||||
return string(l.buf) + "..."
|
||||
}
|
||||
return string(l.buf[:l.n])
|
||||
}
|
||||
|
||||
func (l *limitBuffer) Write(p []byte) (int, error) {
|
||||
func (l *logWriter) Write(p []byte) (n int, err error) {
|
||||
if l.n < cap(l.buf) {
|
||||
l.n += copy(l.buf[l.n:], p)
|
||||
}
|
||||
return len(p), nil
|
||||
n = len(p)
|
||||
if l.debug {
|
||||
if p = trimSpace(p); p != nil {
|
||||
log.Debug().Msgf("[exec] %s", p)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func trimSpace(b []byte) []byte {
|
||||
start := 0
|
||||
stop := len(b)
|
||||
for ; start < stop; start++ {
|
||||
if b[start] >= ' ' {
|
||||
break // trim all ASCII before 0x20
|
||||
}
|
||||
}
|
||||
for ; ; stop-- {
|
||||
if stop == start {
|
||||
return nil // skip empty output
|
||||
}
|
||||
if b[stop-1] > ' ' {
|
||||
break // trim all ASCII before 0x21
|
||||
}
|
||||
}
|
||||
return b[start:stop]
|
||||
}
|
||||
|
||||
@@ -19,15 +19,22 @@ import (
|
||||
func Init() {
|
||||
var cfg struct {
|
||||
Mod map[string]string `yaml:"ffmpeg"`
|
||||
Log struct {
|
||||
Level string `yaml:"ffmpeg"`
|
||||
} `yaml:"log"`
|
||||
}
|
||||
|
||||
cfg.Mod = defaults // will be overriden from yaml
|
||||
cfg.Log.Level = "error"
|
||||
|
||||
app.LoadConfig(&cfg)
|
||||
|
||||
if app.GetLogger("exec").GetLevel() >= 0 {
|
||||
defaults["global"] += " -v error"
|
||||
// zerolog levels: trace debug info warn error fatal panic disabled
|
||||
// FFmpeg levels: trace debug verbose info warning error fatal panic quiet
|
||||
if cfg.Log.Level == "warn" {
|
||||
cfg.Log.Level = "warning"
|
||||
}
|
||||
defaults["global"] += " -v " + cfg.Log.Level
|
||||
|
||||
streams.RedirectFunc("ffmpeg", func(url string) (string, error) {
|
||||
if _, err := Version(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user