Enhance logging and timing in CLI and session operations

- Updated the `_print_checks` function to replace console prints with logging functions for better traceability.
- Introduced timing functionality in the `doctor`, `dry_run`, and `up` functions to log the duration of preflight checks.
- Modified the `wait_ssh` function to accept a logging callback, improving SSH wait feedback.
- Enhanced the `mark` method in `PhaseTimes` to log phase durations, aiding in performance analysis.
- Updated various remote scripts to ensure error messages are printed to stderr for better error handling.
This commit is contained in:
Leonid Pershin
2026-08-21 08:03:04 +03:00
parent 7756d0d4df
commit ccba40a228
16 changed files with 205 additions and 46 deletions
+16 -2
View File
@@ -171,7 +171,12 @@ def probe_ssh(cfg: Config, host: str, attempts: int = 3) -> str:
return "auth" if auth_seen else "down"
def wait_ssh(cfg: Config, host: str, timeout: float = 900.0) -> None:
def wait_ssh(
cfg: Config,
host: str,
timeout: float = 900.0,
log: Callable[[str], None] | None = None,
) -> None:
"""Wait until sshd accepts our key. Paramiko banner noise is muted.
AuthenticationException is normal while cloud-init injects keys: keep
@@ -183,6 +188,8 @@ def wait_ssh(cfg: Config, host: str, timeout: float = 900.0) -> None:
logging.getLogger("paramiko").setLevel(logging.CRITICAL)
logging.getLogger("paramiko.transport").setLevel(logging.CRITICAL)
emit = log if log is not None else print
# sshd may answer before authorized_keys is ready (boot-from-volume / user_data).
auth_give_up = 180.0
@@ -223,7 +230,7 @@ def wait_ssh(cfg: Config, host: str, timeout: float = 900.0) -> None:
except Exception:
pass
if attempt == 1 or attempt % 6 == 0:
print(f"жду SSH {cfg.ssh_user}@{host}… ({name})", flush=True)
emit(f"жду SSH {cfg.ssh_user}@{host}… ({name})")
if (
is_auth
and auth_streak_started is not None
@@ -323,6 +330,10 @@ def run_script_sudo(
_stream_pty_output(stdout, log=log, chunks=chunks)
code = stdout.channel.recv_exit_status()
err = stderr.read().decode("utf-8", errors="replace") if not stdout.channel.closed else ""
# PTY usually merges stderr; if anything remains, don't drop it past timed log.
if log and err.strip():
for line in err.strip().splitlines():
log(line)
out = "".join(chunks)
if code != 0:
raise CloudError(f"remote script exit {code}: {err or out[-2000:]}")
@@ -354,6 +365,9 @@ def run_python(
_stream_pty_output(stdout, log=log, chunks=chunks)
code = stdout.channel.recv_exit_status()
err = stderr.read().decode("utf-8", errors="replace") if not stdout.channel.closed else ""
if log and err.strip():
for line in err.strip().splitlines():
log(line)
out = "".join(chunks)
if code != 0:
raise CloudError(f"remote python exit {code}: {err or out[-2000:]}")