Skip to content

Add docs for new type enum variants to generated settings - #266

Open
MaxFreedomPollard wants to merge 2 commits into
cloudflare:mainfrom
MaxFreedomPollard:settings-enum-variant-docs
Open

Add docs for new type enum variants to generated settings#266
MaxFreedomPollard wants to merge 2 commits into
cloudflare:mainfrom
MaxFreedomPollard:settings-enum-variant-docs

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown

#[settings] on an enum throws away the documentation of everything the enum wraps. expand_enum emits a bare impl Settings for #ident { } (foundations-macros/src/settings.rs:136), so add_docs falls back to the no-op default at foundations/src/settings/mod.rs:418. A new type variant is the one variant kind that gets a key of its own in the YAML, and every field under that key comes out with no comments.

This hits foundations' own settings. TracingSettings::output defaults to TracesOutput::JaegerThriftUdp (foundations/src/telemetry/settings/tracing.rs:84), which wraps JaegerThriftUdpOutputSettings, whose four fields all have doc comments. Here is what to_yaml_string(&TracingSettings::default()) prints today, which is what a service writes out with Cli's --generate:

output:
  jaeger_thrift_udp:
    server_addr: "127.0.0.1:6831"
    reporter_bind_addr: ~
    num_tasks: 1
    max_batch_size: 100

UserTracesOutput::OtlpUds (user_tracing.rs:56) and SamplingStrategy::Active (tracing.rs:222) lose their documentation the same way, and both are the default variant of their enum.

With this change the same call prints:

output:
  # Sends traces to the collector in the [Jaeger Thrift (UDP)] format.
  #
  # [Jaeger Thrift (UDP)]: https://www.jaegertracing.io/docs/1.55/apis/#thrift-over-udp-stable
  jaeger_thrift_udp:
    # The address of the Jaeger Thrift (UDP) agent.
    #
    # The default value is the default Jaeger UDP server address.
    # See: <https://www.jaegertracing.io/docs/1.31/getting-started/#all-in-one>
    server_addr: "127.0.0.1:6831"
    # Overrides the bind address for the reporter API.
    #
    # By default, the reporter API is only exposed on the loopback
    # interface. This won't work in environments where the
    # Jaeger agent is on another host (for example, Docker).
    # Must have the same address family as `jaeger_tracing_server_addr`.
    reporter_bind_addr: ~
    # Number of concurrent tasks to spawn for output.
    #
    # A higher number means more spans can be collected in parallel in a
    # multi-threaded runtime. All tasks share a UDP socket for sending datagrams.
    # The default is 1 task.
    num_tasks: 1
    # Maximum number of spans to batch together for output.
    #
    # Currently, each span is still sent as a separate UDP datagram due to
    # datagram size limits. This setting only affects how many spans are
    # taken from the queue as a batch.
    #
    # Defaults to `100`.
    max_batch_size: 100

expand_enum now generates an add_docs that matches on the variants. For each new type variant that serde serializes it pushes the variant's key, forwards to the wrapped value, then records the variant's own doc comment, which is what the macro already does for a struct field. Unit variants serialize as a bare value, so there is no line to attach a comment to and their arm is empty. serde(skip) variants are left out as well, so the type behind one still does not need to implement Settings: LogOutput::Custom wraps an Arc<dyn Drain> and would otherwise stop compiling. The key honours serde(rename = "...") and otherwise follows the rename_all = "snake_case" the macro puts on every settings enum. Generated code is a match rather than one if let per variant because if let trips irrefutable_let_patterns on a single variant enum, which is what TracesOutput is without telemetry-otlp-grpc.

Verified on macOS with cargo 1.95.0.

cargo test -p foundations --no-default-features --features settings --test settings, and the same with --features settings,serde-saphyr: 13 passed, 0 failed on both. The new enum_new_type_variant_fields test fails on main with the four comment lines missing from the output and passes here, and there is a golden file for each YAML backend. No existing golden file changed.

cargo test -p foundations-macros: 69 passed, 0 failed. Three existing expand_enum* expansion tests needed their expected output updated, and expand_enum_with_variant_docs is new and covers a plain new type variant, a renamed one, a skipped one wrapping a type that is not Settings, and a unit variant.

RUSTFLAGS=-Dwarnings cargo check -p foundations --no-default-features --features settings,client-telemetry,user-tracing,telemetry-otlp-grpc: clean. That is the set that covers LogOutput, TracesOutput, UserTracesOutput, SamplingStrategy and ServiceNameFormat.

cargo clippy with the flags from AGENTS.md on -p foundations-macros --all-targets and on -p foundations --no-default-features --features settings --lib --test settings: clean. rustfmt --check --edition 2024 on both changed Rust files: clean.

I left RELEASE_NOTES.md alone since git-cliff generates it from commit subjects at release time.

`#[settings]` on an enum emitted an empty `Settings` impl, so `add_docs`
fell back to the no-op default in foundations/src/settings/mod.rs. A new
type variant is the one variant kind that gets a key of its own in the
serialized YAML, and everything under that key was written without its
doc comments.

`TracingSettings::output` defaults to `TracesOutput::JaegerThriftUdp`
(foundations/src/telemetry/settings/tracing.rs:80), so a config written
by `Cli`'s `--generate` listed `server_addr`, `reporter_bind_addr`,
`num_tasks` and `max_batch_size` with no documentation at all. Same for
`UserTracesOutput::OtlpUds` and `SamplingStrategy::Active`.

`expand_enum` now builds an `add_docs` that matches on the variants and,
for each new type variant serde actually serializes, pushes the variant's
key and forwards to the wrapped value before recording the variant's own
doc comment. Unit variants serialize as a bare value and have no key to
document. `serde(skip)` variants are left out so the type they wrap does
not have to implement `Settings`, which `LogOutput::Custom` (an
`Arc<dyn Drain>`) does not.
@TheJokr

TheJokr commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Hi Max, thanks for the PR! This is a known issue with the #[settings] macro that we track here: #158 (comment)

The problem with fixing this is that its a breaking change: Right now, the inner type of a newtype variant does not need to impl Settings. By calling add_docs, we are adding this requirement and potentially break existing code. This leaves us with 3 choices:

  • Put this PR on hold until we release foundations 6 (no concrete plans yet).
  • Put the new macro output behind a #[cfg] flag. (#[cfg(foundations_unstable)] is fine IMO)
  • Make the new output opt-in with an attribute on the macro. This can even be combined with the cfg flag, such that the config flag simply flips the default for the attribute.

I'm fine with any of these options, so I'll leave it up to you to pick.

Documenting a new type variant makes the wrapped type reachable through
add_docs, so that type now has to implement Settings. That is a new
requirement on existing code, so the generated impl stays behind
--cfg foundations_unstable until the next breaking release.

Without the flag the macro emits the same empty impl as before.
@MaxFreedomPollard

Copy link
Copy Markdown
Author

Went with the cfg flag, thanks for laying out the options.

The generated add_docs for a new type variant is now behind --cfg foundations_unstable. Without it the macro emits the same empty impl Settings as before, so nothing existing gains a Settings bound. I followed the same pattern as the with_removal gating in the metrics macro, and added the feature to the unstable list in the crate docs.

Tested both ways: 18 macro tests / 12 integration tests without the flag, 19 / 13 with it.

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.

2 participants