Skip to content

Commit de49662

Browse files
committed
Add a minimal tracing-subscriber configuration
While debugging why running azure-init in a local VM hung forever, I added some minimal log configuration to figure out what was happening. Note that this only logs to stderr and is only configurable via the `AZURE_INIT_LOG` environment variable. The most minimal usage is like this: AZURE_INIT_LOG=info azure-init Which emits anything at info level or high. Refer to the tracing-subscriber documentation[0] for more complex examples. Logs look like this: ``` 2024-07-16T14:41:16.924909Z INFO provision: azure_init: new 2024-07-16T14:41:16.928668Z INFO provision:get_environment: azure_init: new ... 2024-07-16T14:41:17.065528Z INFO provision:get_environment: azure_init: close time.busy=133ms time.idle=4.21ms 2024-07-16T14:41:17.073142Z INFO provision:get_username: azure_init: new 2024-07-16T14:41:17.076323Z INFO provision:get_username: azure_init: close time.busy=23.3µs time.idle=3.16ms 2024-07-16T14:41:17.081070Z INFO provision: azure_init: close time.busy=153ms time.idle=3.12ms ``` It's configured to emit logs when a span opens and closes in addition to any explicit `tracing::{debug,info,warn,error}!` call, although we can disable that if folks don't like it. I also added spans to most of the library functions. All the spans are at the default `INFO` level and the default log configuration is to write logs for warning or higher, so running this without specifying `AZURE_INIT_LOG` results in the same behavior as before. This doesn't try to integrate with OpenTelemetry or pipe logs to KVP; those are being wired up in Azure#83. [0] https://docs.rs/tracing-subscriber/0.3.18/tracing_subscriber/filter/struct.EnvFilter.html#directives
1 parent dee43fa commit de49662

File tree

3 files changed

+30
-0
lines changed

3 files changed

+30
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ description = "A reference implementation for provisioning Linux VMs on Azure."
1212
exitcode = "1.1.2"
1313
anyhow = "1.0.81"
1414
tokio = { version = "1", features = ["full"] }
15+
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
16+
tracing = "0.1.40"
1517

1618
[dependencies.libazureinit]
1719
path = "libazureinit"

libazureinit/src/media.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde::Deserialize;
1313
use serde_xml_rs::from_str;
1414

1515
use tracing;
16+
use tracing::instrument;
1617

1718
use crate::error::Error;
1819

@@ -76,6 +77,7 @@ pub const PATH_MOUNT_POINT: &str = "/run/azure-init/media/";
7677
const CDROM_VALID_FS: &[&str] = &["iso9660", "udf"];
7778

7879
// Get a mounted device with any filesystem for CDROM
80+
#[instrument]
7981
pub fn get_mount_device() -> Result<Vec<String>, Error> {
8082
let mut list_devices: Vec<String> = Vec::new();
8183

@@ -90,9 +92,12 @@ pub fn get_mount_device() -> Result<Vec<String>, Error> {
9092
}
9193

9294
// Some zero-sized structs that just provide states for our state machine
95+
#[derive(Debug)]
9396
pub struct Mounted;
97+
#[derive(Debug)]
9498
pub struct Unmounted;
9599

100+
#[derive(Debug)]
96101
pub struct Media<State = Unmounted> {
97102
device_path: PathBuf,
98103
mount_path: PathBuf,
@@ -108,6 +113,7 @@ impl Media<Unmounted> {
108113
}
109114
}
110115

116+
#[instrument]
111117
pub fn mount(self) -> Result<Media<Mounted>, Error> {
112118
create_dir_all(&self.mount_path)?;
113119

@@ -140,6 +146,7 @@ impl Media<Unmounted> {
140146
}
141147

142148
impl Media<Mounted> {
149+
#[instrument]
143150
pub fn unmount(self) -> Result<(), Error> {
144151
let umount_status =
145152
Command::new("umount").arg(self.mount_path).status()?;
@@ -162,6 +169,7 @@ impl Media<Mounted> {
162169
}
163170
}
164171

172+
#[instrument]
165173
pub fn read_ovf_env_to_string(&self) -> Result<String, Error> {
166174
let mut file_path = self.mount_path.clone();
167175
file_path.push("ovf-env.xml");
@@ -174,6 +182,7 @@ impl Media<Mounted> {
174182
}
175183
}
176184

185+
#[instrument(skip_all)]
177186
pub fn parse_ovf_env(ovf_body: &str) -> Result<Environment, Error> {
178187
let environment: Environment = from_str(ovf_body)?;
179188

@@ -190,6 +199,7 @@ pub fn parse_ovf_env(ovf_body: &str) -> Result<Environment, Error> {
190199
}
191200

192201
// Mount the given device, get OVF environment data, return it.
202+
#[instrument(skip_all)]
193203
pub fn mount_parse_ovf_env(dev: String) -> Result<Environment, Error> {
194204
let mount_media =
195205
Media::new(PathBuf::from(dev), PathBuf::from(PATH_MOUNT_POINT));

src/main.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ use libazureinit::{
1414
reqwest::{header, Client},
1515
HostnameProvisioner, PasswordProvisioner, Provision, UserProvisioner,
1616
};
17+
use tracing::instrument;
18+
use tracing_subscriber::fmt::format::FmtSpan;
19+
use tracing_subscriber::layer::SubscriberExt;
20+
use tracing_subscriber::EnvFilter;
1721

1822
const VERSION: &str = env!("CARGO_PKG_VERSION");
1923

24+
#[instrument]
2025
fn get_environment() -> Result<Environment, anyhow::Error> {
2126
let ovf_devices = media::get_mount_device()?;
2227
let mut environment: Option<Environment> = None;
@@ -33,6 +38,7 @@ fn get_environment() -> Result<Environment, anyhow::Error> {
3338
.ok_or_else(|| anyhow::anyhow!("Unable to get list of block devices"))
3439
}
3540

41+
#[instrument(skip_all)]
3642
fn get_username(
3743
instance_metadata: Option<&InstanceMetadata>,
3844
environment: Option<&Environment>,
@@ -60,6 +66,17 @@ fn get_username(
6066

6167
#[tokio::main]
6268
async fn main() -> ExitCode {
69+
let stderr = tracing_subscriber::fmt::layer()
70+
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
71+
.with_writer(std::io::stderr);
72+
let registry = tracing_subscriber::registry()
73+
.with(stderr)
74+
.with(EnvFilter::from_env("AZURE_INIT_LOG"));
75+
tracing::subscriber::set_global_default(registry).expect(
76+
"Only an application should set the global default; \
77+
a library is mis-using the tracing API.",
78+
);
79+
6380
match provision().await {
6481
Ok(_) => ExitCode::SUCCESS,
6582
Err(e) => {
@@ -78,6 +95,7 @@ async fn main() -> ExitCode {
7895
}
7996
}
8097

98+
#[instrument]
8199
async fn provision() -> Result<(), anyhow::Error> {
82100
let mut default_headers = header::HeaderMap::new();
83101
let user_agent = header::HeaderValue::from_str(

0 commit comments

Comments
 (0)