cloudflare / foundations

Cloudflare's Rust service foundations library.
https://blog.cloudflare.com/introducing-foundations-our-open-source-rust-service-foundation-library
BSD 3-Clause "New" or "Revised" License
1.25k stars 51 forks source link

Settings comments not propagated when using `#[serde(flatten)]` #42

Open hgmich opened 5 months ago

hgmich commented 5 months ago

In a shared workspace of several crates, I am sharing a common settings struct like this:

use foundations::settings::settings;
use std::path::PathBuf;

#[settings]
pub struct NatsSettings {
    /// NATS server URL.
    #[serde(default = "NatsSettings::default_url")]
    pub url: String,
    /// NATS credentials file. Set to null to disable authentication.
    #[serde(default = "NatsSettings::default_creds_file")]
    pub credentials_file: Option<PathBuf>,
}

impl NatsSettings {
    fn default_url() -> String {
        "nats://localhost:4222".into()
    }

    fn default_creds_file() -> Option<PathBuf> {
        Some("/etc/nats/creds".into())
    }
}

Since these services all connect to NATS, it makes sense to have a common section for these. However, some services make use of additional features, such as NATS' key-value store. Similar to how one might "extend" traits locally, I adopted a pattern somewhat like this:

use foundations::settings::settings;
use foundations::telemetry::settings::TelemetrySettings;

use workspace_utils::settings::NatsSettings;

#[settings]
pub(crate) struct ServiceSettings {
    /// Telemetry settings.
    pub(crate) telemetry: TelemetrySettings,
    /// NATS client configuration.
    pub(crate) nats: NatsSettingsExt,
}

#[settings]
pub(crate) struct NatsSettingsExt {
    #[serde(flatten)]
    pub(crate) core: NatsSettings,

    /// NATS KV bucket name.
    pub(crate) kv_bucket: String,
}

This actually mostly works as expected - the only thing to note is that in the generated config, the doc comments in NatsSettings are not propagated into the generated config file:

---
# Telemetry settings.
telemetry:
  # Distributed tracing settings
  tracing:
    # Enables tracing.
    enabled: true
    # The address of the Jaeger Thrift (UDP) agent.
    jaeger_tracing_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`.
    jaeger_reporter_bind_addr: ~
    # Sampling ratio.
    #
    # This can be any fractional value between `0.0` and `1.0`.
    # Where `1.0` means "sample everything", and `0.0` means "don't sample anything".
    sampling_ratio: 1.0
    # Settings for rate limiting emission of traces
    rate_limit:
      # Whether to enable rate limiting of events
      enabled: false
      # Maximum number of events that can be emitted per second
      max_events_per_second: 0
  # Logging settings.
  logging:
    # Specifies log output.
    output: terminal
    # The format to use for log messages.
    format: text
    # Set the logging verbosity level.
    verbosity: INFO
    # A list of field keys to redact when emitting logs.
    #
    # This might be useful to hide certain fields in production logs as they may
    # contain sensitive information, but allow them in testing environment.
    redact_keys: []
    # Settings for rate limiting emission of log events
    rate_limit:
      # Whether to enable rate limiting of events
      enabled: false
      # Maximum number of events that can be emitted per second
      max_events_per_second: 0
    # Configure log volume metrics.
    log_volume_metrics:
      # Whether to enable log volume metrics
      enabled: false
  # Metrics settings.
  metrics:
    # How the metrics service identifier defined in `ServiceInfo` is used
    # for this service.
    service_name_format: metric_prefix
    # Whether to report optional metrics in the telemetry server.
    report_optional: false
  # Server settings.
  server:
    # Enables telemetry server
    enabled: true
    # Telemetry server address.
    addr: "127.0.0.1:0"
# NATS client configuration.
nats:
  url: "nats://localhost:4222"
  credentials_file: /etc/nats/creds
  # NATS KV bucket name.
  kv_bucket: ""