From 7c5122af58f0d260d6b49884515e7de7064e9f33 Mon Sep 17 00:00:00 2001 From: Youssuf Elshall Date: Mon, 10 Aug 2026 18:21:20 -0400 Subject: [PATCH] actorlog: add actor UID to JSON logs and handle null input --- internal/actorlog/logger.go | 4 ++++ internal/actorlog/logger_test.go | 38 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/internal/actorlog/logger.go b/internal/actorlog/logger.go index ebbf05a78..ef4c3b5f1 100644 --- a/internal/actorlog/logger.go +++ b/internal/actorlog/logger.go @@ -123,6 +123,9 @@ func (al *ActorLogger) WrapContainerLogs(r io.Reader, actorRef resources.ActorRe dec.UseNumber() unmarshalErr := dec.Decode(&m) + if unmarshalErr == nil && m == nil { + unmarshalErr = errors.New("JSON value is not an object") + } if unmarshalErr == nil { var trailing any if err := dec.Decode(&trailing); err != io.EOF { @@ -155,6 +158,7 @@ func (al *ActorLogger) WrapContainerLogs(r io.Reader, actorRef resources.ActorRe } labels["ate.dev/actor_atespace"] = actorRef.Atespace labels["ate.dev/actor_name"] = actorRef.Name + labels["ate.dev/actor_uid"] = actorUID labels["ate.dev/actor_template_namespace"] = actorTemplateNamespace labels["ate.dev/actor_template_name"] = actorTemplateName labels["ate.dev/container_name"] = containerName diff --git a/internal/actorlog/logger_test.go b/internal/actorlog/logger_test.go index 653d4d839..81cbacfb0 100644 --- a/internal/actorlog/logger_test.go +++ b/internal/actorlog/logger_test.go @@ -123,6 +123,9 @@ func TestWrapContainerLogs_JSONInput(t *testing.T) { if labels["ate.dev/actor_name"] != "act-1" { t.Errorf("got actor_name = %v, want 'act-1'", labels["ate.dev/actor_name"]) } + if labels["ate.dev/actor_uid"] != "uid-1" { + t.Errorf("got actor_uid = %v, want 'uid-1'", labels["ate.dev/actor_uid"]) + } if labels["ate.dev/actor_template_namespace"] != "tmpl-ns" { t.Errorf("got actor_template_namespace = %v, want 'tmpl-ns'", labels["ate.dev/actor_template_namespace"]) } @@ -209,7 +212,7 @@ func TestWrapContainerLogs_MergeLabels(t *testing.T) { } func TestWrapContainerLogs_LabelCollision(t *testing.T) { - input := `{"level":"info","msg":"App log","labels":{"ate.dev/actor_name":"malicious-id","app":"my-app"}}` + "\n" + input := `{"level":"info","msg":"App log","labels":{"ate.dev/actor_name":"malicious-id","ate.dev/actor_uid":"malicious-uid","app":"my-app"}}` + "\n" rdr := strings.NewReader(input) var buf bytes.Buffer @@ -236,6 +239,39 @@ func TestWrapContainerLogs_LabelCollision(t *testing.T) { if labels["ate.dev/actor_name"] != "act-1" { t.Errorf("got actor_name = %v, want 'act-1' (Substrate metadata should take precedence)", labels["ate.dev/actor_name"]) } + if labels["ate.dev/actor_uid"] != "uid-1" { + t.Errorf("got actor_uid = %v, want 'uid-1' (Substrate metadata should take precedence)", labels["ate.dev/actor_uid"]) + } +} + +func TestWrapContainerLogs_JSONNull(t *testing.T) { + input := "null\n" + rdr := strings.NewReader(input) + + var buf bytes.Buffer + al := NewActorLogger(&buf, false) + al.WrapContainerLogs(rdr, resources.ActorRef{Atespace: "default", Name: "act-1"}, "uid-1", "tmpl-ns", "tmpl-1", "ctr-1") + + var m map[string]any + if err := json.Unmarshal(buf.Bytes(), &m); err != nil { + t.Fatalf("failed to parse JSON output: %v", err) + } + + if m["message"] != "null" { + t.Errorf("got message = %v, want 'null'", m["message"]) + } + + labelsAny, ok := m[al.labelsKey] + if !ok { + t.Fatal("missing labels group") + } + labels, ok := labelsAny.(map[string]any) + if !ok { + t.Fatal("labels group is not a map") + } + if labels["ate.dev/actor_uid"] != "uid-1" { + t.Errorf("got actor_uid = %v, want 'uid-1'", labels["ate.dev/actor_uid"]) + } } func TestWrapContainerLogs_TrailingGarbage(t *testing.T) {