172 lines
6.7 KiB
Python
172 lines
6.7 KiB
Python
import logging
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import asdict, dataclass, field, fields
|
|
from typing import Dict, Set
|
|
|
|
from ray._common.filters import CoreContextFilter
|
|
from ray._common.formatters import JSONFormatter, TextFormatter
|
|
from ray._common.logging_constants import LOGRECORD_STANDARD_ATTRS
|
|
from ray._private.ray_logging import default_impl
|
|
from ray.util.annotations import PublicAPI
|
|
|
|
|
|
class LoggingConfigurator(ABC):
|
|
@abstractmethod
|
|
def get_supported_encodings(self) -> Set[str]:
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def configure(self, logging_config: "LoggingConfig"):
|
|
raise NotImplementedError
|
|
|
|
|
|
class DefaultLoggingConfigurator(LoggingConfigurator):
|
|
def __init__(self):
|
|
self._encoding_to_formatter = {
|
|
"TEXT": TextFormatter(),
|
|
"JSON": JSONFormatter(),
|
|
}
|
|
|
|
def get_supported_encodings(self) -> Set[str]:
|
|
return self._encoding_to_formatter.keys()
|
|
|
|
def configure(self, logging_config: "LoggingConfig"):
|
|
formatter = self._encoding_to_formatter[logging_config.encoding]
|
|
formatter.set_additional_log_standard_attrs(
|
|
logging_config.additional_log_standard_attrs
|
|
)
|
|
|
|
core_context_filter = CoreContextFilter()
|
|
handler = logging.StreamHandler()
|
|
handler.setLevel(logging_config.log_level)
|
|
handler.setFormatter(formatter)
|
|
handler.addFilter(core_context_filter)
|
|
|
|
root_logger = logging.getLogger()
|
|
root_logger.setLevel(logging_config.log_level)
|
|
root_logger.addHandler(handler)
|
|
|
|
ray_logger = logging.getLogger("ray")
|
|
ray_logger.setLevel(logging_config.log_level)
|
|
# Remove all existing handlers added by `ray/__init__.py`.
|
|
for h in ray_logger.handlers[:]:
|
|
ray_logger.removeHandler(h)
|
|
ray_logger.addHandler(handler)
|
|
ray_logger.propagate = False
|
|
|
|
|
|
_logging_configurator: LoggingConfigurator = default_impl.get_logging_configurator()
|
|
|
|
|
|
# Class defines the logging configurations for a Ray job.
|
|
# To add a new logging configuration: (1) add a new field to this class; (2) Update the
|
|
# logic in the __post_init__ method in this class to add the validation logic;
|
|
# (3) Update the configure method in the DefaultLoggingConfigurator
|
|
# class to use the new field.
|
|
@PublicAPI(stability="alpha")
|
|
@dataclass
|
|
class LoggingConfig:
|
|
encoding: str = "TEXT"
|
|
log_level: str = "INFO"
|
|
# The list of valid attributes are defined as LOGRECORD_STANDARD_ATTRS in
|
|
# constants.py.
|
|
additional_log_standard_attrs: list = field(default_factory=list)
|
|
|
|
def __post_init__(self):
|
|
if self.encoding not in _logging_configurator.get_supported_encodings():
|
|
raise ValueError(
|
|
f"Invalid encoding type: {self.encoding}. "
|
|
"Valid encoding types are: "
|
|
f"{list(_logging_configurator.get_supported_encodings())}"
|
|
)
|
|
|
|
for attr in self.additional_log_standard_attrs:
|
|
if attr not in LOGRECORD_STANDARD_ATTRS:
|
|
raise ValueError(
|
|
f"Unknown python logging standard attribute: {attr}. "
|
|
"The valid attributes are: "
|
|
f"{set(LOGRECORD_STANDARD_ATTRS)}"
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, object]:
|
|
"""Serialize to a plain dict suitable for JSON transport."""
|
|
return asdict(self)
|
|
|
|
@classmethod
|
|
def from_dict(cls, d: Dict[str, object]) -> "LoggingConfig":
|
|
"""Create a LoggingConfig from a dict, ignoring unknown keys."""
|
|
known = {f.name for f in fields(cls)}
|
|
return cls(**{k: v for k, v in d.items() if k in known})
|
|
|
|
def _configure_logging(self):
|
|
"""Set up the logging configuration for the current process."""
|
|
_logging_configurator.configure(self)
|
|
|
|
def _apply(self):
|
|
"""Set up the logging configuration."""
|
|
self._configure_logging()
|
|
|
|
|
|
LoggingConfig.__doc__ = """
|
|
Logging configuration for a Ray job. These configurations are used to set up the
|
|
root logger of the driver process and all Ray tasks and actor processes that belong
|
|
to the job.
|
|
|
|
Examples: 1. Configure the logging to use TEXT encoding.
|
|
.. testcode::
|
|
|
|
import ray
|
|
import logging
|
|
|
|
ray.init(
|
|
logging_config=ray.LoggingConfig(encoding="TEXT", log_level="INFO", additional_log_standard_attrs=['name'])
|
|
)
|
|
|
|
@ray.remote
|
|
def f():
|
|
logger = logging.getLogger(__name__)
|
|
logger.info("This is a Ray task")
|
|
|
|
ray.get(f.remote())
|
|
ray.shutdown()
|
|
|
|
.. testoutput::
|
|
:options: +MOCK
|
|
|
|
2025-02-12 12:25:16,836 INFO test-log-config.py:11 -- This is a Ray task name=__main__ job_id=01000000 worker_id=51188d9448be4664bf2ea26ac410b67acaaa970c4f31c5ad3ae776a5 node_id=f683dfbffe2c69984859bc19c26b77eaf3866c458884c49d115fdcd4 task_id=c8ef45ccd0112571ffffffffffffffffffffffff01000000 task_name=f task_func_name=test-log-config.f timestamp_ns=1739391916836884000
|
|
|
|
2. Configure the logging to use JSON encoding.
|
|
.. testcode::
|
|
|
|
import ray
|
|
import logging
|
|
|
|
ray.init(
|
|
logging_config=ray.LoggingConfig(encoding="JSON", log_level="INFO", additional_log_standard_attrs=['name'])
|
|
)
|
|
|
|
@ray.remote
|
|
def f():
|
|
logger = logging.getLogger(__name__)
|
|
logger.info("This is a Ray task")
|
|
|
|
ray.get(f.remote())
|
|
ray.shutdown()
|
|
|
|
.. testoutput::
|
|
:options: +MOCK
|
|
|
|
{"asctime": "2025-02-12 12:25:48,766", "levelname": "INFO", "message": "This is a Ray task", "filename": "test-log-config.py", "lineno": 11, "name": "__main__", "job_id": "01000000", "worker_id": "6d307578014873fcdada0fa22ea6d49e0fb1f78960e69d61dfe41f5a", "node_id": "69e3a5e68bdc7eb8ac9abb3155326ee3cc9fc63ea1be04d11c0d93c7", "task_id": "c8ef45ccd0112571ffffffffffffffffffffffff01000000", "task_name": "f", "task_func_name": "test-log-config.f", "timestamp_ns": 1739391948766949000}
|
|
|
|
Args:
|
|
encoding: Encoding type for the logs. The valid values are
|
|
{list(_logging_configurator.get_supported_encodings())}
|
|
log_level: Log level for the logs. Defaults to 'INFO'. You can set
|
|
it to 'DEBUG' to receive more detailed debug logs.
|
|
additional_log_standard_attrs: List of additional standard python logger attributes to
|
|
include in the log. Defaults to an empty list. The list of already
|
|
included standard attributes are: "asctime", "levelname", "message",
|
|
"filename", "lineno", "exc_text". The list of valid attributes are specified
|
|
here: http://docs.python.org/library/logging.html#logrecord-attributes
|
|
""" # noqa: E501
|