Skip to content

feat: kubectl ate logs filter container supervisor#311

Open
Mayowa Fajobi (MayorFaj) wants to merge 3 commits into
agent-substrate:mainfrom
MayorFaj:feat/kubectl-ate-logs-filter-container-supervisor
Open

feat: kubectl ate logs filter container supervisor#311
Mayowa Fajobi (MayorFaj) wants to merge 3 commits into
agent-substrate:mainfrom
MayorFaj:feat/kubectl-ate-logs-filter-container-supervisor

Conversation

@MayorFaj

@MayorFaj Mayowa Fajobi (MayorFaj) commented Jun 25, 2026

Copy link
Copy Markdown

Fixes #294

  • Tests pass
  • Appropriate changes to documentation are included in the PR

Summary

Implements kubectl ate logs actors <id> can now filter by source:

  • default — all of the actor's logs (unchanged)
  • -c, --container <name> — only that container's logs
  • --supervisor — only ateom lifecycle logs (Actor restoring/restored/…)

--container and --supervisor are mutually exclusive. After #290 every
forwarded container line carries an ate.dev/container_name label and
supervisor lifecycle lines carry none, so this is implemented client-side.

What changed

CLI (cmd/kubectl-ate)

  • New --container/-c and --supervisor flags.
  • logLineFilter + matchesSource() encode the selection rules.
  • filterAndDisplayLogLine reads actor_id and container_name atomically
    from the first recognized label key, and returns the zero time for any
    non-displayed line so follow mode's resume cursor only advances on lines the
    user actually sees (a reconnect can't skip wanted lines).
  • validateLogFilterFlags enforces mutual exclusion, called from the cobra
    command and from LogsActorRunner.Run (fail-fast for direct construction).

ateom log wrapper (cmd/ateom-gvisor) — security hardening

  • WrapContainerLogs strips application-provided ate.dev/* labels from both
    recognized label keys before injecting Substrate metadata, so an app cannot
    spoof another actor's actor_id/container_name under the key a consumer
    treats as authoritative.

Docs

  • cmd/kubectl-ate/README.md and docs/observability.md document the flags and
    mutual exclusivity; examples use the required kubectl ate logs actors form.

Design notes

  • Mutual exclusion uses a value-based check rather than cobra's
    MarkFlagsMutuallyExclusive, which keys off flag.Changed and would wrongly
    reject --container x --supervisor=false.

Testing

  • Unit: filter table cases (container/supervisor/default, dual-key precedence +
    atomicity, foreign-actor), validateLogFilterFlags, Run fail-fast,
    follow-mode resume-cursor regression, and TestWrapContainerLogs_CrossKeyLabelSpoofing.
  • make test green; gofmt / go vet clean.
  • Verified on a kind cluster (counter demo): default, -c counter, --supervisor,
    and the mutual-exclusion error all behave as expected.

@google-cla

google-cla Bot commented Jun 25, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@MayorFaj Mayowa Fajobi (MayorFaj) force-pushed the feat/kubectl-ate-logs-filter-container-supervisor branch from 7e57fbc to f0dd7c3 Compare June 25, 2026 21:05
@MayorFaj Mayowa Fajobi (MayorFaj) changed the title Feat/kubectl ate logs filter container supervisor feat: kubectl ate logs filter container supervisor Jun 25, 2026
// Read actor_id and container_name from the same (first actor-identifying)
// label map so a line's source is never split across the two keys.
var actorID, containerName string
for _, labelKey := range logActorLabelKeys {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of iterating over all label keys, how about having a method that takes the log entry map (i.e. m) and returns labels. It iterates on the possible keys and probes them, and return the first one that matches. That simplifies the control flow at the caller.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, extracted it into a helper so the caller no longer iterates the keys inline. Based on follow-up review it ended up as actorSource(m) returning - actorID, containerName - (reads both from the first map carrying ate.dev/actor_id), which keeps the same-map guarantee and drops the loop at the call site. Thanks for the nudge!

func init() {
logsActorsCmd.Flags().BoolVarP(&followLogs, "follow", "f", false, "Specify if the logs should be streamed.")
logsActorsCmd.Flags().StringVarP(&containerFlag, "container", "c", "", "Show logs only from the named container within the actor. Mutually exclusive with --supervisor.")
logsActorsCmd.Flags().BoolVar(&supervisorFlag, "supervisor", false, "Show only the ateom supervisor (lifecycle) logs. Mutually exclusive with --container.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why making --container and supervisor mutually exclusive? They seem orthogonal to me.

I was expecting:

  • --supervisor (boolean, defaults to false): whether to include supervisor logs or not
  • --container (string, default to ""): if set, restricts to the logs of this container.

WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow kubectl ate logs to filter by container and supervisor

2 participants