mirror of
https://github.com/usestrix/strix.git
synced 2026-10-12 03:47:56 +00:00
feat(llm): carry the upstream provider and error type as request-log event fields
This commit is contained in:
parent
dde135c2f3
commit
e68c75b9c2
2 changed files with 11 additions and 18 deletions
|
|
@ -109,6 +109,9 @@ class LlmRequestEvent:
|
|||
# Streamed calls only.
|
||||
time_to_first_token_ms: int | None = None
|
||||
finish_reason: str | None = None
|
||||
# The provider a gateway (OpenRouter) routed the attempt to, and its error type.
|
||||
upstream_provider: str | None = None
|
||||
upstream_error_type: str | None = None
|
||||
# Every response header the provider sent, name-normalized, values capped.
|
||||
response_headers: dict[str, str] | None = None
|
||||
# Free-form: request parameters, full usage object, SDK hidden params,
|
||||
|
|
@ -177,15 +180,6 @@ def record_upstream_provider(provider: object, error_type: object = None) -> Non
|
|||
reply.upstream_error_type = error_type
|
||||
|
||||
|
||||
def _upstream_details(reply: HttpReply | None) -> list[tuple[str, object]]:
|
||||
if reply is None:
|
||||
return []
|
||||
return [
|
||||
("upstream_provider", reply.upstream_provider),
|
||||
("upstream_error_type", reply.upstream_error_type),
|
||||
]
|
||||
|
||||
|
||||
async def record_http_reply(response: Response) -> None:
|
||||
"""httpx ``response`` event hook: remember the reply for the attempt in flight.
|
||||
|
||||
|
|
@ -704,6 +698,7 @@ def event_from_litellm(
|
|||
ttft_ms = max(0, int((first_at - started).total_seconds() * 1000))
|
||||
|
||||
context = current_call_context()
|
||||
reply = _http_reply.get() or HttpReply()
|
||||
base = LlmRequestEvent(
|
||||
call_id=call_id,
|
||||
route="litellm",
|
||||
|
|
@ -726,6 +721,8 @@ def event_from_litellm(
|
|||
request_bytes=json_size(_litellm_request_body(kwargs)),
|
||||
time_to_first_token_ms=ttft_ms,
|
||||
response_headers=headers_from_response(reply_headers),
|
||||
upstream_provider=reply.upstream_provider,
|
||||
upstream_error_type=reply.upstream_error_type,
|
||||
)
|
||||
if outcome == "success":
|
||||
return _litellm_success(base, kwargs, response, hidden, slo)
|
||||
|
|
@ -794,7 +791,6 @@ def _litellm_success(
|
|||
("request", _litellm_request_details(kwargs)),
|
||||
("response", _litellm_response_details(response)),
|
||||
("litellm", _litellm_hidden_details(hidden, slo)),
|
||||
*_upstream_details(_http_reply.get()),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -844,7 +840,6 @@ def _litellm_failure(
|
|||
("request", _litellm_request_details(kwargs)),
|
||||
("error", error or None),
|
||||
("litellm", _litellm_hidden_details(hidden, slo)),
|
||||
*_upstream_details(_http_reply.get()),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -918,7 +913,6 @@ def _observe_sdk_shared_http_client() -> None:
|
|||
|
||||
|
||||
def _log_line_sink(event: LlmRequestEvent) -> None:
|
||||
details = event.details or {}
|
||||
level = logging.DEBUG if event.outcome == "success" else logging.WARNING
|
||||
logger.log(
|
||||
level,
|
||||
|
|
@ -928,8 +922,8 @@ def _log_line_sink(event: LlmRequestEvent) -> None:
|
|||
"in=%s out=%s cached=%s cost=%s agent=%s attempt=%d%s",
|
||||
event.route,
|
||||
event.provider or "-",
|
||||
details.get("upstream_provider") or "-",
|
||||
details.get("upstream_error_type") or "-",
|
||||
event.upstream_provider or "-",
|
||||
event.upstream_error_type or "-",
|
||||
event.model,
|
||||
event.api_host or "-",
|
||||
event.outcome,
|
||||
|
|
@ -1077,6 +1071,8 @@ class RequestLoggingModel(Model):
|
|||
time_to_first_token_ms=ttft_ms,
|
||||
finish_reason=finish_reason,
|
||||
response_headers=headers_from_response(reply.headers),
|
||||
upstream_provider=reply.upstream_provider,
|
||||
upstream_error_type=reply.upstream_error_type,
|
||||
)
|
||||
if exc is None:
|
||||
usage = _openai_usage(response) if response is not None else {}
|
||||
|
|
@ -1097,7 +1093,6 @@ class RequestLoggingModel(Model):
|
|||
details=merge_details(
|
||||
("request", request.details),
|
||||
("response", _openai_response_details(response, raw_response)),
|
||||
*_upstream_details(reply),
|
||||
),
|
||||
)
|
||||
status, request_id = _openai_error_fields(exc)
|
||||
|
|
@ -1117,7 +1112,6 @@ class RequestLoggingModel(Model):
|
|||
details=merge_details(
|
||||
("request", request.details),
|
||||
("error", _exception_details(exc)),
|
||||
*_upstream_details(reply),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -410,8 +410,7 @@ def test_log_line_names_upstream_recorded_during_attempt(
|
|||
)
|
||||
finally:
|
||||
request_log._http_reply.reset(token)
|
||||
assert event.details is not None
|
||||
assert event.details["upstream_provider"] == "Together"
|
||||
assert event.upstream_provider == "Together"
|
||||
with caplog.at_level(logging.DEBUG, logger="strix.llm.request_log"):
|
||||
request_log._log_line_sink(event)
|
||||
line = caplog.records[-1].getMessage()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue