diff --git a/docs/source/usage/logging.md b/docs/source/usage/logging.md index 2352db19..dc803f98 100644 --- a/docs/source/usage/logging.md +++ b/docs/source/usage/logging.md @@ -13,7 +13,7 @@ logging.getLogger("torchrunx.node1").setLevel(logging.INFO) logging.getLogger("torchrunx.node1.1").setLevel(logging.INFO) # worker 1 (local rank) on node 1 ``` -Also, logs from all agents and workers are written to a directory (by the current timestamp) in `$TORCHRUNX_LOG_DIR` (default: `./torchrunx_logs`). These can be controlled using `$TORCHRUNX_LOG_LEVEL` (default: `INFO`). +Also, logs from all agents and workers are written to a directory (by the current timestamp) in `$TORCHRUNX_LOG_DIR` (default: `./torchrunx_logs`). These can be controlled using `$TORCHRUNX_LOG_LEVEL` (default: `INFO`). File logging can be disabled by setting `$TORCHRUNX_LOG_FILE` to `""`. ## Customization diff --git a/pyproject.toml b/pyproject.toml index 2ca735bc..7d54a760 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +requires = ["uv_build"] +build-backend = "uv_build" [project] name = "torchrunx" -version = "0.3.3" +version = "0.3.4" authors = [ { name = "Apoorv Khandelwal", email = "mail@apoorvkh.com" }, { name = "Peter Curtin", email = "peter_curtin@brown.edu" }, diff --git a/src/torchrunx/utils/log_handling.py b/src/torchrunx/utils/log_handling.py index 34e919f1..24dbf85c 100644 --- a/src/torchrunx/utils/log_handling.py +++ b/src/torchrunx/utils/log_handling.py @@ -79,30 +79,36 @@ def default_handlers(hostnames: list[str], workers_per_host: list[int]) -> list[ Logs for the rank 0 agent and rank 0 worker are redirected to loggers in the launcher process. Logs for all hosts/workers are written to files in ``$TORCHRUNX_LOG_DIR`` (named by timestamp, - hostname, local_rank). + hostname, local_rank). If ``$TORCHRUNX_LOG_DIR = ""`` logs will not be written to files. """ - log_dir = Path(os.environ.get("TORCHRUNX_LOG_DIR", "torchrunx_logs")) - - file_log_level = os.environ.get("TORCHRUNX_LOG_LEVEL", "INFO") - if file_log_level.isdigit(): - file_log_level = int(file_log_level) - elif file_log_level in logging._nameToLevel: # noqa: SLF001 - file_log_level = logging._nameToLevel[file_log_level] # noqa: SLF001 - else: - msg = ( - f"Invalid value for $TORCHRUNX_LOG_LEVEL: {file_log_level}. " - f"Should be a positive integer or any of: {', '.join(logging._nameToLevel.keys())}." # noqa: SLF001 - ) - raise ValueError(msg) - - redirect_agent_0_handler = RedirectHandler() - redirect_agent_0_handler.addFilter(get_handler_filter(hostnames[0], None)) + handlers = [] - redirect_worker_0_handler = RedirectHandler() - redirect_worker_0_handler.addFilter(get_handler_filter(hostnames[0], 0)) + # Agent 0 handler + handlers.append(RedirectHandler()) + handlers[-1].addFilter(get_handler_filter(hostnames[0], None)) + + # Worker 0 handler + handlers.append(RedirectHandler()) + handlers[-1].addFilter(get_handler_filter(hostnames[0], 0)) + + # Log to directory + + log_dir = os.environ.get("TORCHRUNX_LOG_DIR", "torchrunx_logs") + if log_dir != "": + file_log_level = os.environ.get("TORCHRUNX_LOG_LEVEL", "INFO") + if file_log_level.isdigit(): + file_log_level = int(file_log_level) + elif file_log_level in logging._nameToLevel: # noqa: SLF001 + file_log_level = logging._nameToLevel[file_log_level] # noqa: SLF001 + else: + msg = ( + f"Invalid value for $TORCHRUNX_LOG_LEVEL: {file_log_level}. " + f"Should be a positive integer or any of: {', '.join(logging._nameToLevel.keys())}." # noqa: SLF001 + ) + raise ValueError(msg) + + handlers += file_handlers( + hostnames, workers_per_host, log_dir=Path(log_dir), log_level=file_log_level + ) - return [ - redirect_agent_0_handler, - redirect_worker_0_handler, - *file_handlers(hostnames, workers_per_host, log_dir=log_dir, log_level=file_log_level), - ] + return handlers diff --git a/uv.lock b/uv.lock index d4035332..a014be72 100644 --- a/uv.lock +++ b/uv.lock @@ -1890,6 +1890,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/cd/85b422d24ee2096eaf6faa360c95ef9bdb59097d19b9624cebce4dd9bc2a/ruamel.yaml.clib-0.2.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:808c7190a0fe7ae7014c42f73897cf8e9ef14ff3aa533450e51b1e72ec5239ad", size = 725028, upload-time = "2025-09-22T19:51:19.782Z" }, { url = "https://files.pythonhosted.org/packages/4d/ac/99e6e0ea2584f84f447069d0187fe411e9b5deb7e3ddecda25001cfc7a95/ruamel.yaml.clib-0.2.14-cp39-cp39-win32.whl", hash = "sha256:6d5472f63a31b042aadf5ed28dd3ef0523da49ac17f0463e10fda9c4a2773352", size = 100915, upload-time = "2025-09-22T19:51:21.764Z" }, { url = "https://files.pythonhosted.org/packages/5d/8d/846e43369658958c99d959bb7774136fff9210f9017d91a4277818ceafbf/ruamel.yaml.clib-0.2.14-cp39-cp39-win_amd64.whl", hash = "sha256:8dd3c2cc49caa7a8d64b67146462aed6723a0495e44bf0aa0a2e94beaa8432f6", size = 118706, upload-time = "2025-09-22T19:51:20.878Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cd/150fdb96b8fab27fe08d8a59fe67554568727981806e6bc2677a16081ec7/ruamel_yaml_clib-0.2.14-cp314-cp314-win32.whl", hash = "sha256:9b4104bf43ca0cd4e6f738cb86326a3b2f6eef00f417bd1e7efb7bdffe74c539", size = 102394, upload-time = "2025-11-14T21:57:36.703Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e6/a3fa40084558c7e1dc9546385f22a93949c890a8b2e445b2ba43935f51da/ruamel_yaml_clib-0.2.14-cp314-cp314-win_amd64.whl", hash = "sha256:13997d7d354a9890ea1ec5937a219817464e5cc344805b37671562a401ca3008", size = 122673, upload-time = "2025-11-14T21:57:38.177Z" }, ] [[package]] @@ -2397,7 +2399,7 @@ wheels = [ [[package]] name = "torchrunx" -version = "0.3.3" +version = "0.3.4" source = { editable = "." } dependencies = [ { name = "cloudpickle" },