Skip to content

Commit 0cf6af7

Browse files
authored
Add improved logging around command failures (#2351)
1 parent 4082867 commit 0cf6af7

3 files changed

Lines changed: 110 additions & 2 deletions

File tree

nativelink-worker/src/running_actions_manager.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,9 @@ impl RunningActionImpl {
987987
// level more effectively and adjust this.
988988
info!(?args, "Executing command");
989989

990-
let program = self.canonicalise_path(args[0], &command_proto.working_directory)?;
990+
let program = self
991+
.canonicalise_path(args[0], &command_proto.working_directory)
992+
.err_tip(|| format!("Canonicalisation failure. Command={args:#?}"))?;
991993

992994
let mut command_builder = process::Command::new(program);
993995
#[cfg(target_family = "unix")]
@@ -1534,6 +1536,7 @@ impl RunningActionImpl {
15341536
exit_code = ?execution_result.exit_code,
15351537
stdout = ?stdout[..min(stdout.len(), 1000)],
15361538
stderr = ?stderr[..min(stderr.len(), 1000)],
1539+
command = ?command_proto.arguments,
15371540
"Command returned non-zero exit code",
15381541
);
15391542
}

nativelink-worker/tests/running_actions_manager_test.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,6 +2489,9 @@ exit 1
24892489
result.error.err_tip(|| "Error should exist")?.code,
24902490
Code::DeadlineExceeded
24912491
);
2492+
assert!(logs_contain(
2493+
"Command returned non-zero exit code exit_code=1 stdout=\"\" stderr=\"\" command=[\"true\"]"
2494+
));
24922495
Ok(())
24932496
}
24942497

@@ -4603,4 +4606,106 @@ exit 1
46034606

46044607
Ok(())
46054608
}
4609+
4610+
#[nativelink_test]
4611+
async fn canonicalisation_failure() -> Result<(), Box<dyn core::error::Error>> {
4612+
const WORKER_ID: &str = "foo_worker_id";
4613+
4614+
fn test_monotonic_clock() -> SystemTime {
4615+
static CLOCK: AtomicU64 = AtomicU64::new(0);
4616+
monotonic_clock(&CLOCK)
4617+
}
4618+
4619+
let root_action_directory = make_temp_path("root_action_directory");
4620+
fs::create_dir_all(&root_action_directory).await?;
4621+
4622+
let (_, _, cas_store, ac_store) = setup_stores().await?;
4623+
4624+
let arguments = vec![
4625+
"garbage/to-canonicalise".to_string(),
4626+
"arguments".to_string(),
4627+
"to test".to_string(),
4628+
];
4629+
let command = Command {
4630+
arguments,
4631+
..Default::default()
4632+
};
4633+
let command_digest = serialize_and_upload_message(
4634+
&command,
4635+
cas_store.as_pin(),
4636+
&mut DigestHasherFunc::Sha256.hasher(),
4637+
)
4638+
.await?;
4639+
let input_root_digest = serialize_and_upload_message(
4640+
&Directory::default(),
4641+
cas_store.as_pin(),
4642+
&mut DigestHasherFunc::Sha256.hasher(),
4643+
)
4644+
.await?;
4645+
4646+
let action = Action {
4647+
command_digest: Some(command_digest.into()),
4648+
input_root_digest: Some(input_root_digest.into()),
4649+
..Default::default()
4650+
};
4651+
let action_digest = serialize_and_upload_message(
4652+
&action,
4653+
cas_store.as_pin(),
4654+
&mut DigestHasherFunc::Sha256.hasher(),
4655+
)
4656+
.await?;
4657+
4658+
let running_actions_manager = Arc::new(RunningActionsManagerImpl::new_with_callbacks(
4659+
RunningActionsManagerArgs {
4660+
root_action_directory: root_action_directory.clone(),
4661+
execution_configuration: ExecutionConfiguration::default(),
4662+
cas_store: cas_store.clone(),
4663+
ac_store: Some(Store::new(ac_store.clone())),
4664+
historical_store: Store::new(cas_store.clone()),
4665+
upload_action_result_config: &UploadActionResultConfig {
4666+
upload_ac_results_strategy: UploadCacheResultsStrategy::Never,
4667+
..Default::default()
4668+
},
4669+
max_action_timeout: Duration::MAX,
4670+
max_upload_timeout: Duration::MAX,
4671+
timeout_handled_externally: false,
4672+
directory_cache: None,
4673+
#[cfg(target_os = "linux")]
4674+
use_namespaces: use_namespaces(),
4675+
},
4676+
Callbacks {
4677+
now_fn: test_monotonic_clock,
4678+
sleep_fn: |_duration| Box::pin(future::pending()),
4679+
},
4680+
)?);
4681+
4682+
let execute_request = ExecuteRequest {
4683+
action_digest: Some(action_digest.into()),
4684+
..Default::default()
4685+
};
4686+
let operation_id = OperationId::default().to_string();
4687+
4688+
let res = running_actions_manager
4689+
.create_and_add_action(
4690+
WORKER_ID.to_string(),
4691+
StartExecute {
4692+
execute_request: Some(execute_request),
4693+
operation_id,
4694+
queued_timestamp: Some(make_system_time(1000).into()),
4695+
platform: action.platform.clone(),
4696+
worker_id: WORKER_ID.to_string(),
4697+
},
4698+
)
4699+
.and_then(|action| action.prepare_action().and_then(RunningAction::execute))
4700+
.await;
4701+
assert!(res.is_err(), "{res:#?}");
4702+
assert_eq!(res.unwrap_err(), Error::new_with_messages(Code::NotFound, vec![
4703+
if cfg!(target_family = "windows") { "The system cannot find the path specified. (os error 3)" } else { "No such file or directory (os error 2)" },
4704+
"Could not canonicalize path for command root garbage/to-canonicalise.",
4705+
"Canonicalisation failure. Command=[\n \"garbage/to-canonicalise\",\n \"arguments\",\n \"to test\",\n]"
4706+
].into_iter().map(String::from).collect()
4707+
4708+
));
4709+
Ok(())
4710+
}
46064711
}

web/platform/src/content/docs/docs/contribute/nix.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ and get tagged with nix derivation hashes.
4141
To build an image locally and make it available to your container runtime:
4242

4343
```sh
44-
nix run create-local-image
44+
create-local-image
4545
```
4646

4747
which will be called `local-nativelink:latest`

0 commit comments

Comments
 (0)