Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f8b9227
telemetry: compile-in Azure Monitor connection string, best-effort Ap…
bfjelds Sep 3, 2026
3303ba3
spec: wire AZURE_MONITOR_CONNECTION_STRING through trident.spec build…
bfjelds Sep 3, 2026
d8884ee
logging: fix unused must_use warning on tracing::subscriber::set_default
bfjelds Sep 3, 2026
5a57cfb
logging: apply cargo fmt
bfjelds Sep 3, 2026
b1f8bde
logging: fix appinsights content-type/status handling and test guard
bfjelds Sep 3, 2026
cb2af38
logging: send appinsights telemetry via background uploader
bfjelds Sep 4, 2026
6e799ed
logging: treat non-2xx responses as upload failures
bfjelds Sep 4, 2026
8e5ca69
docs: correct telemetry failure log level in Agent-Configuration.md
bfjelds Sep 4, 2026
b192024
docs: correct enqueue-failure scenario in Agent-Configuration.md
bfjelds Sep 4, 2026
f725799
appinsights: fix flaky functional test assuming one TCP read is the f…
bfjelds Sep 4, 2026
80a68d2
appinsights: support sovereign-cloud connection strings, isolate tele…
bfjelds Sep 4, 2026
aa7f64f
appinsights: fix sovereign-cloud endpoint without Location, clarify T…
bfjelds Sep 4, 2026
e2fefa6
appinsights: reject non-HTTPS ingestion endpoints
bfjelds Sep 4, 2026
cac07eb
management: merge DatastorePath into existing agent config missing it
bfjelds Sep 4, 2026
77bf60d
docs: disclose host metadata transmitted by opt-in telemetry
bfjelds Sep 4, 2026
96e0da4
spec: use optional macro expansion for trident_azmon_conn_str
bfjelds Sep 4, 2026
b1cb2ee
add trident repo appinsights connection; simplify comments
bfjelds Sep 4, 2026
cf56856
provide prod appinsights connection string
bfjelds Sep 4, 2026
dfee42f
telemetry: log status at startup, fix duplicated InstrumentationKey= …
bfjelds Sep 4, 2026
17ceb02
telemetry: add manual_rollback_start/runtime_update_success metrics, …
bfjelds Sep 4, 2026
c5c6620
docs: disclose correlation_id/operation_id/command in Agent-Configura…
bfjelds Sep 4, 2026
b975b0f
revert: move manual_rollback_start/runtime_update_success metrics to …
bfjelds Sep 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .pipelines/templates/stages/trident_rpms/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ steps:
version=$(echo $full_version | cut -d'-' -f1)
prerelease=$(echo $full_version | cut -d'-' -f2-)

# Application Insights connection string identifying best-effort
# telemetry as coming from Trident's own CI/CD pipeline builds
AZURE_MONITOR_CONNECTION_STRING="InstrumentationKey=e32fc20f-2cc6-4d86-9e12-ab5d24b366f7;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=fb8e8afb-99bd-4143-ae31-22f9070005e2"

# Build RPMs and export only the artifact tarball (no image load/unpack).
# CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN is populated by the CargoAuthenticate task.
outdir="/tmp/_rpm_artifacts"
Expand All @@ -80,6 +84,7 @@ steps:
--build-arg RPM_PACKAGES="$RPM_PACKAGES" \
--build-arg RUST_PACKAGE="$RUST_PACKAGE" \
--build-arg RPM_DEST="$RPM_DEST" \
--build-arg AZURE_MONITOR_CONNECTION_STRING="$AZURE_MONITOR_CONNECTION_STRING" \
--target artifact \
--output type=local,dest="$outdir" \
.
Expand Down
3 changes: 2 additions & 1 deletion crates/trident/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-env-changed=TRIDENT_VERSION");
println!("cargo:rerun-if-env-changed=AZURE_MONITOR_CONNECTION_STRING");
Ok(())
}
}
130 changes: 123 additions & 7 deletions crates/trident/src/agentconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,65 @@ use trident_api::{
error::TridentError,
};

/// Whether Trident should attempt to send tracing data to Application
/// Insights (best-effort, and only when a connection string was compiled
/// into the binary -- see [`crate::AZURE_MONITOR_CONNECTION_STRING`]).
///
/// Defaults to [`TelemetryPreference::OptOut`]: telemetry is disabled unless
/// a user has explicitly opted in via the Agent Configuration file.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TelemetryPreference {
/// Telemetry is disabled. Trident will not send any tracing data off
/// the host.
#[default]
OptOut,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want OptOut as default?

/// Telemetry is enabled, best-effort, provided a connection string was
/// compiled into this Trident binary.
OptIn,
}

pub struct AgentConfig {
datastore: PathBuf,
telemetry: TelemetryPreference,
}

impl AgentConfig {
/// Load the AgentConfig from the default configuration file.
pub fn load() -> Result<Self, TridentError> {
Self::load_from_path(AGENT_CONFIG_PATH)
}

/// Load the AgentConfig from an arbitrary path. Split out from [`load`]
/// so the parsing logic can be unit tested without touching
/// [`AGENT_CONFIG_PATH`].
fn load_from_path(path: &str) -> Result<Self, TridentError> {
let mut config = Self {
datastore: TRIDENT_DATASTORE_PATH_DEFAULT.into(),
telemetry: TelemetryPreference::default(),
};

if let Ok(contents) = std::fs::read_to_string(AGENT_CONFIG_PATH) {
if let Ok(contents) = std::fs::read_to_string(path) {
for line in contents.lines() {
if let Some(path) = line.strip_prefix("DatastorePath=") {
config.datastore = path.trim().into();
if let Some(value) = line.strip_prefix("DatastorePath=") {
config.datastore = value.trim().into();
} else if let Some(value) = line.strip_prefix("Telemetry=") {
config.telemetry = match value.trim().to_ascii_lowercase().as_str() {
Comment thread
bfjelds marked this conversation as resolved.
"optin" => TelemetryPreference::OptIn,
"optout" => TelemetryPreference::OptOut,
other => {
debug!(
"Unrecognized Telemetry setting '{other}' in agent \
configuration file, defaulting to OptOut"
);
TelemetryPreference::OptOut
}
};
}
}
} else {
// If the config file does not exist, we proceed with defaults.
// Only log this at debug level to avoid alarming users unnecessarily.
debug!(
"Agent configuration file not found at {}, using defaults",
AGENT_CONFIG_PATH
);
debug!("Agent configuration file not found at {path}, using defaults");
}

Ok(config)
Expand All @@ -40,4 +75,85 @@ impl AgentConfig {
pub fn datastore_path(&self) -> &Path {
&self.datastore
}

/// Whether telemetry (best-effort tracing to Application Insights) is
/// enabled per the agent configuration file. Defaults to `false`
/// (opt-out) when unset or unrecognized.
pub fn telemetry_enabled(&self) -> bool {
matches!(self.telemetry, TelemetryPreference::OptIn)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_defaults_when_file_missing() {
let config = AgentConfig::load_from_path("/nonexistent/path/for/trident-tests.conf")
.expect("load_from_path should not fail even if the file is missing");
assert_eq!(
config.datastore_path(),
Path::new(TRIDENT_DATASTORE_PATH_DEFAULT)
);
assert!(
!config.telemetry_enabled(),
"telemetry must default to OptOut"
);
}

#[test]
fn test_telemetry_optin() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("trident.conf");
std::fs::write(&path, "Telemetry=OptIn\n").unwrap();

let config = AgentConfig::load_from_path(path.to_str().unwrap()).unwrap();
assert!(config.telemetry_enabled());
}

#[test]
fn test_telemetry_optout_explicit() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("trident.conf");
std::fs::write(&path, "Telemetry=OptOut\n").unwrap();

let config = AgentConfig::load_from_path(path.to_str().unwrap()).unwrap();
assert!(!config.telemetry_enabled());
}

#[test]
fn test_telemetry_is_case_insensitive() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("trident.conf");
std::fs::write(&path, "Telemetry=OPTIN\n").unwrap();

let config = AgentConfig::load_from_path(path.to_str().unwrap()).unwrap();
assert!(config.telemetry_enabled());
}

#[test]
fn test_telemetry_unrecognized_value_defaults_optout() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("trident.conf");
std::fs::write(&path, "Telemetry=maybe\n").unwrap();

let config = AgentConfig::load_from_path(path.to_str().unwrap()).unwrap();
assert!(!config.telemetry_enabled());
}

#[test]
fn test_datastore_and_telemetry_together() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("trident.conf");
std::fs::write(
&path,
"DatastorePath=/custom/path.sqlite\nTelemetry=OptIn\n",
)
.unwrap();

let config = AgentConfig::load_from_path(path.to_str().unwrap()).unwrap();
assert!(config.telemetry_enabled());
assert_eq!(config.datastore_path(), Path::new("/custom/path.sqlite"));
}
}
18 changes: 16 additions & 2 deletions crates/trident/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ pub use crate::{
},
grpc_client::client_main,
logging::{
background_log::BackgroundLog, background_uploader::BackgroundUploader,
logfwd::LogForwarder, logstream::Logstream, tracestream::TraceStream,
appinsights::AppInsightsSender,
background_log::BackgroundLog,
background_uploader::{BackgroundUploadHandle, BackgroundUploader},
logfwd::LogForwarder,
logstream::Logstream,
operation_context::run_with_operation,
tracestream::TraceStream,
},
orchestrate::OrchestratorConnection,
reboot::request_reboot_with_wait,
Expand All @@ -82,6 +87,15 @@ lazy_static::lazy_static! {
.expect("Failed to parse TRIDENT_VERSION as semver::Version");
}

/// Azure Monitor / Application Insights connection string, compiled in at
/// build time via the `AZURE_MONITOR_CONNECTION_STRING` environment
/// variable. Empty when the variable was not provided at build time.
pub const AZURE_MONITOR_CONNECTION_STRING: &str =
match option_env!("AZURE_MONITOR_CONNECTION_STRING") {
Some(v) => v,
None => "",
};

/// Trident binary path.
const TRIDENT_BINARY_PATH: &str = "/usr/bin/trident";

Expand Down
Loading