diff --git a/bin/council/src/args.rs b/bin/council/src/args.rs
index af71dc6c53..152a2ca5ab 100644
--- a/bin/council/src/args.rs
+++ b/bin/council/src/args.rs
@@ -19,6 +19,28 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
+
/// NATS connection URL [example: demo.nats.io]
#[arg(long)]
pub(crate) nats_url: Option,
@@ -30,10 +52,6 @@ pub(crate) struct Args {
/// NATS credentials file
#[arg(long)]
pub(crate) nats_creds_path: Option,
-
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
}
impl TryFrom for Config {
diff --git a/bin/council/src/main.rs b/bin/council/src/main.rs
index 788d92538b..4dc07f0be4 100644
--- a/bin/council/src/main.rs
+++ b/bin/council/src/main.rs
@@ -25,23 +25,32 @@ async fn async_main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("council")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["council", "council_server"])
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("council")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["council", "council_server"]);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
- let (_shutdown_request_tx, shutdown_request_rx) = watch::channel(());
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
}
trace!(arguments =?args, "parsed cli arguments");
+ let (_shutdown_request_tx, shutdown_request_rx) = watch::channel(());
+
task_tracker.close();
let config = council_server::server::Config::try_from(args)?;
diff --git a/bin/cyclone/src/args.rs b/bin/cyclone/src/args.rs
index 177c08e61c..e2fa235736 100644
--- a/bin/cyclone/src/args.rs
+++ b/bin/cyclone/src/args.rs
@@ -24,9 +24,27 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
/// Binds service to a socket address [example: 0.0.0.0:5157]
#[arg(long, group = "bind")]
diff --git a/bin/cyclone/src/main.rs b/bin/cyclone/src/main.rs
index c604df5344..f211ff501f 100644
--- a/bin/cyclone/src/main.rs
+++ b/bin/cyclone/src/main.rs
@@ -19,16 +19,25 @@ async fn main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("cyclone")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["cyclone", "cyclone_server"])
- .custom_default_tracing_level(CUSTOM_DEFAULT_TRACING_LEVEL)
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("cyclone")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["cyclone", "cyclone_server"])
+ .custom_default_tracing_level(CUSTOM_DEFAULT_TRACING_LEVEL);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
diff --git a/bin/module-index/src/args.rs b/bin/module-index/src/args.rs
index 822b266dfd..c6e4a09c84 100644
--- a/bin/module-index/src/args.rs
+++ b/bin/module-index/src/args.rs
@@ -21,6 +21,28 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
+
/// PostgreSQL connection pool dbname [example: myapp]
#[arg(long, env)]
pub(crate) pg_dbname: Option,
@@ -80,14 +102,8 @@ pub(crate) struct Args {
/// The path to the JWT public signing key
#[arg(long, env)]
pub(crate) jwt_public_key: Option,
-
// /// Database migration mode on startup
// #[arg(long, value_parser = PossibleValuesParser::new(MigrationMode::variants()))]
-
- // pub(crate) migration_mode: Option,
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
}
impl TryFrom for Config {
diff --git a/bin/module-index/src/main.rs b/bin/module-index/src/main.rs
index c3fe37b108..9b3da91e9d 100644
--- a/bin/module-index/src/main.rs
+++ b/bin/module-index/src/main.rs
@@ -25,15 +25,24 @@ async fn async_main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("module-index")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["module_index", "module_index_server"])
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("module-index")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["module_index", "module_index_server"]);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
diff --git a/bin/pinga/src/args.rs b/bin/pinga/src/args.rs
index 0533368e74..7b10c348ce 100644
--- a/bin/pinga/src/args.rs
+++ b/bin/pinga/src/args.rs
@@ -21,6 +21,28 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
+
/// PostgreSQL connection pool dbname [example: myapp]
#[arg(long)]
pub(crate) pg_dbname: Option,
@@ -61,10 +83,6 @@ pub(crate) struct Args {
#[arg(long)]
pub(crate) nats_creds_path: Option,
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
-
/// Cyclone encryption key file location [default: /run/pinga/cyclone_encryption.key]
#[arg(long)]
pub(crate) cyclone_encryption_key_path: Option,
diff --git a/bin/pinga/src/main.rs b/bin/pinga/src/main.rs
index 8940411aee..967a36c752 100644
--- a/bin/pinga/src/main.rs
+++ b/bin/pinga/src/main.rs
@@ -25,15 +25,24 @@ async fn async_main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("pinga")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["pinga", "pinga_server"])
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("pinga")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["pinga", "pinga_server"]);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
diff --git a/bin/sdf/src/args.rs b/bin/sdf/src/args.rs
index c4361afbe1..db4b1874de 100644
--- a/bin/sdf/src/args.rs
+++ b/bin/sdf/src/args.rs
@@ -23,6 +23,28 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
+
/// PostgreSQL connection pool dbname [example: myapp]
#[arg(long)]
pub(crate) pg_dbname: Option,
@@ -67,10 +89,6 @@ pub(crate) struct Args {
#[arg(long, value_parser = PossibleValuesParser::new(MigrationMode::variants()))]
pub(crate) migration_mode: Option,
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
-
/// Cyclone encryption key file location [default: /run/sdf/cyclone_encryption.key]
#[arg(long)]
pub(crate) cyclone_encryption_key_path: Option,
diff --git a/bin/sdf/src/main.rs b/bin/sdf/src/main.rs
index 92e2153be6..7e81d46f3c 100644
--- a/bin/sdf/src/main.rs
+++ b/bin/sdf/src/main.rs
@@ -36,15 +36,24 @@ async fn async_main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("sdf")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["sdf", "sdf_server"])
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("sdf")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["sdf", "sdf_server"]);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
diff --git a/bin/veritech/src/args.rs b/bin/veritech/src/args.rs
index dac8162240..36d0c2415e 100644
--- a/bin/veritech/src/args.rs
+++ b/bin/veritech/src/args.rs
@@ -17,6 +17,28 @@ pub(crate) struct Args {
#[arg(short = 'v', long = "verbose", action = ArgAction::Count)]
pub(crate) verbose: u8,
+ /// Disables ANSI coloring in log output, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_NO_COLOR",
+ hide_env_values = true,
+ conflicts_with = "force_color"
+ )]
+ pub(crate) no_color: Option,
+
+ /// Forces ANSI coloring, even if standard output refers to a terminal/TTY.
+ ///
+ /// For more details, visit: .
+ #[arg(
+ long,
+ env = "SI_FORCE_COLOR",
+ hide_env_values = true,
+ conflicts_with = "no_color"
+ )]
+ pub(crate) force_color: Option,
+
/// NATS connection URL [example: 0.0.0.0:4222]
#[arg(long, short = 'u')]
pub(crate) nats_url: Option,
@@ -29,10 +51,6 @@ pub(crate) struct Args {
#[arg(long)]
pub(crate) nats_creds_path: Option,
- /// Disable OpenTelemetry on startup
- #[arg(long)]
- pub(crate) disable_opentelemetry: bool,
-
/// Cyclone runtime type: LocalProcess
#[arg(long)]
pub(crate) cyclone_local_process: bool,
diff --git a/bin/veritech/src/main.rs b/bin/veritech/src/main.rs
index e356733feb..afd7ebb99f 100644
--- a/bin/veritech/src/main.rs
+++ b/bin/veritech/src/main.rs
@@ -11,15 +11,24 @@ async fn main() -> Result<()> {
let task_tracker = TaskTracker::new();
color_eyre::install()?;
- let config = TelemetryConfig::builder()
- .service_name("veritech")
- .service_namespace("si")
- .log_env_var_prefix("SI")
- .app_modules(vec!["veritech", "veritech_server"])
- .build()?;
- let (mut telemetry, telemetry_shutdown) =
- telemetry_application::init(config, &task_tracker, shutdown_token.clone())?;
let args = args::parse();
+ let (mut telemetry, telemetry_shutdown) = {
+ let mut builder = TelemetryConfig::builder();
+ builder
+ .service_name("veritech")
+ .service_namespace("si")
+ .log_env_var_prefix("SI")
+ .app_modules(vec!["veritech", "veritech_server"]);
+ if let Some(force_color) = args.force_color {
+ builder.force_color(force_color);
+ }
+ if let Some(no_color) = args.no_color {
+ builder.no_color(no_color);
+ }
+ let config = builder.build()?;
+
+ telemetry_application::init(config, &task_tracker, shutdown_token.clone())?
+ };
if args.verbose > 0 {
telemetry.set_verbosity(args.verbose.into()).await?;
diff --git a/dev/Tiltfile b/dev/Tiltfile
index f6c489b0fd..880fee850a 100644
--- a/dev/Tiltfile
+++ b/dev/Tiltfile
@@ -83,6 +83,7 @@ local_resource(
labels = ["backend"],
cmd = "buck2 build {}".format(module_index_target),
serve_cmd = "buck2 run {}".format(module_index_target),
+ serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
auto_init = False,
resource_deps = [
@@ -100,6 +101,7 @@ local_resource(
labels = ["backend"],
cmd = "buck2 build {}".format(council_target),
serve_cmd = "buck2 run {}".format(council_target),
+ serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
resource_deps = [
"nats",
@@ -116,6 +118,7 @@ local_resource(
labels = ["backend"],
cmd = "buck2 build {}".format(pinga_target),
serve_cmd = "buck2 run {}".format(pinga_target),
+ serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
resource_deps = [
"council",
@@ -134,6 +137,7 @@ local_resource(
labels = ["backend"],
cmd = "buck2 build {}".format(veritech_target),
serve_cmd = "SI_LOG=debug buck2 run {}".format(veritech_target),
+ serve_env = {"SI_FORCE_COLOR": "true"},
# This is the serve command you might need if you want to execute on firecracker for 10 functione executions.
# NB: BUCK2 MUST RUN AS ROOT OR THIS WILL NOT WORK
# serve_cmd = "SI_LOG=debug buck2 run {} -- --cyclone-local-firecracker --cyclone-pool-size 10".format(veritech_target),
@@ -153,6 +157,7 @@ local_resource(
labels = ["backend"],
cmd = "buck2 build {}".format(sdf_target),
serve_cmd = "buck2 run {}".format(sdf_target),
+ serve_env = {"SI_FORCE_COLOR": "true"},
allow_parallel = True,
resource_deps = [
"nats",
diff --git a/lib/telemetry-application-rs/src/lib.rs b/lib/telemetry-application-rs/src/lib.rs
index 3e9fdb0dfa..07da44e04d 100644
--- a/lib/telemetry-application-rs/src/lib.rs
+++ b/lib/telemetry-application-rs/src/lib.rs
@@ -10,7 +10,8 @@
use std::{
borrow::Cow,
- env, io,
+ env,
+ io::{self, IsTerminal},
ops::Deref,
thread,
time::{Duration, Instant},
@@ -121,6 +122,12 @@ pub struct TelemetryConfig {
)]
secondary_log_span_events_env_var: Option,
+ #[builder(setter(into, strip_option), default = "self.default_no_color()")]
+ no_color: bool,
+
+ #[builder(setter(into, strip_option), default = "false")]
+ force_color: bool,
+
#[builder(default = "true")]
signal_handlers: bool,
}
@@ -194,6 +201,17 @@ impl TelemetryConfigBuilder {
Some(None) | None => None,
}
}
+
+ fn default_no_color(&self) -> bool {
+ // Checks a known/standard var as a fallback. Code upstack will check for an `SI_*`
+ // prefixed version which should have a higher precendence.
+ //
+ // See:
+ #[allow(clippy::disallowed_methods)] // See rationale in comment above
+ std::env::var_os("NO_COLOR")
+ .map(|value| !value.is_empty())
+ .unwrap_or(false)
+ }
}
pub fn init(
@@ -292,6 +310,7 @@ fn tracing_subscriber(
let (console_log_layer, console_log_filter_reload) = {
let layer = tracing_subscriber::fmt::layer()
.with_thread_ids(true)
+ .with_ansi(should_add_ansi(config))
.with_span_events(span_events_fmt);
let env_filter = EnvFilter::try_new(directives.as_str())?;
@@ -387,6 +406,18 @@ fn create_client(
Ok((client, guard))
}
+fn should_add_ansi(config: &TelemetryConfig) -> bool {
+ if config.force_color {
+ // If we're forcing colors, then this is unconditionally true
+ true
+ } else {
+ // Otherwise 2 conditions must be met:
+ // 1. did we *not* ask for `no_color` (or: is `no_color` unset)
+ // 2. is the standard output file descriptor refer to a terminal or TTY
+ !config.no_color && io::stdout().is_terminal()
+ }
+}
+
#[must_use]
pub struct TelemetryShutdownGuard {
update_telemetry_tx: mpsc::UnboundedSender,