Skip to content

refactor(config): replace bottlecap Config with upstream Config<LambdaConfig>#1251

Open
duncanista wants to merge 2 commits into
feat/use-datadog-agent-config-cratefrom
feat/migrate-bottlecap-to-upstream-config
Open

refactor(config): replace bottlecap Config with upstream Config<LambdaConfig>#1251
duncanista wants to merge 2 commits into
feat/use-datadog-agent-config-cratefrom
feat/migrate-bottlecap-to-upstream-config

Conversation

@duncanista

Copy link
Copy Markdown
Contributor

Overview

Stacked on top of #1249. Completes the migration to the shared datadog-agent-config crate: bottlecap::config::Config is now a type alias for datadog_agent_config::Config<LambdaConfig>, Lambda-specific fields live under .ext, and the 10 in-tree config submodules that duplicated upstream implementations are removed.

Structural changes

  • bottlecap/src/config/mod.rs shrinks from 2243 → 602 lines. The legacy Config struct, ConfigBuilder, ConfigSource, ConfigError, the #[macro_export] merge_* macros, all per-field deserializer helpers, and the test module that mirrored upstream's behavior — all gone. What remains: a type Config alias, a get_config(path) wrapper, the LambdaConfig extension itself (from the parent PR), and re-exports of upstream modules under the same crate::config::* paths so existing imports keep working.

  • New module bottlecap/src/config/propagation_wrapper.rs holds a newtype PropConfig(Arc<Config>) so we can implement the foreign PropagationConfig trait on the foreign Config<E> type without tripping Rust's orphan rule. The wrapper is scoped to the dd-trace-rs propagator boundary — nothing else uses it.

  • bottlecap/src/traces/propagation/mod.rs wraps the inner propagator in PropConfig instead of passing Config directly. All call sites that previously handed Arc<Config> to the propagator are unchanged — the wrapping happens inside DatadogCompositePropagator::new.

  • Deleted files (each redundant with upstream):

    • additional_endpoints.rs, apm_replace_rule.rs, env.rs, flush_strategy.rs, log_level.rs, logs_additional_endpoints.rs, processing_rule.rs, service_mapping.rs, trace_propagation_style.rs, yaml.rs
  • ~70 field-access sites referencing Lambda-specific fields (config.api_key_secret_arn, config.serverless_logs_enabled, config.enhanced_metrics, etc.) updated to read through config.ext.X. Test struct literals that constructed Config { ... } with Lambda fields now nest them under ext: LambdaConfig { ..., ..Default::default() }.

What stays the same

  • LambdaConfig itself (and its 33 tests) — already shipped in the parent PR; no behavior change in this commit.
  • All other tests pass: 501 lib + 5 integration tests green.
  • The .ext indirection is invisible to callers that hold an Arc<Config> thanks to Rust's field-access auto-deref — they just go from config.foo to config.ext.foo for the 19 Lambda fields.

Testing

$ cargo test --lib
test result: ok. 501 passed; 0 failed; 0 ignored

$ cargo test --tests
test result: ok. (all integration suites green)

Follow-ups

@duncanista duncanista left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reviewed the migration diff (feat/use-datadog-agent-config-crate...feat/migrate-bottlecap-to-upstream-config). This is a mechanical refactor — ConfigConfig<LambdaConfig> with .ext. indirection on 19 Lambda fields, plus a PropConfig newtype to ferry the foreign Config<E> past the orphan rule. No correctness bugs found. The structural pieces (PropConfig impl, mod.rs rewrite, ~70 read-site rewrites, ~14 test struct-literal rewrites) all check out.

What I verified

  • Field migration completeness. Grepped every one of the 19 Lambda field names across bottlecap/src/ and bottlecap/tests/. The only remaining bare config.<lambda_field> (no .ext.) accesses are inside LambdaConfig/LambdaConfigSource struct literals or comments. Nothing missed.
  • Test struct-literal rewrites. Every Config { lambda_field: …, ..Default::default() } is correctly rewritten to nest the Lambda fields under ext: LambdaConfig { …, ..Default::default() } with the outer ..Config::default() (or ..no_config.as_ref().clone()) preserved. Test intent is preserved in the two cases where a Lambda field was bundled with core fields (e.g. lifecycle/invocation/processor.rs test at the new line 2407 has service: Some("test-service".to_string()) at the top level AND serverless_appsec_enabled: true correctly placed under ext:).
  • metrics/enhanced/lambda.rs test_disabled / test_snapstart_restore_duration_metric_disabled. These override enhanced_metrics over a non-default no_config base. The rewrite correctly uses ..no_config.ext.clone() for the extension and ..no_config.as_ref().clone() for the rest — both layers of "keep everything else from no_config" are preserved.
  • mod.rs rewrite (2243 → 602 lines). Verified that nothing outside the deleted files references the dropped ConfigBuilder / ConfigSource / ConfigError / merge_* macros. The re-exports cover every existing crate::config::{env, flush_strategy, processing_rule, log_level, …}::X import I could find (lifecycle/invocation_times.rs, lifecycle/flush_control.rs, logs/processor.rs, etc.).
  • PropConfig impl parity. The new PropagationConfig for PropConfig impl is a verbatim forward of the old impl PropagationConfig for Config (same emptiness checks, same None for inject, same hard-coded 512 for datadog_tags_max_length). The self.0.foo derefs through Arc<Config> to the same fields as the prior self.foo access.
  • Stacked-PR base. Re-targeting onto main after #1249 lands should be clean — this PR's diff touches only files modified in this branch's HEAD commit (e5cebae0), and #1249 doesn't touch the same lines in those files.

Findings are non-blocking nits — see inline comments.

Comment thread bottlecap/src/config/propagation_wrapper.rs Outdated
Comment thread bottlecap/src/config/propagation_wrapper.rs
Comment thread bottlecap/src/traces/propagation/mod.rs Outdated
duncanista added a commit that referenced this pull request Jun 10, 2026
Three non-blocking nits from the independent review:

1. PropConfig's inner Arc<Config> is no longer pub — keeps the wrapper
   boundary tight; the new() constructor is sufficient and no callers
   outside the module reach for the inner field directly.
2. PropConfig::new returns Arc<Self> instead of Self. Drops the
   redundant `Arc::new(...)` wrap at the single call site in
   traces/propagation/mod.rs.
3. Documents the hard-coded 512 in datadog_tags_max_length — it
   matches dd-trace-rs's default; bottlecap intentionally doesn't
   expose DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH. Saves the next reader
   a round-trip through upstream to confirm parity.

No behavior change. All 505 lib tests still pass.
@duncanista duncanista force-pushed the feat/migrate-bottlecap-to-upstream-config branch from e5cebae to 561096a Compare June 10, 2026 18:27
@duncanista duncanista marked this pull request as ready for review June 10, 2026 18:28
@duncanista duncanista requested review from a team as code owners June 10, 2026 18:28
@duncanista duncanista requested a review from jchrostek-dd June 10, 2026 18:28
…aConfig>

Completes the migration started in the previous PR onto the shared
datadog-agent-config crate. bottlecap::config::Config is now a type
alias for datadog_agent_config::Config<LambdaConfig>; Lambda-specific
fields live under .ext (per the upstream ConfigExtension trait), and
the 10 in-tree config submodules that duplicated upstream
implementations are removed entirely.

What changes structurally:

- bottlecap/src/config/mod.rs shrinks from 2243 lines to ~600. The
  legacy Config struct, ConfigBuilder, ConfigSource, ConfigError,
  the #[macro_export] merge_* macros, all the per-field deserializer
  helpers, and the entire test module that mirrored upstream's
  behavior are gone. What remains: a `type Config` alias, a
  `get_config(path)` wrapper, the LambdaConfig extension itself, and
  re-exports of upstream modules under the same `crate::config::*`
  paths so existing imports keep working.

- New module bottlecap/src/config/propagation_wrapper.rs holds a
  newtype `PropConfig(Arc<Config>)` so we can implement the foreign
  PropagationConfig trait on the foreign Config<E> type without
  running afoul of Rust's orphan rule. The wrapper is scoped to the
  dd-trace-rs propagator boundary; nothing else uses it.

- bottlecap/src/traces/propagation/mod.rs wraps the inner propagator
  in PropConfig instead of passing Config directly. All call sites
  that previously handed `Arc<Config>` to the propagator are
  unchanged - the wrapping happens inside DatadogCompositePropagator::new.

- Deleted files (each redundant with upstream):
    additional_endpoints.rs, apm_replace_rule.rs, env.rs,
    flush_strategy.rs, log_level.rs, logs_additional_endpoints.rs,
    processing_rule.rs, service_mapping.rs,
    trace_propagation_style.rs, yaml.rs

- All ~70 field-access sites referencing Lambda-specific fields
  (config.api_key_secret_arn, config.serverless_logs_enabled,
  config.enhanced_metrics, etc.) updated to read through
  config.ext.X. Test struct literals that construct Config { ... }
  with Lambda fields now nest them under
  `ext: LambdaConfig { ..., ..Default::default() }`.

What stays the same:

- LambdaConfig itself (and its 33 tests) - already shipped in the
  parent PR; no behavior change in this commit.
- All other tests pass: 501 lib + 5 integration tests green.
- The .ext indirection is invisible to callers that hold an
  `Arc<Config>` thanks to Rust's field-access auto-deref - they just
  go from `config.foo` to `config.ext.foo` for the 19 Lambda fields.

Stacked on top of the LambdaConfig foundation PR (#1249).
Three non-blocking nits from the independent review:

1. PropConfig's inner Arc<Config> is no longer pub — keeps the wrapper
   boundary tight; the new() constructor is sufficient and no callers
   outside the module reach for the inner field directly.
2. PropConfig::new returns Arc<Self> instead of Self. Drops the
   redundant `Arc::new(...)` wrap at the single call site in
   traces/propagation/mod.rs.
3. Documents the hard-coded 512 in datadog_tags_max_length — it
   matches dd-trace-rs's default; bottlecap intentionally doesn't
   expose DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH. Saves the next reader
   a round-trip through upstream to confirm parity.

No behavior change. All 505 lib tests still pass.
@duncanista duncanista force-pushed the feat/migrate-bottlecap-to-upstream-config branch from 561096a to a223aee Compare June 10, 2026 18:35
@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Jun 10, 2026

Copy link
Copy Markdown

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 4 Pipeline jobs failed

DataDog/datadog-lambda-extension | e2e-test-status (amd64)   View in Datadog   GitLab

DataDog/datadog-lambda-extension | e2e-test-status (amd64, fips)   View in Datadog   GitLab

DataDog/datadog-lambda-extension | integration-suite: [auth]   View in Datadog   GitLab

View all 4 failed jobs.

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a223aee | Docs | Datadog PR Page | Give us feedback!

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.

1 participant