mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-13 03:59:12 +00:00
fix(otel): compare parsed values in callback var conflict check
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
95be09c25c
commit
0cb337dfd7
3 changed files with 74 additions and 1 deletions
|
|
@ -256,12 +256,22 @@ def conflicting_callback_var_error(
|
|||
f"{variable_name} is already set to {stored!r} by another {callback_name} entry. "
|
||||
f"Every {callback_name} entry shares one value: remove that entry or send the same value."
|
||||
for name, entry_vars in stored_entries
|
||||
if name == callback_name and (stored := entry_vars.get(variable_name)) not in (None, incoming)
|
||||
if name == callback_name
|
||||
and (stored := entry_vars.get(variable_name)) is not None
|
||||
and not _same_callback_var_value(variable_name, stored, incoming)
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
def _same_callback_var_value(variable_name: str, first: str, second: str) -> bool:
|
||||
if variable_name != EXCLUDED_SERVICES_VAR:
|
||||
return first == second
|
||||
from litellm.integrations.otel.model.config import parse_excluded_services
|
||||
|
||||
return parse_excluded_services(first) == parse_excluded_services(second)
|
||||
|
||||
|
||||
def logging_metadata_config_error(metadata: Mapping[str, object] | None) -> str | None:
|
||||
"""Validate every ``logging`` entry of a team/key metadata payload."""
|
||||
if not metadata:
|
||||
|
|
|
|||
|
|
@ -465,6 +465,36 @@ def test_key_logging_entries_for_one_backend_may_not_disagree_on_excluded_servic
|
|||
assert error is not None and "already set to 'redis' by another langfuse_otel entry" in error
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("otel_v2_on")
|
||||
@pytest.mark.parametrize(
|
||||
("stored", "incoming", "conflicts"),
|
||||
[
|
||||
("redis,postgres", "postgres,redis", False),
|
||||
("redis", "REDIS", False),
|
||||
("postgres", "postgresql", False),
|
||||
("none", "NONE", False),
|
||||
("redis", "postgres", True),
|
||||
("none", "redis", True),
|
||||
],
|
||||
)
|
||||
def test_key_logging_entries_compare_excluded_services_by_parsed_value(
|
||||
stored: str, incoming: str, conflicts: bool
|
||||
) -> None:
|
||||
def entry(callback_type: str, excluded_services: str) -> dict[str, str | dict[str, str]]:
|
||||
return {
|
||||
"callback_name": "newrelic",
|
||||
"callback_type": callback_type,
|
||||
"callback_vars": {"newrelic_api_key": "license-key", "excluded_services": excluded_services},
|
||||
}
|
||||
|
||||
error: Final = logging_metadata_config_error(
|
||||
{"logging": [entry("success", stored), entry("success_and_failure", incoming)]}
|
||||
)
|
||||
assert (error is not None) is conflicts
|
||||
if conflicts:
|
||||
assert error is not None and f"already set to {stored!r}" in error
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("otel_v2_on")
|
||||
def test_a_failure_only_entry_rejects_excluded_services() -> None:
|
||||
error: Final = callback_config_error("langfuse_otel", {"excluded_services": "redis"}, "failure")
|
||||
|
|
|
|||
|
|
@ -1719,6 +1719,39 @@ async def test_a_second_newrelic_entry_may_not_change_excluded_services(patched_
|
|||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("otel_v2_on")
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_second_newrelic_entry_accepts_equivalent_excluded_services(patched_prisma) -> None:
|
||||
patched_prisma.get_data = AsyncMock(
|
||||
return_value=_team_row(
|
||||
metadata={
|
||||
"logging": [
|
||||
{
|
||||
"callback_name": "newrelic",
|
||||
"callback_type": "success",
|
||||
"callback_vars": {
|
||||
"newrelic_api_key": "license-key",
|
||||
"excluded_services": "redis,postgres",
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
)
|
||||
data: Final = AddTeamCallback(
|
||||
callback_name="newrelic",
|
||||
callback_type="success_and_failure",
|
||||
callback_vars={"newrelic_api_key": "license-key", "excluded_services": "postgres,redis"},
|
||||
)
|
||||
await add_team_callbacks(
|
||||
data=data,
|
||||
http_request=Mock(spec=Request),
|
||||
team_id="team-victim",
|
||||
user_api_key_dict=_admin_auth(),
|
||||
)
|
||||
patched_prisma.db.litellm_teamtable.update.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_team_callbacks_rejects_out_of_range_arize_sampling_rate(patched_prisma):
|
||||
data = AddTeamCallback(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue