新增自定义日志模块,替换全局logging实现;优化日志输出格式与颜色支持

This commit is contained in:
yinpeng
2024-12-16 16:20:53 +08:00
parent 829c1b02ec
commit 56a069dbac
10 changed files with 131 additions and 24 deletions
+2 -1
View File
@@ -15,7 +15,8 @@
"--host", "--host",
"127.0.0.1", "127.0.0.1",
"--port", "--port",
"8000" "8000",
"--no-access-log"
], ],
"jinja": true "jinja": true
} }
+1 -1
View File
@@ -17,4 +17,4 @@ ENV MODEL_SEARCH='["gemini-2.0-flash-exp"]'
EXPOSE 8000 EXPOSE 8000
# Run the application # Run the application
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
+2 -3
View File
@@ -1,6 +1,5 @@
from http.client import HTTPException from http.client import HTTPException
from fastapi import APIRouter, Depends, Header from fastapi import APIRouter, Depends, Header
import logging
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
from app.core.security import SecurityService from app.core.security import SecurityService
@@ -10,9 +9,10 @@ from app.services.chat_service import ChatService
from app.services.embedding_service import EmbeddingService from app.services.embedding_service import EmbeddingService
from app.schemas.request_model import ChatRequest, EmbeddingRequest from app.schemas.request_model import ChatRequest, EmbeddingRequest
from app.core.config import settings from app.core.config import settings
from app.core.logger import get_api_logger
router = APIRouter() router = APIRouter()
logger = logging.getLogger(__name__) logger = get_api_logger()
# 初始化服务 # 初始化服务
security_service = SecurityService(settings.ALLOWED_TOKENS) security_service = SecurityService(settings.ALLOWED_TOKENS)
@@ -59,7 +59,6 @@ async def chat_completion(
tools=request.tools, tools=request.tools,
tool_choice=request.tool_choice, tool_choice=request.tool_choice,
) )
# 处理流式响应 # 处理流式响应
if request.stream: if request.stream:
+105
View File
@@ -0,0 +1,105 @@
import logging
import sys
from typing import Dict, Optional
import platform
# ANSI转义序列颜色代码
COLORS = {
'DEBUG': '\033[34m', # 蓝色
'INFO': '\033[32m', # 绿色
'WARNING': '\033[33m', # 黄色
'ERROR': '\033[31m', # 红色
'CRITICAL': '\033[1;31m' # 红色加粗
}
# Windows系统启用ANSI支持
if platform.system() == 'Windows':
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
class ColoredFormatter(logging.Formatter):
"""
自定义的日志格式化器,添加颜色支持
"""
def format(self, record):
# 获取对应级别的颜色代码
color = COLORS.get(record.levelname, '')
# 添加颜色代码和重置代码
record.levelname = f"{color}{record.levelname}\033[0m"
return super().format(record)
# 日志格式
FORMATTER = ColoredFormatter(
"%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s"
)
# 日志级别映射
LOG_LEVELS = {
"debug": logging.DEBUG,
"info": logging.INFO,
"warning": logging.WARNING,
"error": logging.ERROR,
"critical": logging.CRITICAL,
}
class Logger:
_loggers: Dict[str, logging.Logger] = {}
@staticmethod
def setup_logger(
name: str,
level: str = "info",
) -> logging.Logger:
"""
设置并获取logger
:param name: logger名称
:param level: 日志级别
:return: logger实例
"""
if name in Logger._loggers:
return Logger._loggers[name]
logger = logging.getLogger(name)
logger.setLevel(LOG_LEVELS.get(level.lower(), logging.INFO))
logger.propagate = False
# 添加控制台输出
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(FORMATTER)
logger.addHandler(console_handler)
Logger._loggers[name] = logger
return logger
@staticmethod
def get_logger(name: str) -> Optional[logging.Logger]:
"""
获取已存在的logger
:param name: logger名称
:return: logger实例或None
"""
return Logger._loggers.get(name)
# 预定义的loggers
def get_api_logger():
return Logger.setup_logger("api")
def get_chat_logger():
return Logger.setup_logger("chat")
def get_model_logger():
return Logger.setup_logger("model")
def get_security_logger():
return Logger.setup_logger("security")
def get_key_manager_logger():
return Logger.setup_logger("key_manager")
def get_main_logger():
return Logger.setup_logger("main")
def get_embeddings_logger():
return Logger.setup_logger("embeddings")
+2 -2
View File
@@ -1,8 +1,8 @@
from fastapi import HTTPException, Header from fastapi import HTTPException, Header
import logging
from typing import Optional from typing import Optional
from app.core.logger import get_security_logger
logger = logging.getLogger(__name__) logger = get_security_logger()
class SecurityService: class SecurityService:
+2 -5
View File
@@ -1,15 +1,12 @@
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
import logging from app.core.logger import get_main_logger
from app.api.routes import router from app.api.routes import router
import uvicorn import uvicorn
# 配置日志 # 配置日志
logging.basicConfig( logger = get_main_logger()
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
app = FastAPI() app = FastAPI()
+10 -5
View File
@@ -2,12 +2,12 @@ import httpx
import json import json
import time import time
import uuid import uuid
import logging
from typing import Dict, Any, Optional, AsyncGenerator, Union from typing import Dict, Any, Optional, AsyncGenerator, Union
import openai import openai
from app.core.config import settings from app.core.config import settings
from app.core.logger import get_chat_logger
logger = logging.getLogger(__name__) logger = get_chat_logger()
class ChatService: class ChatService:
@@ -170,6 +170,9 @@ class ChatService:
gemini_model = model gemini_model = model
gemini_messages = self.convert_messages_to_gemini_format(messages) gemini_messages = self.convert_messages_to_gemini_format(messages)
if not stream:
# 非流式模式下,移除代码执行工具
tools.remove({"code_execution": {}})
payload = { payload = {
"contents": gemini_messages, "contents": gemini_messages,
"generationConfig": {"temperature": temperature}, "generationConfig": {"temperature": temperature},
@@ -241,7 +244,9 @@ class ChatService:
url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemini_model}:generateContent?key={api_key}" url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemini_model}:generateContent?key={api_key}"
response = await client.post(url, json=payload) response = await client.post(url, json=payload)
if response.status_code != 200: if response.status_code != 200:
raise Exception(f"API error: {response.status_code}") error_text = response.text
error_code = response.status_code
raise Exception(f"API调用错误 - 状态码: {error_code}, 响应内容: {error_text}")
gemini_response = response.json() gemini_response = response.json()
return self.convert_gemini_response_to_openai(gemini_response, model, finish_reason="stop") return self.convert_gemini_response_to_openai(gemini_response, model, finish_reason="stop")
except Exception as e: except Exception as e:
@@ -287,10 +292,10 @@ class ChatService:
language = code_data.get("language", "").lower() language = code_data.get("language", "").lower()
code = code_data.get("code", "").strip() code = code_data.get("code", "").strip()
return f"""\n```{language}\n{code}\n```\n""" return f"""\n【代码执行】\n```{language}\n{code}\n```\n"""
def format_execution_result(self, result_data: dict) -> str: def format_execution_result(self, result_data: dict) -> str:
"""格式化执行结果输出""" """格式化执行结果输出"""
outcome = result_data.get("outcome", "") outcome = result_data.get("outcome", "")
output = result_data.get("output", "").strip() output = result_data.get("output", "").strip()
return f"""\n【执行结果】\noutcome: {outcome}\noutput: {output}\n""" return f"""\n【执行结果】\noutcome: {outcome}\noutput:\n```{output}```\n"""
+2 -2
View File
@@ -1,8 +1,8 @@
import logging
import openai import openai
from typing import Union, List, Dict, Any from typing import Union, List, Dict, Any
from app.core.logger import get_embeddings_logger
logger = logging.getLogger(__name__) logger = get_embeddings_logger()
class EmbeddingService: class EmbeddingService:
+3 -3
View File
@@ -1,9 +1,9 @@
import asyncio import asyncio
from itertools import cycle from itertools import cycle
import logging
from typing import Dict from typing import Dict
from app.core.logger import get_key_manager_logger
logger = logging.getLogger(__name__) logger = get_key_manager_logger()
class KeyManager: class KeyManager:
@@ -42,7 +42,7 @@ class KeyManager:
current_key = await self.get_next_key() current_key = await self.get_next_key()
if current_key == initial_key: if current_key == initial_key:
await self.reset_failure_counts() # await self.reset_failure_counts() 取消重置
return current_key return current_key
async def handle_api_failure(self, api_key: str) -> str: async def handle_api_failure(self, api_key: str) -> str:
+2 -2
View File
@@ -1,9 +1,9 @@
import requests import requests
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
import logging from app.core.logger import get_model_logger
logger = logging.getLogger(__name__) logger = get_model_logger()
class ModelService: class ModelService: