Skip to content

Commit 0536a3b

Browse files
committed
Refactor emit_kvp_kayer and otel_layer with improved per-layer filtering, adjust key_buf logic to avoid indexing, refine tracing and function calls, and streamline start/end time declarations as per PR feedback.
1 parent e14d8ac commit 0536a3b

File tree

7 files changed

+88
-72
lines changed

7 files changed

+88
-72
lines changed

libazureinit/src/config.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ impl Config {
292292
Figment::from(Serialized::defaults(Config::default()));
293293

294294
if base_path.exists() {
295-
tracing::debug!(path=?base_path, "Loading base configuration file");
295+
tracing::info!(path=?base_path, "Loading base configuration file");
296296
figment = figment.merge(Toml::file(base_path));
297297
} else {
298298
tracing::warn!(
@@ -307,7 +307,7 @@ impl Config {
307307
if cli_path.is_dir() {
308308
figment = Self::merge_toml_directory(figment, cli_path)?;
309309
} else {
310-
tracing::debug!(
310+
tracing::info!(
311311
"Merging configuration file from CLI: {:?}",
312312
cli_path
313313
);
@@ -318,7 +318,10 @@ impl Config {
318318
figment
319319
.extract::<Config>()
320320
.map(|config| {
321-
tracing::info!("Configuration successfully loaded.");
321+
tracing::info!(
322+
target: "kvp",
323+
"Configuration successfully loaded."
324+
);
322325
config
323326
})
324327
.map_err(|e| {
@@ -355,12 +358,12 @@ impl Config {
355358
entries.sort();
356359

357360
for path_entry in entries {
358-
tracing::debug!("Merging configuration file: {:?}", path_entry);
361+
tracing::info!("Merging configuration file: {:?}", path_entry);
359362
figment = figment.merge(Toml::file(path_entry));
360363
}
361364
Ok(figment)
362365
} else {
363-
tracing::debug!("Directory {:?} not found, skipping.", dir_path);
366+
tracing::info!("Directory {:?} not found, skipping.", dir_path);
364367
Ok(figment.clone())
365368
}
366369
}

libazureinit/src/http.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ async fn request(
111111
let now = std::time::Instant::now();
112112
let mut attempt = 0_u32;
113113
loop {
114-
let span = tracing::debug_span!("request", attempt, http_status = tracing::field::Empty);
114+
let span = tracing::info_span!("request", attempt, http_status = tracing::field::Empty);
115115
let req = request.try_clone().expect("The request body MUST be clone-able");
116116
match client
117117
.execute(req)
@@ -121,12 +121,12 @@ async fn request(
121121
let _enter = span.enter();
122122
let statuscode = response.status();
123123
span.record("http_status", statuscode.as_u16());
124-
tracing::info!(url=response.url().as_str(), "HTTP response received");
124+
tracing::info!(target: "kvp", url=response.url().as_str(), "HTTP response received");
125125

126126
match response.error_for_status() {
127127
Ok(response) => {
128128
if statuscode == StatusCode::OK {
129-
tracing::info!("HTTP response succeeded with status {}", statuscode);
129+
tracing::info!(target: "kvp", "HTTP response succeeded with status {}", statuscode);
130130
return Ok((response, retry_for.saturating_sub(now.elapsed() + retry_interval)));
131131
}
132132
},

libazureinit/src/provision/ssh.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ pub(crate) fn provision_ssh(
8686

8787
chown(&ssh_dir, Some(user.uid), Some(user.gid))?;
8888

89-
tracing::info!("Using authorized_keys path: {:?}", authorized_keys_path);
89+
tracing::info!(
90+
target: "kvp",
91+
"Using authorized_keys path: {:?}",
92+
authorized_keys_path
93+
);
9094

9195
let mut authorized_keys = File::create(&authorized_keys_path)?;
9296
authorized_keys.set_permissions(Permissions::from_mode(0o600))?;
@@ -139,6 +143,7 @@ fn run_sshd_command(
139143
match sshd_config_command_runner() {
140144
Ok(output) if output.status.success() => {
141145
info!(
146+
target: "kvp",
142147
stdout_length = output.stdout.len(),
143148
"Executed sshd -G successfully",
144149
);
@@ -184,6 +189,7 @@ fn extract_authorized_keys_file_path(stdout: &[u8]) -> Option<String> {
184189
if line.starts_with("authorizedkeysfile") {
185190
let keypath = line.split_whitespace().nth(1).map(|s| {
186191
info!(
192+
target: "kvp",
187193
authorizedkeysfile = %s,
188194
"Using sshd's authorizedkeysfile path configuration"
189195
);

libazureinit/src/provision/user.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,15 @@ fn user_exists(username: &str) -> Result<bool, Error> {
135135
fn useradd(user: &User) -> Result<(), Error> {
136136
if user_exists(&user.name)? {
137137
tracing::info!(
138+
target: "kvp",
138139
"User '{}' already exists. Skipping user creation.",
139140
user.name
140141
);
141142

142143
let group_list = user.groups.join(",");
143144

144145
tracing::info!(
146+
target: "kvp",
145147
"User '{}' is being added to the following groups: {}",
146148
user.name,
147149
group_list

src/kvp.rs

Lines changed: 58 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use std::{
1414
fmt::{self as std_fmt, Write as std_write},
1515
fs::{File, OpenOptions},
16-
io::{self, Error, ErrorKind, Write},
16+
io::{self, ErrorKind, Write},
1717
os::unix::fs::MetadataExt,
1818
path::Path,
1919
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
@@ -81,10 +81,10 @@ impl Visit for StringVisitor<'_> {
8181
/// * `value` - The debug value associated with the field.
8282
fn record_debug(
8383
&mut self,
84-
_field: &tracing::field::Field,
84+
field: &tracing::field::Field,
8585
value: &dyn std_fmt::Debug,
8686
) {
87-
write!(self.string, "{}={:?}; ", _field.name(), value)
87+
write!(self.string, "{}={:?}; ", field.name(), value)
8888
.expect("Writing to a string should never fail");
8989
}
9090
}
@@ -134,7 +134,7 @@ impl EmitKVPLayer {
134134
/// # Arguments
135135
/// * `file_path` - The file path where the KVP data will be stored.
136136
///
137-
pub fn new(file_path: std::path::PathBuf) -> Result<Self, std::io::Error> {
137+
pub fn new(file_path: std::path::PathBuf) -> Result<Self, anyhow::Error> {
138138
truncate_guest_pool_file(&file_path)?;
139139

140140
let file = OpenOptions::new()
@@ -309,21 +309,11 @@ where
309309
let start_time =
310310
end_time.checked_sub(elapsed).unwrap_or(UNIX_EPOCH);
311311

312-
let start_time_dt = DateTime::<Utc>::from(
313-
UNIX_EPOCH
314-
+ start_time
315-
.duration_since(UNIX_EPOCH)
316-
.unwrap_or_default(),
317-
)
318-
.format("%Y-%m-%dT%H:%M:%S%.3fZ");
312+
let start_time_dt = DateTime::<Utc>::from(start_time)
313+
.format("%Y-%m-%dT%H:%M:%S%.3fZ");
319314

320-
let end_time_dt = DateTime::<Utc>::from(
321-
UNIX_EPOCH
322-
+ end_time
323-
.duration_since(UNIX_EPOCH)
324-
.unwrap_or_default(),
325-
)
326-
.format("%Y-%m-%dT%H:%M:%S%.3fZ");
315+
let end_time_dt = DateTime::<Utc>::from(end_time)
316+
.format("%Y-%m-%dT%H:%M:%S%.3fZ");
327317

328318
let event_value = format!(
329319
"Start: {} | End: {} | Status: {}",
@@ -362,41 +352,51 @@ fn generate_event_key(
362352
/// exceeds the allowed size, it is split into multiple slices for encoding.
363353
/// This is used for logging events to a KVP file.
364354
///
355+
/// # Note
356+
/// - The key must be zero-padded to `HV_KVP_EXCHANGE_MAX_KEY_SIZE` to meet Hyper-V's expected formatting.
357+
///
365358
/// # Arguments
366359
/// * `key` - The key as a string slice.
367360
/// * `value` - The value associated with the key.
368361
fn encode_kvp_item(key: &str, value: &str) -> Vec<Vec<u8>> {
369-
let key_bytes = key.as_bytes();
370-
let value_bytes = value.as_bytes();
371-
372-
let key_len = key_bytes.len().min(HV_KVP_EXCHANGE_MAX_KEY_SIZE);
373-
let mut key_buf = vec![0u8; HV_KVP_EXCHANGE_MAX_KEY_SIZE];
374-
key_buf[..key_len].copy_from_slice(&key_bytes[..key_len]);
375-
376-
let mut kvp_slices = Vec::new();
362+
let key_buf = key
363+
.as_bytes()
364+
.iter()
365+
.take(HV_KVP_EXCHANGE_MAX_KEY_SIZE)
366+
.chain(
367+
vec![0_u8; HV_KVP_EXCHANGE_MAX_KEY_SIZE.saturating_sub(key.len())]
368+
.iter(),
369+
)
370+
.copied()
371+
.collect::<Vec<_>>();
372+
373+
debug_assert!(key_buf.len() == HV_KVP_EXCHANGE_MAX_KEY_SIZE);
374+
375+
let kvp_slices = value
376+
.as_bytes()
377+
.chunks(HV_KVP_AZURE_MAX_VALUE_SIZE)
378+
.map(|chunk| {
379+
let mut buffer = Vec::with_capacity(
380+
HV_KVP_EXCHANGE_MAX_KEY_SIZE + HV_KVP_EXCHANGE_MAX_VALUE_SIZE,
381+
);
382+
buffer.extend_from_slice(&key_buf);
383+
buffer.extend_from_slice(chunk);
384+
while buffer.len()
385+
< HV_KVP_EXCHANGE_MAX_KEY_SIZE + HV_KVP_EXCHANGE_MAX_VALUE_SIZE
386+
{
387+
buffer.push(0);
388+
}
377389

378-
for chunk in value_bytes.chunks(HV_KVP_AZURE_MAX_VALUE_SIZE) {
379-
let mut value_buf = vec![0u8; HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
380-
value_buf[..chunk.len()].copy_from_slice(chunk);
390+
buffer
391+
})
392+
.collect::<Vec<Vec<u8>>>();
381393

382-
kvp_slices.push(encode_kvp_slice(key_buf.clone(), value_buf));
383-
}
394+
debug_assert!(kvp_slices.iter().all(|kvp| kvp.len()
395+
== HV_KVP_EXCHANGE_MAX_KEY_SIZE + HV_KVP_EXCHANGE_MAX_VALUE_SIZE));
384396

385397
kvp_slices
386398
}
387399

388-
/// Combines the key and value of a KVP into a single byte slice, ensuring
389-
/// proper formatting for consumption by hv_kvp_daemon service,
390-
/// which typically reads from /var/lib/hyperv/.kvp_pool_1.
391-
fn encode_kvp_slice(key: Vec<u8>, value: Vec<u8>) -> Vec<u8> {
392-
let mut buffer = Vec::with_capacity(
393-
HV_KVP_EXCHANGE_MAX_KEY_SIZE + HV_KVP_EXCHANGE_MAX_VALUE_SIZE,
394-
);
395-
buffer.extend_from_slice(&key);
396-
buffer.extend_from_slice(&value);
397-
buffer
398-
}
399-
400400
/// Decodes a KVP byte slice into its corresponding key and value strings.
401401
/// This is useful for inspecting or logging raw KVP data.
402402
#[cfg(test)]
@@ -412,18 +412,23 @@ pub fn decode_kvp_item(
412412
}
413413

414414
let key = String::from_utf8(
415-
record_data[0..HV_KVP_EXCHANGE_MAX_KEY_SIZE].to_vec(),
415+
record_data
416+
.iter()
417+
.take(HV_KVP_EXCHANGE_MAX_KEY_SIZE)
418+
.cloned()
419+
.collect::<Vec<_>>(),
416420
)
417421
.unwrap_or_else(|_| String::new())
418422
.trim_end_matches('\x00')
419423
.to_string();
420424

421425
let value = String::from_utf8(
422-
record_data[HV_KVP_EXCHANGE_MAX_KEY_SIZE..]
426+
record_data
423427
.iter()
428+
.skip(HV_KVP_EXCHANGE_MAX_KEY_SIZE)
424429
.take(HV_KVP_AZURE_MAX_VALUE_SIZE)
425430
.cloned()
426-
.collect(),
431+
.collect::<Vec<_>>(),
427432
)
428433
.unwrap_or_else(|_| String::new())
429434
.trim_end_matches('\x00')
@@ -435,12 +440,9 @@ pub fn decode_kvp_item(
435440
/// Truncates the guest pool KVP file if it contains stale data (i.e., data
436441
/// older than the system's boot time). Logs whether the file was truncated
437442
/// or no action was needed.
438-
fn truncate_guest_pool_file(kvp_file: &Path) -> Result<(), Error> {
439-
let boot_time = SystemTime::now()
440-
.duration_since(UNIX_EPOCH)
441-
.map_err(|e| Error::new(std::io::ErrorKind::Other, e))?
442-
.as_secs()
443-
- get_uptime()?.as_secs();
443+
fn truncate_guest_pool_file(kvp_file: &Path) -> Result<(), anyhow::Error> {
444+
let boot_time = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs()
445+
- get_uptime().as_secs();
444446

445447
match kvp_file.metadata() {
446448
Ok(metadata) => {
@@ -461,7 +463,8 @@ fn truncate_guest_pool_file(kvp_file: &Path) -> Result<(), Error> {
461463
return Ok(());
462464
}
463465
Err(e) => {
464-
return Err(e);
466+
return Err(anyhow::Error::from(e)
467+
.context("Failed to access file metadata"));
465468
}
466469
}
467470

@@ -471,12 +474,12 @@ fn truncate_guest_pool_file(kvp_file: &Path) -> Result<(), Error> {
471474
/// Retrieves the system's uptime using the `sysinfo` crate, returning the duration
472475
/// since the system booted. This can be useful for time-based calculations or checks,
473476
/// such as determining whether data is stale or calculating the approximate boot time.
474-
fn get_uptime() -> Result<Duration, Error> {
477+
fn get_uptime() -> Duration {
475478
let mut system = System::new();
476479
system.refresh_system();
477480

478481
let uptime_seconds = system.uptime();
479-
Ok(Duration::from_secs(uptime_seconds))
482+
Duration::from_secs(uptime_seconds)
480483
}
481484

482485
#[cfg(test)]

src/logging.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use opentelemetry_sdk::trace::{
77
};
88
use tracing::{event, Level};
99
use tracing_opentelemetry::OpenTelemetryLayer;
10+
use tracing_subscriber::filter::LevelFilter;
1011
use tracing_subscriber::fmt::format::FmtSpan;
1112
use tracing_subscriber::{
1213
fmt, layer::SubscriberExt, EnvFilter, Layer, Registry,
@@ -26,15 +27,17 @@ pub fn initialize_tracing() -> sdktrace::Tracer {
2627
pub fn setup_layers(
2728
tracer: sdktrace::Tracer,
2829
) -> Result<(), Box<dyn std::error::Error>> {
29-
let otel_layer = OpenTelemetryLayer::new(tracer);
30+
let otel_layer = OpenTelemetryLayer::new(tracer)
31+
.with_filter(EnvFilter::from_env("AZURE_INIT_LOG"));
32+
33+
let kvp_filter = EnvFilter::builder()
34+
.with_default_directive(LevelFilter::INFO.into())
35+
.parse_lossy("azure_init=INFO,libazureinit=WARN,kvp=INFO");
3036

3137
let emit_kvp_layer = match EmitKVPLayer::new(std::path::PathBuf::from(
3238
"/var/lib/hyperv/.kvp_pool_1",
3339
)) {
34-
Ok(layer) => {
35-
let filter = EnvFilter::new("INFO");
36-
Some(layer.with_filter(filter))
37-
}
40+
Ok(layer) => Some(layer.with_filter(kvp_filter)),
3841
Err(e) => {
3942
event!(Level::ERROR, "Failed to initialize EmitKVPLayer: {}. Continuing without KVP logging.", e);
4043
None

src/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ async fn main() -> ExitCode {
132132
}
133133
}
134134

135-
#[instrument(name = "root")]
135+
#[instrument(name = "root", skip_all)]
136136
async fn provision(config: Config, opts: Cli) -> Result<(), anyhow::Error> {
137137
let system = System::new();
138138
let kernel_version = system
@@ -141,13 +141,12 @@ async fn provision(config: Config, opts: Cli) -> Result<(), anyhow::Error> {
141141
let os_version = system
142142
.os_version()
143143
.unwrap_or("Unknown OS Version".to_string());
144-
let azure_init_version = env!("CARGO_PKG_VERSION");
145144

146145
tracing::info!(
147146
"Kernel Version: {}, OS Version: {}, Azure-Init Version: {}",
148147
kernel_version,
149148
os_version,
150-
azure_init_version
149+
VERSION
151150
);
152151

153152
let mut default_headers = header::HeaderMap::new();

0 commit comments

Comments
 (0)