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
2026-07-31 19:09:01 -05:00
committed by GitHub
parent b67804f2b6
commit 52cfb02c72
40 changed files with 198 additions and 190 deletions
+5 -2
View File
@@ -100,7 +100,7 @@ async def get_function_models(request):
log.exception(e)
sub_pipes = []
log.debug(f"get_function_models: function '{pipe.id}' is a manifold of {sub_pipes}")
log.debug("get_function_models: function '%s' is a manifold of %s", pipe.id, sub_pipes)
for p in sub_pipes:
sub_pipe_id = f'{pipe.id}.{p["id"]}'
@@ -126,7 +126,10 @@ async def get_function_models(request):
pipe_flag = {'type': 'pipe'}
log.debug(
f"get_function_models: function '{pipe.id}' is a single pipe {{ 'id': {pipe.id}, 'name': {pipe.name} }}"
"get_function_models: function '%s' is a single pipe { 'id': %s, 'name': %s }",
pipe.id,
pipe.id,
pipe.name,
)
pipe_models.append(
+7 -7
View File
@@ -878,7 +878,7 @@ async def get_models(request: Request, refresh: bool = False, user=Depends(get_v
tags = list(set(model_tags + tags))
model['tags'] = [{'name': tag} for tag in tags]
except Exception as e:
log.debug(f'Error processing model tags: {e}')
log.debug('Error processing model tags: %s', e)
model['tags'] = []
model_order_list = await Config.get('ui.model_order_list')
@@ -1377,7 +1377,7 @@ async def chat_completion(
user.id,
)
except Exception as e:
log.debug(f'Error inserting chat files: {e}')
log.debug('Error inserting chat files: %s', e)
pass
if initial_title_generation is not None and all_assistant_ids:
@@ -1399,7 +1399,7 @@ async def chat_completion(
try:
await background_tasks_handler(title_ctx)
except Exception as e:
log.debug(f'Error generating initial chat title: {e}')
log.debug('Error generating initial chat title: %s', e)
asyncio.create_task(run_initial_title_generation())
else:
@@ -1487,7 +1487,7 @@ async def chat_completion(
user.id,
)
except Exception as e:
log.debug(f'Error inserting chat files: {e}')
log.debug('Error inserting chat files: %s', e)
pass
# Save ALL assistant placeholders
@@ -1653,9 +1653,9 @@ async def chat_completion(
try:
await client.disconnect()
except BaseException as e:
log.debug(f'Error disconnecting MCP client: {e}')
log.debug('Error disconnecting MCP client: %s', e)
except BaseException as e:
log.debug(f'Error cleaning up MCP clients: {e}')
log.debug('Error cleaning up MCP clients: %s', e)
# Deregister this task, then emit chat:active=false if no others remain
try:
@@ -2051,7 +2051,7 @@ async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De
task_ids = await list_task_ids_by_item_id(request.app.state.redis, chat_id)
log.debug(f'Task IDs for chat {chat_id}: {task_ids}')
log.debug('Task IDs for chat %s: %s', chat_id, task_ids)
return {'task_ids': task_ids}
+1 -1
View File
@@ -97,7 +97,7 @@ class TagTable:
async with get_async_db_context(db) as db:
id = name.replace(' ', '_').lower()
result = await db.execute(delete(Tag).filter_by(id=id, user_id=user_id))
log.debug(f'res: {result.rowcount}')
log.debug('res: %s', result.rowcount)
await db.commit()
return True
except Exception as e:
@@ -98,7 +98,7 @@ class MinerULoader:
files = {'files': (filename, f, 'application/octet-stream')}
log.info(f'Sending file to MinerU Local API: {filename}')
log.debug(f'Local API parameters: {form_data}')
log.debug('Local API parameters: %s', form_data)
response = requests.post(
f'{self.api_url}/file_parse',
@@ -233,7 +233,7 @@ class MinerULoader:
request_body['files'][0]['page_ranges'] = self.page_ranges
log.info(f'Requesting upload URL for: {filename}')
log.debug(f'Cloud API request body: {request_body}')
log.debug('Cloud API request body: %s', request_body)
try:
response = requests.post(
@@ -338,7 +338,7 @@ class MistralLoader:
headers = {**self.headers, 'Accept': 'application/json'}
async def url_request():
self._debug_log(f'Getting signed URL for file ID: {file_id}')
self._debug_log('Getting signed URL for file ID: %s', file_id)
async with session.get(
url,
headers=headers,
@@ -450,7 +450,7 @@ class MistralLoader:
try:
async def delete_request():
self._debug_log(f'Deleting file ID: {file_id}')
self._debug_log('Deleting file ID: %s', file_id)
async with session.delete(
url=f'{self.base_url}/files/{file_id}',
headers=self.headers,
@@ -460,7 +460,7 @@ class MistralLoader:
return await self._handle_response_async(response)
await self._retry_request_async(delete_request)
self._debug_log(f'File {file_id} deleted successfully')
self._debug_log('File %s deleted successfully', file_id)
except Exception as e:
# Don't fail the entire process if cleanup fails
@@ -519,7 +519,7 @@ class MistralLoader:
if page_content is None or page_index is None:
skipped_pages += 1
self._debug_log(
f"Skipping page due to missing 'markdown' or 'index'. Data keys: {list(page_data.keys())}"
"Skipping page due to missing 'markdown' or 'index'. Data keys: %s", list(page_data.keys())
)
continue
@@ -531,7 +531,7 @@ class MistralLoader:
if not cleaned_content:
skipped_pages += 1
self._debug_log(f'Skipping empty page {page_index}')
self._debug_log('Skipping empty page %s', page_index)
continue
# Create document with optimized metadata
@@ -90,7 +90,7 @@ class YoutubeLoader:
if self.proxy_url:
youtube_proxies = GenericProxyConfig(http_url=self.proxy_url, https_url=self.proxy_url)
log.debug(f'Using proxy URL: {self.proxy_url[:14]}...')
log.debug('Using proxy URL: %s...', self.proxy_url[:14])
else:
youtube_proxies = None
@@ -106,23 +106,23 @@ class YoutubeLoader:
try:
transcript = transcript_list.find_transcript([lang])
if transcript.is_generated:
log.debug(f"Found generated transcript for language '{lang}'")
log.debug("Found generated transcript for language '%s'", lang)
try:
transcript = transcript_list.find_manually_created_transcript([lang])
log.debug(f"Found manual transcript for language '{lang}'")
log.debug("Found manual transcript for language '%s'", lang)
except NoTranscriptFound:
log.debug(f"No manual transcript found for language '{lang}', using generated")
log.debug("No manual transcript found for language '%s', using generated", lang)
pass
log.debug(f"Found transcript for language '{lang}'")
log.debug("Found transcript for language '%s'", lang)
try:
transcript_pieces: List[Dict[str, Any]] = transcript.fetch()
except ParseError:
log.debug(f"Empty or invalid transcript for language '{lang}'")
log.debug("Empty or invalid transcript for language '%s'", lang)
continue
if not transcript_pieces:
log.debug(f"Empty transcript for language '{lang}'")
log.debug("Empty transcript for language '%s'", lang)
continue
transcript_text = ' '.join(
@@ -135,7 +135,7 @@ class YoutubeLoader:
)
return [Document(page_content=transcript_text, metadata=self._metadata)]
except NoTranscriptFound:
log.debug(f"No transcript found for language '{lang}'")
log.debug("No transcript found for language '%s'", lang)
continue
except Exception as e:
log.info(f"Error finding transcript for language '{lang}'")
+22 -20
View File
@@ -310,7 +310,7 @@ class VectorSearchRetriever(BaseRetriever):
def query_doc(collection_name: str, query_embedding: list[float], k: int, user: UserModel = None):
try:
log.debug(f'query_doc:doc {collection_name}')
log.debug('query_doc:doc %s', collection_name)
result = VECTOR_DB_CLIENT.search(
collection_name=collection_name,
vectors=[query_embedding],
@@ -328,7 +328,7 @@ def query_doc(collection_name: str, query_embedding: list[float], k: int, user:
def get_doc(collection_name: str, user: UserModel = None):
try:
log.debug(f'get_doc:doc {collection_name}')
log.debug('get_doc:doc %s', collection_name)
result = VECTOR_DB_CLIENT.get(collection_name=collection_name)
if result:
@@ -457,7 +457,7 @@ async def query_doc_with_native_hybrid_search(
'metadatas': [metadatas],
}
except Exception as e:
log.debug(f'Native hybrid search failed for {collection_name}, falling back to legacy hybrid search: {e}')
log.debug('Native hybrid search failed for %s, falling back to legacy hybrid search: %s', collection_name, e)
return None
@@ -510,7 +510,7 @@ async def query_doc_with_hybrid_search(
log.warning(f'query_doc_with_hybrid_search:no_docs {collection_name}')
return {'documents': [], 'metadatas': [], 'distances': []}
log.debug(f'query_doc_with_hybrid_search:doc {collection_name}')
log.debug('query_doc_with_hybrid_search:doc %s', collection_name)
original_texts = collection_result.documents[0]
bm25_metadatas = [
@@ -707,7 +707,7 @@ async def query_collection(
enable_enriched_texts=config.get('rag.enable_hybrid_search_enriched_texts'),
)
except Exception as e:
log.debug(f'Hybrid search failed, falling back to vector search: {e}')
log.debug('Hybrid search failed, falling back to vector search: %s', e)
results = []
error = False
@@ -736,7 +736,7 @@ async def query_collection(
# Generate all query embeddings (in one call)
query_embeddings = await embedding_function(queries, prefix=RAG_EMBEDDING_QUERY_PREFIX)
log.debug(f'query_collection: processing {len(queries)} queries across {len(collection_names)} collections')
log.debug('query_collection: processing %s queries across %s collections', len(queries), len(collection_names))
task_results = await asyncio.gather(
*[
@@ -866,7 +866,7 @@ def generate_openai_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'generate_openai_batch_embeddings:model {model} batch size: {len(texts)}')
log.debug('generate_openai_batch_embeddings:model %s batch size: %s', model, len(texts))
json_data = {'input': texts, 'model': model}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -899,7 +899,7 @@ async def agenerate_openai_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'agenerate_openai_batch_embeddings:model {model} batch size: {len(texts)}')
log.debug('agenerate_openai_batch_embeddings:model %s batch size: %s', model, len(texts))
form_data = {'input': texts, 'model': model}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
form_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -937,7 +937,7 @@ def generate_azure_openai_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'generate_azure_openai_batch_embeddings:deployment {model} batch size: {len(texts)}')
log.debug('generate_azure_openai_batch_embeddings:deployment %s batch size: %s', model, len(texts))
json_data = {'input': texts}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -979,7 +979,7 @@ async def agenerate_azure_openai_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'agenerate_azure_openai_batch_embeddings:deployment {model} batch size: {len(texts)}')
log.debug('agenerate_azure_openai_batch_embeddings:deployment %s batch size: %s', model, len(texts))
form_data = {'input': texts}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
form_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -1018,7 +1018,7 @@ def generate_ollama_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'generate_ollama_batch_embeddings:model {model} batch size: {len(texts)}')
log.debug('generate_ollama_batch_embeddings:model %s batch size: %s', model, len(texts))
json_data = {'input': texts, 'model': model, 'truncate': True}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -1054,7 +1054,7 @@ async def agenerate_ollama_batch_embeddings(
prefix: str = None,
user: UserModel = None,
) -> list[list[float]]:
log.debug(f'agenerate_ollama_batch_embeddings:model {model} batch size: {len(texts)}')
log.debug('agenerate_ollama_batch_embeddings:model %s batch size: %s', model, len(texts))
form_data = {'input': texts, 'model': model, 'truncate': True}
if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
form_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -1138,7 +1138,7 @@ def get_embedding_function(
batches = [query[i : i + embedding_batch_size] for i in range(0, len(query), embedding_batch_size)]
if enable_async:
log.debug(f'generate_multiple_async: Processing {len(batches)} batches in parallel')
log.debug('generate_multiple_async: Processing %s batches in parallel', len(batches))
# Use semaphore to limit concurrent embedding API requests
# 0 = unlimited (no semaphore)
if concurrent_requests:
@@ -1153,7 +1153,7 @@ def get_embedding_function(
tasks = [embedding_function(batch, prefix=prefix, user=user) for batch in batches]
batch_results = await asyncio.gather(*tasks)
else:
log.debug(f'generate_multiple_async: Processing {len(batches)} batches sequentially')
log.debug('generate_multiple_async: Processing %s batches sequentially', len(batches))
batch_results = []
for batch in batches:
batch_results.append(await embedding_function(batch, prefix=prefix, user=user))
@@ -1166,7 +1166,9 @@ def get_embedding_function(
embeddings.extend(batch_embeddings)
log.debug(
f'generate_multiple_async: Generated {len(embeddings)} embeddings from {len(batches)} parallel batches'
'generate_multiple_async: Generated %s embeddings from %s parallel batches',
len(embeddings),
len(batches),
)
return embeddings
else:
@@ -1606,14 +1608,14 @@ async def get_sources_from_items(
if query_result is None and collection_names:
collection_names = set(collection_names).difference(extracted_collections)
if not collection_names:
log.debug(f'skipping {item} as it has already been extracted')
log.debug('skipping %s as it has already been extracted', item)
continue
# Filter out collections the user cannot read
if user and (item.get('type'), item.get('id')) not in folder_items:
collection_names = await filter_accessible_collections(collection_names, user)
if not collection_names:
log.debug(f'access denied for all collections in item {item}')
log.debug('access denied for all collections in item %s', item)
continue
try:
@@ -1672,8 +1674,8 @@ def get_model_path(model: str, update_model: bool = False):
'local_files_only': local_files_only,
}
log.debug(f'model: {model}')
log.debug(f'snapshot_kwargs: {snapshot_kwargs}')
log.debug('model: %s', model)
log.debug('snapshot_kwargs: %s', snapshot_kwargs)
# Inspiration from upstream sentence_transformers
if os.path.exists(model) or ('\\' in model or model.count('/') > 1) and local_files_only:
@@ -1688,7 +1690,7 @@ def get_model_path(model: str, update_model: bool = False):
# Attempt to query the huggingface_hub library to determine the local path and/or to update
try:
model_repo_path = snapshot_download(**snapshot_kwargs)
log.debug(f'model_repo_path: {model_repo_path}')
log.debug('model_repo_path: %s', model_repo_path)
return model_repo_path
except Exception as e:
log.exception(f'Cannot determine model snapshot path: {e}')
@@ -182,7 +182,7 @@ class ChromaClient(VectorDBBase):
collection.delete(where=filter)
except Exception as e:
# If collection doesn't exist, that's fine - nothing to delete
log.debug(f'Attempted to delete from non-existent collection {collection_name}. Ignoring.')
log.debug('Attempted to delete from non-existent collection %s. Ignoring.', collection_name)
pass
def reset(self):
@@ -242,7 +242,7 @@ class MilvusClient(VectorDBBase):
break
all_results.extend(batch)
log.debug(f'Total results from query: {len(all_results)}')
log.debug('Total results from query: %s', len(all_results))
return self._result_to_get_result([all_results] if all_results else [[]])
except Exception as e:
@@ -274,7 +274,7 @@ class PineconeClient(VectorDBBase):
log.error(f'Error inserting batch: {e}')
raise
elapsed = time.time() - start_time
log.debug(f'Insert of {len(points)} vectors took {elapsed:.2f} seconds')
log.debug('Insert of %s vectors took %.2f seconds', len(points), elapsed)
log.info(
f"Successfully inserted {len(points)} vectors in parallel batches into '{collection_name_with_prefix}'"
)
@@ -303,7 +303,7 @@ class PineconeClient(VectorDBBase):
log.error(f'Error upserting batch: {e}')
raise
elapsed = time.time() - start_time
log.debug(f'Upsert of {len(points)} vectors took {elapsed:.2f} seconds')
log.debug('Upsert of %s vectors took %.2f seconds', len(points), elapsed)
log.info(
f"Successfully upserted {len(points)} vectors in parallel batches into '{collection_name_with_prefix}'"
)
@@ -474,7 +474,9 @@ class PineconeClient(VectorDBBase):
# Note: When deleting by ID, we can't filter by collection_name
# This is a limitation of Pinecone - be careful with ID uniqueness
self.index.delete(ids=batch_ids)
log.debug(f"Deleted batch of {len(batch_ids)} vectors by ID from '{collection_name_with_prefix}'")
log.debug(
"Deleted batch of %s vectors by ID from '%s'", len(batch_ids), collection_name_with_prefix
)
log.info(f"Successfully deleted {len(ids)} vectors by ID from '{collection_name_with_prefix}'")
elif filter:
@@ -224,7 +224,7 @@ class QdrantClient(VectorDBBase):
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, nothing to delete")
log.debug("Collection %s doesn't exist, nothing to delete", mt_collection)
return None
must_conditions = [_tenant_filter(tenant_id)]
@@ -255,7 +255,7 @@ class QdrantClient(VectorDBBase):
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, search returns None")
log.debug("Collection %s doesn't exist, search returns None", mt_collection)
return None
tenant_filter = _tenant_filter(tenant_id)
@@ -281,7 +281,7 @@ class QdrantClient(VectorDBBase):
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, query returns None")
log.debug("Collection %s doesn't exist, query returns None", mt_collection)
return None
if limit is None:
limit = NO_LIMIT
@@ -303,7 +303,7 @@ class QdrantClient(VectorDBBase):
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, get returns None")
log.debug("Collection %s doesn't exist, get returns None", mt_collection)
return None
tenant_filter = _tenant_filter(tenant_id)
points = self.client.scroll(
@@ -350,7 +350,7 @@ class QdrantClient(VectorDBBase):
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, nothing to delete")
log.debug("Collection %s doesn't exist, nothing to delete", mt_collection)
return None
self.client.delete(
collection_name=mt_collection,
@@ -54,7 +54,7 @@ class S3VectorClient(VectorDBBase):
Create a new index in the S3 vector bucket for the given collection if it does not exist.
"""
if self.has_collection(index_name):
log.debug(f"Index '{index_name}' already exists, skipping creation")
log.debug("Index '%s' already exists, skipping creation", index_name)
return
try:
@@ -310,7 +310,7 @@ class S3VectorClient(VectorDBBase):
# Process each query vector
for i, query_vector in enumerate(vectors):
log.debug(f'Processing query vector {i + 1}/{len(vectors)}')
log.debug('Processing query vector %s/%s', i + 1, len(vectors))
# Prepare the query vector in S3 Vector format
query_vector_dict = {'float32': [float(x) for x in query_vector]}
@@ -521,7 +521,7 @@ class S3VectorClient(VectorDBBase):
)
# Log the actual content for debugging
log.debug(f'Document text preview (first 200 chars): {str(document_text)[:200]}')
log.debug('Document text preview (first 200 chars): %s', str(document_text)[:200])
else:
document_text = vector_id
@@ -390,7 +390,7 @@ class ValkeyClient(VectorDBBase):
)
except g['RequestError'] as e:
if 'already exists' in str(e).lower():
log.debug(f'Index {index_name} already exists, skipping creation.')
log.debug('Index %s already exists, skipping creation.', index_name)
else:
raise
@@ -458,7 +458,7 @@ class ValkeyClient(VectorDBBase):
self._g['glide_ft'].dropindex(self.client, index_name)
log.info(f'Dropped index {index_name}')
except self._g['RequestError'] as e:
log.debug(f'Could not drop index {index_name}: {e}')
log.debug('Could not drop index %s: %s', index_name, e)
self._delete_keys_by_prefix(self._key_prefix(collection_name))
@@ -492,7 +492,7 @@ class ValkeyClient(VectorDBBase):
}
self.batch_client.hset(self._item_key(collection_name, item['id']), mapping)
log.debug(f'Inserted {len(items)} items into collection {collection_name}')
log.debug('Inserted %s items into collection %s', len(items), collection_name)
def upsert(self, collection_name: str, items: list[VectorItem]):
self.insert(collection_name, items)
+1 -1
View File
@@ -155,7 +155,7 @@ def safe_validate_urls(url: Sequence[str]) -> Sequence[str]:
if validate_url(u):
valid_urls.append(u)
except Exception as e:
log.debug(f'Invalid URL {u}: {str(e)}')
log.debug('Invalid URL %s: %s', u, e)
continue
return valid_urls
+1 -1
View File
@@ -53,7 +53,7 @@ def search_yacy(
# Strip all query parameters from the URL
query_url = query_url.rstrip('/') + '/yacysearch.json'
log.debug(f'searching {query_url}')
log.debug('searching %s', query_url)
response = requests.get(
query_url,
+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
+7 -7
View File
@@ -210,7 +210,7 @@ async def periodic_usage_pool_cleanup():
break
else:
if attempt < max_retries:
log.debug(f'Cleanup lock already exists. Retry {attempt + 1} after {retry_delay}s...')
log.debug('Cleanup lock already exists. Retry %s after %ss...', attempt + 1, retry_delay)
await asyncio.sleep(retry_delay)
else:
log.warning('Failed to acquire cleanup lock after retries. Skipping cleanup.')
@@ -237,7 +237,7 @@ async def periodic_usage_pool_cleanup():
del connections[sid]
if not connections:
log.debug(f'Cleaning up model {model_id} from usage pool')
log.debug('Cleaning up model %s from usage pool', model_id)
del USAGE_POOL[model_id]
else:
USAGE_POOL[model_id] = connections
@@ -299,7 +299,7 @@ async def emit_to_users(event: str, data: dict, user_ids: list[str]):
for user_id in user_ids:
await sio.emit(event, data, room=f'user:{user_id}')
except Exception as e:
log.debug(f'Failed to emit event {event} to users {user_ids}: {e}')
log.debug('Failed to emit event %s to users %s: %s', event, user_ids, e)
async def enter_room_for_users(room: str, user_ids: list[str]):
@@ -315,7 +315,7 @@ async def enter_room_for_users(room: str, user_ids: list[str]):
for sid in session_ids:
await sio.enter_room(sid, room)
except Exception as e:
log.debug(f'Failed to make users {user_ids} join room {room}: {e}')
log.debug('Failed to make users %s join room %s: %s', user_ids, room, e)
async def disconnect_user_sessions(user_id: str):
@@ -411,7 +411,7 @@ async def user_join(sid, data):
# Join all the channels only if user has channels permission
if user.role == 'admin' or await has_permission(user.id, 'features.channels'):
channels = await Channels.get_channels_by_user_id(user.id)
log.debug(f'{channels=}')
log.debug('channels=%r', channels)
for channel in channels:
await sio.enter_room(sid, f'channel:{channel.id}')
@@ -443,7 +443,7 @@ async def join_channel(sid, data):
# Join all the channels only if user has channels permission
if user.role == 'admin' or await has_permission(user.id, 'features.channels'):
channels = await Channels.get_channels_by_user_id(user.id)
log.debug(f'{channels=}')
log.debug('channels=%r', channels)
for channel in channels:
await sio.enter_room(sid, f'channel:{channel.id}')
@@ -480,7 +480,7 @@ async def join_note(sid, data):
log.error(f'User {user.id} does not have access to note {data["note_id"]}')
return
log.debug(f'Joining note {note.id} for user {user.id}')
log.debug('Joining note %s for user %s', note.id, user.id)
await sio.enter_room(sid, f'note:{note.id}')
@@ -34,7 +34,7 @@ async def has_access_to_file(
file.user_id == user.id separately before calling this.
"""
file = await Files.get_file_by_id(file_id, db=db)
log.debug(f'Checking if user has {access_type} access to file')
log.debug('Checking if user has %s access to file', access_type)
if not file:
return False
+1 -1
View File
@@ -222,7 +222,7 @@ class AuditLoggingMiddleware:
user = await get_current_user(request, None, None, get_http_authorization_cred(auth_header))
return user
except Exception as e:
logger.debug(f'Failed to get authenticated user: {str(e)}')
logger.debug('Failed to get authenticated user: {}', e)
return None
+2 -2
View File
@@ -667,7 +667,7 @@ async def _check_calendar_alerts(app) -> None:
CalendarEventUpdateForm(meta={'alerted_at': now_ns}),
)
except Exception:
log.debug(f'Failed to mark event {event.id} as alerted', exc_info=True)
log.debug('Failed to mark event %s as alerted', event.id, exc_info=True)
# Send target notification if user has one configured
try:
@@ -687,7 +687,7 @@ async def _check_calendar_alerts(app) -> None:
message=event.title,
)
except Exception:
log.debug(f'Failed to send notification for calendar alert {event.id}', exc_info=True)
log.debug('Failed to send notification for calendar alert %s', event.id, exc_info=True)
async def _record_run(
+3 -3
View File
@@ -115,7 +115,7 @@ async def generate_direct_chat_completion(
else:
yield f'data: {data}\n\n'
except Exception as e:
log.debug(f'Error in event generator: {e}')
log.debug('Error in event generator: %s', e)
pass
# Define a background task to run the event generator
@@ -155,7 +155,7 @@ async def generate_chat_completion(
bypass_filter: bool = False,
bypass_system_prompt: bool = False,
):
log.debug(f'generate_chat_completion: {form_data}')
log.debug('generate_chat_completion: %s', form_data)
if BYPASS_MODEL_ACCESS_CONTROL:
bypass_filter = True
@@ -184,7 +184,7 @@ async def generate_chat_completion(
**dict(request.app.state.MODELS.items()),
request.state.model['id']: request.state.model,
}
log.debug(f'direct connection to model: {request.state.model["id"]}')
log.debug('direct connection to model: %s', request.state.model['id'])
else:
models = request.app.state.MODELS
+1 -1
View File
@@ -186,7 +186,7 @@ async def process_filter_function(
form_data = await run_filter_handler(handler, params)
except Exception as e:
log.debug(f'Error in {filter_type} handler {filter_id}: {e}')
log.debug('Error in %s handler %s: %s', filter_type, filter_id, e)
raise e
return form_data, valves_by_id, skip_files
+3 -3
View File
@@ -17,7 +17,7 @@ default_headers = {'User-Agent': 'Mozilla/5.0'}
async def queue_prompt(prompt, client_id, base_url, api_key):
log.info('queue_prompt')
p = {'prompt': prompt, 'client_id': client_id}
log.debug(f'queue_prompt data: {p}')
log.debug('queue_prompt data: %s', p)
try:
session = await get_session()
async with session.post(
@@ -202,7 +202,7 @@ async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, clie
) as ws:
log.info('WebSocket connection established.')
log.info('Sending workflow to WebSocket server.')
log.debug(f'Workflow: {workflow}')
log.debug('Workflow: %s', workflow)
images = await _ws_get_images(ws, workflow, client_id, base_url, api_key)
except aiohttp.WSServerHandshakeError as e:
log.exception(f'Failed to connect to WebSocket server: {e}')
@@ -243,7 +243,7 @@ async def comfyui_edit_image(model: str, payload: ComfyUIEditImageForm, client_i
) as ws:
log.info('WebSocket connection established.')
log.info('Sending workflow to WebSocket server.')
log.debug(f'Workflow: {workflow}')
log.debug('Workflow: %s', workflow)
images = await _ws_get_images(ws, workflow, client_id, base_url, api_key)
except aiohttp.WSServerHandshakeError as e:
log.exception(f'Failed to connect to WebSocket server: {e}')
+1 -1
View File
@@ -457,7 +457,7 @@ async def review_memory_after_turn(
try:
done_task.result()
except Exception as e:
log.debug(f'Memory review failed: {e}')
log.debug('Memory review failed: %s', e)
task.add_done_callback(log_failure)
+17 -17
View File
@@ -1210,9 +1210,9 @@ async def chat_completion_tools_handler(
try:
response = await generate_chat_completion(request, form_data=payload, user=user)
log.debug(f'{response=}')
log.debug('response=%r', response)
content = await get_content_from_response(response)
log.debug(f'{content=}')
log.debug('content=%r', content)
if not content:
return body, {}
@@ -1227,7 +1227,7 @@ async def chat_completion_tools_handler(
async def tool_call_handler(tool_call):
nonlocal skip_files
log.debug(f'{tool_call=}')
log.debug('tool_call=%r', tool_call)
tool_function_name = tool_call.get('name', None)
if tool_function_name not in tools:
@@ -1341,13 +1341,13 @@ async def chat_completion_tools_handler(
await tool_call_handler(result)
except Exception as e:
log.debug(f'Error: {e}')
log.debug('Error: %s', e)
content = None
except Exception as e:
log.debug(f'Error: {e}')
log.debug('Error: %s', e)
content = None
log.debug(f'tool_contexts: {sources}')
log.debug('tool_contexts: %s', sources)
if skip_files and 'files' in body.get('metadata', {}):
del body['metadata']['files']
@@ -1912,7 +1912,7 @@ async def chat_completion_files_handler(
except Exception as e:
log.exception(e)
log.debug(f'rag_contexts:sources: {sources}')
log.debug('rag_contexts:sources: %s', sources)
unique_ids = set()
for source in sources or []:
@@ -2028,7 +2028,7 @@ async def convert_url_images_to_base64(form_data, user=None):
else:
new_content.append(item)
except Exception as e:
log.debug(f'Error converting image URL to base64: {e}')
log.debug('Error converting image URL to base64: %s', e)
new_content.append(item)
message['content'] = new_content
@@ -2286,7 +2286,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
model_system_prompt = (form_data.get('params') or {}).get('system')
form_data = apply_params_to_form_data(form_data, model)
log.debug(f'form_data: {form_data}')
log.debug('form_data: %s', form_data)
# Guided regeneration: extract before it reaches the LLM provider
regeneration_prompt = form_data.pop('regeneration_prompt', None)
@@ -2725,8 +2725,8 @@ async def process_chat_payload(request, form_data, user, metadata, model):
# Client side tools
direct_tool_servers = metadata.get('tool_servers', None)
log.debug(f'{tool_ids=}')
log.debug(f'{direct_tool_servers=}')
log.debug('tool_ids=%r', tool_ids)
log.debug('direct_tool_servers=%r', direct_tool_servers)
tools_dict = {}
@@ -3498,7 +3498,7 @@ async def outlet_filter_handler(ctx):
try:
outlet_data = await process_pipeline_outlet_filter(request, outlet_data, user, models)
except Exception as e:
log.debug(f'Pipeline outlet filter error: {e}')
log.debug('Pipeline outlet filter error: %s', e)
# Function outlet filters
extra_params = {
@@ -3559,7 +3559,7 @@ async def outlet_filter_handler(ctx):
}
)
except Exception as e:
log.debug(f'Error running outlet filters: {e}')
log.debug('Error running outlet filters: %s', e)
async def non_streaming_chat_response_handler(response, ctx):
@@ -3704,7 +3704,7 @@ async def non_streaming_chat_response_handler(response, ctx):
response = build_response_object(response, merge_events_into_response(response_data, events))
except Exception as e:
log.debug(f'Error occurred while processing request: {e}')
log.debug('Error occurred while processing request: %s', e)
chat_id = metadata.get('chat_id')
if getattr(request.state, 'internal', False) is not True and chat_id and is_saved_chat_id(chat_id):
webui_url = await Config.get('webui.url')
@@ -4815,7 +4815,7 @@ async def streaming_chat_response_handler(response, ctx):
if done:
pass
else:
log.debug(f'Error: {e}')
log.debug('Error: %s', e)
continue
await flush_pending_delta_data()
@@ -5336,7 +5336,7 @@ async def streaming_chat_response_handler(response, ctx):
)
retries += 1
log.debug(f'Attempt count: {retries}')
log.debug('Attempt count: %s', retries)
ci_item = output[-1]
ci_output = ''
@@ -5398,7 +5398,7 @@ async def streaming_chat_response_handler(response, ctx):
else:
ci_output = {'stdout': 'Code interpreter engine not configured.'}
log.debug(f'Code interpreter output: {ci_output}')
log.debug('Code interpreter output: %s', ci_output)
# Handle error responses from event_caller
# (e.g. session disconnected, timeout)
+2 -2
View File
@@ -307,7 +307,7 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
try:
await get_function_module_from_cache(request, function_id, function=function)
except Exception as e:
log.debug(f'Failed to load function module for {function_id}: {e}')
log.debug('Failed to load function module for %s: %s', function_id, e)
# Apply global model defaults to all models
# Per-model overrides take precedence over global defaults
@@ -413,7 +413,7 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
filter_items_by_id[filter_id] = items
model['filters'].extend({**item} for item in items)
log.debug(f'get_all_models() returned {len(models)} models')
log.debug('get_all_models() returned %s models', len(models))
models_dict = {model['id']: model for model in models}
if isinstance(request.app.state.MODELS, RedisDict):
+37 -36
View File
@@ -241,7 +241,7 @@ def _normalize_token_expiry(token: dict) -> dict:
if exp is not None:
expires_at = min(expires_at, int(exp))
except Exception as e:
log.debug(f'Could not read exp from id_token: {e}')
log.debug('Could not read exp from id_token: %s', e)
token['expires_at'] = expires_at
return token
@@ -411,7 +411,7 @@ async def get_protected_resource_metadata(server_url: str) -> ProtectedResourceM
)
if match:
resource_metadata_urls = [match.group(1) or match.group(2)]
log.debug(f'Found resource_metadata URL: {resource_metadata_urls[0]}')
log.debug('Found resource_metadata URL: %s', resource_metadata_urls[0])
else:
# Fall back to well-known resource metadata URIs (RFC 9728 §4.2)
parsed, base_url = get_parsed_and_base_url(server_url)
@@ -423,7 +423,7 @@ async def get_protected_resource_metadata(server_url: str) -> ProtectedResourceM
resource_metadata_urls.append(
urllib.parse.urljoin(base_url, '/.well-known/oauth-protected-resource')
)
log.debug(f'No resource_metadata in header, trying well-known URIs: {resource_metadata_urls}')
log.debug('No resource_metadata in header, trying well-known URIs: %s', resource_metadata_urls)
# Fetch Protected Resource metadata from candidate URLs
for resource_metadata_url in resource_metadata_urls:
@@ -436,22 +436,22 @@ async def get_protected_resource_metadata(server_url: str) -> ProtectedResourceM
resource = resource_metadata.get('resource') or None
if resource:
log.debug(f'Discovered resource indicator: {resource}')
log.debug('Discovered resource indicator: %s', resource)
servers = resource_metadata.get('authorization_servers', [])
scopes = resource_metadata.get('scopes_supported', [])
if scopes:
log.debug(f'Discovered resource scopes: {scopes}')
log.debug('Discovered resource scopes: %s', scopes)
if servers:
authorization_servers = servers
log.debug(f'Discovered authorization servers: {servers}')
log.debug('Discovered authorization servers: %s', servers)
break
except Exception as e:
log.debug(f'Failed to fetch resource metadata from {resource_metadata_url}: {e}')
log.debug('Failed to fetch resource metadata from %s: %s', resource_metadata_url, e)
continue
except Exception as e:
log.debug(f'MCP Protected Resource discovery failed: {e}')
log.debug('MCP Protected Resource discovery failed: %s', e)
return ProtectedResourceMetadata(
resource=resource, authorization_servers=authorization_servers, scopes_supported=scopes
@@ -801,7 +801,7 @@ async def recover_static_oauth_client_metadata(connection: dict, oauth_client_in
try:
resource_metadata = await get_protected_resource_metadata(server_url)
except Exception as e:
log.debug(f'Unable to recover static OAuth metadata for {server_url}: {e}')
log.debug('Unable to recover static OAuth metadata for %s: %s', server_url, e)
return oauth_client_info
recovered = {**oauth_client_info}
@@ -946,9 +946,7 @@ class OAuthClientManager:
if not authorization_url:
return True
except Exception as e:
log.debug(
f'Skipping OAuth preflight for client {client_info.client_id}: {e}',
)
log.debug('Skipping OAuth preflight for client %s: %s', client_info.client_id, e)
return True
try:
@@ -994,7 +992,7 @@ class OAuthClientManager:
return False
except Exception as e:
log.debug(f'Skipping OAuth preflight network check for client {client_info.client_id}: {e}')
log.debug('Skipping OAuth preflight network check for client %s: %s', client_info.client_id, e)
return True
@@ -1043,7 +1041,7 @@ class OAuthClientManager:
or session.expires_at is None
or datetime.now() + timedelta(minutes=5) >= datetime.fromtimestamp(session.expires_at)
):
log.debug(f'Token refresh needed for user {user_id}, client_id {session.provider}')
log.debug('Token refresh needed for user %s, client_id %s', user_id, session.provider)
refreshed_token = await self._refresh_token(session)
if refreshed_token:
return refreshed_token
@@ -1160,7 +1158,7 @@ class OAuthClientManager:
_normalize_token_expiry(new_token_data)
log.debug(f'Token refresh successful for client_id {client_id}')
log.debug('Token refresh successful for client_id %s', client_id)
return new_token_data
else:
error_text = await r.text()
@@ -1326,8 +1324,9 @@ class OAuthManager:
# the session (#24618).
if (session.provider or '').startswith('mcp:'):
log.debug(
f'Skipping MCP session {session.id} (provider={session.provider}) '
f'in SSO OAuthManager — handled by oauth_client_manager'
'Skipping MCP session %s (provider=%s) in SSO OAuthManager — handled by oauth_client_manager',
session.id,
session.provider,
)
return None
@@ -1336,7 +1335,7 @@ class OAuthManager:
or session.expires_at is None
or datetime.now() + timedelta(minutes=5) >= datetime.fromtimestamp(session.expires_at)
):
log.debug(f'Token refresh needed for user {user_id}, provider {session.provider}')
log.debug('Token refresh needed for user %s, provider %s', user_id, session.provider)
refreshed_token = await self._refresh_token(session)
if refreshed_token:
return refreshed_token
@@ -1452,7 +1451,7 @@ class OAuthManager:
_normalize_token_expiry(new_token_data)
log.debug(f'Token refresh successful for provider {provider}')
log.debug('Token refresh successful for provider %s', provider)
return new_token_data
else:
error_text = await r.text()
@@ -1511,10 +1510,10 @@ class OAuthManager:
elif isinstance(claim_data, int):
oauth_roles = [str(claim_data)]
log.debug(f'Oauth Roles claim: {oauth_claim}')
log.debug(f'User roles from oauth: {oauth_roles}')
log.debug(f'Accepted user roles: {oauth_allowed_roles}')
log.debug(f'Accepted admin roles: {oauth_admin_roles}')
log.debug('Oauth Roles claim: %s', oauth_claim)
log.debug('User roles from oauth: %s', oauth_roles)
log.debug('Accepted user roles: %s', oauth_allowed_roles)
log.debug('Accepted admin roles: %s', oauth_admin_roles)
# If roles are present in the token, they must match; otherwise deny access
if oauth_roles:
@@ -1591,7 +1590,7 @@ class OAuthManager:
# Determine creator ID: Prefer admin, fallback to current user if no admin exists
admin_user = await Users.get_super_admin_user()
creator_id = admin_user.id if admin_user else user.id
log.debug(f'Using creator ID {creator_id} for potential group creation.')
log.debug('Using creator ID %s for potential group creation.', creator_id)
for group_name in user_oauth_groups:
if group_name not in all_group_names:
@@ -1622,10 +1621,10 @@ class OAuthManager:
all_available_groups = await Groups.get_all_groups(db=db)
log.debug('Refreshed list of all available groups after creation.')
log.debug(f'Oauth Groups claim: {oauth_claim}')
log.debug(f'User oauth groups: {user_oauth_groups}')
log.debug(f"User's current groups: {[g.name for g in user_current_groups]}")
log.debug(f'All groups available in OpenWebUI: {[g.name for g in all_available_groups]}')
log.debug('Oauth Groups claim: %s', oauth_claim)
log.debug('User oauth groups: %s', user_oauth_groups)
log.debug("User's current groups: %s", [g.name for g in user_current_groups])
log.debug('All groups available in OpenWebUI: %s', [g.name for g in all_available_groups])
# Remove groups that user is no longer a part of
for group_model in user_current_groups:
@@ -1635,7 +1634,7 @@ class OAuthManager:
and not is_in_blocked_groups(group_model.name, blocked_groups)
):
# Remove group from user
log.debug(f'Removing user from group {group_model.name} as it is no longer in their oauth groups')
log.debug('Removing user from group %s as it is no longer in their oauth groups', group_model.name)
await Groups.remove_users_from_group(group_model.id, [user.id], db=db)
# In case a group is created, but perms are never assigned to the group by hitting "save"
@@ -1663,7 +1662,7 @@ class OAuthManager:
and not is_in_blocked_groups(group_model.name, blocked_groups)
):
# Add user to group
log.debug(f'Adding user to group {group_model.name} as it was found in their oauth groups')
log.debug('Adding user to group %s as it was found in their oauth groups', group_model.name)
await Groups.add_users_to_group(group_model.id, [user.id], db=db)
@@ -1916,7 +1915,7 @@ class OAuthManager:
if new_name and new_name != user.name:
await Users.update_user_by_id(user.id, {'name': new_name}, db=db)
user.name = new_name
log.debug(f'Updated name for user {user.email}')
log.debug('Updated name for user %s', user.email)
if auth_config.OAUTH_UPDATE_EMAIL_ON_LOGIN:
email_claim = auth_config.OAUTH_EMAIL_CLAIM
@@ -1931,7 +1930,7 @@ class OAuthManager:
else:
await Auths.update_email_by_id(user.id, new_email.lower(), db=db)
user.email = new_email.lower()
log.debug(f'Updated email for user {user.id}')
log.debug('Updated email for user %s', user.id)
# Update profile picture if enabled and different from current
if auth_config.OAUTH_UPDATE_PICTURE_ON_LOGIN:
@@ -1946,7 +1945,7 @@ class OAuthManager:
)
if processed_picture_url != user.profile_image_url:
await Users.update_user_profile_image_url_by_id(user.id, processed_picture_url, db=db)
log.debug(f'Updated profile picture for user {user.email}')
log.debug('Updated profile picture for user %s', user.email)
else:
# If the user does not exist, check if signups are enabled
if auth_config.ENABLE_OAUTH_SIGNUP:
@@ -2172,7 +2171,7 @@ class OAuthManager:
matched_issuer = provider_issuer
break
except Exception as e:
log.debug(f'Back-channel logout: error checking provider {provider_name}: {e}')
log.debug('Back-channel logout: error checking provider %s: %s', provider_name, e)
continue
if not matched_provider or not matched_client_id or not matched_jwks_uri:
@@ -2249,10 +2248,12 @@ class OAuthManager:
users_to_logout.append(user)
if not users_to_logout and sid:
log.debug(f'Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid={sid})')
log.debug('Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid=%s)', sid)
if not users_to_logout:
log.debug(f'Back-channel logout: no matching user for provider={matched_provider}, sub={sub}, sid={sid}')
log.debug(
'Back-channel logout: no matching user for provider=%s, sub=%s, sid=%s', matched_provider, sub, sid
)
return JSONResponse(status_code=200, content={})
# 9. Revoke tokens and delete sessions
+3 -3
View File
@@ -1187,7 +1187,7 @@ async def get_terminal_cwd(
data = await resp.json()
return data.get('cwd')
except Exception as e:
log.debug(f'Failed to fetch terminal CWD: {e}')
log.debug('Failed to fetch terminal CWD: %s', e)
return None
@@ -1226,7 +1226,7 @@ async def get_terminal_system_prompt(
data = await resp.json()
return data.get('prompt')
except Exception as e:
log.debug(f'Failed to fetch terminal system prompt: {e}')
log.debug('Failed to fetch terminal system prompt: %s', e)
return None
@@ -1447,7 +1447,7 @@ async def get_tool_server_data(url: str, headers: dict | None) -> dict[str, Any]
error = str(err)
raise Exception(error)
log.debug(f'Fetched data: {res}')
log.debug('Fetched data: %s', res)
return res
+3 -3
View File
@@ -29,7 +29,7 @@ def _event_text(message: str, description: str | None = None, event_data: dict |
async def post_webhook(name: str, url: str, message: str, event_data: dict, description: str | None = None) -> bool:
try:
log.debug(f'post_webhook: {url}, {message}, {event_data}')
log.debug('post_webhook: %s, %s, %s', url, message, event_data)
# Block private-IP / loopback / cloud-metadata targets — the URL is
# caller-controlled (user notification settings under
# ENABLE_USER_WEBHOOKS, automation notification triggers).
@@ -83,7 +83,7 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict, desc
else:
payload = event_data
log.debug(f'payload: {payload}')
log.debug('payload: %s', payload)
async with get_ssrf_safe_session() as session:
async with session.post(
url,
@@ -93,7 +93,7 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict, desc
) as r:
r_text = await r.text()
r.raise_for_status()
log.debug(f'r.text: {r_text}')
log.debug('r.text: %s', r_text)
return True
except Exception as e: