-
Notifications
You must be signed in to change notification settings - Fork 0
chore: various updates to improve debugging apps #123
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: main
Are you sure you want to change the base?
Changes from all commits
6108fbd
4950c2b
db3e41a
f20eed0
b9f9cad
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 |
|---|---|---|
| @@ -1,10 +1,29 @@ | ||
| use init4_bin_base::init4; | ||
| use init4_bin_base::{ | ||
| utils::{from_env::FromEnv, metrics::MetricsConfig, tracing::TracingConfig}, | ||
| Init4Config, | ||
| }; | ||
| use std::sync::{atomic::AtomicBool, Arc}; | ||
|
|
||
| fn main() { | ||
| #[derive(Debug, FromEnv)] | ||
| struct Config { | ||
| tracing: TracingConfig, | ||
| metrics: MetricsConfig, | ||
| } | ||
|
|
||
| impl Init4Config for Config { | ||
| fn tracing(&self) -> &TracingConfig { | ||
| &self.tracing | ||
| } | ||
| fn metrics(&self) -> &MetricsConfig { | ||
| &self.metrics | ||
| } | ||
| } | ||
|
|
||
| fn main() -> eyre::Result<()> { | ||
| let term: Arc<AtomicBool> = Default::default(); | ||
|
|
||
| let _ = signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&term)); | ||
|
|
||
| init4(); | ||
| let _config_and_guard = init4_bin_base::init::<Config>()?; | ||
| Ok(()) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,13 @@ | |
| #![deny(unused_must_use, rust_2018_idioms)] | ||
| #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] | ||
|
|
||
| use crate::utils::{ | ||
| from_env::{FromEnv, FromEnvErr}, | ||
| metrics::MetricsConfig, | ||
| otlp::OtelGuard, | ||
| tracing::TracingConfig, | ||
| }; | ||
|
|
||
| #[cfg(feature = "perms")] | ||
| /// Permissioning and authorization utilities for Signet builders. | ||
| pub mod perms; | ||
|
|
@@ -85,7 +92,8 @@ pub mod deps { | |
| /// | ||
| /// [`init_tracing`]: utils::tracing::init_tracing | ||
| /// [`init_metrics`]: utils::metrics::init_metrics | ||
| pub fn init4() -> Option<utils::otlp::OtelGuard> { | ||
| #[deprecated(since = "0.18.0-rc.11", note = "use `init` instead")] | ||
|
Member
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. goodbye cute little name 🥹 |
||
| pub fn init4() -> Option<OtelGuard> { | ||
| let guard = utils::tracing::init_tracing(); | ||
| utils::metrics::init_metrics(); | ||
|
|
||
|
|
@@ -96,3 +104,72 @@ pub fn init4() -> Option<utils::otlp::OtelGuard> { | |
|
|
||
| guard | ||
| } | ||
|
|
||
| /// Trait for config types that can be used with [`init`]. | ||
| /// | ||
| /// Implementors must provide access to [`TracingConfig`] and [`MetricsConfig`], | ||
| /// and must be loadable from the environment via [`FromEnv`]. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// ```ignore | ||
| /// #[derive(Debug, FromEnv)] | ||
| /// pub struct MyConfig { | ||
| /// pub tracing: TracingConfig, | ||
| /// pub metrics: MetricsConfig, | ||
| /// #[from_env(var = "MY_THING", desc = "some app-specific value")] | ||
| /// pub my_thing: String, | ||
| /// } | ||
| /// | ||
| /// impl Init4Config for MyConfig { | ||
| /// fn tracing(&self) -> &TracingConfig { &self.tracing } | ||
| /// fn metrics(&self) -> &MetricsConfig { &self.metrics } | ||
| /// } | ||
| /// ``` | ||
| pub trait Init4Config: FromEnv { | ||
| /// Get the tracing configuration. | ||
| fn tracing(&self) -> &TracingConfig; | ||
| /// Get the metrics configuration. | ||
| fn metrics(&self) -> &MetricsConfig; | ||
| } | ||
|
|
||
| /// The result of [`init`]: the loaded config and an optional OTLP guard. | ||
| /// | ||
| /// The [`OtelGuard`] (if present) must be kept alive for the lifetime of the | ||
| /// program to ensure the OTLP exporter continues to send data. | ||
| #[derive(Debug)] | ||
| pub struct ConfigAndGuard<T> { | ||
| /// The loaded configuration. | ||
| pub config: T, | ||
| /// The OTLP guard, if OTLP was enabled. | ||
| pub guard: Option<OtelGuard>, | ||
| } | ||
|
|
||
| /// Load config from the environment and initialize metrics and tracing. | ||
| /// | ||
| /// This will perform the following: | ||
| /// - Load `T` from environment variables via [`FromEnv`] | ||
| /// - Read tracing configuration from the loaded config | ||
| /// - Determine whether to enable OTLP | ||
| /// - Install a global tracing subscriber, using the OTLP provider if enabled | ||
| /// - Read metrics configuration from the loaded config | ||
| /// - Install a global metrics recorder and serve it over HTTP on 0.0.0.0 | ||
| /// | ||
| /// See [`init_tracing`] and [`init_metrics`] for more | ||
| /// details on specific actions taken and env vars read. | ||
| /// | ||
| /// [`init_tracing`]: utils::tracing::init_tracing | ||
| /// [`init_metrics`]: utils::metrics::init_metrics | ||
| pub fn init<T: Init4Config>() -> Result<ConfigAndGuard<T>, FromEnvErr> { | ||
| let config = T::from_env()?; | ||
|
|
||
| let guard = utils::tracing::init_tracing_with_config(config.tracing().clone()); | ||
| utils::metrics::init_metrics_with_config(*config.metrics()); | ||
|
|
||
| // This will install the AWS-LC-Rust TLS provider for rustls, if no other | ||
| // provider has been installed yet | ||
| #[cfg(feature = "rustls")] | ||
| let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); | ||
|
|
||
| Ok(ConfigAndGuard { config, guard }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,11 @@ | ||
| //! Service responsible for authenticating with the cache with Oauth tokens. | ||
| //! This authenticator periodically fetches a new token every set amount of seconds. | ||
| use crate::{deps::tracing::error, utils::from_env::FromEnv}; | ||
| use core::{error::Error, fmt}; | ||
| use crate::{ | ||
| deps::tracing::{debug, warn, Instrument}, | ||
| utils::from_env::FromEnv, | ||
| }; | ||
| use core::fmt; | ||
| use eyre::eyre; | ||
| use oauth2::{ | ||
| basic::{BasicClient, BasicTokenType}, | ||
| AccessToken, AuthUrl, ClientId, ClientSecret, EmptyExtraTokenFields, EndpointNotSet, | ||
|
|
@@ -12,8 +16,8 @@ use std::{future::IntoFuture, pin::Pin}; | |
| use tokio::{ | ||
| sync::watch::{self, Ref}, | ||
| task::JoinHandle, | ||
| time::MissedTickBehavior, | ||
| }; | ||
| use tracing::{debug, Instrument}; | ||
|
|
||
| type Token = StandardTokenResponse<EmptyExtraTokenFields, BasicTokenType>; | ||
|
|
||
|
|
@@ -88,10 +92,16 @@ impl Authenticator { | |
| .set_auth_uri(AuthUrl::from_url(config.oauth_authenticate_url.clone())) | ||
| .set_token_uri(TokenUrl::from_url(config.oauth_token_url.clone())); | ||
|
|
||
| // NB: this is MANDATORY | ||
| // NB: redirect policy none is MANDATORY | ||
| // https://docs.rs/oauth2/latest/oauth2/#security-warning | ||
| // | ||
| // Disable connection pooling to avoid stale connection errors. | ||
| // OAuth refreshes are infrequent (typically every 60s), so idle | ||
| // connections are almost always closed by the server or | ||
| // intermediary (e.g. Istio envoy) before the next request. | ||
| let rq_client = reqwest::Client::builder() | ||
| .redirect(reqwest::redirect::Policy::none()) | ||
| .pool_max_idle_per_host(0) | ||
| .build() | ||
| .unwrap(); | ||
|
|
||
|
|
@@ -159,31 +169,20 @@ impl Authenticator { | |
|
|
||
| /// Create a future that contains the periodic refresh loop. | ||
| async fn task_future(self) { | ||
| let interval = self.config.oauth_token_refresh_interval; | ||
| let duration = tokio::time::Duration::from_secs(self.config.oauth_token_refresh_interval); | ||
| let mut interval = tokio::time::interval(duration); | ||
| interval.set_missed_tick_behavior(MissedTickBehavior::Delay); | ||
|
|
||
| loop { | ||
| interval.tick().await; | ||
| debug!("Refreshing oauth token"); | ||
| match self.authenticate().await { | ||
| Ok(_) => { | ||
| debug!("Successfully refreshed oauth token"); | ||
| } | ||
| Err(err) => { | ||
| let mut current = &err as &dyn Error; | ||
|
|
||
| // This is a little hacky, but the oauth library nests | ||
| // errors quite deeply, so we need to walk the source chain | ||
| // to get the full picture. | ||
| let mut source_chain = Vec::new(); | ||
| while let Some(source) = current.source() { | ||
| source_chain.push(source.to_string()); | ||
| current = source; | ||
| } | ||
| let source_chain = source_chain.join("\n\n Caused by: \n"); | ||
|
|
||
| error!(%err, %source_chain, "Failed to refresh oauth token"); | ||
| } | ||
| Ok(_) => debug!("Successfully refreshed oauth token"), | ||
| Err(error) => warn!( | ||
| error = %format!("{:#}", eyre!(error)), | ||
| "Failed to refresh oauth token" | ||
| ), | ||
|
Comment on lines
+172
to
+184
Contributor
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. This changes the behavior to wait before authenticating, but we want to maintain previous behavior, which is authenticate then wait. This ensures fast startups for anything gated by authentication.
Contributor
Author
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. The first tick is immediately ready, so there's no real change in behaviour here. |
||
| }; | ||
| let _sleep = tokio::time::sleep(tokio::time::Duration::from_secs(interval)).await; | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@init4samwise can you list all of the downstream callers of this
init4function ininit4techrepos?