Skip to content

Commit 890c031

Browse files
authored
Instrument chat endpoint for nim. (#1489)
1 parent ae02205 commit 890c031

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

custom_model_runner/datarobot_drum/drum/common.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,34 @@ def otel_context(tracer, span_name, carrier):
182182
yield span
183183
finally:
184184
context.detach(token)
185+
186+
187+
def extract_chat_request_attributes(completion_params):
188+
"""Extracts otel related attributes from chat request payload
189+
190+
Used to populate span with relevant monitoring attriubtes.
191+
"""
192+
attributes = {}
193+
attributes["gen_ai.request.model"] = completion_params.get("model")
194+
for i, m in enumerate(completion_params.get("messages", [])):
195+
attributes[f"gen_ai.prompt.{i}.role"] = m.get("role")
196+
attributes[f"gen_ai.prompt.{i}.content"] = m.get("content")
197+
# last promt wins
198+
attributes["gen_ai.prompt"] = m.get("content")
199+
return attributes
200+
201+
202+
def extract_chat_response_attributes(response):
203+
"""Extracts otel related attributes from chat response.
204+
205+
Used to populate span with relevant monitoring attriubtes.
206+
"""
207+
attributes = {}
208+
attributes["gen_ai.response.model"] = response.get("model")
209+
for i, c in enumerate(response.get("choices", [])):
210+
m = c.get("message", {})
211+
attributes[f"gen_ai.completion.{i}.role"] = m.get("role")
212+
attributes[f"gen_ai.completion.{i}.content"] = m.get("content")
213+
# last completion wins
214+
attributes["gen_ai.completion"] = m.get("content")
215+
return attributes

custom_model_runner/datarobot_drum/drum/root_predictors/prediction_server.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@
3939
get_flask_app,
4040
)
4141
from datarobot_drum.profiler.stats_collector import StatsCollector, StatsOperation
42-
from datarobot_drum.drum.common import otel_context
42+
from datarobot_drum.drum.common import (
43+
otel_context,
44+
extract_chat_request_attributes,
45+
extract_chat_response_attributes,
46+
)
47+
from opentelemetry.trace.status import StatusCode
4348

4449
logger = logging.getLogger(LOGGER_NAME_PREFIX + "." + __name__)
4550

@@ -200,13 +205,17 @@ def predict_unstructured():
200205
@model_api.route("/v1/chat/completions", methods=["POST"])
201206
def chat():
202207
logger.debug("Entering chat endpoint")
203-
with otel_context(tracer, "drum.chat.completions", request.headers):
208+
with otel_context(tracer, "drum.chat.completions", request.headers) as span:
209+
span.set_attributes(extract_chat_request_attributes(request.json))
204210
self._pre_predict_and_transform()
205211
try:
206212
response, response_status = self.do_chat(logger=logger)
207213
finally:
208214
self._post_predict_and_transform()
209215

216+
if isinstance(response, dict) and response_status == 200:
217+
span.set_attributes(extract_chat_response_attributes(response))
218+
210219
return response, response_status
211220

212221
# models routes are defined without trailing slash because this is required by the OpenAI python client.

0 commit comments

Comments
 (0)