From 656d1026910f8a29b3bfc7582c13a5002ac3df4d Mon Sep 17 00:00:00 2001 From: encodeous Date: Wed, 11 Feb 2026 20:11:04 -0500 Subject: [PATCH 1/2] feat(logging): add json option --- cmd/run.go | 1 + core/entrypoint.go | 32 ++++++++++++++++++++------------ state/debug.go | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) 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/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 From be77eec57e985f265fbddc46910fc8fdcbaa0cdb Mon Sep 17 00:00:00 2001 From: Adam Chen Date: Thu, 12 Feb 2026 01:18:11 +0000 Subject: [PATCH 2/2] test(e2e): add json logging test --- e2e/harness.go | 7 +++-- e2e/json_logging_test.go | 65 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 e2e/json_logging_test.go 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":".*"`) +}