Skip to content

Commit

Permalink
API: Add request logging
Browse files Browse the repository at this point in the history
Log all the parts of a request if the config flag is set. The logged
fields are all server side anyways, so nothing is being exposed to
clients.

Signed-off-by: kingbri <[email protected]>
  • Loading branch information
kingbri1 committed Jul 23, 2024
1 parent 522999e commit 3826815
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 28 deletions.
5 changes: 1 addition & 4 deletions common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ def from_args(args: dict):
cur_logging_config = logging_config()
GLOBAL_CONFIG["logging"] = {
**cur_logging_config,
**{
k.replace("log_", ""): logging_override[k]
for k in logging_override
},
**{k.replace("log_", ""): logging_override[k] for k in logging_override},
}

developer_override = args.get("developer")
Expand Down
32 changes: 31 additions & 1 deletion common/networking.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Common utility functions"""

import asyncio
import json
import socket
import traceback
from fastapi import HTTPException, Request
from fastapi import Depends, HTTPException, Request
from loguru import logger
from pydantic import BaseModel
from typing import Optional
Expand Down Expand Up @@ -108,3 +109,32 @@ async def add_request_id(request: Request):

request.state.id = uuid4().hex
return request


async def log_request(request: Request):
"""FastAPI depends to log a request to the user."""

log_message = [f"Information for {request.method} request {request.state.id}:"]

log_message.append(f"URL: {request.url}")
log_message.append(f"Headers: {dict(request.headers)}")

if request.method != "GET":
body_bytes = await request.body()
if body_bytes:
body = json.loads(body_bytes.decode("utf-8"))

log_message.append(f"Body: {dict(body)}")

logger.info("\n".join(log_message))


def get_global_depends():
"""Returns global dependencies for a FastAPI app."""

depends = [Depends(add_request_id)]

if config.logging_config().get("requests"):
depends.append(Depends(log_request))

return depends
4 changes: 4 additions & 0 deletions config_sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ logging:
# Enable generation parameter logging (default: False)
generation_params: False

# Enable request logging (default: False)
# NOTE: Only use this for debugging!
requests: False

# Options for sampling
sampling:
# Override preset name. Find this in the sampler-overrides folder (default: None)
Expand Down
48 changes: 25 additions & 23 deletions endpoints/server.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
import uvicorn
from fastapi import Depends, FastAPI
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from loguru import logger

from common.logger import UVICORN_LOG_CONFIG
from common.networking import add_request_id
from common.networking import get_global_depends
from endpoints.OAI.router import router as OAIRouter

app = FastAPI(
title="TabbyAPI",
summary="An OAI compatible exllamav2 API that's both lightweight and fast",
description=(
"This docs page is not meant to send requests! Please use a service "
"like Postman or a frontend UI."
),
dependencies=[Depends(add_request_id)],
)

# ALlow CORS requests
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)


def setup_app():
"""Includes the correct routers for startup"""

app = FastAPI(
title="TabbyAPI",
summary="An OAI compatible exllamav2 API that's both lightweight and fast",
description=(
"This docs page is not meant to send requests! Please use a service "
"like Postman or a frontend UI."
),
dependencies=get_global_depends(),
)

# ALlow CORS requests
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

app.include_router(OAIRouter)

return app


def export_openapi():
"""Function to return the OpenAPI JSON from the API server"""

setup_app()
app = setup_app()
return app.openapi()


Expand All @@ -49,7 +51,7 @@ async def start_api(host: str, port: int):
logger.info(f"Chat completions: http://{host}:{port}/v1/chat/completions")

# Setup app
setup_app()
app = setup_app()

config = uvicorn.Config(
app,
Expand Down

0 comments on commit 3826815

Please sign in to comment.