diff --git a/cmd/run.go b/cmd/run.go index afbdd89..51e46d9 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -38,6 +38,7 @@ func init() { runCmd.Flags().BoolVarP(&state.DBG_debug, "dbg-perf", "", false, "Enables performance debugging server on port 6060") runCmd.Flags().BoolVarP(&state.DBG_trace, "dbg-trace", "", false, "Enables trace to trace.out") runCmd.Flags().BoolVarP(&state.DBG_trace_tc, "dbg-trace-tc", "", false, "Enables logging of packet routing") + runCmd.Flags().BoolVarP(&state.DBG_log_json, "json", "j", false, "Enables structued json logging") runCmd.Flags().StringP("config", "c", DefaultConfigPath, "Path to the config file") runCmd.Flags().StringP("node", "n", DefaultNodeConfigPath, "Path to the node config file") runCmd.Flags().StringP("log", "l", "", "Path to the log file (overrides config)") diff --git a/core/entrypoint.go b/core/entrypoint.go index 60d3ab1..b297f88 100644 --- a/core/entrypoint.go +++ b/core/entrypoint.go @@ -152,18 +152,26 @@ func Start(ccfg state.CentralCfg, ncfg state.LocalCfg, logLevel slog.Level, conf dispatch := make(chan func(env *state.State) error, 128) handlers := make([]slog.Handler, 0) - handlers = append(handlers, - tint.NewHandler(os.Stderr, &tint.Options{ - Level: logLevel, - AddSource: false, - CustomPrefix: string(ncfg.Id), - ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr { - if attr.Key == "time" { - return slog.Attr{} - } - return attr - }, - })) + if state.DBG_log_json { + handlers = append(handlers, + slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ + Level: logLevel, + }), + ) + } else { + handlers = append(handlers, + tint.NewHandler(os.Stderr, &tint.Options{ + Level: logLevel, + AddSource: false, + CustomPrefix: string(ncfg.Id), + ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr { + if attr.Key == "time" { + return slog.Attr{} + } + return attr + }, + })) + } if ncfg.LogPath != "" { err := os.MkdirAll(path.Dir(ncfg.LogPath), 0700) diff --git a/e2e/harness.go b/e2e/harness.go index 5a8d367..ec96f0a 100644 --- a/e2e/harness.go +++ b/e2e/harness.go @@ -108,6 +108,7 @@ type NodeSpec struct { IP string CentralConfigPath string NodeConfigPath string + ExtraArgs []string } func (h *Harness) StartNodes(specs ...NodeSpec) { @@ -116,12 +117,12 @@ func (h *Harness) StartNodes(specs ...NodeSpec) { for _, spec := range specs { go func(s NodeSpec) { defer wg.Done() - h.StartNode(s.Name, s.IP, s.CentralConfigPath, s.NodeConfigPath) + h.StartNode(s.Name, s.IP, s.CentralConfigPath, s.NodeConfigPath, s.ExtraArgs...) }(spec) } wg.Wait() } -func (h *Harness) StartNode(name string, ip string, centralConfigPath, nodeConfigPath string) testcontainers.Container { +func (h *Harness) StartNode(name string, ip string, centralConfigPath, nodeConfigPath string, extraArgs ...string) testcontainers.Container { h.t.Logf("Starting node %s at %s", name, ip) req := testcontainers.ContainerRequest{ Image: ImageName, @@ -141,7 +142,7 @@ func (h *Harness) StartNode(name string, ip string, centralConfigPath, nodeConfi FileMode: 0644, }, }, - Cmd: nil, // Entrypoint already handles "run -v" + Cmd: extraArgs, Env: map[string]string{ "NYLON_LOG_LEVEL": "debug", }, diff --git a/e2e/json_logging_test.go b/e2e/json_logging_test.go new file mode 100644 index 0000000..2f13f2d --- /dev/null +++ b/e2e/json_logging_test.go @@ -0,0 +1,65 @@ +//go:build e2e + +package e2e + +import ( + "testing" + "time" + + "github.com/encodeous/nylon/state" +) + +func TestJSONLogging(t *testing.T) { + h := NewHarness(t) + + node1Key := state.GenerateKey() + node2Key := state.GenerateKey() + + node1IP := GetIP(h.Subnet, 10) + node2IP := GetIP(h.Subnet, 11) + + node1NylonIP := "10.0.0.1" + node2NylonIP := "10.0.0.2" + + configDir := h.SetupTestDir() + + central := state.CentralCfg{ + Routers: []state.RouterCfg{ + SimpleRouter("node1", node1Key.Pubkey(), node1NylonIP, node1IP), + SimpleRouter("node2", node2Key.Pubkey(), node2NylonIP, node2IP), + }, + Graph: []string{ + "node1, node2", + }, + Timestamp: time.Now().UnixNano(), + } + + centralPath := h.WriteConfig(configDir, "central.yaml", central) + + node1Cfg := SimpleLocal("node1", node1Key) + node1Path := h.WriteConfig(configDir, "node1.yaml", node1Cfg) + + node2Cfg := SimpleLocal("node2", node2Key) + node2Path := h.WriteConfig(configDir, "node2.yaml", node2Cfg) + + h.StartNodes( + NodeSpec{ + Name: "node1", + IP: node1IP, + CentralConfigPath: centralPath, + NodeConfigPath: node1Path, + ExtraArgs: []string{"--json"}, + }, + NodeSpec{ + Name: "node2", + IP: node2IP, + CentralConfigPath: centralPath, + NodeConfigPath: node2Path, + ExtraArgs: []string{"--json"}, + }, + ) + + t.Log("Waiting for JSON log pattern...") + h.WaitForMatch("node1", `\{"time":".*","level":".*","msg":".*"`) + h.WaitForMatch("node2", `\{"time":".*","level":".*","msg":".*"`) +} diff --git a/state/debug.go b/state/debug.go index 0971e30..9b12027 100644 --- a/state/debug.go +++ b/state/debug.go @@ -3,6 +3,7 @@ package state var DBG_log_probe = false var DBG_log_wireguard = false var DBG_log_repo_updates = false +var DBG_log_json = false var DBG_debug = false var DBG_trace = false var DBG_trace_tc = false