|
|
|
|
|
|
|
import os |
|
import traceback |
|
import uuid |
|
from enum import Enum |
|
from typing import Any, Dict, NamedTuple |
|
|
|
from typing_extensions import LiteralString |
|
|
|
from litellm._logging import print_verbose, verbose_logger |
|
from litellm.litellm_core_utils.redact_messages import redact_user_api_key_info |
|
|
|
|
|
class SpanConfig(NamedTuple): |
|
message_template: LiteralString |
|
span_data: Dict[str, Any] |
|
|
|
|
|
class LogfireLevel(str, Enum): |
|
INFO = "info" |
|
ERROR = "error" |
|
|
|
|
|
class LogfireLogger: |
|
|
|
def __init__(self): |
|
try: |
|
verbose_logger.debug("in init logfire logger") |
|
import logfire |
|
|
|
|
|
|
|
if logfire.DEFAULT_LOGFIRE_INSTANCE.config.send_to_logfire: |
|
logfire.configure(token=os.getenv("LOGFIRE_TOKEN")) |
|
except Exception as e: |
|
print_verbose(f"Got exception on init logfire client {str(e)}") |
|
raise e |
|
|
|
def _get_span_config(self, payload) -> SpanConfig: |
|
if ( |
|
payload["call_type"] == "completion" |
|
or payload["call_type"] == "acompletion" |
|
): |
|
return SpanConfig( |
|
message_template="Chat Completion with {request_data[model]!r}", |
|
span_data={"request_data": payload}, |
|
) |
|
elif ( |
|
payload["call_type"] == "embedding" or payload["call_type"] == "aembedding" |
|
): |
|
return SpanConfig( |
|
message_template="Embedding Creation with {request_data[model]!r}", |
|
span_data={"request_data": payload}, |
|
) |
|
elif ( |
|
payload["call_type"] == "image_generation" |
|
or payload["call_type"] == "aimage_generation" |
|
): |
|
return SpanConfig( |
|
message_template="Image Generation with {request_data[model]!r}", |
|
span_data={"request_data": payload}, |
|
) |
|
else: |
|
return SpanConfig( |
|
message_template="Litellm Call with {request_data[model]!r}", |
|
span_data={"request_data": payload}, |
|
) |
|
|
|
async def _async_log_event( |
|
self, |
|
kwargs, |
|
response_obj, |
|
start_time, |
|
end_time, |
|
print_verbose, |
|
level: LogfireLevel, |
|
): |
|
self.log_event( |
|
kwargs=kwargs, |
|
response_obj=response_obj, |
|
start_time=start_time, |
|
end_time=end_time, |
|
print_verbose=print_verbose, |
|
level=level, |
|
) |
|
|
|
def log_event( |
|
self, |
|
kwargs, |
|
start_time, |
|
end_time, |
|
print_verbose, |
|
level: LogfireLevel, |
|
response_obj, |
|
): |
|
try: |
|
import logfire |
|
|
|
verbose_logger.debug( |
|
f"logfire Logging - Enters logging function for model {kwargs}" |
|
) |
|
|
|
if not response_obj: |
|
response_obj = {} |
|
litellm_params = kwargs.get("litellm_params", {}) |
|
metadata = ( |
|
litellm_params.get("metadata", {}) or {} |
|
) |
|
messages = kwargs.get("messages") |
|
optional_params = kwargs.get("optional_params", {}) |
|
call_type = kwargs.get("call_type", "completion") |
|
cache_hit = kwargs.get("cache_hit", False) |
|
usage = response_obj.get("usage", {}) |
|
id = response_obj.get("id", str(uuid.uuid4())) |
|
try: |
|
response_time = (end_time - start_time).total_seconds() |
|
except Exception: |
|
response_time = None |
|
|
|
|
|
|
|
|
|
clean_metadata = {} |
|
if isinstance(metadata, dict): |
|
for key, value in metadata.items(): |
|
|
|
if key in [ |
|
"endpoint", |
|
"caching_groups", |
|
"previous_models", |
|
]: |
|
continue |
|
else: |
|
clean_metadata[key] = value |
|
|
|
clean_metadata = redact_user_api_key_info(metadata=clean_metadata) |
|
|
|
|
|
payload = { |
|
"id": id, |
|
"call_type": call_type, |
|
"cache_hit": cache_hit, |
|
"startTime": start_time, |
|
"endTime": end_time, |
|
"responseTime (seconds)": response_time, |
|
"model": kwargs.get("model", ""), |
|
"user": kwargs.get("user", ""), |
|
"modelParameters": optional_params, |
|
"spend": kwargs.get("response_cost", 0), |
|
"messages": messages, |
|
"response": response_obj, |
|
"usage": usage, |
|
"metadata": clean_metadata, |
|
} |
|
logfire_openai = logfire.with_settings(custom_scope_suffix="openai") |
|
message_template, span_data = self._get_span_config(payload) |
|
if level == LogfireLevel.INFO: |
|
logfire_openai.info( |
|
message_template, |
|
**span_data, |
|
) |
|
elif level == LogfireLevel.ERROR: |
|
logfire_openai.error( |
|
message_template, |
|
**span_data, |
|
_exc_info=True, |
|
) |
|
print_verbose(f"\ndd Logger - Logging payload = {payload}") |
|
|
|
print_verbose( |
|
f"Logfire Layer Logging - final response object: {response_obj}" |
|
) |
|
except Exception as e: |
|
verbose_logger.debug( |
|
f"Logfire Layer Error - {str(e)}\n{traceback.format_exc()}" |
|
) |
|
pass |
|
|