Skip to content

serverboot: give the ateoms a LoggerProvider over the relay - #1857

Merged
Jeff Luo (JeffLuoo) merged 2 commits into
agent-substrate:mainfrom
baizhenyu:ateom-logging-provider
Sep 24, 2026
Merged

Jeff Luo (JeffLuoo) merged 2 commits into
agent-substrate:mainfrom
baizhenyu:ateom-logging-provider

Conversation

@baizhenyu

Copy link
Copy Markdown
Collaborator

Step 2 of #1748, plus the consumer rule from step 1b.

LoggingOptions gains ExporterConn and RelayCapable, mirroring TracingOptions. Both ateoms initialize logging after metrics with the relay connection and defer a nil-guarded shutdown. OTEL_LOGS_EXPORTER still defaults to none, so no ateom emits a record; this is the provider the actor events land on when emission moves.

A relay-capable log resource carries ate.otlp.relay like traces and metrics do. newLoggerProvider is split from InitLogging so the test asserts that on an emitted record's resource, the way TestMeterProviderRelayAttribute does for metrics.

docs/observability.md states the consumer rule that replaced the relay denylist dropped in #1800: a lifecycle record is authoritative only under ateapi's resource, because the relay admits only ateom resources.

Follow-up for the emission step, not here: the controller does not inject OTEL_LOGS_EXPORTER into worker pods, so no environment exercises log-over-relay yet.

LoggingOptions gains ExporterConn and RelayCapable, the same two fields
TracingOptions has, so a component can send log records over a connection it
owns and mark its resource with the path taken. Both ateoms now initialize
logging beside tracing and metrics, passing the relay connection. The exporter
still defaults to none, so no ateom emits a record yet; this only puts the
provider in place for the actor events that will move into the ateom.

newLoggerProvider is split out so a test can read the resource off an emitted
record, since the SDK provider does not expose it.

The observability guide names the rule a consumer applies to lifecycle records:
only ateapi's resource is authoritative, because the relay admits only ateom
resources.

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.

LGTM, added some nit comments!

Comment thread docs/observability.md Outdated
**What this stream won't tell you.** It only writes when something changes. So an actor that has been sitting in the same state since before your logs roll over has no record, and no state. Ask the control plane what state something is in right now. Use this stream to see how it got there and when. Records can also go missing, like any other log, and a gap looks the same as an actor that just sat still. If you want to count activations, use the router's access log instead.

`Actor crashed` is the exception, and carries the same two keys with `ate.actor.state="crashed"`. It is written once per committed transition into `ACTOR_STATE_CRASHED`, beside the [`ate.actor.crashes`](#the-metric-registry) increment and under the same already-crashed guard, so the two can never disagree about how many crashes happened. A consumer deriving state therefore selects on `ate.actor.state`, not on the message:
`Actor crashed` is the exception, and carries the same two keys with `ate.actor.state="crashed"`. It is written once per committed transition into `ACTOR_STATE_CRASHED`, beside the [`ate.actor.crashes`](#the-metric-registry) increment and under the same already-crashed guard, so the two can never disagree about how many crashes happened. A consumer deriving state therefore selects on `ate.actor.state` under ateapi's resource (`service.name=ateapi`), not on the message. The resource is what makes the record authoritative: worker pods export through [the ateom relay](#the-ateom-otlp-relay) when they have it, and the relay admits only ateom resources, so a record carrying these keys under any other resource is not a state change.

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.

The relay only gates the relay path, and a worker pod that falls back to direct export can still send service.name=ateapi to the collector, so please state the rule as holding once that path is closed (a #809 follow-up) rather than as something the relay already guarantees.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. Reworded in c1e619d. The rule now holds once the direct path is closed. Until then the consumer applies it.

Comment thread docs/observability.md Outdated
#### The same records over OTLP

Both records also go out as OTLP log events, so a collector reads them without knowing substrate's stdout envelope. Set `OTEL_LOGS_EXPORTER=otlp` to turn it on; unset means `none`, which is what every environment but kind uses today. Only ateapi has a LoggerProvider today; [the ateom relay](#the-ateom-otlp-relay) carries logs, traces, and metrics, so an ateom exports log records the same way once it has one.
Both records also go out as OTLP log events, so a collector reads them without knowing substrate's stdout envelope. Set `OTEL_LOGS_EXPORTER=otlp` to turn it on; unset means `none`, which is what every environment but kind uses today. ateapi is the only emitter today. The ateoms have a LoggerProvider on the same switch and export through [the ateom relay](#the-ateom-otlp-relay), which carries logs, traces, and metrics.

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.

atecontroller doesn't pass OTEL_LOGS_EXPORTER to worker pods, so setting it in ate-otel-config doesn't turn on the ateoms; can we please document it here as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added in c1e619d. The controller does not pass the switch, so kind turns on ateapi only.

Comment thread cmd/ateom-microvm/main.go
}
// Nil when the exporter is none.
if lp != nil {
defer serverboot.ShutdownProvider("LoggerProvider", lp.Shutdown)

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.

Nice!

@bowei Bowei Du (bowei) added kind/feature An enhancement / feature request or implementation area/observability area/gvisor area/microVM labels Sep 24, 2026
The relay gates only the relay path. A worker pod that falls back to direct
export can still send any resource, so the rule is one the consumer applies
until that path is closed. Also note that the controller does not pass the
logs exporter switch to worker pods, so the kind ConfigMap reaches ateapi only.
@JeffLuoo
Jeff Luo (JeffLuoo) added this pull request to the merge queue Sep 24, 2026
Merged via the queue into agent-substrate:main with commit 93e691d Sep 24, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/gvisor area/microVM area/observability kind/feature An enhancement / feature request or implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants