(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:
Ishaan Jaff 2025-01-20 20:36:27 -08:00 • committed by GitHub
parent 4b88635372
commit 806df5d31c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 82 additions and 3 deletions

View file

@ -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():

View file

@ -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]:

View file

@ -19,3 +19,6 @@ model_list:
general_settings:
store_prompts_in_spend_logs: true
litellm_settings:
callbacks: ["datadog_llm_observability"]

View file

@ -40,6 +40,7 @@ class LLMObsPayload(TypedDict):
start_ns: int
duration: int
metrics: LLMMetrics
tags: List
class DDSpanAttributes(TypedDict):

View file

@ -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