diff --git a/.changesets/feat_marcelo_router_1609.md b/.changesets/feat_marcelo_router_1609.md new file mode 100644 index 0000000000..206cc006ae --- /dev/null +++ b/.changesets/feat_marcelo_router_1609.md @@ -0,0 +1,12 @@ +### Block Router startup when certain OTEL environment variables are set (PR #8915) + +The Apollo Router will now *fail to start* if any of the following OpenTelemetry (OTEL) keyword environment variables are set: + • OTEL_EXPORTER_OTLP_ENDPOINT + • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT + • OTEL_EXPORTER_OTLP_METRICS_ENDPOINT + +Using these variables *is not supported by the Router* since it can override or interfere with its built-in telemetry configuration, leading to unexpected behavior. + +Previously, the Router emitted a warning when OTEL_EXPORTER_OTLP_ENDPOINT was present. With this change, *startup is now blocked* to prevent unintended telemetry configuration conflicts. + +If your deployment defines any of these environment variables (for example, through base container images, platform defaults, or infrastructure tooling), they must be removed before starting the Router. diff --git a/apollo-router/src/executable.rs b/apollo-router/src/executable.rs index 513a1f9671..d6ba909f54 100644 --- a/apollo-router/src/executable.rs +++ b/apollo-router/src/executable.rs @@ -55,6 +55,12 @@ pub(crate) static APOLLO_ROUTER_HOT_RELOAD_CLI: AtomicBool = AtomicBool::new(fal const INITIAL_UPLINK_POLL_INTERVAL: Duration = Duration::from_secs(10); const INITIAL_OCI_POLL_INTERVAL: Duration = Duration::from_secs(30); +const FORBIDDEN_OTEL_VARS: [&str; 3] = [ + "OTEL_EXPORTER_OTLP_ENDPOINT", + "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", + "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", +]; + /// Subcommands #[derive(Subcommand, Debug)] enum Commands { @@ -286,6 +292,10 @@ impl Opt { fn err_require_opt(env_var: &str) -> anyhow::Error { anyhow!("Use of Apollo Graph OS requires setting the {env_var} environment variable") } + + fn prohibit_env_vars(env_vars: &[&'static str]) -> Result<(), anyhow::Error> { + reject_environment_variables(&env_variables_set(env_vars)) + } } /// This is the main router entrypoint. @@ -475,6 +485,9 @@ impl Executable { // Enable hot reload when dev mode is enabled opt.hot_reload = opt.hot_reload || opt.dev; + // ROUTER-1609: prevent router from starting if OTEL environment variables are set. + Opt::prohibit_env_vars(&FORBIDDEN_OTEL_VARS)?; + let configuration = match (config, opt.config_path.as_ref()) { (Some(_), Some(_)) => { return Err(anyhow!( @@ -738,14 +751,6 @@ impl Executable { ); } - // Warn users that OTEL_EXPORTER_OTLP_ENDPOINT takes precedence over default configurations - // and may override trace export to Apollo Studio - if std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").is_ok() { - tracing::warn!( - "The OTEL_EXPORTER_OTLP_ENDPOINT environment variable is set. This takes precedence over default configurations and may override trace export to Apollo Studio." - ); - } - let router = RouterHttpServer::builder() .is_telemetry_disabled(opt.anonymous_telemetry_disabled) .configuration(configuration) @@ -768,6 +773,27 @@ fn graph_os() -> bool { && crate::services::APOLLO_GRAPH_REF.lock().is_some() } +/// Of the environment variable names provided, return a list of those which are set in the environment. +fn env_variables_set(variables: &[&'static str]) -> Vec<&'static str> { + variables + .iter() + .filter(|v| !matches!(std::env::var(v), Err(std::env::VarError::NotPresent))) + .cloned() + .collect() +} + +/// Return an error if the list of environment variables provided is not empty +fn reject_environment_variables(variables: &[&str]) -> Result<(), anyhow::Error> { + if variables.is_empty() { + Ok(()) + } else { + Err(anyhow!( + "the following environment variables must not be set: {}", + variables.join(", ") + )) + } +} + fn setup_panic_handler() { // Redirect panics to the logs. let backtrace_env = std::env::var("RUST_BACKTRACE"); @@ -796,6 +822,8 @@ fn setup_panic_handler() { #[cfg(test)] mod tests { use crate::executable::add_log_filter; + use crate::executable::env_variables_set; + use crate::executable::reject_environment_variables; #[test] fn simplest_logging_modifications() { @@ -1033,4 +1061,33 @@ mod tests { ); } } + + #[test] + fn it_observes_environment_variables() { + const VALID_ENV_VAR: &str = "CARGO_HOME"; + + // if we're running tests, we should have a CARGO_HOME env variable present + assert!(std::env::var(VALID_ENV_VAR).is_ok()); + + // make sure the env_variables_set function can see that, both alone and in a list + assert!(env_variables_set(&[VALID_ENV_VAR]).contains(&VALID_ENV_VAR)); + assert!( + env_variables_set(&[VALID_ENV_VAR, "ANOTHER_ENV_VARIABLE"]).contains(&VALID_ENV_VAR) + ); + + // make sure the env_variables_set variable doesn't find not-present environment variables + assert!(env_variables_set(&["AN_EXTREMELY_UNLIKELY_TO_BE_SET_VARIABLE"]).is_empty()); + } + + #[test] + fn it_returns_an_error_when_env_variable_provided() { + assert!(reject_environment_variables(&[]).is_ok()); + + let err = reject_environment_variables(&["env1"]).unwrap_err(); + assert!(err.to_string().contains("env1")); + + let err = reject_environment_variables(&["env1", "env2"]).unwrap_err(); + assert!(err.to_string().contains("env1")); + assert!(err.to_string().contains("env2")); + } } diff --git a/docs/shared/otel-envvars-caution.mdx b/docs/shared/otel-envvars-caution.mdx new file mode 100644 index 0000000000..52043ce91c --- /dev/null +++ b/docs/shared/otel-envvars-caution.mdx @@ -0,0 +1,15 @@ + + +The following OpenTelemetry (OTEL) environment variables will override router's built-in telemetry configuration: + +- `OTEL_EXPORTER_OTLP_ENDPOINT` +- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` +- `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` + +In Apollo Router v2.12.0 and earlier, these variables will override router's telemetry settings and may cause traces or metrics to be sent to an unintended destination. + +

