diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index dfdf6f57e8..b8c17934b0 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -363,7 +363,7 @@ class ProxyLogging: if self.alerting is not None and "slack" in self.alerting: # NOTE: ENSURE we only add callbacks when alerting is on # We should NOT add callbacks when alerting is off - if "daily_reports" in self.alert_types: + if "daily_reports" in self.alert_types or "outage_alerts" in self.alert_types or "region_outage_alerts" in self.alert_types: litellm.logging_callback_manager.add_litellm_callback(self.slack_alerting_instance) # type: ignore litellm.logging_callback_manager.add_litellm_success_callback( self.slack_alerting_instance.response_taking_too_long_callback diff --git a/tests/litellm_utils_tests/test_logging_callback_manager.py b/tests/litellm_utils_tests/test_logging_callback_manager.py index 1b70631e4d..d6abbd4b10 100644 --- a/tests/litellm_utils_tests/test_logging_callback_manager.py +++ b/tests/litellm_utils_tests/test_logging_callback_manager.py @@ -210,3 +210,70 @@ def test_reset_callbacks(callback_manager): assert len(litellm.failure_callback) == 0 assert len(litellm._async_success_callback) == 0 assert len(litellm._async_failure_callback) == 0 + + +@pytest.mark.asyncio +async def test_slack_alerting_callback_registration(callback_manager): + """ + Test that litellm callbacks are correctly registered for slack alerting + when outage_alerts or region_outage_alerts are enabled + """ + from litellm.caching.caching import DualCache + from litellm.proxy.utils import ProxyLogging + from litellm.integrations.SlackAlerting.slack_alerting import SlackAlerting + from unittest.mock import AsyncMock, patch + + # Mock the async HTTP handler + with patch('litellm.integrations.SlackAlerting.slack_alerting.get_async_httpx_client') as mock_http: + mock_http.return_value = AsyncMock() + + # Create a fresh ProxyLogging instance + proxy_logging = ProxyLogging(user_api_key_cache=DualCache()) + + # Test 1: No callbacks should be added when alerting is None + proxy_logging.update_values( + alerting=None, + alert_types=["outage_alerts", "region_outage_alerts"] + ) + assert len(litellm.callbacks) == 0 + + # Test 2: Callbacks should be added when slack alerting is enabled with outage alerts + proxy_logging.update_values( + alerting=["slack"], + alert_types=["outage_alerts"] + ) + assert len(litellm.callbacks) == 1 + assert isinstance(litellm.callbacks[0], SlackAlerting) + + # Test 3: Callbacks should be added when slack alerting is enabled with region outage alerts + callback_manager._reset_all_callbacks() # Reset callbacks + proxy_logging.update_values( + alerting=["slack"], + alert_types=["region_outage_alerts"] + ) + assert len(litellm.callbacks) == 1 + assert isinstance(litellm.callbacks[0], SlackAlerting) + + # Test 4: No callbacks should be added for other alert types + callback_manager._reset_all_callbacks() # Reset callbacks + proxy_logging.update_values( + alerting=["slack"], + alert_types=["budget_alerts"] # Some other alert type + ) + assert len(litellm.callbacks) == 0 + + # Test 5: Both success and regular callbacks should be added + callback_manager._reset_all_callbacks() # Reset callbacks + proxy_logging.update_values( + alerting=["slack"], + alert_types=["outage_alerts"] + ) + assert len(litellm.callbacks) == 1 # Regular callback for outage alerts + assert len(litellm.success_callback) == 1 # Success callback for response_taking_too_long + assert isinstance(litellm.callbacks[0], SlackAlerting) + # Get the method reference for comparison + response_taking_too_long_callback = proxy_logging.slack_alerting_instance.response_taking_too_long_callback + assert litellm.success_callback[0] == response_taking_too_long_callback + + # Cleanup + callback_manager._reset_all_callbacks()