From e6dd0bfbe0a3cd3eff799146332084fc70e00cb5 Mon Sep 17 00:00:00 2001 From: Self Denial Date: Wed, 20 Mar 2024 17:11:36 -0600 Subject: [PATCH] Migrate to python logging module with env var control. --- backend/apps/audio/main.py | 12 +++-- backend/apps/images/main.py | 9 ++-- backend/apps/litellm/main.py | 9 +++- backend/apps/ollama/main.py | 69 +++++++++++++++------------- backend/apps/openai/main.py | 21 +++++---- backend/apps/rag/main.py | 24 ++++++---- backend/apps/rag/utils.py | 10 ++-- backend/apps/web/internal/db.py | 7 ++- backend/apps/web/models/auths.py | 9 +++- backend/apps/web/models/documents.py | 9 +++- backend/apps/web/models/tags.py | 13 ++++-- backend/apps/web/routers/chats.py | 9 +++- backend/apps/web/routers/users.py | 7 ++- backend/config.py | 38 +++++++++++++-- backend/main.py | 10 +++- 15 files changed, 174 insertions(+), 82 deletions(-) diff --git a/backend/apps/audio/main.py b/backend/apps/audio/main.py index d8cb415fc..10cc56716 100644 --- a/backend/apps/audio/main.py +++ b/backend/apps/audio/main.py @@ -1,4 +1,5 @@ import os +import logging from fastapi import ( FastAPI, Request, @@ -21,7 +22,10 @@ from utils.utils import ( ) from utils.misc import calculate_sha256 -from config import CACHE_DIR, UPLOAD_DIR, WHISPER_MODEL, WHISPER_MODEL_DIR +from config import SRC_LOG_LEVELS, CACHE_DIR, UPLOAD_DIR, WHISPER_MODEL, WHISPER_MODEL_DIR + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["AUDIO"]) app = FastAPI() app.add_middleware( @@ -38,7 +42,7 @@ def transcribe( file: UploadFile = File(...), user=Depends(get_current_user), ): - print(file.content_type) + log.info(f"file.content_type: {file.content_type}") if file.content_type not in ["audio/mpeg", "audio/wav"]: raise HTTPException( @@ -62,7 +66,7 @@ def transcribe( ) segments, info = model.transcribe(file_path, beam_size=5) - print( + log.info( "Detected language '%s' with probability %f" % (info.language, info.language_probability) ) @@ -72,7 +76,7 @@ def transcribe( return {"text": transcript.strip()} except Exception as e: - print(e) + log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/backend/apps/images/main.py b/backend/apps/images/main.py index e14b0f6a7..7be7c8f59 100644 --- a/backend/apps/images/main.py +++ b/backend/apps/images/main.py @@ -25,9 +25,12 @@ from pathlib import Path import uuid import base64 import json +import logging -from config import CACHE_DIR, AUTOMATIC1111_BASE_URL +from config import SRC_LOG_LEVELS, CACHE_DIR, AUTOMATIC1111_BASE_URL +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["IMAGES"]) IMAGE_CACHE_DIR = Path(CACHE_DIR).joinpath("./image/generations/") IMAGE_CACHE_DIR.mkdir(parents=True, exist_ok=True) @@ -268,7 +271,7 @@ def save_b64_image(b64_str): return image_id except Exception as e: - print(f"Error saving image: {e}") + log.error(f"Error saving image: {e}") return None @@ -341,7 +344,7 @@ def generate_image( res = r.json() - print(res) + log.debug(f"res: {res}") images = [] diff --git a/backend/apps/litellm/main.py b/backend/apps/litellm/main.py index 21b9e58a7..9dc5d6f2c 100644 --- a/backend/apps/litellm/main.py +++ b/backend/apps/litellm/main.py @@ -1,10 +1,15 @@ +import logging + from litellm.proxy.proxy_server import ProxyConfig, initialize from litellm.proxy.proxy_server import app from fastapi import FastAPI, Request, Depends, status from fastapi.responses import JSONResponse from utils.utils import get_http_authorization_cred, get_current_user -from config import ENV +from config import SRC_LOG_LEVELS, ENV + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["LITELLM"]) proxy_config = ProxyConfig() @@ -33,7 +38,7 @@ async def auth_middleware(request: Request, call_next): if ENV != "dev": try: user = get_current_user(get_http_authorization_cred(auth_header)) - print(user) + log.debug(f"user: {user}") except Exception as e: return JSONResponse(status_code=400, content={"detail": str(e)}) diff --git a/backend/apps/ollama/main.py b/backend/apps/ollama/main.py index 154be97c9..777203e55 100644 --- a/backend/apps/ollama/main.py +++ b/backend/apps/ollama/main.py @@ -11,14 +11,17 @@ import json import uuid import aiohttp import asyncio +import logging from apps.web.models.users import Users from constants import ERROR_MESSAGES from utils.utils import decode_token, get_current_user, get_admin_user -from config import OLLAMA_BASE_URLS, MODEL_FILTER_ENABLED, MODEL_FILTER_LIST +from config import SRC_LOG_LEVELS, OLLAMA_BASE_URLS, MODEL_FILTER_ENABLED, MODEL_FILTER_LIST from typing import Optional, List, Union +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["OLLAMA"]) app = FastAPI() app.add_middleware( @@ -69,7 +72,7 @@ class UrlUpdateForm(BaseModel): async def update_ollama_api_url(form_data: UrlUpdateForm, user=Depends(get_admin_user)): app.state.OLLAMA_BASE_URLS = form_data.urls - print(app.state.OLLAMA_BASE_URLS) + log.info(f"app.state.OLLAMA_BASE_URLS: {app.state.OLLAMA_BASE_URLS}") return {"OLLAMA_BASE_URLS": app.state.OLLAMA_BASE_URLS} @@ -90,7 +93,7 @@ async def fetch_url(url): return await response.json() except Exception as e: # Handle connection error here - print(f"Connection error: {e}") + log.error(f"Connection error: {e}") return None @@ -114,7 +117,7 @@ def merge_models_lists(model_lists): async def get_all_models(): - print("get_all_models") + log.info("get_all_models()") tasks = [fetch_url(f"{url}/api/tags") for url in app.state.OLLAMA_BASE_URLS] responses = await asyncio.gather(*tasks) @@ -155,7 +158,7 @@ async def get_ollama_tags( return r.json() except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -201,7 +204,7 @@ async def get_ollama_versions(url_idx: Optional[int] = None): return r.json() except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -227,7 +230,7 @@ async def pull_model( form_data: ModelNameForm, url_idx: int = 0, user=Depends(get_admin_user) ): url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") r = None @@ -260,7 +263,7 @@ async def pull_model( try: return await run_in_threadpool(get_request) except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -299,7 +302,7 @@ async def push_model( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.debug(f"url: {url}") r = None @@ -331,7 +334,7 @@ async def push_model( try: return await run_in_threadpool(get_request) except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -359,9 +362,9 @@ class CreateModelForm(BaseModel): async def create_model( form_data: CreateModelForm, url_idx: int = 0, user=Depends(get_admin_user) ): - print(form_data) + log.debug(f"form_data: {form_data}") url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") r = None @@ -383,7 +386,7 @@ async def create_model( r.raise_for_status() - print(r) + log.debug(f"r: {r}") return StreamingResponse( stream_content(), @@ -396,7 +399,7 @@ async def create_model( try: return await run_in_threadpool(get_request) except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -434,7 +437,7 @@ async def copy_model( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") try: r = requests.request( @@ -444,11 +447,11 @@ async def copy_model( ) r.raise_for_status() - print(r.text) + log.debug(f"r.text: {r.text}") return True except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -481,7 +484,7 @@ async def delete_model( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") try: r = requests.request( @@ -491,11 +494,11 @@ async def delete_model( ) r.raise_for_status() - print(r.text) + log.debug(f"r.text: {r.text}") return True except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -521,7 +524,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_current_use url_idx = random.choice(app.state.MODELS[form_data.name]["urls"]) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") try: r = requests.request( @@ -533,7 +536,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_current_use return r.json() except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -573,7 +576,7 @@ async def generate_embeddings( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") try: r = requests.request( @@ -585,7 +588,7 @@ async def generate_embeddings( return r.json() except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -633,7 +636,7 @@ async def generate_completion( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") r = None @@ -654,7 +657,7 @@ async def generate_completion( if request_id in REQUEST_POOL: yield chunk else: - print("User: canceled request") + log.warning("User: canceled request") break finally: if hasattr(r, "close"): @@ -731,11 +734,11 @@ async def generate_chat_completion( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") r = None - print(form_data.model_dump_json(exclude_none=True).encode()) + log.debug("form_data.model_dump_json(exclude_none=True).encode(): {0} ".format(form_data.model_dump_json(exclude_none=True).encode())) def get_request(): nonlocal form_data @@ -754,7 +757,7 @@ async def generate_chat_completion( if request_id in REQUEST_POOL: yield chunk else: - print("User: canceled request") + log.warning("User: canceled request") break finally: if hasattr(r, "close"): @@ -777,7 +780,7 @@ async def generate_chat_completion( headers=dict(r.headers), ) except Exception as e: - print(e) + log.exception(e) raise e try: @@ -831,7 +834,7 @@ async def generate_openai_chat_completion( ) url = app.state.OLLAMA_BASE_URLS[url_idx] - print(url) + log.info(f"url: {url}") r = None @@ -854,7 +857,7 @@ async def generate_openai_chat_completion( if request_id in REQUEST_POOL: yield chunk else: - print("User: canceled request") + log.warning("User: canceled request") break finally: if hasattr(r, "close"): @@ -947,7 +950,7 @@ async def deprecated_proxy(path: str, request: Request, user=Depends(get_current if request_id in REQUEST_POOL: yield chunk else: - print("User: canceled request") + log.warning("User: canceled request") break finally: if hasattr(r, "close"): diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index 67a99794c..4098d73a5 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -6,6 +6,7 @@ import requests import aiohttp import asyncio import json +import logging from pydantic import BaseModel @@ -19,6 +20,7 @@ from utils.utils import ( get_admin_user, ) from config import ( + SRC_LOG_LEVELS, OPENAI_API_BASE_URLS, OPENAI_API_KEYS, CACHE_DIR, @@ -31,6 +33,9 @@ from typing import List, Optional import hashlib from pathlib import Path +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["OPENAI"]) + app = FastAPI() app.add_middleware( CORSMiddleware, @@ -134,7 +139,7 @@ async def speech(request: Request, user=Depends(get_verified_user)): return FileResponse(file_path) except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -160,7 +165,7 @@ async def fetch_url(url, key): return await response.json() except Exception as e: # Handle connection error here - print(f"Connection error: {e}") + log.error(f"Connection error: {e}") return None @@ -182,7 +187,7 @@ def merge_models_lists(model_lists): async def get_all_models(): - print("get_all_models") + log.info("get_all_models()") if len(app.state.OPENAI_API_KEYS) == 1 and app.state.OPENAI_API_KEYS[0] == "": models = {"data": []} @@ -208,7 +213,7 @@ async def get_all_models(): ) } - print(models) + log.info(f"models: {models}") app.state.MODELS = {model["id"]: model for model in models["data"]} return models @@ -246,7 +251,7 @@ async def get_models(url_idx: Optional[int] = None, user=Depends(get_current_use return response_data except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: @@ -280,7 +285,7 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): if body.get("model") == "gpt-4-vision-preview": if "max_tokens" not in body: body["max_tokens"] = 4000 - print("Modified body_dict:", body) + log.debug("Modified body_dict:", body) # Fix for ChatGPT calls failing because the num_ctx key is in body if "num_ctx" in body: @@ -292,7 +297,7 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): # Convert the modified body back to JSON body = json.dumps(body) except json.JSONDecodeError as e: - print("Error loading request body into a dictionary:", e) + log.error("Error loading request body into a dictionary:", e) url = app.state.OPENAI_API_BASE_URLS[idx] key = app.state.OPENAI_API_KEYS[idx] @@ -330,7 +335,7 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): response_data = r.json() return response_data except Exception as e: - print(e) + log.exception(e) error_detail = "Open WebUI: Server Connection Error" if r is not None: try: diff --git a/backend/apps/rag/main.py b/backend/apps/rag/main.py index 5fc38b4a8..d8145f124 100644 --- a/backend/apps/rag/main.py +++ b/backend/apps/rag/main.py @@ -8,7 +8,7 @@ from fastapi import ( Form, ) from fastapi.middleware.cors import CORSMiddleware -import os, shutil +import os, shutil, logging from pathlib import Path from typing import List @@ -54,6 +54,7 @@ from utils.misc import ( ) from utils.utils import get_current_user, get_admin_user from config import ( + SRC_LOG_LEVELS, UPLOAD_DIR, DOCS_DIR, RAG_EMBEDDING_MODEL, @@ -66,6 +67,9 @@ from config import ( from constants import ERROR_MESSAGES +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["RAG"]) + # # if RAG_EMBEDDING_MODEL: # sentence_transformer_ef = SentenceTransformer( @@ -124,7 +128,7 @@ def store_data_in_vector_db(data, collection_name, overwrite: bool = False) -> b if overwrite: for collection in CHROMA_CLIENT.list_collections(): if collection_name == collection.name: - print(f"deleting existing collection {collection_name}") + log.info(f"deleting existing collection {collection_name}") CHROMA_CLIENT.delete_collection(name=collection_name) collection = CHROMA_CLIENT.create_collection( @@ -137,7 +141,7 @@ def store_data_in_vector_db(data, collection_name, overwrite: bool = False) -> b ) return True except Exception as e: - print(e) + log.exception(e) if e.__class__.__name__ == "UniqueConstraintError": return True @@ -274,7 +278,7 @@ def query_doc_handler( embedding_function=app.state.sentence_transformer_ef, ) except Exception as e: - print(e) + log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT(e), @@ -318,7 +322,7 @@ def store_web(form_data: StoreWebForm, user=Depends(get_current_user)): "filename": form_data.url, } except Exception as e: - print(e) + log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT(e), @@ -416,7 +420,7 @@ def store_doc( ): # "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm" - print(file.content_type) + log.info(f"file.content_type: {file.content_type}") try: filename = file.filename file_path = f"{UPLOAD_DIR}/{filename}" @@ -447,7 +451,7 @@ def store_doc( detail=ERROR_MESSAGES.DEFAULT(), ) except Exception as e: - print(e) + log.exception(e) if "No pandoc was found" in str(e): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -512,7 +516,7 @@ def scan_docs_dir(user=Depends(get_admin_user)): ) except Exception as e: - print(e) + log.exception(e) return True @@ -533,11 +537,11 @@ def reset(user=Depends(get_admin_user)) -> bool: elif os.path.isdir(file_path): shutil.rmtree(file_path) except Exception as e: - print("Failed to delete %s. Reason: %s" % (file_path, e)) + log.error("Failed to delete %s. Reason: %s" % (file_path, e)) try: CHROMA_CLIENT.reset() except Exception as e: - print(e) + log.exception(e) return True diff --git a/backend/apps/rag/utils.py b/backend/apps/rag/utils.py index a3537d4d3..e792970c8 100644 --- a/backend/apps/rag/utils.py +++ b/backend/apps/rag/utils.py @@ -1,7 +1,11 @@ import re +import logging from typing import List -from config import CHROMA_CLIENT +from config import SRC_LOG_LEVELS, CHROMA_CLIENT + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["RAG"]) def query_doc(collection_name: str, query: str, k: int, embedding_function): @@ -97,7 +101,7 @@ def rag_template(template: str, context: str, query: str): def rag_messages(docs, messages, template, k, embedding_function): - print(docs) + log.debug(f"docs: {docs}") last_user_message_idx = None for i in range(len(messages) - 1, -1, -1): @@ -145,7 +149,7 @@ def rag_messages(docs, messages, template, k, embedding_function): embedding_function=embedding_function, ) except Exception as e: - print(e) + log.exception(e) context = None relevant_contexts.append(context) diff --git a/backend/apps/web/internal/db.py b/backend/apps/web/internal/db.py index d0aa99695..554f8002d 100644 --- a/backend/apps/web/internal/db.py +++ b/backend/apps/web/internal/db.py @@ -1,13 +1,16 @@ from peewee import * -from config import DATA_DIR +from config import SRC_LOG_LEVELS, DATA_DIR import os +import logging +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["DB"]) # Check if the file exists if os.path.exists(f"{DATA_DIR}/ollama.db"): # Rename the file os.rename(f"{DATA_DIR}/ollama.db", f"{DATA_DIR}/webui.db") - print("File renamed successfully.") + log.info("File renamed successfully.") else: pass diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index 02d2ab861..b26236ef8 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -2,6 +2,7 @@ from pydantic import BaseModel from typing import List, Union, Optional import time import uuid +import logging from peewee import * from apps.web.models.users import UserModel, Users @@ -9,6 +10,10 @@ from utils.utils import verify_password from apps.web.internal.db import DB +from config import SRC_LOG_LEVELS +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MODELS"]) + #################### # DB MODEL #################### @@ -86,7 +91,7 @@ class AuthsTable: def insert_new_auth( self, email: str, password: str, name: str, role: str = "pending" ) -> Optional[UserModel]: - print("insert_new_auth") + log.info("insert_new_auth") id = str(uuid.uuid4()) @@ -103,7 +108,7 @@ class AuthsTable: return None def authenticate_user(self, email: str, password: str) -> Optional[UserModel]: - print("authenticate_user", email) + log.info(f"authenticate_user: {email}") try: auth = Auth.get(Auth.email == email, Auth.active == True) if auth: diff --git a/backend/apps/web/models/documents.py b/backend/apps/web/models/documents.py index 6a372b2c2..f399e7ae4 100644 --- a/backend/apps/web/models/documents.py +++ b/backend/apps/web/models/documents.py @@ -3,6 +3,7 @@ from peewee import * from playhouse.shortcuts import model_to_dict from typing import List, Union, Optional import time +import logging from utils.utils import decode_token from utils.misc import get_gravatar_url @@ -11,6 +12,10 @@ from apps.web.internal.db import DB import json +from config import SRC_LOG_LEVELS +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MODELS"]) + #################### # Documents DB Schema #################### @@ -118,7 +123,7 @@ class DocumentsTable: doc = Document.get(Document.name == form_data.name) return DocumentModel(**model_to_dict(doc)) except Exception as e: - print(e) + log.exception(e) return None def update_doc_content_by_name( @@ -138,7 +143,7 @@ class DocumentsTable: doc = Document.get(Document.name == name) return DocumentModel(**model_to_dict(doc)) except Exception as e: - print(e) + log.exception(e) return None def delete_doc_by_name(self, name: str) -> bool: diff --git a/backend/apps/web/models/tags.py b/backend/apps/web/models/tags.py index d42645015..476e6693d 100644 --- a/backend/apps/web/models/tags.py +++ b/backend/apps/web/models/tags.py @@ -6,9 +6,14 @@ from playhouse.shortcuts import model_to_dict import json import uuid import time +import logging from apps.web.internal.db import DB +from config import SRC_LOG_LEVELS +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MODELS"]) + #################### # Tag DB Schema #################### @@ -173,7 +178,7 @@ class TagTable: (ChatIdTag.tag_name == tag_name) & (ChatIdTag.user_id == user_id) ) res = query.execute() # Remove the rows, return number of rows removed. - print(res) + log.debug(f"res: {res}") tag_count = self.count_chat_ids_by_tag_name_and_user_id(tag_name, user_id) if tag_count == 0: @@ -185,7 +190,7 @@ class TagTable: return True except Exception as e: - print("delete_tag", e) + log.error(f"delete_tag: {e}") return False def delete_tag_by_tag_name_and_chat_id_and_user_id( @@ -198,7 +203,7 @@ class TagTable: & (ChatIdTag.user_id == user_id) ) res = query.execute() # Remove the rows, return number of rows removed. - print(res) + log.debug(f"res: {res}") tag_count = self.count_chat_ids_by_tag_name_and_user_id(tag_name, user_id) if tag_count == 0: @@ -210,7 +215,7 @@ class TagTable: return True except Exception as e: - print("delete_tag", e) + log.error(f"delete_tag: {e}") return False def delete_tags_by_chat_id_and_user_id(self, chat_id: str, user_id: str) -> bool: diff --git a/backend/apps/web/routers/chats.py b/backend/apps/web/routers/chats.py index 0c0ac1ce8..d018b31be 100644 --- a/backend/apps/web/routers/chats.py +++ b/backend/apps/web/routers/chats.py @@ -5,6 +5,7 @@ from utils.utils import get_current_user, get_admin_user from fastapi import APIRouter from pydantic import BaseModel import json +import logging from apps.web.models.users import Users from apps.web.models.chats import ( @@ -27,6 +28,10 @@ from apps.web.models.tags import ( from constants import ERROR_MESSAGES +from config import SRC_LOG_LEVELS +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MODELS"]) + router = APIRouter() ############################ @@ -78,7 +83,7 @@ async def create_new_chat(form_data: ChatForm, user=Depends(get_current_user)): chat = Chats.insert_new_chat(user.id, form_data) return ChatResponse(**{**chat.model_dump(), "chat": json.loads(chat.chat)}) except Exception as e: - print(e) + log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT() ) @@ -95,7 +100,7 @@ async def get_all_tags(user=Depends(get_current_user)): tags = Tags.get_tags_by_user_id(user.id) return tags except Exception as e: - print(e) + log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT() ) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index b8e2732c8..67c136daa 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -7,6 +7,7 @@ from fastapi import APIRouter from pydantic import BaseModel import time import uuid +import logging from apps.web.models.users import UserModel, UserUpdateForm, UserRoleUpdateForm, Users from apps.web.models.auths import Auths @@ -14,6 +15,10 @@ from apps.web.models.auths import Auths from utils.utils import get_current_user, get_password_hash, get_admin_user from constants import ERROR_MESSAGES +from config import SRC_LOG_LEVELS +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MODELS"]) + router = APIRouter() ############################ @@ -83,7 +88,7 @@ async def update_user_by_id( if form_data.password: hashed = get_password_hash(form_data.password) - print(hashed) + log.debug(f"hashed: {hashed}") Auths.update_user_password_by_id(user_id, hashed) Auths.update_email_by_id(user_id, form_data.email.lower()) diff --git a/backend/config.py b/backend/config.py index 099f726ca..6d94d2233 100644 --- a/backend/config.py +++ b/backend/config.py @@ -1,4 +1,6 @@ import os +import sys +import logging import chromadb from chromadb import Settings from base64 import b64encode @@ -21,7 +23,7 @@ try: load_dotenv(find_dotenv("../.env")) except ImportError: - print("dotenv not installed, skipping...") + log.warning("dotenv not installed, skipping...") WEBUI_NAME = "Open WebUI" shutil.copyfile("../build/favicon.png", "./static/favicon.png") @@ -100,6 +102,34 @@ for version in soup.find_all("h2"): CHANGELOG = changelog_json +#################################### +# LOGGING +#################################### +log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] + +GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper() +if GLOBAL_LOG_LEVEL in log_levels: + logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True) +else: + GLOBAL_LOG_LEVEL = "INFO" + +log = logging.getLogger(__name__) +log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}") + +log_sources = ["AUDIO", "CONFIG", "DB", "IMAGES", "LITELLM", "MAIN", "MODELS", "OLLAMA", "OPENAI", "RAG"] + +SRC_LOG_LEVELS = {} + +for source in log_sources: + log_env_var = source + "_LOG_LEVEL" + SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper() + if SRC_LOG_LEVELS[source] not in log_levels: + SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL + log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}") + +log.setLevel(SRC_LOG_LEVELS["CONFIG"]) + + #################################### # CUSTOM_NAME #################################### @@ -125,7 +155,7 @@ if CUSTOM_NAME: WEBUI_NAME = data["name"] except Exception as e: - print(e) + log.exception(e) pass @@ -194,9 +224,9 @@ def create_config_file(file_path): LITELLM_CONFIG_PATH = f"{DATA_DIR}/litellm/config.yaml" if not os.path.exists(LITELLM_CONFIG_PATH): - print("Config file doesn't exist. Creating...") + log.info("Config file doesn't exist. Creating...") create_config_file(LITELLM_CONFIG_PATH) - print("Config file created successfully.") + log.info("Config file created successfully.") #################################### diff --git a/backend/main.py b/backend/main.py index 253227182..24989c814 100644 --- a/backend/main.py +++ b/backend/main.py @@ -4,6 +4,7 @@ import markdown import time import os import sys +import logging import requests from fastapi import FastAPI, Request, Depends, status @@ -38,9 +39,14 @@ from config import ( FRONTEND_BUILD_DIR, MODEL_FILTER_ENABLED, MODEL_FILTER_LIST, + GLOBAL_LOG_LEVEL, + SRC_LOG_LEVELS, ) from constants import ERROR_MESSAGES +logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MAIN"]) class SPAStaticFiles(StaticFiles): async def get_response(self, path: str, scope): @@ -66,7 +72,7 @@ class RAGMiddleware(BaseHTTPMiddleware): if request.method == "POST" and ( "/api/chat" in request.url.path or "/chat/completions" in request.url.path ): - print(request.url.path) + log.debug(f"request.url.path: {request.url.path}") # Read the original request body body = await request.body() @@ -89,7 +95,7 @@ class RAGMiddleware(BaseHTTPMiddleware): ) del data["docs"] - print(data["messages"]) + log.debug(f"data['messages']: {data['messages']}") modified_body_bytes = json.dumps(data).encode("utf-8")