@@ -13,6 +13,7 @@ import (
"github.com/charmbracelet/crush/internal/config"
crushlog "github.com/charmbracelet/crush/internal/log"
"github.com/charmbracelet/crush/internal/server"
+ "github.com/charmbracelet/x/term"
"github.com/spf13/cobra"
)
@@ -42,7 +43,12 @@ var serverCmd = &cobra.Command{
}
logFile := filepath.Join(config.GlobalCacheDir(), "server-"+safeNameRegexp.ReplaceAllString(serverHost, "_"), "crush.log")
- crushlog.Setup(logFile, debug)
+
+ if term.IsTerminal(os.Stderr.Fd()) {
+ crushlog.Setup(logFile, debug, os.Stderr)
+ } else {
+ crushlog.Setup(logFile, debug)
+ }
hostURL, err := server.ParseHostURL(serverHost)
if err != nil {
@@ -2,6 +2,7 @@ package log
import (
"fmt"
+ "io"
"log/slog"
"os"
"runtime/debug"
@@ -10,6 +11,7 @@ import (
"time"
"github.com/charmbracelet/crush/internal/event"
+ "github.com/charmbracelet/x/term"
"gopkg.in/natefinch/lumberjack.v2"
)
@@ -18,7 +20,7 @@ var (
initialized atomic.Bool
)
-func Setup(logFile string, debug bool) {
+func Setup(logFile string, debug bool, ws ...io.Writer) {
initOnce.Do(func() {
logRotator := &lumberjack.Logger{
Filename: logFile,
@@ -33,12 +35,26 @@ func Setup(logFile string, debug bool) {
level = slog.LevelDebug
}
- logger := slog.NewJSONHandler(logRotator, &slog.HandlerOptions{
+ opts := &slog.HandlerOptions{
Level: level,
AddSource: true,
- })
+ }
+
+ var handlers []slog.Handler
+ handlers = append(handlers, slog.NewJSONHandler(logRotator, opts))
+
+ for _, w := range ws {
+ if w == nil {
+ continue
+ }
+ if f, ok := w.(term.File); ok && term.IsTerminal(f.Fd()) {
+ handlers = append(handlers, slog.NewTextHandler(w, opts))
+ } else {
+ handlers = append(handlers, slog.NewJSONHandler(w, opts))
+ }
+ }
- slog.SetDefault(slog.New(logger))
+ slog.SetDefault(slog.New(slog.NewMultiHandler(handlers...)))
initialized.Store(true)
})
}