perf: build debug log messages lazily so disabled debug logs cost nothing (#27834)
GLOBAL_LOG_LEVEL defaults to INFO, so every log.debug(...) in the backend is discarded, but the message is built first: 187 call sites interpolate their payload into an f-string before the logging call runs, so the work happens on every request and the result is thrown away. The worst one sits in process_chat_payload and stringifies the whole request body, full conversation history included, once per chat completion.
That one line with DEBUG disabled, CPython 3.12:
| conversation | payload | before | after |
| ------------ | ------- | -------- | ------- |
| 4 messages | 1.2 kB | 3.4 us | 0.07 us |
| 20 messages | 17 kB | 24.8 us | 0.07 us |
| 60 messages | 123 kB | 216.6 us | 0.07 us |
The lazy form log.debug('form_data: %s', form_data) hands the payload to record.getMessage(), which the InterceptHandler only reaches once a record has passed the level check. With DEBUG enabled the emitted lines are byte-identical, f'{x=}' sites included: those map to %r. MistralLoader._debug_log callers get the same treatment, since that wrapper already forwards *args.
This commit is contained in:
1 parent
b67804f2b6
commit
52cfb02c72
40 files changed
+198
-190
No files matched your search
@@ -486,7 +486,7 @@ async def _tts_transformers(request, payload, file_path, file_body_path, user):
|
||||
try:
|
||||
idx = embeddings['filename'].index(model_name)
|
||||
except (ValueError, KeyError):
|
||||
log.debug(f'Speaker embedding not found for {model_name}, using default index {idx}')
|
||||
log.debug('Speaker embedding not found for %s, using default index %s', model_name, idx)
|
||||
|
||||
def _run_pipeline():
|
||||
speaker_embedding = torch.tensor(embeddings[idx]['xvector']).unsqueeze(0)
|
||||
@@ -1303,7 +1303,7 @@ async def get_available_models(request: Request) -> list[dict]:
|
||||
data = await resp.json()
|
||||
available_models = data.get('models', [])
|
||||
except Exception as e:
|
||||
log.debug(f'/audio/models not available, trying /models fallback: {e}')
|
||||
log.debug('/audio/models not available, trying /models fallback: %s', e)
|
||||
try:
|
||||
async with session.get(
|
||||
f'{base_url}/models',
|
||||
|
||||
@@ -448,7 +448,7 @@ def _process_chat_for_export(chat) -> ChatStatsExport | None:
|
||||
history_models[model] = 0
|
||||
history_models[model] += 1
|
||||
except Exception as e:
|
||||
log.debug(f'Error processing message {key}: {e}')
|
||||
log.debug('Error processing message %s: %s', key, e)
|
||||
continue
|
||||
|
||||
# Calculate Averages
|
||||
@@ -614,7 +614,7 @@ async def export_chat_stats(
|
||||
return ChatStatsExportList(items=chat_stats_export_list, total=total, page=page)
|
||||
|
||||
except Exception as e:
|
||||
log.debug(f'Error exporting chat stats: {e}')
|
||||
log.debug('Error exporting chat stats: %s', e)
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT())
|
||||
|
||||
|
||||
@@ -671,7 +671,7 @@ async def export_single_chat_stats(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.debug(f'Error exporting single chat stats: {e}')
|
||||
log.debug('Error exporting single chat stats: %s', e)
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT())
|
||||
|
||||
|
||||
@@ -877,7 +877,7 @@ async def search_user_chats(
|
||||
tag_id = words[0].replace('tag:', '')
|
||||
if len(chat_list) == 0:
|
||||
if await Tags.get_tag_by_name_and_user_id(tag_id, user.id, db=db):
|
||||
log.debug(f'deleting tag: {tag_id}')
|
||||
log.debug('deleting tag: %s', tag_id)
|
||||
await Tags.delete_tag_by_name_and_user_id(tag_id, user.id, db=db)
|
||||
|
||||
return await add_active_state_to_chat_list(request, chat_list)
|
||||
|
||||
@@ -202,7 +202,7 @@ async def register_oauth_client(
|
||||
'oauth_client_info': encrypt_data(oauth_client_info.model_dump(mode='json')),
|
||||
}
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to register OAuth client: {e}')
|
||||
log.debug('Failed to register OAuth client: %s', e)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f'Failed to register OAuth client: {e}',
|
||||
@@ -279,7 +279,7 @@ async def set_tool_servers_config(
|
||||
OAuthClientInformationFull(**oauth_client_info),
|
||||
)
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to add OAuth client for MCP tool server: {e}')
|
||||
log.debug('Failed to add OAuth client for MCP tool server: %s', e)
|
||||
continue
|
||||
|
||||
await publish_event(
|
||||
@@ -390,7 +390,7 @@ async def verify_terminal_server_connection(
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to connect to the terminal server: {e}')
|
||||
log.debug('Failed to connect to the terminal server: %s', e)
|
||||
|
||||
raise HTTPException(status_code=400, detail='Failed to connect to the terminal server')
|
||||
|
||||
@@ -454,7 +454,7 @@ async def put_terminal_server_policy(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to access policy on terminal server: {e}')
|
||||
log.debug('Failed to access policy on terminal server: %s', e)
|
||||
raise HTTPException(status_code=400, detail='Failed to access policy on terminal server')
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ async def put_terminal_server_lifecycle(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to access lifecycle on terminal server: {e}')
|
||||
log.debug('Failed to access lifecycle on terminal server: %s', e)
|
||||
raise HTTPException(status_code=400, detail='Failed to access lifecycle on terminal server')
|
||||
|
||||
|
||||
@@ -538,7 +538,7 @@ async def refresh_terminal_server_terminals(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to refresh terminals: {e}')
|
||||
log.debug('Failed to refresh terminals: %s', e)
|
||||
raise HTTPException(status_code=400, detail='Failed to refresh terminals')
|
||||
|
||||
|
||||
@@ -557,7 +557,7 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn
|
||||
)
|
||||
discovery_urls = await get_discovery_urls(oauth_server_url)
|
||||
for discovery_url in discovery_urls:
|
||||
log.debug(f'Trying to fetch OAuth 2.1 discovery document from {discovery_url}')
|
||||
log.debug('Trying to fetch OAuth 2.1 discovery document from %s', discovery_url)
|
||||
async with aiohttp.ClientSession(
|
||||
trust_env=True,
|
||||
timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT),
|
||||
@@ -624,7 +624,7 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn
|
||||
'specs': specs,
|
||||
}
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to create MCP client: {e}')
|
||||
log.debug('Failed to create MCP client: %s', e)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f'Failed to create MCP client',
|
||||
@@ -667,7 +667,7 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to connect to the tool server: {e}')
|
||||
log.debug('Failed to connect to the tool server: %s', e)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f'Failed to connect to the tool server',
|
||||
|
||||
@@ -103,7 +103,7 @@ def _cleanup_local_cache(file_path: str) -> None:
|
||||
local_path = os.path.join(UPLOAD_DIR, local_filename)
|
||||
if os.path.isfile(local_path):
|
||||
os.remove(local_path)
|
||||
log.debug(f'Cleaned up local cache: {local_path}')
|
||||
log.debug('Cleaned up local cache: %s', local_path)
|
||||
except OSError as e:
|
||||
log.warning(f'Failed to clean up local cache for {file_path}: {e}')
|
||||
|
||||
@@ -1021,7 +1021,7 @@ async def delete_file_by_id(
|
||||
if file.hash:
|
||||
await ASYNC_VECTOR_DB_CLIENT.delete(collection_name=knowledge.id, filter={'hash': file.hash})
|
||||
except Exception as e:
|
||||
log.debug(f'KB embedding cleanup for {knowledge.id}: {e}')
|
||||
log.debug('KB embedding cleanup for %s: %s', knowledge.id, e)
|
||||
|
||||
result = await Files.delete_file_by_id(id, db=db)
|
||||
if result:
|
||||
|
||||
@@ -149,7 +149,7 @@ def normalize_openai_edit_image_data_url(data_url: str) -> str:
|
||||
normalized_image = base64.b64encode(output.getvalue()).decode('utf-8')
|
||||
return f'data:image/jpeg;base64,{normalized_image}'
|
||||
except Exception as e:
|
||||
log.debug(f'Image edit normalization skipped: {e}')
|
||||
log.debug('Image edit normalization skipped: %s', e)
|
||||
|
||||
return data_url
|
||||
|
||||
@@ -194,7 +194,7 @@ async def set_image_model(request: Request, model: str):
|
||||
) as r:
|
||||
r.raise_for_status()
|
||||
except Exception as e:
|
||||
log.debug(f'{e}')
|
||||
log.debug('%s', e)
|
||||
|
||||
return image_config.IMAGE_GENERATION_MODEL
|
||||
|
||||
@@ -488,7 +488,7 @@ async def get_image_data(data: str, headers=None, trusted_base_url: str | None =
|
||||
# ENABLE_LOCAL_WEB_FETCH hammer and a blanket trust flag
|
||||
# that would follow arbitrary redirects.
|
||||
if trusted_base_url and _is_same_origin(data, trusted_base_url):
|
||||
log.debug(f'Skipping URL validation for trusted backend: {data}')
|
||||
log.debug('Skipping URL validation for trusted backend: %s', data)
|
||||
else:
|
||||
await asyncio.to_thread(validate_url, data)
|
||||
session = await get_session()
|
||||
@@ -762,7 +762,7 @@ async def image_generations(
|
||||
image_config.COMFYUI_BASE_URL,
|
||||
image_config.COMFYUI_API_KEY,
|
||||
)
|
||||
log.debug(f'res: {res}')
|
||||
log.debug('res: %s', res)
|
||||
|
||||
images = []
|
||||
|
||||
@@ -817,7 +817,7 @@ async def image_generations(
|
||||
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||
) as r:
|
||||
res = await r.json(content_type=None)
|
||||
log.debug(f'res: {res}')
|
||||
log.debug('res: %s', res)
|
||||
|
||||
images = []
|
||||
|
||||
@@ -1119,7 +1119,7 @@ async def image_edits(
|
||||
)
|
||||
comfyui_images.append(res.get('name', file_item[1][0]))
|
||||
except Exception as e:
|
||||
log.debug(f'Error uploading images to ComfyUI: {e}')
|
||||
log.debug('Error uploading images to ComfyUI: %s', e)
|
||||
raise Exception('Failed to upload images to ComfyUI.')
|
||||
|
||||
data = {
|
||||
@@ -1148,7 +1148,7 @@ async def image_edits(
|
||||
image_config.IMAGES_EDIT_COMFYUI_BASE_URL,
|
||||
image_config.IMAGES_EDIT_COMFYUI_API_KEY,
|
||||
)
|
||||
log.debug(f'res: {res}')
|
||||
log.debug('res: %s', res)
|
||||
|
||||
image_urls = set()
|
||||
for image in res['data']:
|
||||
@@ -1160,7 +1160,7 @@ async def image_edits(
|
||||
if output_type_urls:
|
||||
image_urls = output_type_urls
|
||||
|
||||
log.debug(f'Image URLs: {image_urls}')
|
||||
log.debug('Image URLs: %s', image_urls)
|
||||
images = []
|
||||
|
||||
for image_url in image_urls:
|
||||
|
||||
@@ -103,7 +103,7 @@ async def remove_knowledge_base_metadata_embedding(knowledge_base_id: str) -> bo
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
log.debug(f'Failed to remove embedding for {knowledge_base_id}: {e}')
|
||||
log.debug('Failed to remove embedding for %s: %s', knowledge_base_id, e)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ async def get_all_models(request: Request, user: UserModel | None = None):
|
||||
dt = datetime.fromisoformat(expires_map[m['model']])
|
||||
m['expires_at'] = int(dt.timestamp())
|
||||
except Exception as exc:
|
||||
log.debug(f'Failed to get loaded models: {exc}')
|
||||
log.debug('Failed to get loaded models: %s', exc)
|
||||
|
||||
request.app.state.OLLAMA_MODELS = {m['model']: m for m in models_dict['models']}
|
||||
return models_dict
|
||||
@@ -691,7 +691,7 @@ async def push_model(
|
||||
url_idx = models[form_data.model]['urls'][0]
|
||||
|
||||
url = (await Config.get('ollama.base_urls', []))[url_idx]
|
||||
log.debug(f'url: {url}')
|
||||
log.debug('url: %s', url)
|
||||
|
||||
return await send_request(
|
||||
f'{url}/api/push',
|
||||
@@ -723,7 +723,7 @@ async def create_model(
|
||||
if not await Config.get('ollama.enable'):
|
||||
raise HTTPException(status_code=503, detail=ERROR_MESSAGES.OLLAMA_API_DISABLED)
|
||||
|
||||
log.debug(f'form_data: {form_data}')
|
||||
log.debug('form_data: %s', form_data)
|
||||
url = (await Config.get('ollama.base_urls', []))[url_idx]
|
||||
|
||||
return await send_request(
|
||||
|
||||
@@ -613,7 +613,7 @@ async def get_all_models_responses(request: Request, user: UserModel) -> list:
|
||||
if provider:
|
||||
model['provider'] = provider
|
||||
|
||||
log.debug(f'get_all_models:responses() {responses}')
|
||||
log.debug('get_all_models:responses() %s', responses)
|
||||
return responses
|
||||
|
||||
|
||||
@@ -669,7 +669,7 @@ async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
|
||||
return not any(name in model_id for name in _UNSUPPORTED_OPENAI_MODEL_KEYWORDS)
|
||||
|
||||
def get_merged_models(model_lists):
|
||||
log.debug(f'merge_models_lists {model_lists}')
|
||||
log.debug('merge_models_lists %s', model_lists)
|
||||
models = {}
|
||||
|
||||
for idx, model_list in enumerate(model_lists):
|
||||
@@ -710,7 +710,7 @@ async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
|
||||
return models
|
||||
|
||||
models = get_merged_models(map(extract_data, responses))
|
||||
log.debug(f'models: {models}')
|
||||
log.debug('models: %s', models)
|
||||
|
||||
request.app.state.OPENAI_MODELS = models
|
||||
return {'data': list(models.values())}
|
||||
@@ -923,7 +923,7 @@ def get_azure_allowed_params(api_version: str) -> set[str]:
|
||||
if api_version >= '2024-09-01-preview':
|
||||
allowed_params.add('stream_options')
|
||||
except ValueError:
|
||||
log.debug(f'Invalid API version {api_version} for Azure OpenAI. Defaulting to allowed parameters.')
|
||||
log.debug('Invalid API version %s for Azure OpenAI. Defaulting to allowed parameters.', api_version)
|
||||
|
||||
return allowed_params
|
||||
|
||||
@@ -971,7 +971,7 @@ def convert_to_azure_payload(url, payload: dict, api_version: str):
|
||||
# Remove temperature if not 1 for o-series models
|
||||
if 'temperature' in payload and payload['temperature'] != 1:
|
||||
log.debug(
|
||||
f'Removing temperature parameter for o-series model {model} as only default value (1) is supported'
|
||||
'Removing temperature parameter for o-series model %s as only default value (1) is supported', model
|
||||
)
|
||||
del payload['temperature']
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ router = APIRouter()
|
||||
@router.get('/list')
|
||||
async def get_pipelines_list(request: Request, user=Depends(get_admin_user)):
|
||||
responses = await get_all_models_responses(request, user)
|
||||
log.debug(f'get_pipelines_list: get_openai_models_responses returned {responses}')
|
||||
log.debug('get_pipelines_list: get_openai_models_responses returned %s', responses)
|
||||
|
||||
urlIdxs = [idx for idx, response in enumerate(responses) if response is not None and 'pipelines' in response]
|
||||
base_urls = await Config.get('openai.api_base_urls', [])
|
||||
|
||||
@@ -230,7 +230,7 @@ def get_rf(
|
||||
eos = getattr(cfg, 'eos_token_id', None)
|
||||
if eos is not None:
|
||||
cfg.pad_token_id = eos
|
||||
log.debug(f'Missing pad_token_id detected; set to eos_token_id={eos}')
|
||||
log.debug('Missing pad_token_id detected; set to eos_token_id=%s', eos)
|
||||
else:
|
||||
log.warning('Neither pad_token_id nor eos_token_id present in model config')
|
||||
except Exception as e2:
|
||||
@@ -1643,7 +1643,7 @@ def save_docs_to_vector_db(
|
||||
|
||||
return ', '.join(docs_info)
|
||||
|
||||
log.debug(f'save_docs_to_vector_db: document {_get_docs_info(docs)} {collection_name}')
|
||||
log.debug('save_docs_to_vector_db: document %s %s', _get_docs_info(docs), collection_name)
|
||||
|
||||
# Check if entries with the same hash (metadata.hash) already exist
|
||||
if metadata and 'hash' in metadata:
|
||||
@@ -2567,7 +2567,7 @@ async def process_web_search(request: Request, form_data: SearchForm, user=Depen
|
||||
result_items = []
|
||||
|
||||
try:
|
||||
logging.debug(f'trying to web search with {config.WEB_SEARCH_ENGINE, form_data.queries}')
|
||||
logging.debug('trying to web search with %s', (config.WEB_SEARCH_ENGINE, form_data.queries))
|
||||
|
||||
# Use semaphore to limit concurrent requests based on WEB_SEARCH_CONCURRENT_REQUESTS
|
||||
# 0 or None = unlimited (previous behavior), positive number = limited concurrency
|
||||
@@ -2610,7 +2610,7 @@ async def process_web_search(request: Request, form_data: SearchForm, user=Depen
|
||||
urls.append(item.link)
|
||||
|
||||
urls = list(dict.fromkeys(urls))
|
||||
log.debug(f'urls: {urls}')
|
||||
log.debug('urls: %s', urls)
|
||||
|
||||
except Exception as e:
|
||||
log.exception('Web search failed')
|
||||
|
||||
@@ -268,7 +268,7 @@ def get_scim_auth(request: Request, authorization: Optional[str] = Header(None))
|
||||
|
||||
# Verify the SCIM token
|
||||
scim_token = getattr(request.app.state, 'SCIM_TOKEN', None)
|
||||
log.debug(f'SCIM token configured: {bool(scim_token)}')
|
||||
log.debug('SCIM token configured: %s', bool(scim_token))
|
||||
if not scim_token or not hmac.compare_digest(token, scim_token):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
|
||||
@@ -144,7 +144,7 @@ async def generate_title(request: Request, form_data: dict, user=Depends(get_ver
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating chat title using model {task_model_id} for user {user.email} ')
|
||||
log.debug('generating chat title using model %s for user %s ', task_model_id, user.email)
|
||||
|
||||
title_template = await Config.get('task.title.prompt_template')
|
||||
if title_template != '':
|
||||
@@ -223,7 +223,7 @@ async def generate_follow_ups(request: Request, form_data: dict, user=Depends(ge
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating chat title using model {task_model_id} for user {user.email} ')
|
||||
log.debug('generating chat title using model %s for user %s ', task_model_id, user.email)
|
||||
|
||||
follow_up_template = await Config.get('task.follow_up.prompt_template')
|
||||
if follow_up_template != '':
|
||||
@@ -293,7 +293,7 @@ async def generate_chat_tags(request: Request, form_data: dict, user=Depends(get
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating chat tags using model {task_model_id} for user {user.email} ')
|
||||
log.debug('generating chat tags using model %s for user %s ', task_model_id, user.email)
|
||||
|
||||
tags_template = await Config.get('task.tags.prompt_template')
|
||||
if tags_template != '':
|
||||
@@ -357,7 +357,7 @@ async def generate_image_prompt(request: Request, form_data: dict, user=Depends(
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating image prompt using model {task_model_id} for user {user.email} ')
|
||||
log.debug('generating image prompt using model %s for user %s ', task_model_id, user.email)
|
||||
|
||||
image_prompt_template = await Config.get('task.image.prompt_template')
|
||||
if image_prompt_template != '':
|
||||
@@ -439,7 +439,7 @@ async def generate_queries(request: Request, form_data: dict, user=Depends(get_v
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating {type} queries using model {task_model_id} for user {user.email}')
|
||||
log.debug('generating %s queries using model %s for user %s', type, task_model_id, user.email)
|
||||
|
||||
query_template = await Config.get('task.query.prompt_template')
|
||||
if query_template.strip() != '':
|
||||
@@ -520,7 +520,7 @@ async def generate_autocompletion(request: Request, form_data: dict, user=Depend
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating autocompletion using model {task_model_id} for user {user.email}')
|
||||
log.debug('generating autocompletion using model %s for user %s', task_model_id, user.email)
|
||||
|
||||
autocomplete_template = await Config.get('task.autocomplete.prompt_template')
|
||||
if autocomplete_template.strip() != '':
|
||||
@@ -584,7 +584,7 @@ async def generate_emoji(request: Request, form_data: dict, user=Depends(get_ver
|
||||
models,
|
||||
)
|
||||
|
||||
log.debug(f'generating emoji using model {task_model_id} for user {user.email} ')
|
||||
log.debug('generating emoji using model %s for user %s ', task_model_id, user.email)
|
||||
|
||||
template = DEFAULT_EMOJI_GENERATION_PROMPT_TEMPLATE
|
||||
|
||||
|
||||
Reference in new issue
Block a user