From 6e9d7acb9c26a086bf068c278055db25b515f82c Mon Sep 17 00:00:00 2001 From: Weves Date: Sat, 1 Jun 2024 14:55:36 -0700 Subject: [PATCH] Latency logging --- backend/danswer/configs/app_configs.py | 1 + backend/danswer/main.py | 4 ++++ .../server/middleware/latency_logging.py | 23 +++++++++++++++++++ deployment/data/nginx/app.conf.template | 8 +++++++ deployment/data/nginx/app.conf.template.dev | 9 ++++++++ .../nginx/app.conf.template.no-letsencrypt | 8 +++++++ web/src/app/chat/ChatPage.tsx | 3 ++- 7 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 backend/danswer/server/middleware/latency_logging.py diff --git a/backend/danswer/configs/app_configs.py b/backend/danswer/configs/app_configs.py index e33962971..577ef2f0a 100644 --- a/backend/danswer/configs/app_configs.py +++ b/backend/danswer/configs/app_configs.py @@ -251,6 +251,7 @@ LOG_ALL_MODEL_INTERACTIONS = ( LOG_VESPA_TIMING_INFORMATION = ( os.environ.get("LOG_VESPA_TIMING_INFORMATION", "").lower() == "true" ) +LOG_ENDPOINT_LATENCY = os.environ.get("LOG_ENDPOINT_LATENCY", "").lower() == "true" # Anonymous usage telemetry DISABLE_TELEMETRY = os.environ.get("DISABLE_TELEMETRY", "").lower() == "true" diff --git a/backend/danswer/main.py b/backend/danswer/main.py index d717f06a4..e44f1febd 100644 --- a/backend/danswer/main.py +++ b/backend/danswer/main.py @@ -27,6 +27,7 @@ from danswer.configs.app_configs import APP_PORT from danswer.configs.app_configs import AUTH_TYPE from danswer.configs.app_configs import DISABLE_GENERATIVE_AI from danswer.configs.app_configs import DISABLE_INDEX_UPDATE_ON_SWAP +from danswer.configs.app_configs import LOG_ENDPOINT_LATENCY from danswer.configs.app_configs import OAUTH_CLIENT_ID from danswer.configs.app_configs import OAUTH_CLIENT_SECRET from danswer.configs.app_configs import USER_AUTH_SECRET @@ -70,6 +71,7 @@ from danswer.server.manage.llm.api import basic_router as llm_router from danswer.server.manage.secondary_index import router as secondary_index_router from danswer.server.manage.slack_bot import router as slack_bot_management_router from danswer.server.manage.users import router as user_router +from danswer.server.middleware.latency_logging import add_latency_logging_middleware from danswer.server.query_and_chat.chat_backend import router as chat_router from danswer.server.query_and_chat.query_backend import ( admin_router as admin_query_router, @@ -352,6 +354,8 @@ def get_application() -> FastAPI: allow_methods=["*"], allow_headers=["*"], ) + if LOG_ENDPOINT_LATENCY: + add_latency_logging_middleware(application, logger) # Ensure all routes have auth enabled or are explicitly marked as public check_router_auth(application) diff --git a/backend/danswer/server/middleware/latency_logging.py b/backend/danswer/server/middleware/latency_logging.py new file mode 100644 index 000000000..f2bc3127a --- /dev/null +++ b/backend/danswer/server/middleware/latency_logging.py @@ -0,0 +1,23 @@ +import logging +import time +from collections.abc import Awaitable +from collections.abc import Callable + +from fastapi import FastAPI +from fastapi import Request +from fastapi import Response + + +def add_latency_logging_middleware(app: FastAPI, logger: logging.LoggerAdapter) -> None: + @app.middleware("http") + async def log_latency( + request: Request, call_next: Callable[[Request], Awaitable[Response]] + ) -> Response: + start_time = time.monotonic() + response = await call_next(request) + process_time = time.monotonic() - start_time + logger.info( + f"Path: {request.url.path} - Method: {request.method} - " + f"Status Code: {response.status_code} - Time: {process_time:.4f} secs" + ) + return response diff --git a/deployment/data/nginx/app.conf.template b/deployment/data/nginx/app.conf.template index e02d8ff2f..b698c744b 100644 --- a/deployment/data/nginx/app.conf.template +++ b/deployment/data/nginx/app.conf.template @@ -1,3 +1,9 @@ +# Log format to include request latency +log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'rt=$request_time'; + upstream api_server { # fail_timeout=0 means we always retry an upstream even if it failed # to return a good HTTP response @@ -20,6 +26,8 @@ server { client_max_body_size 5G; # Maximum upload size + access_log /var/log/nginx/access.log custom_main; + # Match both /api/* and /openapi.json in a single rule location ~ ^/(api|openapi.json)(/.*)?$ { # Rewrite /api prefixed matched paths diff --git a/deployment/data/nginx/app.conf.template.dev b/deployment/data/nginx/app.conf.template.dev index a0e7237e7..a7a0efa19 100644 --- a/deployment/data/nginx/app.conf.template.dev +++ b/deployment/data/nginx/app.conf.template.dev @@ -1,3 +1,9 @@ +# Override log format to include request latency +log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'rt=$request_time'; + upstream api_server { # fail_timeout=0 means we always retry an upstream even if it failed # to return a good HTTP response @@ -20,6 +26,8 @@ server { client_max_body_size 5G; # Maximum upload size + access_log /var/log/nginx/access.log custom_main; + # Match both /api/* and /openapi.json in a single rule location ~ ^/(api|openapi.json)(/.*)?$ { # Rewrite /api prefixed matched paths @@ -58,3 +66,4 @@ server { proxy_pass http://web_server; } } + diff --git a/deployment/data/nginx/app.conf.template.no-letsencrypt b/deployment/data/nginx/app.conf.template.no-letsencrypt index abf4371fc..4d5096374 100644 --- a/deployment/data/nginx/app.conf.template.no-letsencrypt +++ b/deployment/data/nginx/app.conf.template.no-letsencrypt @@ -1,3 +1,9 @@ +# Log format to include request latency +log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'rt=$request_time'; + upstream api_server { # fail_timeout=0 means we always retry an upstream even if it failed # to return a good HTTP response @@ -20,6 +26,8 @@ server { client_max_body_size 5G; # Maximum upload size + access_log /var/log/nginx/access.log custom_main; + # Match both /api/* and /openapi.json in a single rule location ~ ^/(api|openapi.json)(/.*)?$ { # Rewrite /api prefixed matched paths diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx index bab94e9a9..fa2e090c1 100644 --- a/web/src/app/chat/ChatPage.tsx +++ b/web/src/app/chat/ChatPage.tsx @@ -337,7 +337,8 @@ export function ChatPage({ ) : undefined ); - const livePersona = selectedPersona || filteredAssistants[0]; + const livePersona = + selectedPersona || filteredAssistants[0] || availablePersonas[0]; const [chatSessionSharedStatus, setChatSessionSharedStatus] = useState(ChatSessionSharedStatus.Private);