From a79061c7c285d0d93b385c2b57c3adb3250a10dd Mon Sep 17 00:00:00 2001 From: Sergey Krashevich Date: Tue, 28 May 2024 09:10:32 +0300 Subject: [PATCH 1/3] feat(logging): add interactive shell detection for console output --- internal/app/log.go | 3 ++- pkg/shell/tty.go | 7 +++++++ pkg/shell/tty_unix.go | 10 ++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 pkg/shell/tty.go create mode 100644 pkg/shell/tty_unix.go diff --git a/internal/app/log.go b/internal/app/log.go index e8d4bc880..e656737c4 100644 --- a/internal/app/log.go +++ b/internal/app/log.go @@ -4,6 +4,7 @@ import ( "io" "os" + "github.com/AlexxIT/go2rtc/pkg/shell" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) @@ -15,7 +16,7 @@ func NewLogger(format string, level string) zerolog.Logger { if format != "json" { writer = zerolog.ConsoleWriter{ - Out: writer, TimeFormat: "15:04:05.000", NoColor: format == "text", + Out: writer, TimeFormat: "15:04:05.000", NoColor: (format == "text" || !shell.IsInteractive(os.Stdout.Fd())), } } diff --git a/pkg/shell/tty.go b/pkg/shell/tty.go new file mode 100644 index 000000000..d433369ff --- /dev/null +++ b/pkg/shell/tty.go @@ -0,0 +1,7 @@ +//go:build !unix + +package shell + +func IsInteractive(fd uintptr) bool { + return false +} diff --git a/pkg/shell/tty_unix.go b/pkg/shell/tty_unix.go new file mode 100644 index 000000000..07b68a600 --- /dev/null +++ b/pkg/shell/tty_unix.go @@ -0,0 +1,10 @@ +//go:build unix + +package shell + +import "golang.org/x/sys/unix" + +func IsInteractive(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA) + return err == nil +} From cc74504ed812df848e00fad26c6660ca3df1978c Mon Sep 17 00:00:00 2001 From: Sergey Krashevich Date: Tue, 28 May 2024 10:16:48 +0300 Subject: [PATCH 2/3] feat(shell): add Windows support for TTY detection --- pkg/shell/tty.go | 2 +- pkg/shell/tty_windows.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 pkg/shell/tty_windows.go diff --git a/pkg/shell/tty.go b/pkg/shell/tty.go index d433369ff..f320130c2 100644 --- a/pkg/shell/tty.go +++ b/pkg/shell/tty.go @@ -1,4 +1,4 @@ -//go:build !unix +//go:build !unix && !windows package shell diff --git a/pkg/shell/tty_windows.go b/pkg/shell/tty_windows.go new file mode 100644 index 000000000..6216e7428 --- /dev/null +++ b/pkg/shell/tty_windows.go @@ -0,0 +1,19 @@ +//go:build windows + +package shell + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") +) + +func IsInteractive(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} From a6b9b4993f42fc3b61927d3723dfc934885095c1 Mon Sep 17 00:00:00 2001 From: Alex X Date: Tue, 28 May 2024 13:21:33 +0300 Subject: [PATCH 3/3] Code refactoring after #1141 --- internal/app/app.go | 2 +- internal/app/log.go | 45 ++++++++++++++++++++++++---------------- pkg/shell/tty.go | 7 ------- pkg/shell/tty_unix.go | 10 --------- pkg/shell/tty_windows.go | 19 ----------------- 5 files changed, 28 insertions(+), 55 deletions(-) delete mode 100644 pkg/shell/tty.go delete mode 100644 pkg/shell/tty_unix.go delete mode 100644 pkg/shell/tty_windows.go diff --git a/internal/app/app.go b/internal/app/app.go index add11dd79..9dec2848b 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -119,7 +119,7 @@ func Init() { } cfg.Mod = map[string]string{ - "format": "color", + "format": "", // useless, but anyway "level": "info", "output": "stdout", // TODO: change to stderr someday "time": zerolog.TimeFormatUnixMs, diff --git a/internal/app/log.go b/internal/app/log.go index 65be3161f..222f6f2bb 100644 --- a/internal/app/log.go +++ b/internal/app/log.go @@ -4,17 +4,21 @@ import ( "io" "os" - "github.com/AlexxIT/go2rtc/pkg/shell" + "github.com/mattn/go-isatty" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) var MemoryLog = newBuffer(16) +// NewLogger support: +// - output: empty (only to memory), stderr, stdout +// - format: empty (autodetect color support), color, json, text +// - time: empty (disable timestamp), UNIXMS, UNIXMICRO, UNIXNANO +// - level: disabled, trace, debug, info, warn, error... func NewLogger(config map[string]string) zerolog.Logger { var writer io.Writer - // support output only to memory switch config["output"] { case "stderr": writer = os.Stderr @@ -25,26 +29,31 @@ func NewLogger(config map[string]string) zerolog.Logger { timeFormat := config["time"] if writer != nil { - switch format := config["format"]; format { - case "color", "text": + if format := config["format"]; format != "json" { + console := &zerolog.ConsoleWriter{Out: writer} + + switch format { + case "text": + console.NoColor = true + case "color": + console.NoColor = false // useless, but anyway + default: + // autodetection if output support color + // go-isatty - dependency for go-colorable - dependency for ConsoleWriter + console.NoColor = !isatty.IsTerminal(writer.(*os.File).Fd()) + } + if timeFormat != "" { - writer = &zerolog.ConsoleWriter{ - Out: writer, - NoColor: format == "text" || !shell.IsInteractive(os.Stdout.Fd()), - TimeFormat: "15:04:05.000", - } + console.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, - }, + console.PartsOrder = []string{ + zerolog.LevelFieldName, + zerolog.CallerFieldName, + zerolog.MessageFieldName, } } - case "json": // none + + writer = console } writer = zerolog.MultiLevelWriter(writer, MemoryLog) diff --git a/pkg/shell/tty.go b/pkg/shell/tty.go deleted file mode 100644 index f320130c2..000000000 --- a/pkg/shell/tty.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !unix && !windows - -package shell - -func IsInteractive(fd uintptr) bool { - return false -} diff --git a/pkg/shell/tty_unix.go b/pkg/shell/tty_unix.go deleted file mode 100644 index 07b68a600..000000000 --- a/pkg/shell/tty_unix.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build unix - -package shell - -import "golang.org/x/sys/unix" - -func IsInteractive(fd uintptr) bool { - _, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA) - return err == nil -} diff --git a/pkg/shell/tty_windows.go b/pkg/shell/tty_windows.go deleted file mode 100644 index 6216e7428..000000000 --- a/pkg/shell/tty_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build windows - -package shell - -import ( - "syscall" - "unsafe" -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -func IsInteractive(fd uintptr) bool { - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -}