87 lines
2.9 KiB
Python
Raw Permalink Normal View History

2023-04-28 22:40:46 -07:00
import time
from collections.abc import Callable
from collections.abc import Generator
2023-09-05 22:32:00 -07:00
from collections.abc import Iterator
2023-11-07 14:21:04 -08:00
from functools import wraps
2023-05-12 20:37:52 -07:00
from typing import Any
2023-05-21 13:24:25 -07:00
from typing import cast
from typing import TypeVar
2023-04-28 22:40:46 -07:00
2024-12-13 09:48:43 -08:00
from onyx.utils.logger import setup_logger
from onyx.utils.telemetry import optional_telemetry
from onyx.utils.telemetry import RecordType
2023-04-28 22:40:46 -07:00
logger = setup_logger()
F = TypeVar("F", bound=Callable)
2023-09-05 22:32:00 -07:00
FG = TypeVar("FG", bound=Callable[..., Generator | Iterator])
2023-04-28 22:40:46 -07:00
2023-12-24 17:39:37 -08:00
def log_function_time(
func_name: str | None = None,
print_only: bool = False,
debug_only: bool = False,
include_args: bool = False,
2023-12-24 17:39:37 -08:00
) -> Callable[[F], F]:
2023-11-07 14:21:04 -08:00
def decorator(func: F) -> F:
@wraps(func)
2023-05-12 20:37:52 -07:00
def wrapped_func(*args: Any, **kwargs: Any) -> Any:
2023-04-28 22:40:46 -07:00
start_time = time.time()
2024-02-04 13:41:19 -08:00
user = kwargs.get("user")
2023-04-28 22:40:46 -07:00
result = func(*args, **kwargs)
elapsed_time = time.time() - start_time
elapsed_time_str = f"{elapsed_time:.3f}"
2023-11-16 09:22:36 -08:00
log_name = func_name or func.__name__
args_str = f" args={args} kwargs={kwargs}" if include_args else ""
final_log = f"{log_name}{args_str} took {elapsed_time_str} seconds"
if debug_only:
logger.debug(final_log)
else:
2024-08-18 21:53:40 -07:00
# These are generally more important logs so the level is a bit higher
logger.notice(final_log)
2023-12-24 17:39:37 -08:00
if not print_only:
optional_telemetry(
record_type=RecordType.LATENCY,
data={"function": log_name, "latency": str(elapsed_time_str)},
2024-02-04 13:41:19 -08:00
user_id=str(user.id) if user else "Unknown",
2023-12-24 17:39:37 -08:00
)
2023-04-28 22:40:46 -07:00
return result
2023-05-21 13:24:25 -07:00
return cast(F, wrapped_func)
2023-04-28 22:40:46 -07:00
2023-11-07 14:21:04 -08:00
return decorator
2023-12-24 17:39:37 -08:00
def log_generator_function_time(
func_name: str | None = None, print_only: bool = False
) -> Callable[[FG], FG]:
2023-11-07 14:21:04 -08:00
def decorator(func: FG) -> FG:
@wraps(func)
def wrapped_func(*args: Any, **kwargs: Any) -> Any:
start_time = time.time()
2024-02-04 13:41:19 -08:00
user = kwargs.get("user")
2023-11-07 14:21:04 -08:00
gen = func(*args, **kwargs)
try:
value = next(gen)
while True:
yield value
value = next(gen)
except StopIteration:
pass
finally:
2023-11-16 09:22:36 -08:00
elapsed_time_str = str(time.time() - start_time)
log_name = func_name or func.__name__
logger.info(f"{log_name} took {elapsed_time_str} seconds")
2023-12-24 17:39:37 -08:00
if not print_only:
optional_telemetry(
record_type=RecordType.LATENCY,
data={"function": log_name, "latency": str(elapsed_time_str)},
2024-02-04 13:41:19 -08:00
user_id=str(user.id) if user else "Unknown",
2023-12-24 17:39:37 -08:00
)
return cast(FG, wrapped_func)
2023-11-07 14:21:04 -08:00
return decorator