Repository: apache/airflow
File: task-sdk/src/airflow/sdk/log.py (Python)

Code before:

import structlog
import structlog.processors

# We have to import this here, as it is used in the type annotations at runtime even if it seems it is
# not used in the code. This is because Pydantic uses type at runtime to validate the types of the fields.
from pydantic import JsonValue  # noqa: TC002

if TYPE_CHECKING:
    from structlog.typing import EventDict, FilteringBoundLogger, Processor

    from airflow.logging_config import RemoteLogIO
    from airflow.sdk.types import Logger, RuntimeTaskInstanceProtocol as RuntimeTI


def redact(
    value: Any, name: str | None = None, max_depth: int | None = None, replacement: str = "***"
) -> Any:
    """
    Redact any secrets found in ``value`` with the given replacement.

    This is a re-export from airflow.sdk._shared.secrets_masker for provider compatibility.
    """
    from airflow.sdk._shared.secrets_masker import redact as _redact

    return _redact(value, name, max_depth, replacement)


__all__ = ["configure_logging", "reset_logging", "mask_secret", "redact"]


class _WarningsInterceptor:
    """A class to hold the reference to the original warnings.showwarning function."""

    _original_showwarning: Callable | None = None

    @staticmethod
    def register(new_callable: Callable) -> None:
        if _WarningsInterceptor._original_showwarning is None:
            _WarningsInterceptor._original_showwarning = warnings.showwarning
        warnings.showwarning = new_callable

    @staticmethod
    def reset() -> None:
        if _WarningsInterceptor._original_showwarning is not None:
            warnings.showwarning = _WarningsInterceptor._original_showwarning
            _WarningsInterceptor._original_showwarning = None

    @staticmethod
    def emit_warning(*args: Any) -> None:
        if _WarningsInterceptor._original_showwarning is not None:

Review comment (security):
Can we not just re-export? Why do we need the wrapper?

```
from airflow.sdk._shared.secrets_masker import redact as _redact
```

Should be enough

Code after:

import structlog
import structlog.processors

# We have to import this here, as it is used in the type annotations at runtime even if it seems it is
# not used in the code. This is because Pydantic uses type at runtime to validate the types of the fields.
from pydantic import JsonValue  # noqa: TC002

if TYPE_CHECKING:
    from structlog.typing import EventDict, FilteringBoundLogger, Processor

    from airflow.logging_config import RemoteLogIO
    from airflow.sdk.types import Logger, RuntimeTaskInstanceProtocol as RuntimeTI


from airflow.sdk._shared.secrets_masker import redact


class _WarningsInterceptor:
    """A class to hold the reference to the original warnings.showwarning function."""

    _original_showwarning: Callable | None = None

    @staticmethod
    def register(new_callable: Callable) -> None:
        if _WarningsInterceptor._original_showwarning is None:
            _WarningsInterceptor._original_showwarning = warnings.showwarning
        warnings.showwarning = new_callable

    @staticmethod
    def reset() -> None:
        if _WarningsInterceptor._original_showwarning is not None:
            warnings.showwarning = _WarningsInterceptor._original_showwarning
            _WarningsInterceptor._original_showwarning = None

    @staticmethod
    def emit_warning(*args: Any) -> None:
        if _WarningsInterceptor._original_showwarning is not None:
            _WarningsInterceptor._original_showwarning(*args)


def mask_logs(logger: Any, method_name: str, event_dict: EventDict) -> EventDict:
    event_dict = redact(event_dict)  # type: ignore[assignment]
    return event_dict


@cache
def logging_processors(
    json_output: bool,
    log_format: str = "",
    colors: bool = True,