Per the log schema: 'package' is the Go package (absent on Python-emitted lines), 'file' the Go/Python source basename, 'class' the Go receiver or Python class (omitted when there is none -- free functions no longer masquerade under a package-as-class), 'method' the emitting function. applog.App() now takes no arguments and derives all of it from runtime.Caller, so labels can never drift from the code; the manual http/wrapper emitters and forwarded wrapper.py lines (file= wrapper.py, no package) carry the same fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
package applog
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewLogger_FiltersBelowConfiguredLevel(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
logger := NewLogger("warn", &buf)
|
|
|
|
logger.Info("should be dropped")
|
|
if buf.Len() != 0 {
|
|
t.Fatalf("expected no output for an Info message under a warn-level logger, got %q", buf.String())
|
|
}
|
|
|
|
logger.Warn("should appear")
|
|
if !strings.Contains(buf.String(), "should appear") {
|
|
t.Fatalf("expected the Warn message in output, got %q", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNewLogger_WritesValidJSON(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
logger := NewLogger("info", &buf)
|
|
logger.Info("hello", "key", "value")
|
|
|
|
var decoded map[string]any
|
|
if err := json.Unmarshal(buf.Bytes(), &decoded); err != nil {
|
|
t.Fatalf("output is not valid JSON: %v (%q)", err, buf.String())
|
|
}
|
|
if decoded["msg"] != "hello" || decoded["key"] != "value" {
|
|
t.Errorf("decoded = %+v, want msg=hello key=value", decoded)
|
|
}
|
|
}
|
|
|
|
func TestNewLogger_OmitsEmptyMsg(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
logger := NewLogger("info", &buf)
|
|
logger.Info("", "type", "http", "status", 200)
|
|
|
|
var decoded map[string]any
|
|
if err := json.Unmarshal(buf.Bytes(), &decoded); err != nil {
|
|
t.Fatalf("output not JSON: %v (%q)", err, buf.String())
|
|
}
|
|
if _, present := decoded["msg"]; present {
|
|
t.Errorf("empty msg should be omitted, got %+v", decoded)
|
|
}
|
|
if decoded["type"] != "http" {
|
|
t.Errorf("attrs lost alongside dropped msg: %+v", decoded)
|
|
}
|
|
}
|
|
|
|
func TestApp_TagsMandatoryFields(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
prev := slog.Default()
|
|
slog.SetDefault(NewLogger("info", &buf))
|
|
defer slog.SetDefault(prev)
|
|
|
|
App().Info("did it", "extra", 1)
|
|
|
|
var decoded map[string]any
|
|
if err := json.Unmarshal(buf.Bytes(), &decoded); err != nil {
|
|
t.Fatalf("output not JSON: %v", err)
|
|
}
|
|
if decoded["type"] != "app" || decoded["package"] != "log" || decoded["file"] != "log_test.go" {
|
|
t.Errorf("fields = %+v, want type=app package=log (import-path element) file=log_test.go", decoded)
|
|
}
|
|
if decoded["method"] != "TestApp_TagsMandatoryFields" {
|
|
t.Errorf("method = %v, want the emitting function name", decoded["method"])
|
|
}
|
|
if _, hasClass := decoded["class"]; hasClass {
|
|
t.Errorf("class should be omitted for a free function, got %v", decoded["class"])
|
|
}
|
|
}
|