Publish release-5edbadb22804 filtered source
Private source: 5edbadb2280419cf2cb42b5237835304ad7040e0 Public tree identity: sha256:e0d4d5e1c8693959e69448684a71582edfc13e9b18d7f1e733034fea5ce62cda
This commit is contained in:
parent
b93aef4f25
commit
a9f6f8b7a9
12 changed files with 430 additions and 166 deletions
|
|
@ -9,6 +9,26 @@ struct LiveLogChunk {
|
|||
truncated: bool,
|
||||
}
|
||||
|
||||
fn append_bounded_tail(tail: &mut Vec<u8>, bytes: &[u8], maximum: usize) {
|
||||
if maximum == 0 {
|
||||
tail.clear();
|
||||
return;
|
||||
}
|
||||
if bytes.len() >= maximum {
|
||||
tail.clear();
|
||||
tail.extend_from_slice(&bytes[bytes.len() - maximum..]);
|
||||
return;
|
||||
}
|
||||
let overflow = tail
|
||||
.len()
|
||||
.saturating_add(bytes.len())
|
||||
.saturating_sub(maximum);
|
||||
if overflow > 0 {
|
||||
tail.drain(..overflow);
|
||||
}
|
||||
tail.extend_from_slice(bytes);
|
||||
}
|
||||
|
||||
fn redact_safe_live_log_prefix(
|
||||
pending: &[u8],
|
||||
configured_secrets: &[String],
|
||||
|
|
@ -279,9 +299,9 @@ impl CoordinatorControlledProcessRunner {
|
|||
let mut captured = Vec::new();
|
||||
let mut buffer = [0_u8; 16 * 1024];
|
||||
let stream_base = source_bytes_total.load(Ordering::Relaxed);
|
||||
let mut source_bytes_read = 0_u64;
|
||||
let mut pending_offset = stream_base;
|
||||
let mut pending = Vec::new();
|
||||
let mut discarded = false;
|
||||
loop {
|
||||
let count = reader
|
||||
.read(&mut buffer)
|
||||
|
|
@ -294,27 +314,21 @@ impl CoordinatorControlledProcessRunner {
|
|||
Ordering::Relaxed,
|
||||
|current| Some(current.saturating_add(count as u64)),
|
||||
);
|
||||
let remaining = maximum.saturating_sub(captured.len());
|
||||
let retained = count.min(remaining);
|
||||
if retained > 0 {
|
||||
captured.extend_from_slice(&buffer[..retained]);
|
||||
pending.extend_from_slice(&buffer[..retained]);
|
||||
if let Some((consumed, text)) =
|
||||
redact_safe_live_log_prefix(&pending, &configured_secrets, false)
|
||||
{
|
||||
let _ = sender.try_send(LiveLogChunk {
|
||||
stream,
|
||||
offset: pending_offset,
|
||||
source_bytes: consumed as u64,
|
||||
bytes: text.into_bytes(),
|
||||
truncated: false,
|
||||
});
|
||||
pending.drain(..consumed);
|
||||
pending_offset = pending_offset.saturating_add(consumed as u64);
|
||||
}
|
||||
}
|
||||
if retained < count {
|
||||
discarded = true;
|
||||
source_bytes_read = source_bytes_read.saturating_add(count as u64);
|
||||
append_bounded_tail(&mut captured, &buffer[..count], maximum);
|
||||
pending.extend_from_slice(&buffer[..count]);
|
||||
if let Some((consumed, text)) =
|
||||
redact_safe_live_log_prefix(&pending, &configured_secrets, false)
|
||||
{
|
||||
let _ = sender.try_send(LiveLogChunk {
|
||||
stream,
|
||||
offset: pending_offset,
|
||||
source_bytes: consumed as u64,
|
||||
bytes: text.into_bytes(),
|
||||
truncated: false,
|
||||
});
|
||||
pending.drain(..consumed);
|
||||
pending_offset = pending_offset.saturating_add(consumed as u64);
|
||||
}
|
||||
}
|
||||
if let Some((consumed, text)) =
|
||||
|
|
@ -328,10 +342,10 @@ impl CoordinatorControlledProcessRunner {
|
|||
truncated: false,
|
||||
});
|
||||
}
|
||||
if discarded {
|
||||
if source_bytes_read > maximum as u64 {
|
||||
let _ = sender.try_send(LiveLogChunk {
|
||||
stream,
|
||||
offset: stream_base.saturating_add(maximum as u64),
|
||||
offset: stream_base.saturating_add(source_bytes_read),
|
||||
source_bytes: 0,
|
||||
bytes: b"[log output truncated at node capture limit]".to_vec(),
|
||||
truncated: true,
|
||||
|
|
@ -616,11 +630,11 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn bounded_capture_retains_the_complete_source_byte_count() {
|
||||
fn bounded_capture_retains_the_real_tail_and_complete_source_byte_count() {
|
||||
let source_bytes = Arc::new(AtomicU64::new(5));
|
||||
let (sender, receiver) = mpsc::sync_channel(8);
|
||||
let reader = CoordinatorControlledProcessRunner::drain_bounded(
|
||||
Cursor::new(vec![b'x'; 32]),
|
||||
Cursor::new(b"0123456789abcdefghijklmnopqrstuv".to_vec()),
|
||||
8,
|
||||
"stdout",
|
||||
sender,
|
||||
|
|
@ -630,14 +644,14 @@ mod tests {
|
|||
let captured = reader.join().unwrap().unwrap();
|
||||
let chunks = receiver.into_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(captured, vec![b'x'; 8]);
|
||||
assert_eq!(captured, b"opqrstuv");
|
||||
assert_eq!(source_bytes.load(Ordering::Relaxed), 37);
|
||||
assert_eq!(
|
||||
chunks.iter().map(|chunk| chunk.source_bytes).sum::<u64>(),
|
||||
8
|
||||
32
|
||||
);
|
||||
assert_eq!(chunks[0].offset, 5);
|
||||
assert_eq!(chunks.last().unwrap().offset, 13);
|
||||
assert_eq!(chunks.last().unwrap().offset, 37);
|
||||
assert!(chunks.iter().any(|chunk| chunk.truncated));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clusterflux_core::{
|
||||
CommandInvocation, Digest, LogBuffer, NativeCommandPolicy, NodeId, TaskInstanceId, VfsObject,
|
||||
VfsOverlay, VfsPath,
|
||||
CommandInvocation, Digest, NativeCommandPolicy, NodeId, TaskInstanceId, VfsObject, VfsOverlay,
|
||||
VfsPath,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -113,24 +113,20 @@ impl LocalCommandExecutor {
|
|||
}
|
||||
|
||||
pub(super) fn capture_command_logs(
|
||||
task: &TaskInstanceId,
|
||||
_task: &TaskInstanceId,
|
||||
stdout: &[u8],
|
||||
stderr: &[u8],
|
||||
max_log_bytes: usize,
|
||||
) -> CapturedCommandLogs {
|
||||
let mut logs = LogBuffer::new(max_log_bytes);
|
||||
logs.push(task.clone(), stdout);
|
||||
logs.push(task.clone(), stderr);
|
||||
let records = logs.records();
|
||||
let stdout_record = &records[0];
|
||||
let stderr_record = &records[1];
|
||||
debug_assert_eq!(&stdout_record.task, task);
|
||||
debug_assert_eq!(&stderr_record.task, task);
|
||||
let stdout_truncated = stdout.len() > max_log_bytes;
|
||||
let stderr_truncated = stderr.len() > max_log_bytes;
|
||||
let stdout_start = stdout.len().saturating_sub(max_log_bytes);
|
||||
let stderr_start = stderr.len().saturating_sub(max_log_bytes);
|
||||
CapturedCommandLogs {
|
||||
stdout: String::from_utf8_lossy(&stdout_record.bytes).into_owned(),
|
||||
stderr: String::from_utf8_lossy(&stderr_record.bytes).into_owned(),
|
||||
stdout_truncated: stdout_record.truncated,
|
||||
stderr_truncated: stderr_record.truncated,
|
||||
backpressured: logs.backpressured(),
|
||||
stdout: String::from_utf8_lossy(&stdout[stdout_start..]).into_owned(),
|
||||
stderr: String::from_utf8_lossy(&stderr[stderr_start..]).into_owned(),
|
||||
stdout_truncated,
|
||||
stderr_truncated,
|
||||
backpressured: stdout_truncated || stderr_truncated,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn linux_backend_caps_logs_without_truncating_staged_artifact_bytes() {
|
||||
fn linux_backend_retains_final_log_tail_without_truncating_staged_artifact_bytes() {
|
||||
let invocation = CommandInvocation {
|
||||
program: "cargo".to_owned(),
|
||||
args: vec!["build".to_owned()],
|
||||
|
|
@ -774,7 +774,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(output.virtual_thread, TaskInstanceId::from("compile-linux"));
|
||||
assert_eq!(output.stdout, "abcd");
|
||||
assert_eq!(output.stdout, "cdef");
|
||||
assert!(output.stdout_truncated);
|
||||
assert!(output.log_backpressured);
|
||||
assert_eq!(output.staged_artifact.as_ref().unwrap().size, 6);
|
||||
|
|
@ -992,7 +992,7 @@ mod tests {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn local_command_executor_caps_logs_and_reports_backpressure_by_virtual_thread() {
|
||||
fn local_command_executor_retains_each_stream_tail_and_reports_backpressure() {
|
||||
let executor = LocalCommandExecutor {
|
||||
node: clusterflux_core::NodeId::from("node"),
|
||||
hosted_control_plane: false,
|
||||
|
|
@ -1021,10 +1021,10 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(output.virtual_thread, TaskInstanceId::from("compile-linux"));
|
||||
assert_eq!(output.stdout, "abcd");
|
||||
assert_eq!(output.stderr, "");
|
||||
assert_eq!(output.stdout, "cdef");
|
||||
assert_eq!(output.stderr, "err");
|
||||
assert!(output.stdout_truncated);
|
||||
assert!(output.stderr_truncated);
|
||||
assert!(!output.stderr_truncated);
|
||||
assert!(output.log_backpressured);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue