This commit is contained in:
Mateo Wang 2026-11-05 09:51:04 +00:00 • committed by GitHub
commit d380c56978
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 9 deletions

View file

@ -427,6 +427,13 @@ in_memory_dynamic_logger_cache: Final = DynamicLoggingCache()
_PrometheusLogger = None
def _get_custom_logger() -> CustomLogger:
global customLogger
if customLogger is None:
customLogger = CustomLogger() # rebind-ok: process-wide callable callback adapter shared by logging handlers
return customLogger
def _get_cached_prometheus_logger():
"""
Get cached PrometheusLogger class.
@ -4074,12 +4081,10 @@ class Logging(LiteLLMLoggingBaseClass):
start_time=start_time,
end_time=end_time,
)
if (
callable(callback) is True and is_sync_request and customLogger is not None
): # custom logger functions
if callable(callback) and is_sync_request:
print_verbose(f"success callbacks: Running Custom Callback Function - {callback}")
customLogger.log_event(
_get_custom_logger().log_event(
kwargs=call_details,
response_obj=result,
start_time=start_time,
@ -4451,12 +4456,9 @@ class Logging(LiteLLMLoggingBaseClass):
end_time=end_time,
)
if callable(callback): # custom logger functions
global customLogger
if customLogger is None:
customLogger = CustomLogger()
if self.stream:
if "async_complete_streaming_response" in self.model_call_details:
await customLogger.async_log_event(
await _get_custom_logger().async_log_event(
kwargs=self.model_call_details,
response_obj=self.model_call_details["async_complete_streaming_response"],
start_time=start_time,
@ -4465,7 +4467,7 @@ class Logging(LiteLLMLoggingBaseClass):
callback_func=callback,
)
else:
await customLogger.async_log_event(
await _get_custom_logger().async_log_event(
kwargs=self.model_call_details,
response_obj=result,
start_time=start_time,

View file

@ -8932,6 +8932,53 @@ async def test_logger_in_the_global_failure_callback_lists_gets_one_failure_hook
assert recorder.hooks == ["async_failure"]
@pytest.mark.usefixtures("no_global_callbacks")
@pytest.mark.parametrize("event", ["success", "failure"])
def test_sync_callable_after_string_callback_setup_receives_the_call(
monkeypatch: pytest.MonkeyPatch, event: str
) -> None:
monkeypatch.setattr(litellm.utils, "callback_list", [])
monkeypatch.setattr(litellm_logging, "customLogger", None)
monkeypatch.setattr(litellm_logging, "promptLayerLogger", None)
monkeypatch.setattr(litellm, "input_callback", [])
monkeypatch.setattr(litellm, "_async_input_callback", [])
monkeypatch.setattr(litellm, "success_callback", ["promptlayer"])
start: Final = datetime.datetime(2026, 1, 1)
end: Final = start + datetime.timedelta(seconds=1)
litellm.utils.function_setup(
original_function="completion",
rules_obj=litellm.utils.Rules(),
start_time=start,
is_async_call=False,
model="gpt-4o",
messages=[{"role": "user", "content": "hi"}],
litellm_call_id="string-callback",
)
calls: Final[list[tuple[object, object, object, object]]] = []
def callback(kwargs: dict[str, object], response: object, started: object, ended: object) -> None:
calls.append((kwargs["litellm_call_id"], response, started, ended))
monkeypatch.setattr(litellm, "success_callback", [callback] if event == "success" else [])
monkeypatch.setattr(litellm, "failure_callback", [callback] if event == "failure" else [])
logging_obj, _ = litellm.utils.function_setup(
original_function="completion",
rules_obj=litellm.utils.Rules(),
start_time=start,
is_async_call=False,
model="gpt-4o",
messages=[{"role": "user", "content": "hi"}],
litellm_call_id="callable-callback",
)
response: Final = ModelResponse(model="gpt-4o")
if event == "success":
logging_obj.success_handler(response, start, end)
else:
logging_obj.failure_handler(ValueError("upstream rejected"), "traceback", start, end)
assert calls == [("callable-callback", response if event == "success" else None, start, end)]
@pytest.mark.usefixtures("no_global_callbacks")
def test_failure_handler_run_without_an_async_failure_run_keeps_the_sync_hook() -> None:
recorder: Final = _BothFailureHooksRecorder()