Skip to content

Commit 1d2982d

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 933f9f1 + 42d8261 commit 1d2982d

File tree

28 files changed

+809
-319
lines changed

28 files changed

+809
-319
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ FIRST_SUPERUSER_PASSWORD=123456 # Change this to your pwd
1414

1515
TOKEN_KEY="X-SQLBOT-TOKEN"
1616
DEFAULT_PWD="SQLBot@123456"
17+
ASSISTANT_TOKEN_KEY="X-SQLBOT-ASSISTANT-TOKEN"
18+
19+
LOG_LEVEL="INFO" # DEBUG, INFO, WARNING, ERROR
20+
LOG_DIR="/opt/sqlbot/logs"
21+
LOG_FORMAT="%(asctime)s - %(name)s - %(levelname)s:%(lineno)d - %(message)s"
22+
SQL_DEBUG=False
1723

1824
# Postgres
1925
POSTGRES_SERVER=localhost

backend/alembic/env.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
sys.path.insert(0, dirname(dirname(abspath(__file__))))
66

77
import os
8-
from logging.config import fileConfig
98

109
from alembic import context
1110
from sqlalchemy import engine_from_config, pool
@@ -16,7 +15,6 @@
1615

1716
# Interpret the config file for Python logging.
1817
# This line sets up loggers basically.
19-
fileConfig(config.config_file_name)
2018

2119
# add your model's MetaData object here
2220
# for 'autogenerate' support

backend/apps/chat/task/llm.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
import sqlparse
3-
import logging
43
import traceback
54
import warnings
65
from typing import Any, List, Optional, Union, Dict
@@ -35,7 +34,7 @@
3534
from apps.system.schemas.system_schema import AssistantOutDsSchema
3635
from common.core.config import settings
3736
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
38-
from common.utils.utils import extract_nested_json
37+
from common.utils.utils import SQLBotLogUtil, extract_nested_json
3938

4039
warnings.filterwarnings("ignore")
4140

@@ -223,7 +222,7 @@ def generate_analysis(self):
223222
res = self.llm.stream(analysis_msg)
224223
token_usage = {}
225224
for chunk in res:
226-
print(chunk)
225+
SQLBotLogUtil.info(chunk)
227226
reasoning_content_chunk = ''
228227
if 'reasoning_content' in chunk.additional_kwargs:
229228
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -273,7 +272,7 @@ def generate_predict(self):
273272
res = self.llm.stream(predict_msg)
274273
token_usage = {}
275274
for chunk in res:
276-
print(chunk)
275+
SQLBotLogUtil.info(chunk)
277276
reasoning_content_chunk = ''
278277
if 'reasoning_content' in chunk.additional_kwargs:
279278
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -323,7 +322,7 @@ def generate_recommend_questions_task(self):
323322
token_usage = {}
324323
res = self.llm.stream(guess_msg)
325324
for chunk in res:
326-
print(chunk)
325+
SQLBotLogUtil.info(chunk)
327326
reasoning_content_chunk = ''
328327
if 'reasoning_content' in chunk.additional_kwargs:
329328
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -390,7 +389,7 @@ def select_datasource(self):
390389
token_usage = {}
391390
res = self.llm.stream(datasource_msg)
392391
for chunk in res:
393-
print(chunk)
392+
SQLBotLogUtil.info(chunk)
394393
reasoning_content_chunk = ''
395394
if 'reasoning_content' in chunk.additional_kwargs:
396395
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -474,7 +473,7 @@ def generate_sql(self):
474473
token_usage = {}
475474
res = self.llm.stream(self.sql_message)
476475
for chunk in res:
477-
print(chunk)
476+
SQLBotLogUtil.info(chunk)
478477
reasoning_content_chunk = ''
479478
if 'reasoning_content' in chunk.additional_kwargs:
480479
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -543,7 +542,7 @@ def generate_filter(self, sql: str, tables: List):
543542
res = self.llm.stream(msg)
544543
token_usage = {}
545544
for chunk in res:
546-
print(chunk)
545+
SQLBotLogUtil.info(chunk)
547546
reasoning_content_chunk = ''
548547
if 'reasoning_content' in chunk.additional_kwargs:
549548
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -567,7 +566,7 @@ def generate_filter(self, sql: str, tables: List):
567566
# 'content': msg.content} for msg
568567
# in
569568
# analysis_msg]).decode())
570-
print(full_filter_text)
569+
SQLBotLogUtil.info(full_filter_text)
571570
return full_filter_text
572571

573572
def generate_chart(self):
@@ -582,7 +581,7 @@ def generate_chart(self):
582581
token_usage = {}
583582
res = self.llm.stream(self.chart_message)
584583
for chunk in res:
585-
print(chunk)
584+
SQLBotLogUtil.info(chunk)
586585
reasoning_content_chunk = ''
587586
if 'reasoning_content' in chunk.additional_kwargs:
588587
reasoning_content_chunk = chunk.additional_kwargs.get('reasoning_content', '')
@@ -691,7 +690,7 @@ def execute_sql(self, sql: str):
691690
Returns:
692691
Query results
693692
"""
694-
print(f"Executing SQL on ds_id {self.ds.id}: {sql}")
693+
SQLBotLogUtil.info(f"Executing SQL on ds_id {self.ds.id}: {sql}")
695694
return exec_sql(self.ds, sql)
696695

697696

@@ -717,7 +716,7 @@ def execute_sql_with_db(db: SQLDatabase, sql: str) -> str:
717716

718717
except Exception as e:
719718
error_msg = f"SQL execution failed: {str(e)}"
720-
logging.error(error_msg)
719+
SQLBotLogUtil.exception(error_msg)
721720
raise RuntimeError(error_msg)
722721

723722

@@ -741,7 +740,7 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
741740
ds_res = llm_service.select_datasource()
742741

743742
for chunk in ds_res:
744-
print(chunk)
743+
SQLBotLogUtil.info(chunk)
745744
if in_chat:
746745
yield orjson.dumps(
747746
{'content': chunk.get('content'), 'reasoning_content': chunk.get('reasoning_content'),
@@ -765,7 +764,7 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
765764
yield orjson.dumps({'type': 'info', 'msg': 'sql generated'}).decode() + '\n\n'
766765

767766
# filter sql
768-
print(full_sql_text)
767+
SQLBotLogUtil.info(full_sql_text)
769768

770769
# todo row permission
771770
sql_json_str = extract_nested_json(full_sql_text)
@@ -785,11 +784,11 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
785784
raise Exception("SQL query is empty")
786785

787786
sql_result = llm_service.generate_filter(data.get('sql'), data.get('tables')) # maybe no sql and tables
788-
print(sql_result)
787+
SQLBotLogUtil.info(sql_result)
789788
sql = llm_service.check_save_sql(res=sql_result)
790789
# sql = llm_service.check_save_sql(res=full_sql_text)
791790

792-
print(sql)
791+
SQLBotLogUtil.info(sql)
793792
format_sql = sqlparse.format(sql, reindent=True)
794793
if in_chat:
795794
yield orjson.dumps({'content': format_sql, 'type': 'sql'}).decode() + '\n\n'
@@ -815,9 +814,9 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
815814
yield orjson.dumps({'type': 'info', 'msg': 'chart generated'}).decode() + '\n\n'
816815

817816
# filter chart
818-
print(full_chart_text)
817+
SQLBotLogUtil.info(full_chart_text)
819818
chart = llm_service.check_save_chart(res=full_chart_text)
820-
print(chart)
819+
SQLBotLogUtil.info(chart)
821820
if in_chat:
822821
yield orjson.dumps({'content': orjson.dumps(chart).decode(), 'type': 'chart'}).decode() + '\n\n'
823822
else:
@@ -856,7 +855,7 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
856855
if chart['type'] != 'table':
857856
yield '### generated chart picture\n\n'
858857
image_url = request_picture(llm_service.record.chat_id, llm_service.record.id, chart, result)
859-
print(image_url)
858+
SQLBotLogUtil.info(image_url)
860859
yield f'![{chart["type"]}]({image_url})'
861860
except Exception as e:
862861
traceback.print_exc()

backend/apps/datasource/crud/datasource.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from apps.db.engine import get_engine_config, get_engine_conn
1616
from apps.db.type import db_type_relation
1717
from common.core.deps import SessionDep, CurrentUser, Trans
18-
from common.utils.utils import deepcopy_ignore_extra
18+
from common.utils.utils import SQLBotLogUtil, deepcopy_ignore_extra
1919
from .table import get_tables_by_ds_id
2020
from ..crud.field import delete_field_by_ds_id, update_field
2121
from ..crud.table import delete_table_by_ds_id, update_table
@@ -39,12 +39,12 @@ def check_status(session: SessionDep, ds: CoreDatasource, is_raise: bool = False
3939
conn = get_engine(ds)
4040
try:
4141
with conn.connect() as connection:
42-
print("success")
42+
SQLBotLogUtil.info("success")
4343
return True
4444
except Exception as e:
45+
SQLBotLogUtil.error(f"Datasource {ds.id} connection failed: {e}")
4546
if is_raise:
4647
raise HTTPException(status_code=500, detail=f'Connect Failed: {e.args}')
47-
print("Fail:", e)
4848
return False
4949

5050

backend/apps/system/crud/user.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11

22
from typing import Optional
33
from sqlmodel import Session, select, delete as sqlmodel_delete
4-
import logging
54
from apps.system.models.system_model import UserWsModel, WorkspaceModel
65
from apps.system.schemas.auth import CacheName, CacheNamespace
76
from apps.system.schemas.system_schema import BaseUserDTO, UserInfoDTO, UserWs
87
from common.core.deps import SessionDep
98
from common.core.sqlbot_cache import cache, clear_cache
109
from common.utils.locale import I18n
10+
from common.utils.utils import SQLBotLogUtil
1111
from ..models.user import UserModel
1212
from common.core.security import verify_md5pwd
1313

@@ -68,4 +68,4 @@ async def single_delete(session: SessionDep, id: int):
6868

6969
#@clear_cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.USER_INFO, keyExpression="id")
7070
async def clean_user_cache(id: int):
71-
logging.info(f"User cache for [{id}] has been cleaned")
71+
SQLBotLogUtil.info(f"User cache for [{id}] has been cleaned")

backend/apps/system/middleware/auth.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
from typing import Optional
3-
from fastapi import HTTPException, Request
3+
from fastapi import Request
44
from fastapi.responses import JSONResponse
55
import jwt
66
from sqlmodel import Session
@@ -13,6 +13,7 @@
1313
from common.core import security
1414
from common.core.config import settings
1515
from common.core.schemas import TokenPayload
16+
from common.utils.utils import SQLBotLogUtil
1617
from common.utils.whitelist import whiteUtils
1718
from fastapi.security.utils import get_authorization_scheme_param
1819
class TokenMiddleware(BaseHTTPMiddleware):
@@ -70,6 +71,7 @@ async def validateToken(self, token: Optional[str]):
7071
) """
7172
return True, session_user
7273
except Exception as e:
74+
SQLBotLogUtil.exception(f"Token validation error: {str(e)}", exc_info=True)
7375
return False, e
7476

7577

@@ -95,4 +97,6 @@ async def validateAssistant(self, assistantToken: Optional[str]) -> tuple[any]:
9597
assistant_info = AssistantHeader.model_validate(assistant_info.model_dump(exclude_unset=True))
9698
return True, session_user, assistant_info
9799
except Exception as e:
100+
SQLBotLogUtil.exception(f"Assistant validation error: {str(e)}", exc_info=True)
101+
# Return False and the exception message
98102
return False, e

backend/common/core/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def all_cors_origins(self) -> list[str]:
6060
TOKEN_KEY: str = "X-SQLBOT-TOKEN"
6161
DEFAULT_PWD: str = "SQLBot@123456"
6262
ASSISTANT_TOKEN_KEY: str = "X-SQLBOT-ASSISTANT-TOKEN"
63+
64+
LOG_LEVEL: str = "INFO" # DEBUG, INFO, WARNING, ERROR
65+
LOG_DIR: str = "logs"
66+
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s:%(lineno)d - %(message)s"
67+
SQL_DEBUG: bool = False
6368

6469
@computed_field # type: ignore[prop-decorator]
6570
@property

backend/common/core/response_middleware.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import json
2-
import logging
32
from starlette.middleware.base import BaseHTTPMiddleware
43
from starlette.responses import JSONResponse
54
from starlette.exceptions import HTTPException
65
from starlette.requests import Request
76
from common.core.config import settings
7+
from common.utils.utils import SQLBotLogUtil
88
class ResponseMiddleware(BaseHTTPMiddleware):
99
def __init__(self, app):
1010
super().__init__(app)
@@ -48,7 +48,7 @@ async def dispatch(self, request, call_next):
4848
}
4949
)
5050
except Exception as e:
51-
logging.error(f"Response processing error: {str(e)}", exc_info=True)
51+
SQLBotLogUtil.error(f"Response processing error: {str(e)}", exc_info=True)
5252
return JSONResponse(
5353
status_code=500,
5454
content={
@@ -68,6 +68,7 @@ async def dispatch(self, request, call_next):
6868
class exception_handler():
6969
@staticmethod
7070
async def http_exception_handler(request: Request, exc: HTTPException):
71+
SQLBotLogUtil.exception(f"HTTP Exception: {exc.detail}", exc_info=True)
7172
return JSONResponse(
7273
status_code=exc.status_code,
7374
content={
@@ -81,8 +82,7 @@ async def http_exception_handler(request: Request, exc: HTTPException):
8182

8283
@staticmethod
8384
async def global_exception_handler(request: Request, exc: Exception):
84-
logging.error(f"Error info: {str(exc)}", exc_info=True)
85-
85+
SQLBotLogUtil.exception(f"Unhandled Exception: {str(exc)}", exc_info=True)
8686
return JSONResponse(
8787
status_code=500,
8888
content={

backend/common/core/sqlbot_cache.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import logging
21
from fastapi_cache import FastAPICache
32
from fastapi_cache.decorator import cache as original_cache
43
from functools import partial, wraps
5-
from typing import Optional, Set, Any, Dict, Tuple, Callable
4+
from typing import Optional, Set, Any, Dict, Tuple
65
from inspect import Parameter, signature
76
from contextlib import asynccontextmanager
87
import asyncio
98

9+
from common.utils.utils import SQLBotLogUtil
10+
1011

1112
# 锁管理
1213
_cache_locks = {}
@@ -65,7 +66,7 @@ def custom_key_builder(
6566
base_key += f"{value}:"
6667

6768
except (IndexError, KeyError, AttributeError) as e:
68-
logging.warning(f"Failed to evaluate keyExpression '{keyExpression}': {str(e)}")
69+
SQLBotLogUtil.warning(f"Failed to evaluate keyExpression '{keyExpression}': {str(e)}")
6970

7071
return base_key
7172

@@ -127,19 +128,16 @@ async def wrapper(*args, **kwargs):
127128
)
128129

129130
async with _get_cache_lock(cache_key):
130-
logging.info(f"Using cache key: {cache_key}")
131-
print(f"Using cache key: {cache_key}")
131+
SQLBotLogUtil.info(f"Using cache key: {cache_key}")
132132
backend = FastAPICache.get_backend()
133133
cached_value = await backend.get(cache_key)
134134
if cached_value is not None:
135-
logging.info(f"Cache hit for key: {cache_key}, the value is: {cached_value}")
136-
print(f"Cache hit for key: {cache_key}, the value is: {cached_value}")
135+
SQLBotLogUtil.info(f"Cache hit for key: {cache_key}, the value is: {cached_value}")
137136
return cached_value
138137

139138
result = await func(*args, **kwargs)
140139
await backend.set(cache_key, result, expire)
141-
logging.info(f"Cache miss for key: {cache_key}, result cached.")
142-
print(f"Cache miss for key: {cache_key}, result cached.")
140+
SQLBotLogUtil.info(f"Cache miss for key: {cache_key}, result cached.")
143141
return result
144142

145143
return wrapper
@@ -167,8 +165,7 @@ async def wrapper(*args, **kwargs):
167165
if await FastAPICache.get_backend().get(cache_key):
168166
await FastAPICache.clear(key=cache_key)
169167
result = await func(*args, **kwargs)
170-
logging.info(f"Clearing cache for key: {cache_key}")
171-
print(f"Clearing cache for key: {cache_key}")
168+
SQLBotLogUtil.info(f"Clearing cache for key: {cache_key}")
172169
return result
173170
return await func(*args, **kwargs)
174171

0 commit comments

Comments
 (0)