-
Notifications
You must be signed in to change notification settings - Fork 6.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[core] Ray Core / Ray Data logging configuration leads to unexpected behavior #48958
[core] Ray Core / Ray Data logging configuration leads to unexpected behavior #48958
Conversation
I don't know the expected behavior for the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG.
Need to change python/ray/_private/log.py
as well since there is old dictConfig
call there.
|
yea let's rewrite to avoid any surprises in the future. |
python/ray/_private/log.py
Outdated
import threading | ||
|
||
# TODO (kevin85421): It is not used, but a weird error occurs if it is removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's spend some time figuring out why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ray_logging/__init__.py
contains a function setup_component_logger
, which uses logging.handlers.RotatingFileHandler
. However, the file doesn't import logging.handlers
.
Instead, log.py
imports logging.config
, which implicitly imports logging.handlers
.
When the runtime environment agent calls setup_component_logger
, it fails, causing the Raylet to also terminate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solution: import logging.handlers
in ray_logging/__init__.py
directly.
python/ray/_private/log.py
Outdated
import threading | ||
|
||
# TODO (kevin85421): It is not used, but a weird error occurs if it is removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's spend some time figuring out why.
ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) | ||
|
||
new_test_logger = logging.getLogger("ray.test") | ||
assert old_test_logger.getEffectiveLevel() == logging.DEBUG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so with dictConfig, log level will also be cleared not just handlers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, see https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L193-L196 for more details.
Child logger's level will be set to NOTSET
.
Signed-off-by: kaihsun <kaihsun@anyscale.com>
…behavior (ray-project#48958) ### Issue In the Ray codebase, [logging.config.dictConfig](https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig) may be called multiple times. However, we found that if a logger’s child loggers are set before the logger is set via `dictConfig`, it may cause issues. * [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f) (incremental: False): The logger `Ray.data` loses its original handler and uses the `Ray` logger’s handler after the Ray logger is set via `dictConfig`. ``` 2024-11-27 04:32:06,213 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - INFO - Ray data propagate False abc Ray - DEBUG - This is a DEBUG log from Ray. abc Ray - ERROR - This is an ERROR log from Ray. abc Ray.data - INFO - Another INFO log from Ray.data. abc Ray.data - INFO - Ray data propagate True ``` * [Example2](https://gist.github.com/kevin85421/9cf6ee70ceec42be3de888174d0c8e6a) (incremental: True): It looks like `Ray.data`’s handlers are removed after the `Ray` logger is set via `dictConfig`. ``` 2024-11-27 04:35:25,379 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False This is an ERROR log from Ray. 2024-11-27 04:35:25,379 - Ray.data - INFO - Another INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False ``` * CPython implementation * Case 1: `incremental` is `False` * If an existing logger is also a child logger of a new logger, the child logger’s handlers will be reset, and its `propagate` attribute will be set to true. * In [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f), `Ray.data` is not only an existing logger but also a child logger of Ray. Therefore, its handlers will be reset, and propagate will be set to true. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L193-L196 * Case 2: `incremental` is `True` * No handlers & filters will be added to the new logger. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L906-L915 ### Solution Instead of using `dictConfig` to set the root logger and the Ray logger, call other functions to set the loggers explicitly. ## Related issue number Closes ray-project#48732 <!-- For example: "Closes ray-project#1234" --> ## Checks * Test 1 ```python import ray import logging import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) root_logger = logging.getLogger() root_logger.info("root logger") ray_logger = logging.getLogger("ray") ray_logger.info("ray logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") @ray.remote def f(): root_logger = logging.getLogger() root_logger.info("root logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") ray.get(f.remote()) ``` <img width="1440" alt="image" src="https://github.com/user-attachments/assets/e522a257-28c5-4b3c-ad62-c41e4cd61664"> * Test 2 ```python import ray import logging def report_logger(logger): # Collect this logger and its parents loggers = [] current_logger = logger while current_logger: loggers.append(current_logger) if not current_logger.parent or current_logger.parent == current_logger: break current_logger = current_logger.parent # Report the configuration of each logger in the hierarchy print(f"Logging configuration for '{logger.name}' and its hierarchy:") for log in reversed(loggers): # Start from the root and go down to the given logger print(f"\nLogger: {log.name or 'root'} (Level: {logging.getLevelName(log.level)})") if log.handlers: print(" Handlers:") for handler in log.handlers: print(f" - {handler.__class__.__name__} (Level: {logging.getLevelName(handler.level)})") else: print(" No handlers configured") print("BEFORE") report_logger(logging.getLogger("ray.data")) print() import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) print("AFTER:") report_logger(logging.getLogger("ray.data")) ``` <img width="1189" alt="image" src="https://github.com/user-attachments/assets/9129b22a-f436-40ca-9f42-f1ecacf6c515"> Signed-off-by: kaihsun <kaihsun@anyscale.com> Signed-off-by: Kai-Hsun Chen <kaihsun@apache.org> Co-authored-by: Jiajun Yao <jeromeyjj@gmail.com> Signed-off-by: Connor Sanders <connor@elastiflow.com>
…behavior (ray-project#48958) ### Issue In the Ray codebase, [logging.config.dictConfig](https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig) may be called multiple times. However, we found that if a logger’s child loggers are set before the logger is set via `dictConfig`, it may cause issues. * [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f) (incremental: False): The logger `Ray.data` loses its original handler and uses the `Ray` logger’s handler after the Ray logger is set via `dictConfig`. ``` 2024-11-27 04:32:06,213 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - INFO - Ray data propagate False abc Ray - DEBUG - This is a DEBUG log from Ray. abc Ray - ERROR - This is an ERROR log from Ray. abc Ray.data - INFO - Another INFO log from Ray.data. abc Ray.data - INFO - Ray data propagate True ``` * [Example2](https://gist.github.com/kevin85421/9cf6ee70ceec42be3de888174d0c8e6a) (incremental: True): It looks like `Ray.data`’s handlers are removed after the `Ray` logger is set via `dictConfig`. ``` 2024-11-27 04:35:25,379 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False This is an ERROR log from Ray. 2024-11-27 04:35:25,379 - Ray.data - INFO - Another INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False ``` * CPython implementation * Case 1: `incremental` is `False` * If an existing logger is also a child logger of a new logger, the child logger’s handlers will be reset, and its `propagate` attribute will be set to true. * In [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f), `Ray.data` is not only an existing logger but also a child logger of Ray. Therefore, its handlers will be reset, and propagate will be set to true. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L193-L196 * Case 2: `incremental` is `True` * No handlers & filters will be added to the new logger. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L906-L915 ### Solution Instead of using `dictConfig` to set the root logger and the Ray logger, call other functions to set the loggers explicitly. ## Related issue number Closes ray-project#48732 <!-- For example: "Closes ray-project#1234" --> ## Checks * Test 1 ```python import ray import logging import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) root_logger = logging.getLogger() root_logger.info("root logger") ray_logger = logging.getLogger("ray") ray_logger.info("ray logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") @ray.remote def f(): root_logger = logging.getLogger() root_logger.info("root logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") ray.get(f.remote()) ``` <img width="1440" alt="image" src="https://github.com/user-attachments/assets/e522a257-28c5-4b3c-ad62-c41e4cd61664"> * Test 2 ```python import ray import logging def report_logger(logger): # Collect this logger and its parents loggers = [] current_logger = logger while current_logger: loggers.append(current_logger) if not current_logger.parent or current_logger.parent == current_logger: break current_logger = current_logger.parent # Report the configuration of each logger in the hierarchy print(f"Logging configuration for '{logger.name}' and its hierarchy:") for log in reversed(loggers): # Start from the root and go down to the given logger print(f"\nLogger: {log.name or 'root'} (Level: {logging.getLevelName(log.level)})") if log.handlers: print(" Handlers:") for handler in log.handlers: print(f" - {handler.__class__.__name__} (Level: {logging.getLevelName(handler.level)})") else: print(" No handlers configured") print("BEFORE") report_logger(logging.getLogger("ray.data")) print() import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) print("AFTER:") report_logger(logging.getLogger("ray.data")) ``` <img width="1189" alt="image" src="https://github.com/user-attachments/assets/9129b22a-f436-40ca-9f42-f1ecacf6c515"> Signed-off-by: kaihsun <kaihsun@anyscale.com> Signed-off-by: Kai-Hsun Chen <kaihsun@apache.org> Co-authored-by: Jiajun Yao <jeromeyjj@gmail.com> Signed-off-by: hjiang <dentinyhao@gmail.com>
…behavior (ray-project#48958) ### Issue In the Ray codebase, [logging.config.dictConfig](https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig) may be called multiple times. However, we found that if a logger’s child loggers are set before the logger is set via `dictConfig`, it may cause issues. * [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f) (incremental: False): The logger `Ray.data` loses its original handler and uses the `Ray` logger’s handler after the Ray logger is set via `dictConfig`. ``` 2024-11-27 04:32:06,213 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:32:06,213 - Ray.data - INFO - Ray data propagate False abc Ray - DEBUG - This is a DEBUG log from Ray. abc Ray - ERROR - This is an ERROR log from Ray. abc Ray.data - INFO - Another INFO log from Ray.data. abc Ray.data - INFO - Ray data propagate True ``` * [Example2](https://gist.github.com/kevin85421/9cf6ee70ceec42be3de888174d0c8e6a) (incremental: True): It looks like `Ray.data`’s handlers are removed after the `Ray` logger is set via `dictConfig`. ``` 2024-11-27 04:35:25,379 - Ray.data - INFO - This is an INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - WARNING - This is a WARNING log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False This is an ERROR log from Ray. 2024-11-27 04:35:25,379 - Ray.data - INFO - Another INFO log from Ray.data. 2024-11-27 04:35:25,379 - Ray.data - INFO - Ray data propagate False ``` * CPython implementation * Case 1: `incremental` is `False` * If an existing logger is also a child logger of a new logger, the child logger’s handlers will be reset, and its `propagate` attribute will be set to true. * In [Example1](https://gist.github.com/kevin85421/24849e06c61f221fd95063a4ce81ca8f), `Ray.data` is not only an existing logger but also a child logger of Ray. Therefore, its handlers will be reset, and propagate will be set to true. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L193-L196 * Case 2: `incremental` is `True` * No handlers & filters will be added to the new logger. * See the function for more details: https://github.com/python/cpython/blob/71ede1142ddad2d31cc966b8fe4a5aff664f4d53/Lib/logging/config.py#L906-L915 ### Solution Instead of using `dictConfig` to set the root logger and the Ray logger, call other functions to set the loggers explicitly. ## Related issue number Closes ray-project#48732 <!-- For example: "Closes ray-project#1234" --> ## Checks * Test 1 ```python import ray import logging import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) root_logger = logging.getLogger() root_logger.info("root logger") ray_logger = logging.getLogger("ray") ray_logger.info("ray logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") @ray.remote def f(): root_logger = logging.getLogger() root_logger.info("root logger") ray_data_logger = logging.getLogger("ray.data") ray_data_logger.info("ray data logger") ray.get(f.remote()) ``` <img width="1440" alt="image" src="https://github.com/user-attachments/assets/e522a257-28c5-4b3c-ad62-c41e4cd61664"> * Test 2 ```python import ray import logging def report_logger(logger): # Collect this logger and its parents loggers = [] current_logger = logger while current_logger: loggers.append(current_logger) if not current_logger.parent or current_logger.parent == current_logger: break current_logger = current_logger.parent # Report the configuration of each logger in the hierarchy print(f"Logging configuration for '{logger.name}' and its hierarchy:") for log in reversed(loggers): # Start from the root and go down to the given logger print(f"\nLogger: {log.name or 'root'} (Level: {logging.getLevelName(log.level)})") if log.handlers: print(" Handlers:") for handler in log.handlers: print(f" - {handler.__class__.__name__} (Level: {logging.getLevelName(handler.level)})") else: print(" No handlers configured") print("BEFORE") report_logger(logging.getLogger("ray.data")) print() import ray.data ray.init(logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO")) print("AFTER:") report_logger(logging.getLogger("ray.data")) ``` <img width="1189" alt="image" src="https://github.com/user-attachments/assets/9129b22a-f436-40ca-9f42-f1ecacf6c515"> Signed-off-by: kaihsun <kaihsun@anyscale.com> Signed-off-by: Kai-Hsun Chen <kaihsun@apache.org> Co-authored-by: Jiajun Yao <jeromeyjj@gmail.com> Signed-off-by: ujjawal-khare <ujjawal.khare@dream11.com>
[core] Ray Core / Ray Data logging configuration leads to unexpected behavior (ray-project#48958) See merge request xlabs/x77-taiga/ray-oss!143
Why are these changes needed?
Issue
In the Ray codebase, logging.config.dictConfig may be called multiple times. However, we found that if a logger’s child loggers are set before the logger is set via
dictConfig
, it may cause issues.Example1 (incremental: False): The logger
Ray.data
loses its original handler and uses theRay
logger’s handler after the Ray logger is set viadictConfig
.Example2 (incremental: True): It looks like
Ray.data
’s handlers are removed after theRay
logger is set viadictConfig
.CPython implementation
incremental
isFalse
propagate
attribute will be set to true.Ray.data
is not only an existing logger but also a child logger of Ray. Therefore, its handlers will be reset, and propagate will be set to true.Case 2:
incremental
isTrue
Solution
Instead of using
dictConfig
to set the root logger and the Ray logger, call other functions to set the loggers explicitly.Related issue number
Closes #48732
Checks
Test 1
Test 2
git commit -s
) in this PR.scripts/format.sh
to lint the changes in this PR.method in Tune, I've added it in
doc/source/tune/api/
under thecorresponding
.rst
file.