use logging

This commit is contained in:
ars
2026-06-15 03:29:42 +03:00
parent 25ca35c097
commit a321d64169
7 changed files with 91 additions and 11 deletions
+2
View File
@@ -1,6 +1,8 @@
import sys
from nexus_sync.client.runtime import main
from nexus_sync.utils import configure_logging
if __name__ == "__main__":
configure_logging()
raise SystemExit(main(sys.argv[1:]))
+7 -5
View File
@@ -1,8 +1,8 @@
import json
import logging
import os
import platform
import socket
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass
@@ -27,6 +27,7 @@ CLIENT_ID_ENV = "NEXUS_SYNC_CLIENT_ID"
CLIENT_TOKEN_ENV = "NEXUS_SYNC_CLIENT_TOKEN"
CLIENT_VERSION = "0.1.0"
HEARTBEAT_PATH = "/api/v1/client/heartbeat"
logger = logging.getLogger(__name__)
class ClientConfigError(ValueError):
@@ -142,19 +143,20 @@ def main(argv: list[str] | None = None) -> int:
config = load_client_config()
result = run_once(config)
except (ClientConfigError, HeartbeatError, ValueError) as error:
print(f"nexus-sync client error: {error}", file=sys.stderr)
logger.error("nexus-sync client error: %s", error)
return 1
if result is None:
print("heartbeat accepted; no command")
logger.info("heartbeat accepted; no command")
return 0
print(
logger.info(
"command result: %s",
json.dumps(
result.model_dump(mode="json"),
ensure_ascii=False,
separators=(",", ":"),
)
),
)
return 0
+2
View File
@@ -1,9 +1,11 @@
import uvicorn
from nexus_sync.server.app import app
from nexus_sync.utils import configure_logging
def main() -> None:
configure_logging()
uvicorn.run(app, host="0.0.0.0", port=8000)
+5
View File
@@ -0,0 +1,5 @@
from nexus_sync.utils.log_config import configure_logging
__all__ = [
"configure_logging",
]
+19
View File
@@ -0,0 +1,19 @@
import logging
import os
LOG_LEVEL_ENV = "NEXUS_SYNC_LOG_LEVEL"
DEFAULT_LOG_LEVEL = "INFO"
DEFAULT_LOG_FORMAT = "%(levelname)s %(name)s %(message)s"
def configure_logging(level: str | None = None) -> None:
raw_level = level or os.environ.get(LOG_LEVEL_ENV, DEFAULT_LOG_LEVEL)
log_level = getattr(logging, raw_level.upper(), None)
if not isinstance(log_level, int):
raise ValueError(f"invalid log level: {raw_level}")
logging.basicConfig(
level=log_level,
format=DEFAULT_LOG_FORMAT,
)
logging.getLogger().setLevel(log_level)
+28 -6
View File
@@ -294,19 +294,19 @@ def test_run_once_sends_previous_command_result() -> None:
assert seen["last_command_result"] == previous_result
def test_main_returns_non_zero_for_missing_config(monkeypatch, capsys) -> None:
def test_main_returns_non_zero_for_missing_config(monkeypatch, caplog) -> None:
monkeypatch.delenv(SERVER_URL_ENV, raising=False)
monkeypatch.delenv(CLIENT_ID_ENV, raising=False)
monkeypatch.delenv(CLIENT_TOKEN_ENV, raising=False)
exit_code = main([])
captured = capsys.readouterr()
assert exit_code == 1
assert SERVER_URL_ENV in captured.err
assert SERVER_URL_ENV in caplog.text
def test_main_prints_success_without_command(monkeypatch, capsys) -> None:
def test_main_logs_success_without_command(monkeypatch, caplog) -> None:
caplog.set_level("INFO")
monkeypatch.setenv(SERVER_URL_ENV, "https://nexus.example.test")
monkeypatch.setenv(CLIENT_ID_ENV, "macbook-pro-01")
monkeypatch.setenv(CLIENT_TOKEN_ENV, "client-token")
@@ -314,9 +314,31 @@ def test_main_prints_success_without_command(monkeypatch, capsys) -> None:
exit_code = main([])
captured = capsys.readouterr()
assert exit_code == 0
assert captured.out == "heartbeat accepted; no command\n"
assert "heartbeat accepted; no command" in caplog.text
def test_main_logs_command_result(monkeypatch, caplog) -> None:
caplog.set_level("INFO")
monkeypatch.setenv(SERVER_URL_ENV, "https://nexus.example.test")
monkeypatch.setenv(CLIENT_ID_ENV, "macbook-pro-01")
monkeypatch.setenv(CLIENT_TOKEN_ENV, "client-token")
monkeypatch.setattr(
"nexus_sync.client.runtime.run_once",
lambda _config: CommandResult(
command_id="cmd_01JY3H8V8W8P3FXDR3S2BM7M6B",
status=CommandResultStatus.SUCCEEDED,
return_code=0,
stdout="host\n",
stderr="",
),
)
exit_code = main([])
assert exit_code == 0
assert "command result:" in caplog.text
assert '"command_id":"cmd_01JY3H8V8W8P3FXDR3S2BM7M6B"' in caplog.text
class _Response:
+28
View File
@@ -0,0 +1,28 @@
import logging
import pytest
from nexus_sync.utils.log_config import LOG_LEVEL_ENV, configure_logging
def test_configure_logging_uses_default_info_level(monkeypatch) -> None:
monkeypatch.delenv(LOG_LEVEL_ENV, raising=False)
configure_logging()
assert logging.getLogger().getEffectiveLevel() == logging.INFO
def test_configure_logging_reads_level_from_env(monkeypatch) -> None:
monkeypatch.setenv(LOG_LEVEL_ENV, "debug")
configure_logging()
assert logging.getLogger().getEffectiveLevel() == logging.DEBUG
def test_configure_logging_rejects_invalid_level(monkeypatch) -> None:
monkeypatch.setenv(LOG_LEVEL_ENV, "verbose")
with pytest.raises(ValueError, match="invalid log level"):
configure_logging()