Files
beacon-server/internal/logging/logging_test.go
T
n30nex dab228e9bb feat(logging): configure levels and structured runtime output (#144)
* feat(logging): configure levels and structured runtime output

* fix(logging): bound request-derived log fields

* fix(logging): retain malformed IATA source attributes safely

* test(logging): capture structured REST rate-limit records
2026-09-19 10:36:26 -04:00

98 lines
2.9 KiB
Go

// Copyright 2026 Beacon Contributors
// SPDX-License-Identifier: AGPL-3.0-or-later
package logging
import (
"bytes"
"encoding/json"
"log/slog"
"strings"
"testing"
"github.com/MeshCore-Beacon/beacon-server/internal/config"
)
func TestLevelsAndFormats(t *testing.T) {
for _, format := range []string{"text", "json"} {
for i, level := range []string{"debug", "info", "warn", "error"} {
t.Run(format+"/"+level, func(t *testing.T) {
t.Setenv("LOG_LEVEL", "")
t.Setenv("LOG_FORMAT", "")
var out bytes.Buffer
logger, err := New(&out, config.LogConfig{Level: level, Format: format})
if err != nil {
t.Fatal(err)
}
logger = logger.With("component", "ingest", "broker", "test")
logger.Debug("debug message")
logger.Info("info message")
logger.Warn("warn message")
logger.Error("error message")
lines := strings.Split(strings.TrimSpace(out.String()), "\n")
if len(lines) != 4-i {
t.Fatalf("got %d records, want %d: %s", len(lines), 4-i, out.String())
}
for _, line := range lines {
if format == "json" {
var record map[string]any
if err := json.Unmarshal([]byte(line), &record); err != nil {
t.Fatal(err)
}
if record["component"] != "ingest" || record["broker"] != "test" || record["time"] == nil {
t.Fatalf("missing fields: %v", record)
}
} else if !strings.Contains(line, "component=ingest") || !strings.Contains(line, "broker=test") {
t.Fatalf("missing fields: %s", line)
}
}
if !strings.Contains(out.String(), "error message") {
t.Fatal("error suppressed")
}
})
}
}
}
func TestDefaultsAndEnvironment(t *testing.T) {
t.Setenv("LOG_LEVEL", "")
t.Setenv("LOG_FORMAT", "")
var out bytes.Buffer
logger, err := New(&out, config.LogConfig{})
if err != nil {
t.Fatal(err)
}
if logger.Enabled(t.Context(), slog.LevelDebug) || !logger.Enabled(t.Context(), slog.LevelInfo) {
t.Fatal("default must be info")
}
t.Setenv("LOG_LEVEL", " WARN ")
t.Setenv("LOG_FORMAT", "JSON")
logger, err = New(&out, config.LogConfig{Level: "debug", Format: "text"})
if err != nil {
t.Fatal(err)
}
logger.Info("hidden")
logger.Error("visible")
var record map[string]any
if err = json.Unmarshal(bytes.TrimSpace(out.Bytes()), &record); err != nil {
t.Fatal(err)
}
if record["level"] != "ERROR" || record["msg"] != "visible" {
t.Fatalf("env overrides ignored: %v", record)
}
}
func TestInvalidOptions(t *testing.T) {
for _, cfg := range []config.LogConfig{{Level: "verbose"}, {Level: "off"}, {Level: "INFO+2"}, {Format: "xml"}} {
t.Setenv("LOG_LEVEL", "")
t.Setenv("LOG_FORMAT", "")
if _, err := New(&bytes.Buffer{}, cfg); err == nil {
t.Fatalf("accepted invalid options: %+v", cfg)
}
}
t.Setenv("LOG_LEVEL", "invalid")
if _, err := New(&bytes.Buffer{}, config.LogConfig{Level: "info"}); err == nil {
t.Fatal("invalid environment override accepted")
}
}