Skip to content

Commit 4c4e8df

Browse files
authored
Log request times and content lengths (#570)
1 parent 14e7376 commit 4c4e8df

File tree

7 files changed

+76
-3
lines changed

7 files changed

+76
-3
lines changed

libraries/python/semantic-workbench-assistant/semantic_workbench_assistant/assistant_service.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from starlette.exceptions import HTTPException as StarletteHTTPException
4141

4242
from . import auth, settings
43+
from .logging_config import log_request_middleware
4344

4445
logger = logging.getLogger(__name__)
4546

@@ -129,7 +130,7 @@ async def _ping_semantic_workbench(self, client: workbench_service_client.Assist
129130
name=self.service_name,
130131
description=self.service_description,
131132
url=HttpUrl(settings.callback_url),
132-
online_expires_in_seconds=settings.workbench_service_ping_interval_seconds * 2.5,
133+
online_expires_in_seconds=settings.workbench_service_ping_interval_seconds * 3.5,
133134
),
134135
)
135136

@@ -292,6 +293,7 @@ def _assistant_service_api(
292293
exclude_paths=set(settings.anonymous_paths),
293294
)
294295
app.add_middleware(asgi_correlation_id.CorrelationIdMiddleware)
296+
app.middleware("http")(log_request_middleware())
295297

296298
@app.exception_handler(StarletteHTTPException)
297299
async def custom_http_exception_handler(request: Request, exc: StarletteHTTPException) -> Response:

libraries/python/semantic-workbench-assistant/semantic_workbench_assistant/logging_config.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import logging
22
import logging.config
33
import re
4+
from time import perf_counter
5+
from typing import Awaitable, Callable
46

57
import asgi_correlation_id
8+
from fastapi import Request, Response
69
from pydantic_settings import BaseSettings
710
from pythonjsonlogger import json as jsonlogger
811

@@ -141,3 +144,31 @@ def config(settings: LoggingSettings):
141144
},
142145
},
143146
})
147+
148+
149+
def log_request_middleware(
150+
logger: logging.Logger | None = None,
151+
) -> Callable[[Request, Callable[[Request], Awaitable[Response]]], Awaitable[Response]]:
152+
access_logger = logger or logging.getLogger("access_log")
153+
154+
async def middleware(request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
155+
"""
156+
This middleware will log all requests and their processing time.
157+
E.g. log:
158+
0.0.0.0:1234 - "GET /ping HTTP/1.1" 200 OK 1.00ms 0b
159+
"""
160+
url = f"{request.url.path}?{request.query_params}" if request.query_params else request.url.path
161+
start_time = perf_counter()
162+
response = await call_next(request)
163+
process_time = (perf_counter() - start_time) * 1000
164+
formatted_process_time = "{0:.2f}".format(process_time)
165+
host = getattr(getattr(request, "client", None), "host", None)
166+
port = getattr(getattr(request, "client", None), "port", None)
167+
http_version = f"HTTP/{request.scope.get('http_version', '1.1')}"
168+
content_length = response.headers.get("content-length", 0)
169+
access_logger.info(
170+
f'{host}:{port} - "{request.method} {url} {http_version}" {response.status_code} {formatted_process_time}ms {content_length}b',
171+
)
172+
return response
173+
174+
return middleware

libraries/python/semantic-workbench-assistant/semantic_workbench_assistant/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Settings(BaseSettings):
1616

1717
workbench_service_url: HttpUrl = HttpUrl("http://127.0.0.1:3000")
1818
workbench_service_api_key: str = ""
19-
workbench_service_ping_interval_seconds: float = 20.0
19+
workbench_service_ping_interval_seconds: float = 30.0
2020

2121
assistant_service_id: str | None = None
2222
assistant_service_name: str | None = None

libraries/python/semantic-workbench-assistant/semantic_workbench_assistant/start.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def main():
9595
host=settings.host,
9696
port=settings.port,
9797
reload=reload,
98+
access_log=False,
9899
log_config={"version": 1, "disable_existing_loggers": False},
99100
)
100101

workbench-service/semantic_workbench_service/logging_config.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import logging
22
import re
3+
from time import perf_counter
4+
from typing import Awaitable, Callable
35

46
import asgi_correlation_id
7+
from fastapi import Request, Response
58
from pydantic_settings import BaseSettings
69
from pythonjsonlogger import json as jsonlogger
710
from rich.logging import RichHandler
@@ -65,3 +68,31 @@ def config(settings: LoggingSettings):
6568
datefmt="[%X]",
6669
handlers=[handler],
6770
)
71+
72+
73+
def log_request_middleware(
74+
logger: logging.Logger | None = None,
75+
) -> Callable[[Request, Callable[[Request], Awaitable[Response]]], Awaitable[Response]]:
76+
access_logger = logger or logging.getLogger("access_log")
77+
78+
async def middleware(request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
79+
"""
80+
This middleware will log all requests and their processing time.
81+
E.g. log:
82+
0.0.0.0:1234 - "GET /ping HTTP/1.1" 200 OK 1.00ms 0b
83+
"""
84+
url = f"{request.url.path}?{request.query_params}" if request.query_params else request.url.path
85+
start_time = perf_counter()
86+
response = await call_next(request)
87+
process_time = (perf_counter() - start_time) * 1000
88+
formatted_process_time = "{0:.2f}".format(process_time)
89+
host = getattr(getattr(request, "client", None), "host", None)
90+
port = getattr(getattr(request, "client", None), "port", None)
91+
http_version = f"HTTP/{request.scope.get('http_version', '1.1')}"
92+
content_length = response.headers.get("content-length", 0)
93+
access_logger.info(
94+
f'{host}:{port} - "{request.method} {url} {http_version}" {response.status_code} {formatted_process_time}ms {content_length}b',
95+
)
96+
return response
97+
98+
return middleware

workbench-service/semantic_workbench_service/service.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
from sse_starlette import EventSourceResponse, ServerSentEvent
8787

8888
from semantic_workbench_service import azure_speech
89+
from semantic_workbench_service.logging_config import log_request_middleware
8990

9091
from . import assistant_api_key, auth, controller, db, files, middleware, settings
9192
from .event import ConversationEventQueueItem
@@ -160,11 +161,15 @@ async def _notify_event(queue_item: ConversationEventQueueItem) -> None:
160161
)
161162

162163
if "user" in queue_item.event_audience:
164+
enqueued_count = 0
163165
async with conversation_sse_queues_lock:
164166
for queue in conversation_sse_queues.get(queue_item.event.conversation_id, {}):
167+
enqueued_count += 1
165168
await queue.put(queue_item.event)
169+
166170
logger.debug(
167-
"enqueued event for SSE; conversation_id: %s, event: %s, event_id: %s",
171+
"enqueued event for SSE; count: %d, conversation_id: %s, event: %s, event_id: %s",
172+
enqueued_count,
168173
queue_item.event.conversation_id,
169174
queue_item.event.event,
170175
queue_item.event.id,
@@ -265,6 +270,8 @@ async def _notify_user_event(event: ConversationEvent) -> None:
265270
)
266271
app.add_middleware(CorrelationIdMiddleware)
267272

273+
app.middleware("http")(log_request_middleware())
274+
268275
user_controller = controller.UserController(get_session=_controller_get_session)
269276
assistant_controller = controller.AssistantController(
270277
get_session=_controller_get_session,

workbench-service/semantic_workbench_service/start.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def main():
4646
app,
4747
host=settings.service.host,
4848
port=settings.service.port,
49+
access_log=False,
4950
log_config={"version": 1, "disable_existing_loggers": False},
5051
)
5152

0 commit comments

Comments
 (0)