-
Notifications
You must be signed in to change notification settings - Fork 11
Add EdgeZero canary routing (rollout_pct flag + FNV-1a bucket assignment) (PR 19) #727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/edgezero-pr19-spin-adapter
Are you sure you want to change the base?
Changes from all commits
611fab8
5718303
8ef14ec
8b8c303
76aee4a
a1678dc
81d5179
9c35fbf
951a35c
9743550
7b420cc
30002e2
cbaa4a1
722c6dc
08168cb
3715cf5
706b077
5f81e80
17925a7
403de35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,21 +16,52 @@ fn target_label(target: &str) -> &str { | |||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// Environment variable that overrides the Fastly logger's maximum level. | ||||||||||||
| /// | ||||||||||||
| /// Production ships at `Info`; this override exists for local pre-production | ||||||||||||
| /// validation under Viceroy, where raising the level to `debug` makes the | ||||||||||||
| /// `should_route_to_edgezero` route-decision lines observable. Production Fastly | ||||||||||||
| /// Compute does not surface arbitrary process environment variables, so the | ||||||||||||
| /// override is effectively local-only and the level stays at the safe default | ||||||||||||
| /// when the variable is unset or unparseable. | ||||||||||||
| /// | ||||||||||||
| /// Fastly-only by design: this knob is safe here *because* Compute hides runtime | ||||||||||||
| /// env vars. It must not be copied verbatim into the axum/spin/cloudflare | ||||||||||||
| /// adapters, which run where env vars are readable — there it would reintroduce | ||||||||||||
| /// the per-request production debug flood this path deliberately avoids. | ||||||||||||
| const LOG_LEVEL_ENV: &str = "EDGEZERO_LOG_LEVEL"; | ||||||||||||
|
|
||||||||||||
| /// Resolves the logger's maximum level from an optional configured value, | ||||||||||||
| /// falling back to `Info` when it is absent or not a recognised level filter. | ||||||||||||
| fn resolve_max_level(configured: Option<&str>) -> log::LevelFilter { | ||||||||||||
| configured | ||||||||||||
| .and_then(|value| value.trim().parse::<log::LevelFilter>().ok()) | ||||||||||||
| .unwrap_or(log::LevelFilter::Info) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// Initialises the Fastly-backed `fern` logger and installs it as the global logger. | ||||||||||||
| /// | ||||||||||||
| /// Log records are forwarded to the `tslog` Fastly endpoint and echoed to stdout. | ||||||||||||
| /// Each line is prefixed with an RFC 3339 timestamp, level, and the final segment | ||||||||||||
| /// of the record's target module path. | ||||||||||||
| /// | ||||||||||||
| /// The maximum level defaults to `Info`. Setting the [`LOG_LEVEL_ENV`] | ||||||||||||
| /// environment variable (e.g. `EDGEZERO_LOG_LEVEL=debug`) overrides it for local | ||||||||||||
| /// Viceroy validation — the value is used as-is, so `error`/`off` lowers it just | ||||||||||||
| /// as `debug` raises it; see [`resolve_max_level`]. | ||||||||||||
| /// | ||||||||||||
| /// # Panics | ||||||||||||
| /// | ||||||||||||
| /// Panics if the Fastly logger cannot be built or if the global logger has already | ||||||||||||
| /// been set. | ||||||||||||
| pub(crate) fn init_logger() { | ||||||||||||
| let configured = std::env::var(LOG_LEVEL_ENV).ok(); | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔧 wrench —
One minimal way to make the local validation path real is to key off the Fastly-provided local hostname and keep production at the safe default:
Suggested change
|
||||||||||||
| let max_level = resolve_max_level(configured.as_deref()); | ||||||||||||
|
|
||||||||||||
| let logger = Logger::builder() | ||||||||||||
| .default_endpoint("tslog") | ||||||||||||
| .echo_stdout(true) | ||||||||||||
| .max_level(log::LevelFilter::Info) | ||||||||||||
| .max_level(max_level) | ||||||||||||
| .build() | ||||||||||||
| .expect("should build Logger"); | ||||||||||||
|
|
||||||||||||
|
|
@@ -77,4 +108,36 @@ mod tests { | |||||||||||
| "should strip separator when trailing segment is empty" | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| #[test] | ||||||||||||
| fn resolve_max_level_defaults_to_info_when_unset() { | ||||||||||||
| assert_eq!( | ||||||||||||
| resolve_max_level(None), | ||||||||||||
| log::LevelFilter::Info, | ||||||||||||
| "should default to Info when the override is unset" | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| #[test] | ||||||||||||
| fn resolve_max_level_raises_to_debug_for_viceroy_validation() { | ||||||||||||
| assert_eq!( | ||||||||||||
| resolve_max_level(Some("debug")), | ||||||||||||
| log::LevelFilter::Debug, | ||||||||||||
| "should raise to Debug so route-decision lines are observable locally" | ||||||||||||
| ); | ||||||||||||
| assert_eq!( | ||||||||||||
| resolve_max_level(Some(" DEBUG ")), | ||||||||||||
| log::LevelFilter::Debug, | ||||||||||||
| "should accept case-insensitive, surrounding-whitespace values" | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| #[test] | ||||||||||||
| fn resolve_max_level_falls_back_to_info_on_unrecognised_value() { | ||||||||||||
| assert_eq!( | ||||||||||||
| resolve_max_level(Some("not-a-level")), | ||||||||||||
| log::LevelFilter::Info, | ||||||||||||
| "should keep the safe Info default for an unparseable override" | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
Uh oh!
There was an error while loading. Please reload this page.