From 1601d298a7e212be2e8a64ecea9e5820e2310d98 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:51:28 +0000 Subject: [PATCH 1/3] Initial plan From 12d43c452b20c9bc09ebcd370869adf3860fd243 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:59:28 +0000 Subject: [PATCH 2/3] Fix weaver live check RemoteDisconnected by reading report from stdout When weaver v0.22.1 exits quickly after processing OTLP data, the POST to /stop gets a RemoteDisconnected error because weaver has already shut down its HTTP server. Fix: remove --output=http so weaver writes the JSON report to stdout on exit (default behavior). Add --no-stream to produce the full report as one JSON document. Rewrite _do_stop to signal /stop (ignoring connection errors), wait for process exit, then read the report from stdout. Update _read_weaver_logs to only read stderr since stdout now contains the JSON report. Assisted-by: Claude Sonnet 4.6 Co-authored-by: emdneto <9735060+emdneto@users.noreply.github.com> --- .../opentelemetry/test/weaver_live_check.py | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py index 115fa1c282f..4142b8b7487 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py @@ -277,8 +277,8 @@ def __init__( f"--inactivity-timeout={inactivity_timeout}", f"--otlp-grpc-port={self._otlp_port}", f"--admin-port={self._admin_port}", - "--output=http", "--format=json", + "--no-stream", ] if policies_dir: @@ -366,29 +366,61 @@ def otlp_endpoint(self) -> str: return f"http://localhost:{self._otlp_port}" def _do_stop(self, timeout: int) -> tuple["LiveCheckReport", int]: - """POST /stop, wait for the process to exit, return (report, exit_code). + """Signal weaver to stop, wait for the process to exit, return (report, exit_code). - Raises for infrastructure errors (HTTP failure, process communication). + Sends POST /stop to trigger an orderly shutdown. If weaver has already + exited (race condition between inactivity timeout and our /stop call), + the connection error is silently ignored. The JSON report is always + read from stdout after the process exits — weaver writes the complete + report to stdout on shutdown when ``--format=json --no-stream`` is used. + + Raises for infrastructure errors (process communication). Never raises for semconv violations. """ if not self._ready: raise RuntimeError( "WeaverLiveCheck process did not start successfully" ) + assert self._process is not None try: - response = post( + post( f"http://localhost:{self._admin_port}/stop", timeout=5 ) - response.raise_for_status() - report = LiveCheckReport(response.json()) - assert self._process is not None + except Exception: # pylint: disable=broad-except + # Weaver may have already exited (e.g. inactivity timeout fired + # before we could call /stop). This is not an error — we will + # still read the report from stdout below. + pass + try: exit_code = self._process.wait(timeout=timeout) - except Exception as exc: # pylint: disable=broad-except + except subprocess.TimeoutExpired as exc: logs = self._read_weaver_logs() logger.error( - "Error communicating with weaver: %s, logs: %s", exc, logs + "Weaver process did not exit in time: %s, logs: %s", exc, logs ) raise + stdout_content = "" + if self._stdout_path and os.path.exists(self._stdout_path): + with open(self._stdout_path, "rb") as fp: + stdout_content = fp.read().decode(errors="replace").strip() + if stdout_content: + try: + report = LiveCheckReport(json.loads(stdout_content)) + except (json.JSONDecodeError, ValueError) as exc: + logs = self._read_weaver_logs() + logger.error( + "Failed to parse weaver JSON report: %s, logs: %s", + exc, + logs, + ) + raise RuntimeError( + f"Failed to parse weaver JSON report: {exc}" + ) from exc + else: + logger.warning( + "Weaver process produced no output; returning empty report" + ) + report = LiveCheckReport({}) return report, exit_code def end(self, timeout: int = 30) -> "LiveCheckReport": @@ -460,7 +492,8 @@ def _read(path: str | None) -> str: with open(path, "rb") as fp: return fp.read().decode(errors="replace") - return f"{_read(self._stdout_path)}\n{_read(self._stderr_path)}" + # stdout contains the JSON report; stderr contains human-readable logs + return _read(self._stderr_path) except Exception as exc: # pylint: disable=broad-except logger.error("Could not get weaver logs: %s", exc) return None From 988d6cd9ca917426eded134b35e0c01ff4bc7c44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:07:11 +0000 Subject: [PATCH 3/3] Apply ruff format fixes from precommit Co-authored-by: emdneto <9735060+emdneto@users.noreply.github.com> --- .../src/opentelemetry/test/weaver_live_check.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py index 4142b8b7487..2dca1c93d0c 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/weaver_live_check.py @@ -383,9 +383,7 @@ def _do_stop(self, timeout: int) -> tuple["LiveCheckReport", int]: ) assert self._process is not None try: - post( - f"http://localhost:{self._admin_port}/stop", timeout=5 - ) + post(f"http://localhost:{self._admin_port}/stop", timeout=5) except Exception: # pylint: disable=broad-except # Weaver may have already exited (e.g. inactivity timeout fired # before we could call /stop). This is not an error — we will