mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
(Feat) datadog_llm_observability callback - emit request_tags on logs (#7883)
* dd - emit tags on llm obs payload * dd - show requester tags on traces * test_get_datadog_tags * _get_datadog_tags * fix dd POD_NAME * test_get_datadog_tags
This commit is contained in:
parent
4b88635372
commit
806df5d31c
5 changed files with 82 additions and 3 deletions
|
|
@ -274,7 +274,9 @@ class DataDogLogger(CustomBatchLogger):
|
|||
|
||||
dd_payload = DatadogPayload(
|
||||
ddsource=self._get_datadog_source(),
|
||||
ddtags=self._get_datadog_tags(),
|
||||
ddtags=self._get_datadog_tags(
|
||||
standard_logging_object=standard_logging_object
|
||||
),
|
||||
hostname=self._get_datadog_hostname(),
|
||||
message=json_payload,
|
||||
service=self._get_datadog_service(),
|
||||
|
|
@ -444,8 +446,33 @@ class DataDogLogger(CustomBatchLogger):
|
|||
return dd_payload
|
||||
|
||||
@staticmethod
|
||||
def _get_datadog_tags():
|
||||
return f"env:{os.getenv('DD_ENV', 'unknown')},service:{os.getenv('DD_SERVICE', 'litellm')},version:{os.getenv('DD_VERSION', 'unknown')},HOSTNAME:{DataDogLogger._get_datadog_hostname()},POD_NAME:{os.getenv('POD_NAME', 'unknown')}"
|
||||
def _get_datadog_tags(
|
||||
standard_logging_object: Optional[StandardLoggingPayload] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Get the datadog tags for the request
|
||||
|
||||
DD tags need to be as follows:
|
||||
- tags: ["user_handle:dog@gmail.com", "app_version:1.0.0"]
|
||||
"""
|
||||
base_tags = {
|
||||
"env": os.getenv("DD_ENV", "unknown"),
|
||||
"service": os.getenv("DD_SERVICE", "litellm"),
|
||||
"version": os.getenv("DD_VERSION", "unknown"),
|
||||
"HOSTNAME": DataDogLogger._get_datadog_hostname(),
|
||||
"POD_NAME": os.getenv("POD_NAME", "unknown"),
|
||||
}
|
||||
|
||||
tags = [f"{k}:{v}" for k, v in base_tags.items()]
|
||||
|
||||
if standard_logging_object:
|
||||
_request_tags: List[str] = (
|
||||
standard_logging_object.get("request_tags", []) or []
|
||||
)
|
||||
request_tags = [f"request_tag:{tag}" for tag in _request_tags]
|
||||
tags.extend(request_tags)
|
||||
|
||||
return ",".join(tags)
|
||||
|
||||
@staticmethod
|
||||
def _get_datadog_source():
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ class DataDogLLMObsLogger(DataDogLogger, CustomBatchLogger):
|
|||
start_ns=int(start_time.timestamp() * 1e9),
|
||||
duration=int((end_time - start_time).total_seconds() * 1e9),
|
||||
metrics=metrics,
|
||||
tags=[
|
||||
self._get_datadog_tags(standard_logging_object=standard_logging_payload)
|
||||
],
|
||||
)
|
||||
|
||||
def _get_response_messages(self, response_obj: Any) -> List[Any]:
|
||||
|
|
|
|||
|
|
@ -19,3 +19,6 @@ model_list:
|
|||
|
||||
general_settings:
|
||||
store_prompts_in_spend_logs: true
|
||||
|
||||
litellm_settings:
|
||||
callbacks: ["datadog_llm_observability"]
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class LLMObsPayload(TypedDict):
|
|||
start_ns: int
|
||||
duration: int
|
||||
metrics: LLMMetrics
|
||||
tags: List
|
||||
|
||||
|
||||
class DDSpanAttributes(TypedDict):
|
||||
|
|
|
|||
|
|
@ -532,3 +532,48 @@ async def test_datadog_non_serializable_messages():
|
|||
# Check that the non-serializable objects were converted to strings
|
||||
assert isinstance(dict_payload["messages"][0]["content"], str)
|
||||
assert isinstance(dict_payload["response"]["choices"][0]["message"]["content"], str)
|
||||
|
||||
|
||||
def test_get_datadog_tags():
|
||||
"""Test the _get_datadog_tags static method with various inputs"""
|
||||
# Test with no standard_logging_object and default env vars
|
||||
base_tags = DataDogLogger._get_datadog_tags()
|
||||
assert "env:" in base_tags
|
||||
assert "service:" in base_tags
|
||||
assert "version:" in base_tags
|
||||
assert "POD_NAME:" in base_tags
|
||||
assert "HOSTNAME:" in base_tags
|
||||
|
||||
# Test with custom env vars
|
||||
test_env = {
|
||||
"DD_ENV": "production",
|
||||
"DD_SERVICE": "custom-service",
|
||||
"DD_VERSION": "1.0.0",
|
||||
"HOSTNAME": "test-host",
|
||||
"POD_NAME": "pod-123",
|
||||
}
|
||||
with patch.dict(os.environ, test_env):
|
||||
custom_tags = DataDogLogger._get_datadog_tags()
|
||||
assert "env:production" in custom_tags
|
||||
assert "service:custom-service" in custom_tags
|
||||
assert "version:1.0.0" in custom_tags
|
||||
assert "HOSTNAME:test-host" in custom_tags
|
||||
assert "POD_NAME:pod-123" in custom_tags
|
||||
|
||||
# Test with standard_logging_object containing request_tags
|
||||
standard_logging_obj = create_standard_logging_payload()
|
||||
standard_logging_obj["request_tags"] = ["tag1", "tag2"]
|
||||
|
||||
tags_with_request = DataDogLogger._get_datadog_tags(standard_logging_obj)
|
||||
assert "request_tag:tag1" in tags_with_request
|
||||
assert "request_tag:tag2" in tags_with_request
|
||||
|
||||
# Test with empty request_tags
|
||||
standard_logging_obj["request_tags"] = []
|
||||
tags_empty_request = DataDogLogger._get_datadog_tags(standard_logging_obj)
|
||||
assert "request_tag:" not in tags_empty_request
|
||||
|
||||
# Test with None request_tags
|
||||
standard_logging_obj["request_tags"] = None
|
||||
tags_none_request = DataDogLogger._get_datadog_tags(standard_logging_obj)
|
||||
assert "request_tag:" not in tags_none_request
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue