Skip to content

refactor(build): feature-gate OTLP and AppSec subsystems (default-on)#1280

Closed
duncanista wants to merge 2 commits into
jordan.gonzalez/cold-start-instrumentation/featurefrom
jordan.gonzalez/feature-gate-otlp-appsec/feature
Closed

refactor(build): feature-gate OTLP and AppSec subsystems (default-on)#1280
duncanista wants to merge 2 commits into
jordan.gonzalez/cold-start-instrumentation/featurefrom
jordan.gonzalez/feature-gate-otlp-appsec/feature

Conversation

@duncanista

Copy link
Copy Markdown
Contributor

Note

DRAFT — stacked on #1271 (jordan.gonzalez/cold-start-instrumentation/feature). Review/merge that PR first; this diff is scoped to the build/feature-gating change on top of it.

Jira: none yet — add before marking ready.

Overview

Puts the otlp and appsec subsystems behind Cargo features that are ON by default, so the shipped binary is byte-for-byte unchanged, but can be turned off to drop their heavy, exclusive dependencies. This is part of the cold-start dependency/binary-size reduction work (Confluence H13).

Deps gated

  • otlp feature → opentelemetry-proto, opentelemetry-semantic-conventions, tonic, tonic-types (verified otlp-only).
  • appsec feature → libddwaf (and transitively libddwaf-sys + its C build toolchain — bindgen/clang-sys/cmake/nom/tar/… — plus aws-lc-rs/aws-lc-sys).

Deliberately NOT gated

  • prost — shared: used by proxy/interceptor.rs, traces/trace_processor.rs, and datadog-protos. Left as a normal dependency (verified by grep before gating).

How the gating works

  • src/lib.rs: #[cfg(feature = "otlp")] pub mod otlp; and #[cfg(feature = "appsec")] pub mod appsec;.
  • When appsec is off, an uninhabited AppSecProcessorStub enum stands in for the processor type, so the Option<Arc<Mutex<…>>> fields (SendingTraceProcessor, TraceAgent), the proxy InterceptorState tuple, and every appsec: None construction site keep the same shape across both builds. Only the code paths that actually call into the WAF (process_span / process_invocation_next / process_invocation_result / hold-trace) are #[cfg(feature = "appsec")]-gated. The stub is never constructed (the Option is always None).
  • start_otlp_agent gets a no-op #[cfg(not(feature = "otlp"))] fallback that returns None, so its call site and shutdown wiring are unchanged.
  • fips now implies appsec (FIPS-mode WAF requires libddwaf compiled in); fips feature resolution verified to still pull in libddwaf.

Dependency-graph delta (proxy for binary size — a precise stripped/LTO/cross-target binary measurement was not run, it is expensive): turning off otlp+appsec drops 26 crates from the graph (396 → 370), including the native-compiled libddwaf-sys + aws-lc-sys and the bindgen/clang/cmake build chain.

Testing

Both builds are clippy-clean (pedantic + unwrap_used denied; only the pre-existing accepted buf_redux/multipart future-incompat note remains):

  • Default build (otlp + appsec on):
    cargo clippy --bin bottlecap --no-deps → exit 0
    cargo clippy --all-targets --no-deps (compiles tests) → exit 0
  • Feature-OFF build (everything in default EXCEPT otlp/appsec) — verified:
    cargo clippy --bin bottlecap --no-deps --no-default-features \
      --features="reqwest/rustls-tls-native-roots,datadog-fips/default,datadog-agent-config/https,libdd-common/https,libdd-trace-utils/https,libdd-trace-obfuscation/https,libdd-trace-stats/https"
    
    → exit 0 (libddwaf/libddwaf-sys confirmed absent from the dependency graph; direct opentelemetry-proto/tonic-types dropped).

Put the otlp and appsec subsystems behind Cargo features that are ON by
default, so the shipped binary is unchanged, but can be turned off to drop
their heavy, exclusive dependencies:

- otlp gates: opentelemetry-proto, opentelemetry-semantic-conventions,
  tonic, tonic-types (all otlp-only; prost stays since it is shared with
  proxy/interceptor, traces/trace_processor and datadog-protos).
- appsec gates: libddwaf (and transitively libddwaf-sys + its C build
  toolchain and aws-lc crypto).

lib.rs cfg-gates 'pub mod otlp' / 'pub mod appsec'. When appsec is off, an
uninhabited AppSecProcessorStub stands in for the processor type so the
Option<Arc<Mutex<..>>> fields, the proxy state tuple, and all 'appsec: None'
call sites keep the same shape; only the code paths that actually call into
the WAF are cfg-gated. start_otlp_agent gets a no-op fallback returning None.

fips implies appsec (FIPS-mode WAF requires libddwaf compiled in).

Both the default build and a build with everything in 'default' except
otlp/appsec are clippy-clean (pedantic + unwrap_used denied).
@datadog-official

datadog-official Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 1 Pipeline job failed

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

Useful? React with 👍 / 👎

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

fips builds use --no-default-features --features=fips, which omitted otlp and would drop the OTLP subsystem from shipped FIPS layers. Add otlp to the fips feature list alongside appsec.
@duncanista

Copy link
Copy Markdown
Contributor Author

Closing: the extension always ships as a single binary with all subsystems compiled in, and OTLP/AppSec are enabled at runtime via env vars — so compile-time feature-gating provides no value for the shipped product. The disabled subsystems also do no eager work at init, so there's no cold-start win either (only a build-time/size effect that we never actually take advantage of given the single-artifact shipping model). Reopen if the shipping model ever changes to slim/per-feature binaries.

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