From f7f778225fbb4a58996b6fa8e8bef9cca25810f4 Mon Sep 17 00:00:00 2001 From: edenfunf Date: Sat, 14 Mar 2026 01:41:01 +0800 Subject: [PATCH] Honor ORT_LOGGING_LEVEL environment variable on Python import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Python binding's CreateOrtEnv() function hardcoded ORT_LOGGING_LEVEL_WARNING as the initial logging severity, which meant the ORT_LOGGING_LEVEL environment variable had no effect on the messages emitted during module import. This change reads ORT_LOGGING_LEVEL (integer 0–4) before creating the OrtEnv instance so that the chosen severity is respected from the very first log message. The same fix is applied to the training binding (orttraining_python_module.cc), which contained an identical hardcoded value. A companion get_default_logger_severity() Python API is added alongside the existing set_default_logger_severity() so callers can inspect the active level, and two new unit tests verify both the API and the env-var behaviour. Fixes #27092 --- onnxruntime/__init__.py | 1 + .../python/onnxruntime_pybind_module.cc | 17 ++++++++++++- .../python/onnxruntime_pybind_state.cc | 5 ++++ .../test/python/onnxruntime_test_python.py | 25 +++++++++++++++++++ .../python/orttraining_python_module.cc | 17 ++++++++++++- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/onnxruntime/__init__.py b/onnxruntime/__init__.py index 31bf8082fa9cc..55864a263ccbf 100644 --- a/onnxruntime/__init__.py +++ b/onnxruntime/__init__.py @@ -56,6 +56,7 @@ get_all_providers, # noqa: F401 get_available_providers, # noqa: F401 get_build_info, # noqa: F401 + get_default_logger_severity, # noqa: F401 get_device, # noqa: F401 get_ep_devices, # noqa: F401 get_version_string, # noqa: F401 diff --git a/onnxruntime/python/onnxruntime_pybind_module.cc b/onnxruntime/python/onnxruntime_pybind_module.cc index e1c883f960dde..a9d3f100d9739 100644 --- a/onnxruntime/python/onnxruntime_pybind_module.cc +++ b/onnxruntime/python/onnxruntime_pybind_module.cc @@ -3,6 +3,7 @@ #include "onnxruntime_pybind_exceptions.h" #include "onnxruntime_pybind_module_functions.h" +#include #include #include "core/providers/get_execution_providers.h" #include "onnxruntime_config.h" @@ -33,7 +34,21 @@ OrtEnv* GetOrtEnv() { } static Status CreateOrtEnv() { Env::Default().GetTelemetryProvider().SetLanguageProjection(OrtLanguageProjection::ORT_PROJECTION_PYTHON); - OrtEnv::LoggingManagerConstructionInfo lm_info{nullptr, nullptr, ORT_LOGGING_LEVEL_WARNING, "Default"}; + + // Allow the default logging severity to be configured via ORT_LOGGING_LEVEL before the first import. + // Valid integer values: 0 (Verbose), 1 (Info), 2 (Warning), 3 (Error), 4 (Fatal). + OrtLoggingLevel logging_level = ORT_LOGGING_LEVEL_WARNING; + const std::string logging_env = Env::Default().GetEnvironmentVar("ORT_LOGGING_LEVEL"); + if (!logging_env.empty()) { + char* end = nullptr; + long level = std::strtol(logging_env.c_str(), &end, 10); + if (end != logging_env.c_str() && *end == '\0' && + level >= ORT_LOGGING_LEVEL_VERBOSE && level <= ORT_LOGGING_LEVEL_FATAL) { + logging_level = static_cast(level); + } + } + + OrtEnv::LoggingManagerConstructionInfo lm_info{nullptr, nullptr, logging_level, "Default"}; Status status; ort_env = OrtEnv::GetOrCreateInstance(lm_info, status, use_global_tp ? &global_tp_options : nullptr).release(); if (!status.IsOK()) return status; diff --git a/onnxruntime/python/onnxruntime_pybind_state.cc b/onnxruntime/python/onnxruntime_pybind_state.cc index 1a925a16a6a71..c7704d8292e4c 100644 --- a/onnxruntime/python/onnxruntime_pybind_state.cc +++ b/onnxruntime/python/onnxruntime_pybind_state.cc @@ -1467,6 +1467,11 @@ void addGlobalMethods(py::module& m) { default_logging_manager->SetDefaultLoggerSeverity(static_cast(severity)); }, "Sets the default logging severity. 0:Verbose, 1:Info, 2:Warning, 3:Error, 4:Fatal"); + m.def( + "get_default_logger_severity", []() -> int { + return static_cast(logging::LoggingManager::DefaultLogger().GetSeverity()); + }, + "Gets the default logging severity. 0:Verbose, 1:Info, 2:Warning, 3:Error, 4:Fatal"); m.def( "set_default_logger_verbosity", [](int vlog_level) { logging::LoggingManager* default_logging_manager = GetEnv().GetLoggingManager(); diff --git a/onnxruntime/test/python/onnxruntime_test_python.py b/onnxruntime/test/python/onnxruntime_test_python.py index 90e67e114808f..11ea6e5f30d5c 100644 --- a/onnxruntime/test/python/onnxruntime_test_python.py +++ b/onnxruntime/test/python/onnxruntime_test_python.py @@ -9,6 +9,7 @@ import pathlib import platform import queue +import subprocess import sys import threading import unittest @@ -104,6 +105,30 @@ def test_get_build_info(self): self.assertIsNot(onnxrt.get_build_info(), None) self.assertIn("Build Info", onnxrt.get_build_info()) + def test_get_default_logger_severity(self): + # Default severity should be WARNING (2) when ORT_LOGGING_LEVEL is not set. + severity = onnxrt.get_default_logger_severity() + self.assertIsInstance(severity, int) + self.assertGreaterEqual(severity, 0) + self.assertLessEqual(severity, 4) + + def test_ort_logging_level_env_var(self): + # Verify that ORT_LOGGING_LEVEL is honored on import by running a subprocess. + for level in [0, 1, 2, 3, 4]: + result = subprocess.run( + [ + sys.executable, + "-c", + "import onnxruntime as ort; print(ort.get_default_logger_severity())", + ], + capture_output=True, + check=False, + text=True, + env={**os.environ, "ORT_LOGGING_LEVEL": str(level)}, + ) + self.assertEqual(result.returncode, 0, msg=result.stderr) + self.assertEqual(result.stdout.strip(), str(level), msg=f"Expected severity {level}, got {result.stdout.strip()}") + def test_model_serialization(self): try: so = onnxrt.SessionOptions() diff --git a/orttraining/orttraining/python/orttraining_python_module.cc b/orttraining/orttraining/python/orttraining_python_module.cc index 67e6e90726d38..9634728d33419 100644 --- a/orttraining/orttraining/python/orttraining_python_module.cc +++ b/orttraining/orttraining/python/orttraining_python_module.cc @@ -4,6 +4,7 @@ #include "orttraining/python/orttraining_pybind_common.h" #include "python/onnxruntime_pybind_mlvalue.h" +#include #include "core/common/logging/logging.h" #include "core/common/logging/severity.h" #include "core/common/path_string.h" @@ -171,7 +172,21 @@ onnxruntime::Environment& GetEnv() { static Status CreateOrtEnv() { Env::Default().GetTelemetryProvider().SetLanguageProjection(OrtLanguageProjection::ORT_PROJECTION_PYTHON); - OrtEnv::LoggingManagerConstructionInfo lm_info{nullptr, nullptr, ORT_LOGGING_LEVEL_WARNING, "Default"}; + + // Allow the default logging severity to be configured via ORT_LOGGING_LEVEL before the first import. + // Valid integer values: 0 (Verbose), 1 (Info), 2 (Warning), 3 (Error), 4 (Fatal). + OrtLoggingLevel logging_level = ORT_LOGGING_LEVEL_WARNING; + const std::string logging_env = Env::Default().GetEnvironmentVar("ORT_LOGGING_LEVEL"); + if (!logging_env.empty()) { + char* end = nullptr; + long level = std::strtol(logging_env.c_str(), &end, 10); + if (end != logging_env.c_str() && *end == '\0' && + level >= ORT_LOGGING_LEVEL_VERBOSE && level <= ORT_LOGGING_LEVEL_FATAL) { + logging_level = static_cast(level); + } + } + + OrtEnv::LoggingManagerConstructionInfo lm_info{nullptr, nullptr, logging_level, "Default"}; Status status; OrtEnvPtr ort_env = OrtEnv::GetOrCreateInstance(lm_info, status, use_global_tp ? &global_tp_options : nullptr); if (!status.IsOK()) return status;