Skip to content

Listen only to stdout for test-proxy errors #2897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ Similarly, if running on the command line pass `PROXY_MANUAL_START=true`.
To log tracing information to the terminal, you can add the `RUST_LOG` environment variable as shown above using the [same format supported by `env_logger`](https://docs.rs/env_logger/latest/env_logger/#enabling-logging).
The targets are the crate names if you want to trace more or less for specific targets e.g., `RUST_LOG=info,azure_core=trace` to trace information messages by default but detailed traces for the `azure_core` crate.

To log traces from the [Test Proxy] itself, pass `test-proxy=trace` to `RUST_LOG` e.g.,

```sh
RUST_LOG=info,azure_core=debug,test-proxy=trace cargo test -p azure_security_keyvault_secrets --test secret_client
```

#### Debugging in Windows

Using the recommended [CodeLLDB] Visual Studio Code extension on Windows will stop at breakpoints but may not pretty print variables e.g.,
Expand Down
3 changes: 3 additions & 0 deletions sdk/core/azure_core_test/src/proxy/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ pub async fn start(
.to_str()
.ok_or_else(|| ErrorKind::Other.into_error())?
.into(),
// Write exceptions to stdout; otherwise,
// reading from stderr on a separate thread hangs the process on Windows.
"--universal".into(),
]);
options.unwrap_or_default().copy_to(&mut args);
tracing::debug!(
Expand Down
38 changes: 15 additions & 23 deletions sdk/core/azure_core_test/src/proxy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use serde::Serializer;
use std::process::ExitStatus;
use std::{fmt, str::FromStr, sync::Arc};
#[cfg(not(target_arch = "wasm32"))]
use tokio::process::Child;
use tokio::{io::Lines, process::Child};

const ABSTRACTION_IDENTIFIER: HeaderName = HeaderName::from_static("x-abstraction-identifier");
const RECORDING_ID: HeaderName = HeaderName::from_static("x-recording-id");
Expand Down Expand Up @@ -76,36 +76,26 @@ impl Proxy {
)
})?;

let mut stdout = command
.stdout
.take()
.ok_or_else(|| azure_core::Error::message(ErrorKind::Io, "no stdout pipe"))?;
// Take stderr now but we won't listen until after start up, such that messages should buffer.
let mut stderr = command
.stderr
.take()
.ok_or_else(|| azure_core::Error::message(ErrorKind::Io, "no stderr pipe"))?;
let mut stdout = BufReader::new(
command
.stdout
.take()
.ok_or_else(|| azure_core::Error::message(ErrorKind::Io, "no stdout pipe"))?,
)
.lines();
self.command = Some(command);

// Wait until the service is listening on a port.
self.wait_till_listening(&mut stdout).await?;

// Then spawn a thread to keep pumping messages to stdout and stderr.
// Then spawn a thread to keep pumping messages to stdout.
// The pipe will be closed when the process is shut down, which will terminate the task.
tokio::spawn(async move {
let mut reader = BufReader::new(&mut stdout).lines();
while let Some(line) = reader.next_line().await.unwrap_or(None) {
while let Some(line) = stdout.next_line().await.unwrap_or(None) {
// Trace useful lines that test-proxy writes to stdout.
trace_line(Level::TRACE, &line);
}
});
tokio::spawn(async move {
let mut reader = BufReader::new(&mut stderr).lines();
while let Some(line) = reader.next_line().await.unwrap_or(None) {
// Trace useful lines that test-proxy writes to stdout.
trace_line(Level::ERROR, &line);
}
});

if let Some(endpoint) = &self.endpoint {
self.client = Some(Client::new(endpoint.clone())?);
Expand Down Expand Up @@ -153,10 +143,12 @@ impl Proxy {
Ok(ExitStatus::default())
}

async fn wait_till_listening(&mut self, stdout: &mut ChildStdout) -> Result<()> {
async fn wait_till_listening(
&mut self,
stdout: &mut Lines<BufReader<ChildStdout>>,
) -> Result<()> {
let pid = self.command.as_ref().and_then(Child::id);
let mut reader = BufReader::new(stdout).lines();
while let Some(line) = reader.next_line().await? {
while let Some(line) = stdout.next_line().await? {
const RUNNING_PATTERN: &str = "Running proxy version is Azure.Sdk.Tools.TestProxy ";
const LISTENING_PATTERN: &str = "Now listening on: ";

Expand Down