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:
Classic298 authored and GitHub committed 2026-07-31 19:09:01 -05:00
1 parent b67804f2b6
commit 52cfb02c72
40 files changed
+198 -190

No files matched your search

+2 -2
View File
@@ -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',
+4 -4
View File
@@ -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)
+9 -9
View File
@@ -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',
+2 -2
View File
@@ -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:
+8 -8
View File
@@ -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:
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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(
+5 -5
View File
@@ -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']
+1 -1
View File
@@ -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', [])
+4 -4
View File
@@ -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')
+1 -1
View File
@@ -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,
+7 -7
View File
@@ -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