diff --git a/internal/logging/home_app_log_forwarder.go b/internal/logging/home_app_log_forwarder.go index e74e47a1c..e86e66032 100644 --- a/internal/logging/home_app_log_forwarder.go +++ b/internal/logging/home_app_log_forwarder.go @@ -24,6 +24,7 @@ type homeAppLogPayload struct { Line string `json:"line"` Level string `json:"level,omitempty"` Timestamp string `json:"timestamp,omitempty"` + RequestID string `json:"request_id,omitempty"` } var currentHomeAppLogClient = func() homeAppLogClient { @@ -92,6 +93,7 @@ func (f *HomeAppLogForwarder) Fire(entry *log.Entry) error { Line: line, Level: entry.Level.String(), Timestamp: entry.Time.Format(time.RFC3339Nano), + RequestID: appLogRequestID(entry), } select { case f.queue <- payload: @@ -100,6 +102,18 @@ func (f *HomeAppLogForwarder) Fire(entry *log.Entry) error { return nil } +func appLogRequestID(entry *log.Entry) string { + if entry == nil { + return "" + } + requestID, _ := entry.Data["request_id"].(string) + requestID = strings.TrimSpace(requestID) + if requestID == "--------" { + return "" + } + return requestID +} + func (f *HomeAppLogForwarder) formatEntry(entry *log.Entry) (string, error) { formatter := f.formatter if formatter == nil { diff --git a/internal/logging/home_app_log_forwarder_test.go b/internal/logging/home_app_log_forwarder_test.go index 59476d1c0..b6a1b6808 100644 --- a/internal/logging/home_app_log_forwarder_test.go +++ b/internal/logging/home_app_log_forwarder_test.go @@ -72,6 +72,7 @@ func TestHomeAppLogForwarder_ForwardsFormattedLogWhenHomeHealthy(t *testing.T) { entry.Time = time.Date(2026, 5, 29, 8, 0, 0, 0, time.Local) entry.Level = log.DebugLevel entry.Message = "debug details" + entry.Data["request_id"] = "req-app-1" if errFire := forwarder.Fire(entry); errFire != nil { t.Fatalf("Fire error: %v", errFire) @@ -92,14 +93,29 @@ func TestHomeAppLogForwarder_ForwardsFormattedLogWhenHomeHealthy(t *testing.T) { if got.Level != "debug" { t.Fatalf("level = %q, want debug", got.Level) } + if got.RequestID != "req-app-1" { + t.Fatalf("request_id = %q, want req-app-1", got.RequestID) + } if !strings.Contains(got.Line, "debug details") { t.Fatalf("line %q missing log message", got.Line) } + if !strings.Contains(got.Line, "[req-app-1]") { + t.Fatalf("line %q missing matching request id", got.Line) + } if strings.TrimSpace(got.Timestamp) == "" { t.Fatal("timestamp empty, want non-empty") } } +func TestHomeAppLogForwarder_OmitsPlaceholderRequestID(t *testing.T) { + entry := log.NewEntry(log.StandardLogger()) + entry.Data["request_id"] = "--------" + + if got := appLogRequestID(entry); got != "" { + t.Fatalf("request id = %q, want empty for placeholder", got) + } +} + func TestHomeAppLogForwarder_SkipsWhenHomeHeartbeatIsDown(t *testing.T) { original := currentHomeAppLogClient defer func() {