+ +In Apollo Router v2.13.0 and later, your router will not start if any of these variables are set. Remove them from your environment before launching. + +
\ No newline at end of file diff --git a/docs/source/routing/observability/graphos/graphos-reporting.mdx b/docs/source/routing/observability/graphos/graphos-reporting.mdx index 563ad13efd..a3ece4eccf 100644 --- a/docs/source/routing/observability/graphos/graphos-reporting.mdx +++ b/docs/source/routing/observability/graphos/graphos-reporting.mdx @@ -6,6 +6,8 @@ redirectFrom: - /graphos/routing/graphos-reporting --- +import OTelEnvVarsCaution from '../../../../shared/otel-envvars-caution.mdx'; + The GraphOS Router and Apollo Router Core can report operation usage metrics to [GraphOS](/graphos/) that you can then visualize in GraphOS Studio. These metrics also enable powerful GraphOS features like [schema checks](/graphos/delivery/schema-checks/). ## Enabling usage reporting @@ -67,11 +69,7 @@ telemetry: sampler: 0.01 ``` - - -If your environment defines `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, they take precedence over your Router settings and may send traces to a different destination. Verify whether these variables are set and unset them if needed. For details, see the [OTLP exporter documentation](/router/configuration/telemetry/exporters/tracing/otlp). - - + ## Reporting field-level traces diff --git a/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/metrics-exporters/otlp.mdx b/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/metrics-exporters/otlp.mdx index 460d7122ab..dd1411dff8 100644 --- a/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/metrics-exporters/otlp.mdx +++ b/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/metrics-exporters/otlp.mdx @@ -9,6 +9,7 @@ redirectFrom: --- import BatchProcessorPreamble from '../../../../../../shared/batch-processor-preamble.mdx'; import BatchProcessorRef from '../../../../../../shared/batch-processor-ref.mdx'; +import OTelEnvVarsCaution from '../../../../../../shared/otel-envvars-caution.mdx'; Enable and configure the [OpenTelemetry Protocol (OTLP)](https://www.opentelemetry.io/) exporter for metrics in the GraphOS Router or Apollo Router Core. @@ -69,11 +70,7 @@ Defaults to: * http://127.0.0.1:4317 for gRPC * http://127.0.0.1:4318 for HTTP - - -If your environment sets `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`, these variables take precedence over the `endpoint` configured in your `router.yaml`. If metrics aren't appearing at your expected endpoint, check if these environment variables are set and unset them if necessary. - - + ### `grpc` diff --git a/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/otlp.mdx b/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/otlp.mdx index 0f1143eb97..baf99543c0 100644 --- a/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/otlp.mdx +++ b/docs/source/routing/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/otlp.mdx @@ -9,6 +9,7 @@ redirectFrom: --- import BatchProcessorPreamble from '../../../../../../shared/batch-processor-preamble.mdx'; import BatchProcessorRef from '../../../../../../shared/batch-processor-ref.mdx'; +import OTelEnvVarsCaution from '../../../../../../shared/otel-envvars-caution.mdx'; Enable and configure the [OpenTelemetry Protocol (OTLP)](https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md) exporter for tracing in the GraphOS Router or Apollo Router Core. @@ -65,11 +66,7 @@ Specify only the base URL in the endpoint parameter. The router automatically ad - - -If your environment sets `OTEL_EXPORTER_OTLP_ENDPOINT` or `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, these variables take precedence over the `endpoint` configured in your `router.yaml`. If traces aren't appearing at your expected endpoint, check if these environment variables are set and unset them if necessary. - - + ### `grpc` Settings specific to the gRPC protocol for setting a custom SSL certificate, domain name, and metadata.