Source code for ray._private.ray_logging.logging_config

from abc import ABC, abstractmethod
from typing import Set

from ray._private.ray_logging import default_impl
from ray._private.ray_logging.constants import LOGRECORD_STANDARD_ATTRS
from ray._private.ray_logging.formatters import TextFormatter, JSONFormatter
from ray._private.ray_logging.filters import CoreContextFilter
from ray.util.annotations import PublicAPI

from dataclasses import dataclass, field

import logging


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.
[docs] @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"{LOGRECORD_STANDARD_ATTRS}" ) 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