aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-08-18 15:58:37 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:57:39 +0200
commit9884eca784e853e48ff82ecd904890d28b2fe0fa (patch)
treeda7ce36527d68d48d974149cbd3214285b39ce35
parent408a1d0ec8f22623769eba7f7923d6268ba834ca (diff)
downloadmuhqs-game-9884eca784e853e48ff82ecd904890d28b2fe0fa.tar.gz
muhqs-game-9884eca784e853e48ff82ecd904890d28b2fe0fa.zip
allow game log to be configured using command line flags
-rw-r--r--go/client/main.go15
-rw-r--r--go/log/handler.go41
-rw-r--r--go/log/log.go30
3 files changed, 81 insertions, 5 deletions
diff --git a/go/client/main.go b/go/client/main.go
index b631269e..2d936d55 100644
--- a/go/client/main.go
+++ b/go/client/main.go
@@ -3,13 +3,15 @@ package main
import (
"flag"
"io"
- "log"
+ "log/slog"
"os"
+ "strings"
"github.com/hajimehoshi/ebiten/v2"
"muhq.space/muhqs-game/go/activities"
"muhq.space/muhqs-game/go/font"
+ "muhq.space/muhqs-game/go/log"
)
const (
@@ -50,8 +52,19 @@ func main() {
flag.StringVar(&startMenu.mapPath, "map", "the-kraken", "the map to load")
flag.StringVar(&startMenu.remote, "remote", "", "address of remote game to connect to")
+
+ logLevel := flag.Int("logLevel", int(slog.LevelInfo.Level()), "active log level")
+ loggedFilesVar := flag.String("loggedFiles", "", "files to log")
flag.Parse()
+ if *logLevel != int(slog.LevelInfo.Level()) || *loggedFilesVar != "" {
+ loggedFiles := strings.Split(*loggedFilesVar, " ")
+ log.Configure(loggedFiles, &slog.HandlerOptions{
+ AddSource: true,
+ Level: slog.Level(*logLevel),
+ })
+ }
+
ebiten.SetWindowSize(app.windowWidth, app.windowHeight)
ebiten.SetWindowTitle("Muhq's Game")
diff --git a/go/log/handler.go b/go/log/handler.go
new file mode 100644
index 00000000..75231098
--- /dev/null
+++ b/go/log/handler.go
@@ -0,0 +1,41 @@
+package log
+
+import (
+ "context"
+ "log/slog"
+ "os"
+ "runtime"
+
+ "golang.org/x/exp/slices"
+)
+
+type gameLogHandler struct {
+ h slog.Handler
+ files []string
+}
+
+func NewGameLogHandler(files []string, opts *slog.HandlerOptions) *gameLogHandler {
+ return &gameLogHandler{h: slog.NewTextHandler(os.Stdout, opts), files: files}
+}
+
+func (h *gameLogHandler) Enabled(ctx context.Context, level slog.Level) bool {
+ return h.h.Enabled(ctx, level)
+}
+
+func (h *gameLogHandler) Handle(ctx context.Context, r slog.Record) error {
+ frames := runtime.CallersFrames([]uintptr{r.PC})
+ frame, _ := frames.Next()
+ if slices.Contains(h.files, frame.File) {
+ return nil
+ }
+
+ return h.h.Handle(ctx, r)
+}
+
+func (h *gameLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
+ return &gameLogHandler{h: h.h.WithAttrs(attrs), files: h.files}
+}
+
+func (h *gameLogHandler) WithGroup(name string) slog.Handler {
+ return &gameLogHandler{h: h.h.WithGroup(name), files: h.files}
+}
diff --git a/go/log/log.go b/go/log/log.go
index ff090425..dbe3af66 100644
--- a/go/log/log.go
+++ b/go/log/log.go
@@ -8,18 +8,32 @@ import (
"os"
)
-const GameLogLevel = 99
+var GameLogLevel slog.Level = 99
+
+var Logger *slog.Logger
var handleGameRecord func(any)
+// RegisterGameRecordHandler registers a callback for game records.
+// The registered callback can be used by the game's UI to present game log entries to the user.
+func RegisterGameRecordHandler(handler func(any)) {
+ handleGameRecord = handler
+}
+
func init() {
- // TODO: allow to specify the value and the file
- l := slog.New(slog.NewTextHandler(
+ Logger = slog.New(slog.NewTextHandler(
os.Stdout,
&slog.HandlerOptions{AddSource: true}))
- slog.SetDefault(l)
+ slog.SetDefault(Logger)
+}
+
+// Configure controls the logging behavior of the default logger.
+func Configure(files []string, opts *slog.HandlerOptions) {
+ Logger = slog.New(NewGameLogHandler(files, opts))
+ slog.SetDefault(Logger)
}
+// Game calls the registered handleGameRecord callback and [Logger.Log] on the default logger.
func Game(obj any) {
if handleGameRecord != nil {
handleGameRecord(obj)
@@ -28,34 +42,42 @@ func Game(obj any) {
slog.Log(context.Background(), GameLogLevel, msg)
}
+// Debug calls [Logger.Debug] on the default logger.
func Debug(msg string, args ...any) {
slog.Debug(msg, args...)
}
+// Info calls [Logger.Info] on the default logger.
func Info(msg string, args ...any) {
slog.Info(msg, args...)
}
+// Warn calls [Logger.Warn] on the default logger.
func Warn(msg string, args ...any) {
slog.Warn(msg, args...)
}
+// Error calls [Logger.Error] on the default logger.
func Error(msg string, args ...any) {
slog.Error(msg, args...)
}
+// Fatal calls [log.Fatal].
func Fatal(args ...any) {
log.Fatal(args...)
}
+// Fatalf calls [log.Fatalf].
func Fatalf(msg string, args ...any) {
log.Fatalf(msg, args...)
}
+// Panic calls [log.Panic].
func Panic(args ...any) {
log.Panic(args...)
}
+// Panicf calls [log.Panicf].
func Panicf(msg string, args ...any) {
log.Panicf(msg, args...)
}