Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[core] Ray Core / Ray Data logging configuration leads to unexpected …
…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>
- Loading branch information