refactor(log): split location into package/file/class/method, auto-derived

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>
This commit is contained in:
2026-08-04 19:59:48 +02:00
parent 6effb79097
commit 10cdc4176a
14 changed files with 91 additions and 47 deletions

View File

@@ -60,13 +60,19 @@ func TestApp_TagsMandatoryFields(t *testing.T) {
slog.SetDefault(NewLogger("info", &buf))
defer slog.SetDefault(prev)
App("api.Server", "handleThing").Info("did it", "extra", 1)
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["class"] != "api.Server" || decoded["method"] != "handleThing" {
t.Errorf("mandatory fields = %+v, want type=app class=api.Server method=handleThing", decoded)
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"])
}
}