-
Notifications
You must be signed in to change notification settings - Fork 216
feat(otel): set ate.* actor telemetry identity on ateapi spans #412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Zoe Zhao (zoez7)
merged 5 commits into
agent-substrate:main
from
krisztianfekete:feat/actor-identity-spans
Jul 20, 2026
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5ba9da5
feat(otel): set ate.* actor identity on router and ateapi spans
krisztianfekete 5230263
Merge main into feat/actor-identity-spans
krisztianfekete 8067f63
address review comments, split span identity tests by method
krisztianfekete 692d7ac
tidy ate.* actor span attrs + review nits
krisztianfekete 8f46526
address review comments
krisztianfekete File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package controlapi | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "go.opentelemetry.io/otel/attribute" | ||
|
|
||
| "github.com/agent-substrate/substrate/internal/ateattr" | ||
| "github.com/agent-substrate/substrate/pkg/proto/ateapipb" | ||
| ) | ||
|
|
||
| // CreateActor is the only lifecycle op with the full identity (incl. version) | ||
| // available in the request, so the whole ate.* set should land on its span. | ||
| func TestCreateActor_StampsFullSpanIdentity(t *testing.T) { | ||
| ns := namespaceForTest("ns-span-create") | ||
| tc := setupTest(t, ns) | ||
| defer tc.cleanup() | ||
| createTemplate(t, tc, ns) | ||
|
|
||
| attrs := recordRootSpanAttrs(t, func(ctx context.Context) { | ||
| if _, err := tc.service.CreateActor(ctx, &ateapipb.CreateActorRequest{ | ||
| Actor: &ateapipb.Actor{ | ||
| Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: testActorID}, | ||
| ActorTemplateNamespace: ns, | ||
| ActorTemplateName: "tmpl1", | ||
| }, | ||
| }); err != nil { | ||
| t.Fatalf("CreateActor: %v", err) | ||
| } | ||
| }) | ||
|
|
||
| assertSpanStr(t, attrs, ateattr.AtespaceKey, testAtespace) | ||
| assertSpanStr(t, attrs, ateattr.ActorNameKey, testActorID) | ||
| assertSpanStr(t, attrs, ateattr.TemplateNameKey, "tmpl1") | ||
| assertSpanStr(t, attrs, ateattr.TemplateNamespaceKey, ns) | ||
| // uid is server-assigned on create, so assert it is present and non-empty | ||
| // rather than a fixed value. | ||
| if v, ok := attrs[ateattr.ActorUIDKey]; !ok || v.Type() != attribute.STRING || v.AsString() == "" { | ||
| t.Errorf("%s = %v, want non-empty server-assigned uid", ateattr.ActorUIDKey, v.Emit()) | ||
| } | ||
| if v, ok := attrs[ateattr.ActorVersionKey]; !ok || v.Type() != attribute.INT64 || v.AsInt64() != 1 { | ||
| t.Errorf("%s = %v, want int64 1", ateattr.ActorVersionKey, v.Emit()) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package controlapi | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/agent-substrate/substrate/internal/ateattr" | ||
| "github.com/agent-substrate/substrate/pkg/proto/ateapipb" | ||
| ) | ||
|
|
||
| // Delete addresses the actor by ref (atespace + id) and does not resolve the | ||
| // template/version, so only the ref identity is stamped. | ||
| func TestDeleteActor_StampsRefSpanIdentity(t *testing.T) { | ||
| ns := namespaceForTest("ns-span-delete") | ||
| tc := setupTest(t, ns) | ||
| defer tc.cleanup() | ||
| createTemplate(t, tc, ns) | ||
| if _, err := tc.service.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ | ||
| Actor: &ateapipb.Actor{ | ||
| Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: testActorID}, | ||
| ActorTemplateNamespace: ns, | ||
| ActorTemplateName: "tmpl1", | ||
| }, | ||
| }); err != nil { | ||
| t.Fatalf("seed CreateActor: %v", err) | ||
| } | ||
|
|
||
| attrs := recordRootSpanAttrs(t, func(ctx context.Context) { | ||
| if _, err := tc.service.DeleteActor(ctx, &ateapipb.DeleteActorRequest{ | ||
| Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: testActorID}, | ||
| }); err != nil { | ||
| t.Fatalf("DeleteActor: %v", err) | ||
| } | ||
| }) | ||
|
|
||
| assertSpanStr(t, attrs, ateattr.AtespaceKey, testAtespace) | ||
| assertSpanStr(t, attrs, ateattr.ActorNameKey, testActorID) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package controlapi | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "go.opentelemetry.io/otel/attribute" | ||
| "google.golang.org/grpc/codes" | ||
| "google.golang.org/grpc/status" | ||
|
|
||
| "github.com/agent-substrate/substrate/internal/ateattr" | ||
| "github.com/agent-substrate/substrate/pkg/proto/ateapipb" | ||
| ) | ||
|
|
||
| // Pause stamps the ref identity before resolving the Actor record, so a failed | ||
| // lookup still carries who/where; it must not invent template/version, which are | ||
| // known only once the record resolves (and stamped on success). | ||
| func TestPauseActor_FailedLookupStampsRefIdentityOnly(t *testing.T) { | ||
| ns := namespaceForTest("ns-span-pause-err") | ||
| tc := setupTest(t, ns) | ||
| defer tc.cleanup() | ||
|
|
||
| attrs := recordRootSpanAttrs(t, func(ctx context.Context) { | ||
| if _, err := tc.service.PauseActor(ctx, &ateapipb.PauseActorRequest{ | ||
| Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: testActorID}, | ||
| }); status.Code(err) != codes.NotFound { | ||
| t.Fatalf("PauseActor(missing) error = %v, want code NotFound", err) | ||
| } | ||
| }) | ||
|
|
||
| assertSpanStr(t, attrs, ateattr.AtespaceKey, testAtespace) | ||
| assertSpanStr(t, attrs, ateattr.ActorNameKey, testActorID) | ||
| for _, k := range []attribute.Key{ateattr.ActorUIDKey, ateattr.TemplateNameKey, ateattr.TemplateNamespaceKey, ateattr.ActorVersionKey} { | ||
| if _, ok := attrs[k]; ok { | ||
| t.Errorf("unexpected %s on failed-pause span", k) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package controlapi | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/agent-substrate/substrate/internal/ateattr" | ||
| "github.com/agent-substrate/substrate/pkg/proto/ateapipb" | ||
| ) | ||
|
|
||
| // The early ref stamp must land on the span even when the op fails, so a failed | ||
| // resume is still attributable to who/where. | ||
| func TestResumeActor_ErrorStillStampsRefSpanIdentity(t *testing.T) { | ||
| ns := namespaceForTest("ns-span-resume-err") | ||
| tc := setupTest(t, ns) | ||
| defer tc.cleanup() | ||
|
|
||
| attrs := recordRootSpanAttrs(t, func(ctx context.Context) { | ||
| if _, err := tc.service.ResumeActor(ctx, &ateapipb.ResumeActorRequest{ | ||
| Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "missing"}, | ||
| }); err == nil { | ||
| t.Fatal("expected error resuming missing actor") | ||
| } | ||
| }) | ||
|
|
||
| assertSpanStr(t, attrs, ateattr.AtespaceKey, testAtespace) | ||
| assertSpanStr(t, attrs, ateattr.ActorNameKey, "missing") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package controlapi | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "go.opentelemetry.io/otel/trace" | ||
|
|
||
| "github.com/agent-substrate/substrate/internal/ateattr" | ||
| "github.com/agent-substrate/substrate/pkg/proto/ateapipb" | ||
| ) | ||
|
|
||
| // setSpanActorAttributes annotates the RPC's server span (from ctx) with the | ||
| // actor's full identity. A no-op when ctx carries no recording span. | ||
| func setSpanActorAttributes(ctx context.Context, a *ateapipb.Actor) { | ||
| trace.SpanFromContext(ctx).SetAttributes(ateattr.ActorAttributes(a)...) | ||
|
zoez7 marked this conversation as resolved.
|
||
| } | ||
|
|
||
| // setSpanActorRefAttributes is setSpanActorAttributes for the identity subset known | ||
| // before the Actor record resolves, so a failed lookup still carries who/where. | ||
| func setSpanActorRefAttributes(ctx context.Context, atespace, name string) { | ||
| trace.SpanFromContext(ctx).SetAttributes(ateattr.ActorRefAttributes(atespace, name)...) | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.