diff --git a/demo-01-cmcp-in-action/run.py b/demo-01-cmcp-in-action/run.py index fb79276..85cebb7 100644 --- a/demo-01-cmcp-in-action/run.py +++ b/demo-01-cmcp-in-action/run.py @@ -36,6 +36,25 @@ def _find_cmcp() -> str: sys.exit("cmcp not found. Run: pip install cmcp-runtime") + +def _log_tail(what: str, lines: int = 15) -> str: + """Return the tail of the log for `what`, or "" if there is nothing to show. + + A service that fails to bind has already written the reason to its log. The + launcher used to point at the file and leave; printing the tail turns a 60 + second wait plus a scavenger hunt into the actual error. + """ + name = "cmcp.log" if "cMCP" in what or "cmcp" in what else "server.log" + path = pathlib.Path(__file__).parent.resolve() / name + try: + tail = path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:] + except OSError: + return "" + if not tail: + return "" + body = "\n".join(" " + line for line in tail) + return f"\n\nLast {len(tail)} lines of {name}:\n{body}" + def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> None: """Block until something is listening on 127.0.0.1:port. @@ -46,15 +65,15 @@ def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> deadline = time.monotonic() + timeout while time.monotonic() < deadline: if process is not None and process.poll() is not None: - sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}." + + _log_tail(what)) try: with socket.create_connection(("127.0.0.1", port), timeout=1): return except OSError: time.sleep(0.25) - sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s." + + _log_tail(what)) def _assert_port_free(port: int, what: str) -> None: diff --git a/demo-02-policy-swap/run.py b/demo-02-policy-swap/run.py index c4b807a..f2322db 100644 --- a/demo-02-policy-swap/run.py +++ b/demo-02-policy-swap/run.py @@ -42,6 +42,25 @@ def _find_cmcp() -> str: sys.exit("cmcp not found. Run: pip install cmcp-runtime") + +def _log_tail(what: str, lines: int = 15) -> str: + """Return the tail of the log for `what`, or "" if there is nothing to show. + + A service that fails to bind has already written the reason to its log. The + launcher used to point at the file and leave; printing the tail turns a 60 + second wait plus a scavenger hunt into the actual error. + """ + name = "cmcp.log" if "cMCP" in what or "cmcp" in what else "server.log" + path = pathlib.Path(__file__).parent.resolve() / name + try: + tail = path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:] + except OSError: + return "" + if not tail: + return "" + body = "\n".join(" " + line for line in tail) + return f"\n\nLast {len(tail)} lines of {name}:\n{body}" + def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> None: """Block until something is listening on 127.0.0.1:port. @@ -52,15 +71,15 @@ def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> deadline = time.monotonic() + timeout while time.monotonic() < deadline: if process is not None and process.poll() is not None: - sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}." + + _log_tail(what)) try: with socket.create_connection(("127.0.0.1", port), timeout=1): return except OSError: time.sleep(0.25) - sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s." + + _log_tail(what)) def _post(url: str, payload: dict, token: str) -> dict: diff --git a/demo-04-context-enforcement/run.py b/demo-04-context-enforcement/run.py index 949d462..e361830 100644 --- a/demo-04-context-enforcement/run.py +++ b/demo-04-context-enforcement/run.py @@ -36,6 +36,25 @@ def _find_cmcp() -> str: sys.exit("cmcp not found. Run: pip install cmcp-runtime") + +def _log_tail(what: str, lines: int = 15) -> str: + """Return the tail of the log for `what`, or "" if there is nothing to show. + + A service that fails to bind has already written the reason to its log. The + launcher used to point at the file and leave; printing the tail turns a 60 + second wait plus a scavenger hunt into the actual error. + """ + name = "cmcp.log" if "cMCP" in what or "cmcp" in what else "server.log" + path = pathlib.Path(__file__).parent.resolve() / name + try: + tail = path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:] + except OSError: + return "" + if not tail: + return "" + body = "\n".join(" " + line for line in tail) + return f"\n\nLast {len(tail)} lines of {name}:\n{body}" + def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> None: """Block until something is listening on 127.0.0.1:port. @@ -46,15 +65,15 @@ def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> deadline = time.monotonic() + timeout while time.monotonic() < deadline: if process is not None and process.poll() is not None: - sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}." + + _log_tail(what)) try: with socket.create_connection(("127.0.0.1", port), timeout=1): return except OSError: time.sleep(0.25) - sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s." + + _log_tail(what)) def _assert_port_free(port: int, what: str) -> None: diff --git a/demo-05-compliance-domain/run.py b/demo-05-compliance-domain/run.py index 03021c3..5b6fb5a 100644 --- a/demo-05-compliance-domain/run.py +++ b/demo-05-compliance-domain/run.py @@ -36,6 +36,25 @@ def _find_cmcp() -> str: sys.exit("cmcp not found. Run: pip install cmcp-runtime") + +def _log_tail(what: str, lines: int = 15) -> str: + """Return the tail of the log for `what`, or "" if there is nothing to show. + + A service that fails to bind has already written the reason to its log. The + launcher used to point at the file and leave; printing the tail turns a 60 + second wait plus a scavenger hunt into the actual error. + """ + name = "cmcp.log" if "cMCP" in what or "cmcp" in what else "server.log" + path = pathlib.Path(__file__).parent.resolve() / name + try: + tail = path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:] + except OSError: + return "" + if not tail: + return "" + body = "\n".join(" " + line for line in tail) + return f"\n\nLast {len(tail)} lines of {name}:\n{body}" + def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> None: """Block until something is listening on 127.0.0.1:port. @@ -46,15 +65,15 @@ def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> deadline = time.monotonic() + timeout while time.monotonic() < deadline: if process is not None and process.poll() is not None: - sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}." + + _log_tail(what)) try: with socket.create_connection(("127.0.0.1", port), timeout=1): return except OSError: time.sleep(0.25) - sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s. " - "See the *.log files in this demo folder.") + sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s." + + _log_tail(what)) def _assert_port_free(port: int, what: str) -> None: diff --git a/web-console/run.py b/web-console/run.py index d62bc97..5e4095b 100644 --- a/web-console/run.py +++ b/web-console/run.py @@ -47,6 +47,25 @@ def _find_cmcp() -> str: sys.exit("cmcp not found. Run: pip install cmcp-runtime httpx") +def _log_tail(what: str, lines: int = 15) -> str: + """Return the tail of the log for `what`, or "" if there is nothing to show. + + A service that fails to bind has already written the reason to its log. The + launcher used to point at the file and leave; printing the tail turns a 60 + second wait plus a scavenger hunt into the actual error. + """ + name = "cmcp.log" if "cMCP" in what or "cmcp" in what else "server.log" + path = pathlib.Path(__file__).parent.resolve() / name + try: + tail = path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:] + except OSError: + return "" + if not tail: + return "" + body = "\n".join(" " + line for line in tail) + return f"\n\nLast {len(tail)} lines of {name}:\n{body}" + + def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> None: """Block until something is listening on 127.0.0.1:port. @@ -57,15 +76,15 @@ def _wait_for_port(port: int, what: str, process=None, timeout: float = 60.0) -> deadline = time.monotonic() + timeout while time.monotonic() < deadline: if process is not None and process.poll() is not None: - sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}. " - "See server.log and cmcp.log in this folder.") + sys.exit(f"{what} exited with code {process.returncode} before listening on :{port}." + + _log_tail(what)) try: with socket.create_connection(("127.0.0.1", port), timeout=1): return except OSError: time.sleep(0.25) - sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s. " - "See server.log and cmcp.log in this folder.") + sys.exit(f"{what} did not start listening on :{port} within {timeout:.0f}s." + + _log_tail(what)) def _ensure_submodule() -> None: