diff --git a/backend/alembic/env.py b/backend/alembic/env.py
index 4560e32db6..19a299094c 100644
--- a/backend/alembic/env.py
+++ b/backend/alembic/env.py
@@ -161,7 +161,7 @@ def get_schema_options() -> (
name.strip() for name in schema_names_str.split(",") if name.strip()
]
if schemas:
- logger.info(f"Specific schema names specified: {schemas}")
+ logger.info("Specific schema names specified: %s", schemas)
# Validate that only one method is used at a time
range_filtering = tenant_range_start is not None or tenant_range_end is not None
@@ -282,14 +282,17 @@ async def run_async_migrations() -> None:
if schemas:
# Use specific schema names directly without fetching all tenants
- logger.info(f"Migrating specific schema names: {schemas}")
+ logger.info("Migrating specific schema names: %s", schemas)
i_schema = 0
num_schemas = len(schemas)
for schema in schemas:
i_schema += 1
logger.info(
- f"Migrating schema: index={i_schema} num_schemas={num_schemas} schema={schema}"
+ "Migrating schema: index=%s num_schemas=%s schema=%s",
+ i_schema,
+ num_schemas,
+ schema,
)
try:
async with engine.connect() as connection:
@@ -300,7 +303,7 @@ async def run_async_migrations() -> None:
)
await connection.commit()
except Exception as e:
- logger.error(f"Error migrating schema {schema}: {e}")
+ logger.error("Error migrating schema %s: %s", schema, e)
if not continue_on_error:
logger.error("--continue=true is not set, raising exception!")
raise
@@ -316,10 +319,14 @@ async def run_async_migrations() -> None:
if tenant_range_start is not None or tenant_range_end is not None:
logger.info(
- f"Filtering tenants by range: start={tenant_range_start}, end={tenant_range_end}"
+ "Filtering tenants by range: start=%s, end=%s",
+ tenant_range_start,
+ tenant_range_end,
)
logger.info(
- f"Total tenants: {len(tenant_schemas)}, Filtered tenants: {len(filtered_tenant_schemas)}"
+ "Total tenants: %s, Filtered tenants: %s",
+ len(tenant_schemas),
+ len(filtered_tenant_schemas),
)
i_tenant = 0
@@ -327,7 +334,10 @@ async def run_async_migrations() -> None:
for schema in filtered_tenant_schemas:
i_tenant += 1
logger.info(
- f"Migrating schema: index={i_tenant} num_tenants={num_tenants} schema={schema}"
+ "Migrating schema: index=%s num_tenants=%s schema=%s",
+ i_tenant,
+ num_tenants,
+ schema,
)
try:
async with engine.connect() as connection:
@@ -338,7 +348,7 @@ async def run_async_migrations() -> None:
)
await connection.commit()
except Exception as e:
- logger.error(f"Error migrating schema {schema}: {e}")
+ logger.error("Error migrating schema %s: %s", schema, e)
if not continue_on_error:
logger.error("--continue=true is not set, raising exception!")
raise
@@ -384,10 +394,10 @@ def run_migrations_offline() -> None:
if schemas:
# Use specific schema names directly without fetching all tenants
- logger.info(f"Migrating specific schema names: {schemas}")
+ logger.info("Migrating specific schema names: %s", schemas)
for schema in schemas:
- logger.info(f"Migrating schema: {schema}")
+ logger.info("Migrating schema: %s", schema)
context.configure(
url=url,
target_metadata=target_metadata,
@@ -421,14 +431,18 @@ def run_migrations_offline() -> None:
if tenant_range_start is not None or tenant_range_end is not None:
logger.info(
- f"Filtering tenants by range: start={tenant_range_start}, end={tenant_range_end}"
+ "Filtering tenants by range: start=%s, end=%s",
+ tenant_range_start,
+ tenant_range_end,
)
logger.info(
- f"Total tenants: {len(tenant_schemas)}, Filtered tenants: {len(filtered_tenant_schemas)}"
+ "Total tenants: %s, Filtered tenants: %s",
+ len(tenant_schemas),
+ len(filtered_tenant_schemas),
)
for schema in filtered_tenant_schemas:
- logger.info(f"Migrating schema: {schema}")
+ logger.info("Migrating schema: %s", schema)
context.configure(
url=url,
target_metadata=target_metadata,
diff --git a/backend/alembic/run_multitenant_migrations.py b/backend/alembic/run_multitenant_migrations.py
index c738213242..d4fbbc39f9 100755
--- a/backend/alembic/run_multitenant_migrations.py
+++ b/backend/alembic/run_multitenant_migrations.py
@@ -32,7 +32,6 @@ from onyx.db.engine.tenant_utils import get_all_tenant_ids
from onyx.db.engine.tenant_utils import get_schemas_needing_migration
from shared_configs.configs import TENANT_ID_PREFIX
-
# ---------------------------------------------------------------------------
# Data types
# ---------------------------------------------------------------------------
diff --git a/backend/alembic/versions/01f8e6d95a33_populate_flow_mapping_data.py b/backend/alembic/versions/01f8e6d95a33_populate_flow_mapping_data.py
index a44738eb65..51879ab9a7 100644
--- a/backend/alembic/versions/01f8e6d95a33_populate_flow_mapping_data.py
+++ b/backend/alembic/versions/01f8e6d95a33_populate_flow_mapping_data.py
@@ -8,7 +8,6 @@ Create Date: 2026-01-31 17:37:10.485558
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "01f8e6d95a33"
down_revision = "d5c86e2c6dc6"
diff --git a/backend/alembic/versions/027381bce97c_add_shortcut_option_for_users.py b/backend/alembic/versions/027381bce97c_add_shortcut_option_for_users.py
index 3a7cf36863..2a29067c23 100644
--- a/backend/alembic/versions/027381bce97c_add_shortcut_option_for_users.py
+++ b/backend/alembic/versions/027381bce97c_add_shortcut_option_for_users.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-14 12:14:00.814390
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "027381bce97c"
down_revision = "6fc7886d665d"
diff --git a/backend/alembic/versions/03bf8be6b53a_rework_kg_config.py b/backend/alembic/versions/03bf8be6b53a_rework_kg_config.py
index f780eefd00..7a744ed1b2 100644
--- a/backend/alembic/versions/03bf8be6b53a_rework_kg_config.py
+++ b/backend/alembic/versions/03bf8be6b53a_rework_kg_config.py
@@ -16,7 +16,6 @@ from sqlalchemy import text
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "03bf8be6b53a"
down_revision = "65bc6e0f8500"
diff --git a/backend/alembic/versions/03d085c5c38d_backfill_account_type.py b/backend/alembic/versions/03d085c5c38d_backfill_account_type.py
index 2ead1876a9..1b5570558f 100644
--- a/backend/alembic/versions/03d085c5c38d_backfill_account_type.py
+++ b/backend/alembic/versions/03d085c5c38d_backfill_account_type.py
@@ -9,7 +9,6 @@ Create Date: 2026-03-25 16:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "03d085c5c38d"
down_revision = "977e834c1427"
diff --git a/backend/alembic/versions/03d710ccf29c_add_permission_sync_attempt_tables.py b/backend/alembic/versions/03d710ccf29c_add_permission_sync_attempt_tables.py
index f0c641f3eb..c9d2c273c4 100644
--- a/backend/alembic/versions/03d710ccf29c_add_permission_sync_attempt_tables.py
+++ b/backend/alembic/versions/03d710ccf29c_add_permission_sync_attempt_tables.py
@@ -9,7 +9,6 @@ Create Date: 2025-09-11 13:30:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "03d710ccf29c" # Generate a new unique ID
down_revision = "96a5702df6aa"
diff --git a/backend/alembic/versions/07b98176f1de_code_interpreter_seed.py b/backend/alembic/versions/07b98176f1de_code_interpreter_seed.py
index 554c36c59e..083d757b31 100644
--- a/backend/alembic/versions/07b98176f1de_code_interpreter_seed.py
+++ b/backend/alembic/versions/07b98176f1de_code_interpreter_seed.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-23 15:55:07.606784
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "07b98176f1de"
down_revision = "7cb492013621"
diff --git a/backend/alembic/versions/0816326d83aa_add_federated_connector_tables.py b/backend/alembic/versions/0816326d83aa_add_federated_connector_tables.py
index be1a386fc9..865424a768 100644
--- a/backend/alembic/versions/0816326d83aa_add_federated_connector_tables.py
+++ b/backend/alembic/versions/0816326d83aa_add_federated_connector_tables.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "0816326d83aa"
down_revision = "12635f6655b7"
diff --git a/backend/alembic/versions/08a1eda20fe1_add_earliest_indexing_to_connector.py b/backend/alembic/versions/08a1eda20fe1_add_earliest_indexing_to_connector.py
index 7df288e1da..4e53b583a8 100644
--- a/backend/alembic/versions/08a1eda20fe1_add_earliest_indexing_to_connector.py
+++ b/backend/alembic/versions/08a1eda20fe1_add_earliest_indexing_to_connector.py
@@ -9,7 +9,6 @@ Create Date: 2024-07-23 11:12:39.462397
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "08a1eda20fe1"
down_revision = "8a87bd6ec550"
diff --git a/backend/alembic/versions/09995b8811eb_add_theme_preference_to_user.py b/backend/alembic/versions/09995b8811eb_add_theme_preference_to_user.py
index 43bda42ca4..c906be26f3 100644
--- a/backend/alembic/versions/09995b8811eb_add_theme_preference_to_user.py
+++ b/backend/alembic/versions/09995b8811eb_add_theme_preference_to_user.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from onyx.db.enums import ThemePreference
-
# revision identifiers, used by Alembic.
revision = "09995b8811eb"
down_revision = "3d1cca026fe8"
diff --git a/backend/alembic/versions/0bb4558f35df_add_scim_username_to_scim_user_mapping.py b/backend/alembic/versions/0bb4558f35df_add_scim_username_to_scim_user_mapping.py
index a130a6aa23..def41204b9 100644
--- a/backend/alembic/versions/0bb4558f35df_add_scim_username_to_scim_user_mapping.py
+++ b/backend/alembic/versions/0bb4558f35df_add_scim_username_to_scim_user_mapping.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-20 10:45:30.340188
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "0bb4558f35df"
down_revision = "631fd2504136"
diff --git a/backend/alembic/versions/0cd424f32b1d_user_file_data_preparation_and_backfill.py b/backend/alembic/versions/0cd424f32b1d_user_file_data_preparation_and_backfill.py
index 55e2ef6e24..03ada7619f 100644
--- a/backend/alembic/versions/0cd424f32b1d_user_file_data_preparation_and_backfill.py
+++ b/backend/alembic/versions/0cd424f32b1d_user_file_data_preparation_and_backfill.py
@@ -41,7 +41,7 @@ def upgrade() -> None:
).scalar_one()
if null_count > 0:
- logger.info(f"Generating UUIDs for {null_count} user_file records...")
+ logger.info("Generating UUIDs for %s user_file records...", null_count)
# Populate in batches to avoid long locks
batch_size = 10000
@@ -70,9 +70,9 @@ def upgrade() -> None:
if updated < batch_size:
break
- logger.info(f" Updated {total_updated}/{null_count} records...")
+ logger.info(" Updated %s/%s records...", total_updated, null_count)
- logger.info(f"Generated UUIDs for {total_updated} user_file records")
+ logger.info("Generated UUIDs for %s user_file records", total_updated)
# Verify all records have UUIDs
remaining_null = bind.execute(
@@ -108,7 +108,7 @@ def upgrade() -> None:
).scalar_one()
if null_count > 0:
- logger.info(f"Updating {null_count} persona__user_file records...")
+ logger.info("Updating %s persona__user_file records...", null_count)
# Update in batches
batch_size = 10000
@@ -140,9 +140,9 @@ def upgrade() -> None:
if updated < batch_size:
break
- logger.info(f" Updated {total_updated}/{null_count} records...")
+ logger.info(" Updated %s/%s records...", total_updated, null_count)
- logger.info(f"Updated {total_updated} persona__user_file records")
+ logger.info("Updated %s persona__user_file records", total_updated)
# Verify all records are populated
remaining_null = bind.execute(
@@ -181,7 +181,7 @@ def upgrade() -> None:
)
)
- logger.info(f"Created {result.rowcount} user_project records from chat_folder")
+ logger.info("Created %s user_project records from chat_folder", result.rowcount)
# === Step 4: Populate chat_session.project_id ===
chat_session_columns = [
@@ -202,7 +202,7 @@ def upgrade() -> None:
).scalar_one()
if null_count > 0:
- logger.info(f"Updating {null_count} chat_session records...")
+ logger.info("Updating %s chat_session records...", null_count)
result = bind.execute(
text(
@@ -216,7 +216,7 @@ def upgrade() -> None:
)
)
- logger.info(f"Updated {result.rowcount} chat_session records")
+ logger.info("Updated %s chat_session records", result.rowcount)
# Verify all records are populated
remaining_null = bind.execute(
@@ -230,7 +230,8 @@ def upgrade() -> None:
if remaining_null > 0:
logger.warning(
- f"Warning: {remaining_null} chat_session records could not be mapped to projects"
+ "Warning: %s chat_session records could not be mapped to projects",
+ remaining_null,
)
# === Step 5: Update plaintext FileRecord IDs/display names to UUID scheme ===
@@ -251,7 +252,7 @@ def upgrade() -> None:
legacy_count = bind.execute(count_query).scalar_one()
if legacy_count and legacy_count > 0:
- logger.info(f"Found {legacy_count} legacy plaintext file records to update")
+ logger.info("Found %s legacy plaintext file records to update", legacy_count)
# Update display_name first for readability (safe regardless of rename)
bind.execute(
@@ -281,7 +282,7 @@ def upgrade() -> None:
)
)
logger.info(
- f"Updated {result.rowcount} plaintext file_record ids to UUID scheme"
+ "Updated %s plaintext file_record ids to UUID scheme", result.rowcount
)
# === Step 6: Ensure document_id_migrated default TRUE and backfill existing FALSE ===
@@ -338,7 +339,7 @@ def upgrade() -> None:
)
)
- logger.info(f"Updated status for {result.rowcount} user_file records")
+ logger.info("Updated status for %s user_file records", result.rowcount)
logger.info("Migration 2 (data preparation) completed successfully")
diff --git a/backend/alembic/versions/0ebb1d516877_add_ccpair_deletion_failure_message.py b/backend/alembic/versions/0ebb1d516877_add_ccpair_deletion_failure_message.py
index 030df76048..b1321b40c8 100644
--- a/backend/alembic/versions/0ebb1d516877_add_ccpair_deletion_failure_message.py
+++ b/backend/alembic/versions/0ebb1d516877_add_ccpair_deletion_failure_message.py
@@ -9,7 +9,6 @@ Create Date: 2024-09-10 15:03:48.233926
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "0ebb1d516877"
down_revision = "52a219fb5233"
diff --git a/backend/alembic/versions/114a638452db_add_default_app_mode_to_user.py b/backend/alembic/versions/114a638452db_add_default_app_mode_to_user.py
index 8df7fd6585..2d207ec8b0 100644
--- a/backend/alembic/versions/114a638452db_add_default_app_mode_to_user.py
+++ b/backend/alembic/versions/114a638452db_add_default_app_mode_to_user.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-09 18:57:08.274640
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "114a638452db"
down_revision = "feead2911109"
diff --git a/backend/alembic/versions/12635f6655b7_drive_canonical_ids.py b/backend/alembic/versions/12635f6655b7_drive_canonical_ids.py
index 4653586ff9..4fcf55e63a 100644
--- a/backend/alembic/versions/12635f6655b7_drive_canonical_ids.py
+++ b/backend/alembic/versions/12635f6655b7_drive_canonical_ids.py
@@ -155,7 +155,7 @@ def update_document_id_in_database(
# print(f"Successfully updated database tables for document {old_doc_id} -> {new_doc_id}")
except Exception as e:
# If the full INSERT fails, try a more basic version with only core columns
- logger.warning(f"Full INSERT failed, trying basic version: {e}")
+ logger.warning("Full INSERT failed, trying basic version: %s", e)
bind.execute(
sa.text(
"""
@@ -273,7 +273,7 @@ def update_document_id_in_database(
)
# print(f"Successfully updated chunk_stats ID field for document {old_doc_id} -> {new_doc_id}")
except Exception as e:
- logger.warning(f"Some KG/chunk tables may not exist or failed to update: {e}")
+ logger.warning("Some KG/chunk tables may not exist or failed to update: %s", e)
# Step 3: Delete the old document row (this should now be safe since all FKs point to new row)
bind.execute(
@@ -498,7 +498,7 @@ def delete_document_from_db(current_doc_id: str, index_name: str) -> None:
except Exception as e:
logger.warning(
- f"Some KG/chunk tables may not exist or failed to delete from: {e}"
+ "Some KG/chunk tables may not exist or failed to delete from: %s", e
)
# Finally delete the document itself
@@ -581,7 +581,7 @@ def upgrade() -> None:
# Continue with other documents instead of failing the entire migration
continue
- logger.info(f"Migration complete. Updated {updated_count} Google Drive documents")
+ logger.info("Migration complete. Updated %s Google Drive documents", updated_count)
def downgrade() -> None:
diff --git a/backend/alembic/versions/16c37a30adf2_user_file_relationship_migration.py b/backend/alembic/versions/16c37a30adf2_user_file_relationship_migration.py
index 8ce34b7395..9e30ba0b02 100644
--- a/backend/alembic/versions/16c37a30adf2_user_file_relationship_migration.py
+++ b/backend/alembic/versions/16c37a30adf2_user_file_relationship_migration.py
@@ -60,7 +60,7 @@ def upgrade() -> None:
to_migrate = bind.execute(count_query).scalar_one()
if to_migrate > 0:
- logger.info(f"Creating {to_migrate} persona-file relationships...")
+ logger.info("Creating %s persona-file relationships...", to_migrate)
# Migrate in batches to avoid memory issues
batch_size = 10000
@@ -94,11 +94,11 @@ def upgrade() -> None:
break
logger.info(
- f" Migrated {total_inserted}/{to_migrate} relationships..."
+ " Migrated %s/%s relationships...", total_inserted, to_migrate
)
logger.info(
- f"Created {total_inserted} persona__user_file relationships"
+ "Created %s persona__user_file relationships", total_inserted
)
# === Step 2: Add foreign key for chat_session.project_id ===
@@ -142,7 +142,7 @@ def upgrade() -> None:
to_create = bind.execute(count_query).scalar_one()
if to_create > 0:
- logger.info(f"Creating {to_create} project-file relationships...")
+ logger.info("Creating %s project-file relationships...", to_create)
# Insert in batches
batch_size = 10000
@@ -175,9 +175,11 @@ def upgrade() -> None:
if inserted < batch_size:
break
- logger.info(f" Created {total_inserted}/{to_create} relationships...")
+ logger.info(
+ " Created %s/%s relationships...", total_inserted, to_create
+ )
- logger.info(f"Created {total_inserted} project__user_file relationships")
+ logger.info("Created %s project__user_file relationships", total_inserted)
# === Step 4: Create index on chat_session.project_id ===
try:
@@ -229,7 +231,7 @@ def downgrade() -> None:
# Clear project__user_file relationships (but keep the table for migration 1 to handle)
if "project__user_file" in inspector.get_table_names():
result = bind.execute(text("DELETE FROM project__user_file"))
- logger.info(f"Cleared {result.rowcount} records from project__user_file")
+ logger.info("Cleared %s records from project__user_file", result.rowcount)
# Remove migrated persona__user_file relationships
# Only remove those that came from folder relationships
@@ -255,7 +257,7 @@ def downgrade() -> None:
)
)
logger.info(
- f"Removed {result.rowcount} migrated persona__user_file relationships"
+ "Removed %s migrated persona__user_file relationships", result.rowcount
)
logger.info("Downgrade completed successfully")
diff --git a/backend/alembic/versions/19c0ccb01687_migrate_to_contextual_rag_model.py b/backend/alembic/versions/19c0ccb01687_migrate_to_contextual_rag_model.py
index 89550e8b66..3edfa0a24f 100644
--- a/backend/alembic/versions/19c0ccb01687_migrate_to_contextual_rag_model.py
+++ b/backend/alembic/versions/19c0ccb01687_migrate_to_contextual_rag_model.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-12 11:21:41.798037
import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "19c0ccb01687"
down_revision = "9c54986124c6"
diff --git a/backend/alembic/versions/1b8206b29c5d_add_user_delete_cascades.py b/backend/alembic/versions/1b8206b29c5d_add_user_delete_cascades.py
index fca19c7aff..22fd4bdf9e 100644
--- a/backend/alembic/versions/1b8206b29c5d_add_user_delete_cascades.py
+++ b/backend/alembic/versions/1b8206b29c5d_add_user_delete_cascades.py
@@ -8,7 +8,6 @@ Create Date: 2024-09-18 11:48:59.418726
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "1b8206b29c5d"
down_revision = "35e6853a51d5"
diff --git a/backend/alembic/versions/1d78c0ca7853_remove_voice_provider_deleted_column.py b/backend/alembic/versions/1d78c0ca7853_remove_voice_provider_deleted_column.py
index 5ba8d8ba81..b19ae7740a 100644
--- a/backend/alembic/versions/1d78c0ca7853_remove_voice_provider_deleted_column.py
+++ b/backend/alembic/versions/1d78c0ca7853_remove_voice_provider_deleted_column.py
@@ -9,7 +9,6 @@ Create Date: 2026-03-26 11:30:53.883127
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "1d78c0ca7853"
down_revision = "a3f8b2c1d4e5"
diff --git a/backend/alembic/versions/1f2a3b4c5d6e_add_internet_search_and_content_providers.py b/backend/alembic/versions/1f2a3b4c5d6e_add_internet_search_and_content_providers.py
index 89a4713d4c..a6a1033acf 100644
--- a/backend/alembic/versions/1f2a3b4c5d6e_add_internet_search_and_content_providers.py
+++ b/backend/alembic/versions/1f2a3b4c5d6e_add_internet_search_and_content_providers.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "1f2a3b4c5d6e"
down_revision = "9drpiiw74ljy"
diff --git a/backend/alembic/versions/2020d417ec84_single_onyx_craft_migration.py b/backend/alembic/versions/2020d417ec84_single_onyx_craft_migration.py
index 4b480618eb..06aef3ffc0 100644
--- a/backend/alembic/versions/2020d417ec84_single_onyx_craft_migration.py
+++ b/backend/alembic/versions/2020d417ec84_single_onyx_craft_migration.py
@@ -22,7 +22,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "2020d417ec84"
down_revision = "41fa44bef321"
diff --git a/backend/alembic/versions/238b84885828_add_foreign_key_to_user__external_user_.py b/backend/alembic/versions/238b84885828_add_foreign_key_to_user__external_user_.py
index 1117f156e5..9dd7c10cd4 100644
--- a/backend/alembic/versions/238b84885828_add_foreign_key_to_user__external_user_.py
+++ b/backend/alembic/versions/238b84885828_add_foreign_key_to_user__external_user_.py
@@ -8,7 +8,6 @@ Create Date: 2025-05-19 17:15:33.424584
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "238b84885828"
down_revision = "a7688ab35c45"
diff --git a/backend/alembic/versions/25a5501dc766_group_permissions_phase1.py b/backend/alembic/versions/25a5501dc766_group_permissions_phase1.py
index 250318882d..9fbf90eee5 100644
--- a/backend/alembic/versions/25a5501dc766_group_permissions_phase1.py
+++ b/backend/alembic/versions/25a5501dc766_group_permissions_phase1.py
@@ -14,7 +14,6 @@ from onyx.db.enums import AccountType
from onyx.db.enums import GrantSource
from onyx.db.enums import Permission
-
# revision identifiers, used by Alembic.
revision = "25a5501dc766"
down_revision = "b728689f45b1"
diff --git a/backend/alembic/versions/2666d766cb9b_google_oauth2.py b/backend/alembic/versions/2666d766cb9b_google_oauth2.py
index 399fa72b95..268b71aa3e 100644
--- a/backend/alembic/versions/2666d766cb9b_google_oauth2.py
+++ b/backend/alembic/versions/2666d766cb9b_google_oauth2.py
@@ -10,7 +10,6 @@ import fastapi_users_db_sqlalchemy
import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "2666d766cb9b"
down_revision = "6d387b3196c2"
diff --git a/backend/alembic/versions/27fb147a843f_add_timestamps_to_user_table.py b/backend/alembic/versions/27fb147a843f_add_timestamps_to_user_table.py
index 1f7f077759..87ef6ed89d 100644
--- a/backend/alembic/versions/27fb147a843f_add_timestamps_to_user_table.py
+++ b/backend/alembic/versions/27fb147a843f_add_timestamps_to_user_table.py
@@ -9,7 +9,6 @@ Create Date: 2026-03-08 17:18:40.828644
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "27fb147a843f"
down_revision = "b5c4d7e8f9a1"
diff --git a/backend/alembic/versions/2955778aa44c_add_chunk_count_to_document.py b/backend/alembic/versions/2955778aa44c_add_chunk_count_to_document.py
index 8e345f7af4..02e8a243db 100644
--- a/backend/alembic/versions/2955778aa44c_add_chunk_count_to_document.py
+++ b/backend/alembic/versions/2955778aa44c_add_chunk_count_to_document.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-04 11:39:43.268612
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "2955778aa44c"
down_revision = "c0aab6edb6dd"
diff --git a/backend/alembic/versions/2acdef638fc2_add_switchover_type_field.py b/backend/alembic/versions/2acdef638fc2_add_switchover_type_field.py
index 3604e929e6..44e8e35829 100644
--- a/backend/alembic/versions/2acdef638fc2_add_switchover_type_field.py
+++ b/backend/alembic/versions/2acdef638fc2_add_switchover_type_field.py
@@ -11,7 +11,6 @@ import sqlalchemy as sa
from onyx.db.enums import SwitchoverType
-
# revision identifiers, used by Alembic.
revision = "2acdef638fc2"
down_revision = "a4f23d6b71c8"
diff --git a/backend/alembic/versions/2b75d0a8ffcb_user_file_schema_cleanup.py b/backend/alembic/versions/2b75d0a8ffcb_user_file_schema_cleanup.py
index 7843fd5b94..26b46e5ca9 100644
--- a/backend/alembic/versions/2b75d0a8ffcb_user_file_schema_cleanup.py
+++ b/backend/alembic/versions/2b75d0a8ffcb_user_file_schema_cleanup.py
@@ -50,7 +50,8 @@ def upgrade() -> None:
if orphaned_count > 0:
logger.warning(
- f"WARNING: {orphaned_count} chat_session records still have folder_id without project_id. Proceeding anyway."
+ "WARNING: %s chat_session records still have folder_id without project_id. Proceeding anyway.",
+ orphaned_count,
)
# === Step 2: Drop chat_session.folder_id ===
@@ -80,7 +81,7 @@ def upgrade() -> None:
if remaining > 0:
logger.warning(
- f"WARNING: Dropping persona__user_folder with {remaining} records"
+ "WARNING: Dropping persona__user_folder with %s records", remaining
)
op.drop_table("persona__user_folder")
@@ -94,7 +95,7 @@ def upgrade() -> None:
remaining = bind.execute(text("SELECT COUNT(*) FROM chat_folder")).scalar_one()
if remaining > 0:
- logger.warning(f"WARNING: Dropping chat_folder with {remaining} records")
+ logger.warning("WARNING: Dropping chat_folder with %s records", remaining)
op.drop_table("chat_folder")
logger.info("Dropped chat_folder table")
diff --git a/backend/alembic/versions/2b90f3af54b8_usage_limits.py b/backend/alembic/versions/2b90f3af54b8_usage_limits.py
index afec940d9a..69fd8ca3bc 100644
--- a/backend/alembic/versions/2b90f3af54b8_usage_limits.py
+++ b/backend/alembic/versions/2b90f3af54b8_usage_limits.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-03 16:55:30.449692
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "2b90f3af54b8"
down_revision = "9a0296d7421e"
diff --git a/backend/alembic/versions/2c2430828bdf_add_unique_constraint_to_inputprompt_.py b/backend/alembic/versions/2c2430828bdf_add_unique_constraint_to_inputprompt_.py
index 74b539edb9..7e15a6ee93 100644
--- a/backend/alembic/versions/2c2430828bdf_add_unique_constraint_to_inputprompt_.py
+++ b/backend/alembic/versions/2c2430828bdf_add_unique_constraint_to_inputprompt_.py
@@ -8,7 +8,6 @@ Create Date: 2026-01-20 16:01:54.314805
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "2c2430828bdf"
down_revision = "fb80bdd256de"
diff --git a/backend/alembic/versions/2cdeff6d8c93_set_built_in_to_default.py b/backend/alembic/versions/2cdeff6d8c93_set_built_in_to_default.py
index 20dd2cc05c..3e8441bd67 100644
--- a/backend/alembic/versions/2cdeff6d8c93_set_built_in_to_default.py
+++ b/backend/alembic/versions/2cdeff6d8c93_set_built_in_to_default.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-11 14:57:51.308775
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "2cdeff6d8c93"
down_revision = "f5437cc136c5"
diff --git a/backend/alembic/versions/2f80c6a2550f_add_chat_session_specific_temperature_.py b/backend/alembic/versions/2f80c6a2550f_add_chat_session_specific_temperature_.py
index 464a73576f..89e1689c79 100644
--- a/backend/alembic/versions/2f80c6a2550f_add_chat_session_specific_temperature_.py
+++ b/backend/alembic/versions/2f80c6a2550f_add_chat_session_specific_temperature_.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-31 10:30:27.289646
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "2f80c6a2550f"
down_revision = "33ea50e88f24"
diff --git a/backend/alembic/versions/2f95e36923e6_add_indexing_coordination.py b/backend/alembic/versions/2f95e36923e6_add_indexing_coordination.py
index 80bcc98eec..0627e0845e 100644
--- a/backend/alembic/versions/2f95e36923e6_add_indexing_coordination.py
+++ b/backend/alembic/versions/2f95e36923e6_add_indexing_coordination.py
@@ -9,7 +9,6 @@ Create Date: 2025-07-10 16:17:57.762182
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "2f95e36923e6"
down_revision = "0816326d83aa"
diff --git a/backend/alembic/versions/31bd8c17325e_targeted_reindex_schema.py b/backend/alembic/versions/31bd8c17325e_targeted_reindex_schema.py
index 2f7f232254..74b0e520bc 100644
--- a/backend/alembic/versions/31bd8c17325e_targeted_reindex_schema.py
+++ b/backend/alembic/versions/31bd8c17325e_targeted_reindex_schema.py
@@ -11,7 +11,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "31bd8c17325e"
down_revision = "14162713706c"
diff --git a/backend/alembic/versions/33cb72ea4d80_single_tool_call_per_message.py b/backend/alembic/versions/33cb72ea4d80_single_tool_call_per_message.py
index c60f249826..08ff7c14cf 100644
--- a/backend/alembic/versions/33cb72ea4d80_single_tool_call_per_message.py
+++ b/backend/alembic/versions/33cb72ea4d80_single_tool_call_per_message.py
@@ -9,7 +9,6 @@ Create Date: 2024-11-01 12:51:01.535003
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "33cb72ea4d80"
down_revision = "5b29123cd710"
diff --git a/backend/alembic/versions/33ea50e88f24_foreign_key_input_prompts.py b/backend/alembic/versions/33ea50e88f24_foreign_key_input_prompts.py
index 88c6df4212..6c9edb6183 100644
--- a/backend/alembic/versions/33ea50e88f24_foreign_key_input_prompts.py
+++ b/backend/alembic/versions/33ea50e88f24_foreign_key_input_prompts.py
@@ -8,7 +8,6 @@ Create Date: 2025-01-29 10:54:22.141765
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "33ea50e88f24"
down_revision = "a6df6b88ef81"
diff --git a/backend/alembic/versions/35e518e0ddf4_properly_cascade.py b/backend/alembic/versions/35e518e0ddf4_properly_cascade.py
index 9b238d2adc..0769902440 100644
--- a/backend/alembic/versions/35e518e0ddf4_properly_cascade.py
+++ b/backend/alembic/versions/35e518e0ddf4_properly_cascade.py
@@ -8,7 +8,6 @@ Create Date: 2024-09-20 21:24:04.891018
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "35e518e0ddf4"
down_revision = "91a0a4d62b14"
diff --git a/backend/alembic/versions/3934b1bc7b62_update_github_connector_repo_name_to_.py b/backend/alembic/versions/3934b1bc7b62_update_github_connector_repo_name_to_.py
index 498135a60c..ca7e4d6d5d 100644
--- a/backend/alembic/versions/3934b1bc7b62_update_github_connector_repo_name_to_.py
+++ b/backend/alembic/versions/3934b1bc7b62_update_github_connector_repo_name_to_.py
@@ -40,7 +40,7 @@ def upgrade() -> None:
for connector_id, config in github_connectors:
try:
if not config:
- logger.warning(f"Connector {connector_id} has no config, skipping")
+ logger.warning("Connector %s has no config, skipping", connector_id)
continue
# Parse the config if it's a string
@@ -68,7 +68,7 @@ def upgrade() -> None:
)
updated_count += 1
except Exception as e:
- logger.error(f"Error updating connector {connector_id}: {str(e)}")
+ logger.error("Error updating connector %s: %s", connector_id, str(e))
def downgrade() -> None:
@@ -89,7 +89,7 @@ def downgrade() -> None:
)
).fetchall()
- logger.debug(f"Found {len(github_connectors)} GitHub connectors to rollback")
+ logger.debug("Found %s GitHub connectors to rollback", len(github_connectors))
# Revert each GitHub connector to use repo_name instead of repositories
reverted_count = 0
@@ -123,4 +123,4 @@ def downgrade() -> None:
)
reverted_count += 1
except Exception as e:
- logger.error(f"Error reverting connector {connector_id}: {str(e)}")
+ logger.error("Error reverting connector %s: %s", connector_id, str(e))
diff --git a/backend/alembic/versions/3a7802814195_add_alternate_assistant_to_chat_message.py b/backend/alembic/versions/3a7802814195_add_alternate_assistant_to_chat_message.py
index bfde0162ba..a704e95153 100644
--- a/backend/alembic/versions/3a7802814195_add_alternate_assistant_to_chat_message.py
+++ b/backend/alembic/versions/3a7802814195_add_alternate_assistant_to_chat_message.py
@@ -9,7 +9,6 @@ Create Date: 2024-06-05 11:18:49.966333
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "3a7802814195"
down_revision = "23957775e5f5"
diff --git a/backend/alembic/versions/3a78dba1080a_user_file_legacy_data_cleanup.py b/backend/alembic/versions/3a78dba1080a_user_file_legacy_data_cleanup.py
index d0e63c3725..dbe5f171b9 100644
--- a/backend/alembic/versions/3a78dba1080a_user_file_legacy_data_cleanup.py
+++ b/backend/alembic/versions/3a78dba1080a_user_file_legacy_data_cleanup.py
@@ -39,7 +39,7 @@ def batch_delete(
return 0
logger.info(
- f"Starting batch deletion of {total_count} records from {table_name}..."
+ "Starting batch deletion of %s records from %s...", total_count, table_name
)
# Determine appropriate ARRAY type
@@ -66,16 +66,23 @@ def batch_delete(
batch_num = (i // batch_size) + 1
if batch_num % 10 == 0 or i + batch_size >= total_count:
logger.info(
- f" Deleted {min(i + batch_size, total_count)}/{total_count} records "
- f"({total_deleted} actual) from {table_name}"
+ " Deleted %s/%s records (%s actual) from %s",
+ min(i + batch_size, total_count),
+ total_count,
+ total_deleted,
+ table_name,
)
except Exception as e:
- logger.error(f"Failed to delete batch {(i // batch_size) + 1}: {e}")
+ logger.error("Failed to delete batch %s: %s", i // batch_size + 1, e)
failed_batches.append((i, min(i + batch_size, total_count)))
if failed_batches:
logger.warning(
- f"Failed to delete {len(failed_batches)} batches from {table_name}. Total deleted: {total_deleted}/{total_count}"
+ "Failed to delete %s batches from %s. Total deleted: %s/%s",
+ len(failed_batches),
+ table_name,
+ total_deleted,
+ total_count,
)
# Fail the migration to avoid silently succeeding on partial cleanup
raise RuntimeError(
@@ -115,7 +122,7 @@ def upgrade() -> None:
doc_ids = [r[0] for r in doc_rows]
if doc_ids:
- logger.info(f"Found {len(doc_ids)} user-file documents to delete")
+ logger.info("Found %s user-file documents to delete", len(doc_ids))
# Delete dependent rows first
tables_to_clean = [
@@ -130,17 +137,17 @@ def upgrade() -> None:
deleted = batch_delete(
bind, table_name, column_name, doc_ids, id_type="str"
)
- logger.info(f"Deleted {deleted} records from {table_name}")
+ logger.info("Deleted %s records from %s", deleted, table_name)
# Delete document_by_connector_credential_pair entries
deleted = batch_delete(
bind, "document_by_connector_credential_pair", "id", doc_ids, id_type="str"
)
- logger.info(f"Deleted {deleted} document_by_connector_credential_pair records")
+ logger.info("Deleted %s document_by_connector_credential_pair records", deleted)
# Delete documents themselves
deleted = batch_delete(bind, "document", "id", doc_ids, id_type="str")
- logger.info(f"Deleted {deleted} document records")
+ logger.info("Deleted %s document records", deleted)
else:
logger.info("No user-file documents found to delete")
@@ -162,7 +169,8 @@ def upgrade() -> None:
if cc_pair_ids:
logger.info(
- f"Found {len(cc_pair_ids)} user-file connector_credential_pairs to clean up"
+ "Found %s user-file connector_credential_pairs to clean up",
+ len(cc_pair_ids),
)
# Delete related records
@@ -181,7 +189,7 @@ def upgrade() -> None:
deleted = batch_delete(
bind, table_name, column_name, cc_pair_ids, id_type="int"
)
- logger.info(f"Deleted {deleted} records from {table_name}")
+ logger.info("Deleted %s records from %s", deleted, table_name)
# === Step 3: Identify connectors and credentials to delete ===
logger.info("Identifying orphaned connectors and credentials...")
@@ -255,14 +263,14 @@ def upgrade() -> None:
deleted = batch_delete(
bind, "connector_credential_pair", "id", cc_pair_ids, id_type="int"
)
- logger.info(f"Deleted {deleted} connector_credential_pair records")
+ logger.info("Deleted %s connector_credential_pair records", deleted)
# === Step 5: Delete orphaned connectors ===
if userfile_only_connector_ids:
deleted = batch_delete(
bind, "connector", "id", userfile_only_connector_ids, id_type="int"
)
- logger.info(f"Deleted {deleted} orphaned connector records")
+ logger.info("Deleted %s orphaned connector records", deleted)
# === Step 6: Delete orphaned credentials ===
if userfile_only_credential_ids:
@@ -274,13 +282,13 @@ def upgrade() -> None:
userfile_only_credential_ids,
id_type="int",
)
- logger.info(f"Deleted {deleted} credential__user_group records")
+ logger.info("Deleted %s credential__user_group records", deleted)
# Delete credentials
deleted = batch_delete(
bind, "credential", "id", userfile_only_credential_ids, id_type="int"
)
- logger.info(f"Deleted {deleted} orphaned credential records")
+ logger.info("Deleted %s orphaned credential records", deleted)
logger.info("Migration 5 (legacy data cleanup) completed successfully")
diff --git a/backend/alembic/versions/3bd4c84fe72f_improved_index.py b/backend/alembic/versions/3bd4c84fe72f_improved_index.py
index b92ad09108..ac9b71222c 100644
--- a/backend/alembic/versions/3bd4c84fe72f_improved_index.py
+++ b/backend/alembic/versions/3bd4c84fe72f_improved_index.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-26 13:07:56.217791
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "3bd4c84fe72f"
down_revision = "8f43500ee275"
diff --git a/backend/alembic/versions/3c5e35aa9af0_polling_document_count.py b/backend/alembic/versions/3c5e35aa9af0_polling_document_count.py
index 75a89f969d..312d586194 100644
--- a/backend/alembic/versions/3c5e35aa9af0_polling_document_count.py
+++ b/backend/alembic/versions/3c5e35aa9af0_polling_document_count.py
@@ -9,7 +9,6 @@ Create Date: 2023-06-14 23:45:51.760440
import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "3c5e35aa9af0"
down_revision = "27c6ecc08586"
diff --git a/backend/alembic/versions/465f78d9b7f9_larger_access_tokens_for_oauth.py b/backend/alembic/versions/465f78d9b7f9_larger_access_tokens_for_oauth.py
index 21d7e52386..b315ad1e80 100644
--- a/backend/alembic/versions/465f78d9b7f9_larger_access_tokens_for_oauth.py
+++ b/backend/alembic/versions/465f78d9b7f9_larger_access_tokens_for_oauth.py
@@ -9,7 +9,6 @@ Create Date: 2023-07-18 17:33:40.365034
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "465f78d9b7f9"
down_revision = "3c5e35aa9af0"
diff --git a/backend/alembic/versions/4794bc13e484_update_prompt_length.py b/backend/alembic/versions/4794bc13e484_update_prompt_length.py
index c80a9adad6..ff45f531fe 100644
--- a/backend/alembic/versions/4794bc13e484_update_prompt_length.py
+++ b/backend/alembic/versions/4794bc13e484_update_prompt_length.py
@@ -9,7 +9,6 @@ Create Date: 2025-04-02 11:26:36.180328
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "4794bc13e484"
down_revision = "f7505c5b0284"
diff --git a/backend/alembic/versions/47a07e1a38f1_fix_invalid_model_configurations_state.py b/backend/alembic/versions/47a07e1a38f1_fix_invalid_model_configurations_state.py
index bf43bc6acd..8e70570df0 100644
--- a/backend/alembic/versions/47a07e1a38f1_fix_invalid_model_configurations_state.py
+++ b/backend/alembic/versions/47a07e1a38f1_fix_invalid_model_configurations_state.py
@@ -16,7 +16,6 @@ from onyx.llm.well_known_providers.llm_provider_options import (
fetch_visible_model_names_for_provider_as_set,
)
-
# revision identifiers, used by Alembic.
revision = "47a07e1a38f1"
down_revision = "7a70b7664e37"
diff --git a/backend/alembic/versions/47e5bef3a1d7_add_persona_categories.py b/backend/alembic/versions/47e5bef3a1d7_add_persona_categories.py
index 89027dfa02..9b8af5e4bc 100644
--- a/backend/alembic/versions/47e5bef3a1d7_add_persona_categories.py
+++ b/backend/alembic/versions/47e5bef3a1d7_add_persona_categories.py
@@ -9,7 +9,6 @@ Create Date: 2024-11-05 18:55:02.221064
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "47e5bef3a1d7"
down_revision = "dfbe9e93d3c7"
diff --git a/backend/alembic/versions/495cb26ce93e_create_knowlege_graph_tables.py b/backend/alembic/versions/495cb26ce93e_create_knowlege_graph_tables.py
index 1b8cc02228..6bc4017c33 100644
--- a/backend/alembic/versions/495cb26ce93e_create_knowlege_graph_tables.py
+++ b/backend/alembic/versions/495cb26ce93e_create_knowlege_graph_tables.py
@@ -17,7 +17,6 @@ from onyx.configs.app_configs import DB_READONLY_PASSWORD
from shared_configs.configs import MULTI_TENANT
from shared_configs.configs import POSTGRES_DEFAULT_SCHEMA
-
# revision identifiers, used by Alembic.
revision = "495cb26ce93e"
down_revision = "ca04500b9ee8"
diff --git a/backend/alembic/versions/4d58345da04a_lowercase_user_emails.py b/backend/alembic/versions/4d58345da04a_lowercase_user_emails.py
index a3d94f0fbe..6a55e913b6 100644
--- a/backend/alembic/versions/4d58345da04a_lowercase_user_emails.py
+++ b/backend/alembic/versions/4d58345da04a_lowercase_user_emails.py
@@ -12,7 +12,6 @@ from alembic import op
from sqlalchemy.exc import IntegrityError
from sqlalchemy.sql import text
-
# revision identifiers, used by Alembic.
revision = "4d58345da04a"
down_revision = "f1ca58b2f2ec"
@@ -51,7 +50,10 @@ def upgrade() -> None:
next_email = f"{username.lower()}_{attempt}@{domain.lower()}"
# Email conflict occurred, append `_1`, `_2`, etc., to the username
logger.warning(
- f"Conflict while lowercasing email: old_email={email} conflicting_email={new_email} next_email={next_email}"
+ "Conflict while lowercasing email: old_email=%s conflicting_email=%s next_email=%s",
+ email,
+ new_email,
+ next_email,
)
new_email = next_email
attempt += 1
diff --git a/backend/alembic/versions/4f8a2b3c1d9e_add_open_url_tool.py b/backend/alembic/versions/4f8a2b3c1d9e_add_open_url_tool.py
index ec91df7b1f..b07992fd66 100644
--- a/backend/alembic/versions/4f8a2b3c1d9e_add_open_url_tool.py
+++ b/backend/alembic/versions/4f8a2b3c1d9e_add_open_url_tool.py
@@ -9,7 +9,6 @@ Create Date: 2025-11-24 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "4f8a2b3c1d9e"
down_revision = "a852cbe15577"
diff --git a/backend/alembic/versions/503883791c39_add_effective_permissions.py b/backend/alembic/versions/503883791c39_add_effective_permissions.py
index d6c11eadf0..5b5177de88 100644
--- a/backend/alembic/versions/503883791c39_add_effective_permissions.py
+++ b/backend/alembic/versions/503883791c39_add_effective_permissions.py
@@ -20,7 +20,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "503883791c39"
down_revision = "b4b7e1028dfd"
diff --git a/backend/alembic/versions/505c488f6662_merge_default_assistants_into_unified.py b/backend/alembic/versions/505c488f6662_merge_default_assistants_into_unified.py
index 011b608787..d124742881 100644
--- a/backend/alembic/versions/505c488f6662_merge_default_assistants_into_unified.py
+++ b/backend/alembic/versions/505c488f6662_merge_default_assistants_into_unified.py
@@ -14,7 +14,6 @@ from uuid import UUID
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "505c488f6662"
down_revision = "d09fc20a3c66"
diff --git a/backend/alembic/versions/54a74a0417fc_danswerbot_onyxbot.py b/backend/alembic/versions/54a74a0417fc_danswerbot_onyxbot.py
index 1de2960bb4..b7ffcca94b 100644
--- a/backend/alembic/versions/54a74a0417fc_danswerbot_onyxbot.py
+++ b/backend/alembic/versions/54a74a0417fc_danswerbot_onyxbot.py
@@ -8,7 +8,6 @@ Create Date: 2024-12-11 18:05:05.490737
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "54a74a0417fc"
down_revision = "94dc3d0236f8"
diff --git a/backend/alembic/versions/55546a7967ee_assistant_rework.py b/backend/alembic/versions/55546a7967ee_assistant_rework.py
index 1237c8d4d7..8bbb9a96c8 100644
--- a/backend/alembic/versions/55546a7967ee_assistant_rework.py
+++ b/backend/alembic/versions/55546a7967ee_assistant_rework.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "55546a7967ee"
down_revision = "61ff3651add4"
diff --git a/backend/alembic/versions/57122d037335_add_python_tool_on_default.py b/backend/alembic/versions/57122d037335_add_python_tool_on_default.py
index 256a13cc52..03ad1cbc57 100644
--- a/backend/alembic/versions/57122d037335_add_python_tool_on_default.py
+++ b/backend/alembic/versions/57122d037335_add_python_tool_on_default.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-27 10:10:40.124925
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "57122d037335"
down_revision = "c0c937d5c9e5"
diff --git a/backend/alembic/versions/5809c0787398_add_chat_sessions.py b/backend/alembic/versions/5809c0787398_add_chat_sessions.py
index 7b114159b0..84085f963a 100644
--- a/backend/alembic/versions/5809c0787398_add_chat_sessions.py
+++ b/backend/alembic/versions/5809c0787398_add_chat_sessions.py
@@ -10,7 +10,6 @@ import fastapi_users_db_sqlalchemy
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5809c0787398"
down_revision = "d929f0c1c6af"
diff --git a/backend/alembic/versions/58c50ef19f08_add_stale_column_to_user__external_user_.py b/backend/alembic/versions/58c50ef19f08_add_stale_column_to_user__external_user_.py
index 68204289d3..9efab9d234 100644
--- a/backend/alembic/versions/58c50ef19f08_add_stale_column_to_user__external_user_.py
+++ b/backend/alembic/versions/58c50ef19f08_add_stale_column_to_user__external_user_.py
@@ -9,7 +9,6 @@ Create Date: 2025-06-25 14:08:14.162380
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "58c50ef19f08"
down_revision = "7b9b952abdf6"
diff --git a/backend/alembic/versions/5ae8240accb3_add_research_agent_database_tables_and_.py b/backend/alembic/versions/5ae8240accb3_add_research_agent_database_tables_and_.py
index 9fe1388918..327408a2e9 100644
--- a/backend/alembic/versions/5ae8240accb3_add_research_agent_database_tables_and_.py
+++ b/backend/alembic/versions/5ae8240accb3_add_research_agent_database_tables_and_.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "5ae8240accb3"
down_revision = "b558f51620b4"
diff --git a/backend/alembic/versions/5b29123cd710_nullable_search_settings_for_historic_.py b/backend/alembic/versions/5b29123cd710_nullable_search_settings_for_historic_.py
index 9c83bfa874..7c6b60e391 100644
--- a/backend/alembic/versions/5b29123cd710_nullable_search_settings_for_historic_.py
+++ b/backend/alembic/versions/5b29123cd710_nullable_search_settings_for_historic_.py
@@ -9,7 +9,6 @@ Create Date: 2024-10-30 19:37:59.630704
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5b29123cd710"
down_revision = "949b4a92a401"
diff --git a/backend/alembic/versions/5c3dca366b35_backend_driven_notification_details.py b/backend/alembic/versions/5c3dca366b35_backend_driven_notification_details.py
index 8aa951b1dc..a70d2b2b94 100644
--- a/backend/alembic/versions/5c3dca366b35_backend_driven_notification_details.py
+++ b/backend/alembic/versions/5c3dca366b35_backend_driven_notification_details.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-06 16:03:11.413724
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5c3dca366b35"
down_revision = "9087b548dd69"
diff --git a/backend/alembic/versions/5d12a446f5c0_add_api_version_and_deployment_name_to_.py b/backend/alembic/versions/5d12a446f5c0_add_api_version_and_deployment_name_to_.py
index 826044234e..e42a387d5d 100644
--- a/backend/alembic/versions/5d12a446f5c0_add_api_version_and_deployment_name_to_.py
+++ b/backend/alembic/versions/5d12a446f5c0_add_api_version_and_deployment_name_to_.py
@@ -9,7 +9,6 @@ Create Date: 2024-10-08 15:56:07.975636
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5d12a446f5c0"
down_revision = "e4334d5b33ba"
diff --git a/backend/alembic/versions/5e1c073d48a3_add_personal_access_token_table.py b/backend/alembic/versions/5e1c073d48a3_add_personal_access_token_table.py
index 41fad4aff3..487347cba5 100644
--- a/backend/alembic/versions/5e1c073d48a3_add_personal_access_token_table.py
+++ b/backend/alembic/versions/5e1c073d48a3_add_personal_access_token_table.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "5e1c073d48a3"
down_revision = "09995b8811eb"
diff --git a/backend/alembic/versions/5e6f7a8b9c0d_update_default_persona_prompt.py b/backend/alembic/versions/5e6f7a8b9c0d_update_default_persona_prompt.py
index 03a2ce6d46..5060ad0ded 100644
--- a/backend/alembic/versions/5e6f7a8b9c0d_update_default_persona_prompt.py
+++ b/backend/alembic/versions/5e6f7a8b9c0d_update_default_persona_prompt.py
@@ -9,7 +9,6 @@ Create Date: 2025-11-30 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5e6f7a8b9c0d"
down_revision = "4f8a2b3c1d9e"
diff --git a/backend/alembic/versions/5e84129c8be3_add_docs_indexed_column_to_index_.py b/backend/alembic/versions/5e84129c8be3_add_docs_indexed_column_to_index_.py
index 38bc5cf501..980d5b7f29 100644
--- a/backend/alembic/versions/5e84129c8be3_add_docs_indexed_column_to_index_.py
+++ b/backend/alembic/versions/5e84129c8be3_add_docs_indexed_column_to_index_.py
@@ -9,7 +9,6 @@ Create Date: 2023-08-10 21:43:09.069523
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "5e84129c8be3"
down_revision = "e6a4bbc13fe4"
diff --git a/backend/alembic/versions/62c3a055a141_add_file_names_to_file_connector_config.py b/backend/alembic/versions/62c3a055a141_add_file_names_to_file_connector_config.py
index 486defd86e..cfac069022 100644
--- a/backend/alembic/versions/62c3a055a141_add_file_names_to_file_connector_config.py
+++ b/backend/alembic/versions/62c3a055a141_add_file_names_to_file_connector_config.py
@@ -12,7 +12,6 @@ import json
import os
import logging
-
# revision identifiers, used by Alembic.
revision = "62c3a055a141"
down_revision = "3fc5d75723b3"
diff --git a/backend/alembic/versions/631fd2504136_add_approx_chunk_count_in_vespa_to_.py b/backend/alembic/versions/631fd2504136_add_approx_chunk_count_in_vespa_to_.py
index 40c4eb08f0..cd6314d4c8 100644
--- a/backend/alembic/versions/631fd2504136_add_approx_chunk_count_in_vespa_to_.py
+++ b/backend/alembic/versions/631fd2504136_add_approx_chunk_count_in_vespa_to_.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-18 21:07:52.831215
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "631fd2504136"
down_revision = "c7f2e1b4a9d3"
diff --git a/backend/alembic/versions/64bd5677aeb6_add_image_input_support_to_model_config.py b/backend/alembic/versions/64bd5677aeb6_add_image_input_support_to_model_config.py
index b373114302..f86cea46d4 100644
--- a/backend/alembic/versions/64bd5677aeb6_add_image_input_support_to_model_config.py
+++ b/backend/alembic/versions/64bd5677aeb6_add_image_input_support_to_model_config.py
@@ -9,7 +9,6 @@ Create Date: 2025-09-28 15:48:12.003612
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "64bd5677aeb6"
down_revision = "b30353be4eec"
diff --git a/backend/alembic/versions/65bc6e0f8500_remove_kg_subtype_from_db.py b/backend/alembic/versions/65bc6e0f8500_remove_kg_subtype_from_db.py
index 53b2f6fa3a..d7ae4d6cda 100644
--- a/backend/alembic/versions/65bc6e0f8500_remove_kg_subtype_from_db.py
+++ b/backend/alembic/versions/65bc6e0f8500_remove_kg_subtype_from_db.py
@@ -9,7 +9,6 @@ Create Date: 2025-06-13 10:04:27.705976
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "65bc6e0f8500"
down_revision = "cec7ec36c505"
diff --git a/backend/alembic/versions/689433b0d8de_add_hook_and_hook_execution_log_tables.py b/backend/alembic/versions/689433b0d8de_add_hook_and_hook_execution_log_tables.py
index 1f12a349f2..9e51e9d5da 100644
--- a/backend/alembic/versions/689433b0d8de_add_hook_and_hook_execution_log_tables.py
+++ b/backend/alembic/versions/689433b0d8de_add_hook_and_hook_execution_log_tables.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID as PGUUID
-
# revision identifiers, used by Alembic.
revision = "689433b0d8de"
down_revision = "93a2e195e25c"
diff --git a/backend/alembic/versions/699221885109_nullify_default_task_prompt.py b/backend/alembic/versions/699221885109_nullify_default_task_prompt.py
index 9d277ed5dd..5eeeb7a053 100644
--- a/backend/alembic/versions/699221885109_nullify_default_task_prompt.py
+++ b/backend/alembic/versions/699221885109_nullify_default_task_prompt.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-30 10:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "699221885109"
down_revision = "7e490836d179"
diff --git a/backend/alembic/versions/6b3b4083c5aa_persona_cleanup_and_featured.py b/backend/alembic/versions/6b3b4083c5aa_persona_cleanup_and_featured.py
index b05ff686cf..e4c4695bf2 100644
--- a/backend/alembic/versions/6b3b4083c5aa_persona_cleanup_and_featured.py
+++ b/backend/alembic/versions/6b3b4083c5aa_persona_cleanup_and_featured.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-26 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "6b3b4083c5aa"
down_revision = "57122d037335"
diff --git a/backend/alembic/versions/6f4f86aef280_add_queries_and_is_web_fetch_to_.py b/backend/alembic/versions/6f4f86aef280_add_queries_and_is_web_fetch_to_.py
index bb57335919..c910ff3af5 100644
--- a/backend/alembic/versions/6f4f86aef280_add_queries_and_is_web_fetch_to_.py
+++ b/backend/alembic/versions/6f4f86aef280_add_queries_and_is_web_fetch_to_.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "6f4f86aef280"
down_revision = "03d710ccf29c"
diff --git a/backend/alembic/versions/6fc7886d665d_make_categories_labels_and_many_to_many.py b/backend/alembic/versions/6fc7886d665d_make_categories_labels_and_many_to_many.py
index a2e02f6571..6557175974 100644
--- a/backend/alembic/versions/6fc7886d665d_make_categories_labels_and_many_to_many.py
+++ b/backend/alembic/versions/6fc7886d665d_make_categories_labels_and_many_to_many.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-13 18:12:18.029112
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "6fc7886d665d"
down_revision = "3c6531f32351"
diff --git a/backend/alembic/versions/7206234e012a_add_image_generation_config_table.py b/backend/alembic/versions/7206234e012a_add_image_generation_config_table.py
index c90efde221..8437a5c18a 100644
--- a/backend/alembic/versions/7206234e012a_add_image_generation_config_table.py
+++ b/backend/alembic/versions/7206234e012a_add_image_generation_config_table.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-21 00:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "7206234e012a"
down_revision = "699221885109"
diff --git a/backend/alembic/versions/72aa7de2e5cf_make_processing_mode_default_all_caps.py b/backend/alembic/versions/72aa7de2e5cf_make_processing_mode_default_all_caps.py
index 3a3a6413be..85083de6e4 100644
--- a/backend/alembic/versions/72aa7de2e5cf_make_processing_mode_default_all_caps.py
+++ b/backend/alembic/versions/72aa7de2e5cf_make_processing_mode_default_all_caps.py
@@ -13,7 +13,6 @@ This migration fixes the ProcessingMode enum value mismatch:
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "72aa7de2e5cf"
down_revision = "2020d417ec84"
diff --git a/backend/alembic/versions/7616121f6e97_add_enterprise_fields_to_scim_user_mapping.py b/backend/alembic/versions/7616121f6e97_add_enterprise_fields_to_scim_user_mapping.py
index 1b74392fc6..b484fdc7ae 100644
--- a/backend/alembic/versions/7616121f6e97_add_enterprise_fields_to_scim_user_mapping.py
+++ b/backend/alembic/versions/7616121f6e97_add_enterprise_fields_to_scim_user_mapping.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-23 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "7616121f6e97"
down_revision = "07b98176f1de"
diff --git a/backend/alembic/versions/767f1c2a00eb_count_chat_tokens.py b/backend/alembic/versions/767f1c2a00eb_count_chat_tokens.py
index 03867b5335..e347097f88 100644
--- a/backend/alembic/versions/767f1c2a00eb_count_chat_tokens.py
+++ b/backend/alembic/versions/767f1c2a00eb_count_chat_tokens.py
@@ -9,7 +9,6 @@ Create Date: 2023-09-21 10:03:21.509899
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "767f1c2a00eb"
down_revision = "dba7f71618f5"
diff --git a/backend/alembic/versions/77d07dffae64_forcibly_remove_more_enum_types_from_.py b/backend/alembic/versions/77d07dffae64_forcibly_remove_more_enum_types_from_.py
index 76f2a7cea7..3575914afb 100644
--- a/backend/alembic/versions/77d07dffae64_forcibly_remove_more_enum_types_from_.py
+++ b/backend/alembic/versions/77d07dffae64_forcibly_remove_more_enum_types_from_.py
@@ -9,7 +9,6 @@ Create Date: 2023-11-01 12:33:01.999617
from alembic import op
from sqlalchemy import String
-
# revision identifiers, used by Alembic.
revision = "77d07dffae64"
down_revision = "d61e513bef0a"
diff --git a/backend/alembic/versions/795b20b85b4b_add_llm_group_permissions_control.py b/backend/alembic/versions/795b20b85b4b_add_llm_group_permissions_control.py
index 6965818142..df4fbdeba5 100644
--- a/backend/alembic/versions/795b20b85b4b_add_llm_group_permissions_control.py
+++ b/backend/alembic/versions/795b20b85b4b_add_llm_group_permissions_control.py
@@ -9,7 +9,6 @@ Create Date: 2024-07-19 11:54:35.701558
from alembic import op
import sqlalchemy as sa
-
revision = "795b20b85b4b"
down_revision = "05c07bf07c00"
branch_labels: None = None
diff --git a/backend/alembic/versions/797089dfb4d2_persona_start_date.py b/backend/alembic/versions/797089dfb4d2_persona_start_date.py
index d19c663b27..d635446c32 100644
--- a/backend/alembic/versions/797089dfb4d2_persona_start_date.py
+++ b/backend/alembic/versions/797089dfb4d2_persona_start_date.py
@@ -9,7 +9,6 @@ Create Date: 2024-09-11 14:51:49.785835
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "797089dfb4d2"
down_revision = "55546a7967ee"
diff --git a/backend/alembic/versions/7b9b952abdf6_update_entities.py b/backend/alembic/versions/7b9b952abdf6_update_entities.py
index 4d49180116..dc04b4cae0 100644
--- a/backend/alembic/versions/7b9b952abdf6_update_entities.py
+++ b/backend/alembic/versions/7b9b952abdf6_update_entities.py
@@ -11,7 +11,6 @@ import json
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "7b9b952abdf6"
down_revision = "36e9220ab794"
diff --git a/backend/alembic/versions/7cb492013621_code_interpreter_server_model.py b/backend/alembic/versions/7cb492013621_code_interpreter_server_model.py
index 2fa5025ea3..ae44408c07 100644
--- a/backend/alembic/versions/7cb492013621_code_interpreter_server_model.py
+++ b/backend/alembic/versions/7cb492013621_code_interpreter_server_model.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-22 18:54:54.007265
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "7cb492013621"
down_revision = "0bb4558f35df"
diff --git a/backend/alembic/versions/7e490836d179_nullify_default_system_prompt.py b/backend/alembic/versions/7e490836d179_nullify_default_system_prompt.py
index 33ae1d8080..096fb63345 100644
--- a/backend/alembic/versions/7e490836d179_nullify_default_system_prompt.py
+++ b/backend/alembic/versions/7e490836d179_nullify_default_system_prompt.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-29 16:54:36.635574
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "7e490836d179"
down_revision = "c1d2e3f4a5b6"
diff --git a/backend/alembic/versions/7f99be1cb9f5_add_index_for_getting_documents_just_by_.py b/backend/alembic/versions/7f99be1cb9f5_add_index_for_getting_documents_just_by_.py
index cec472e1ee..0d78f24438 100644
--- a/backend/alembic/versions/7f99be1cb9f5_add_index_for_getting_documents_just_by_.py
+++ b/backend/alembic/versions/7f99be1cb9f5_add_index_for_getting_documents_just_by_.py
@@ -8,7 +8,6 @@ Create Date: 2023-10-15 22:48:15.487762
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "7f99be1cb9f5"
down_revision = "78dbe7e38469"
diff --git a/backend/alembic/versions/8188861f4e92_csv_to_tabular_chat_file_type.py b/backend/alembic/versions/8188861f4e92_csv_to_tabular_chat_file_type.py
index dc39e9a342..4163185b3f 100644
--- a/backend/alembic/versions/8188861f4e92_csv_to_tabular_chat_file_type.py
+++ b/backend/alembic/versions/8188861f4e92_csv_to_tabular_chat_file_type.py
@@ -8,7 +8,6 @@ Create Date: 2026-03-31 19:23:05.753184
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "8188861f4e92"
down_revision = "d8cdfee5df80"
diff --git a/backend/alembic/versions/81c22b1e2e78_hierarchy_nodes_v1.py b/backend/alembic/versions/81c22b1e2e78_hierarchy_nodes_v1.py
index f97a2e47f0..f02f91c345 100644
--- a/backend/alembic/versions/81c22b1e2e78_hierarchy_nodes_v1.py
+++ b/backend/alembic/versions/81c22b1e2e78_hierarchy_nodes_v1.py
@@ -12,7 +12,6 @@ from sqlalchemy.dialects import postgresql
from onyx.configs.constants import DocumentSource
-
# revision identifiers, used by Alembic.
revision = "81c22b1e2e78"
down_revision = "72aa7de2e5cf"
diff --git a/backend/alembic/versions/8405ca81cc83_notifications_constraint.py b/backend/alembic/versions/8405ca81cc83_notifications_constraint.py
index 2502c0c3cb..b8a2d0669d 100644
--- a/backend/alembic/versions/8405ca81cc83_notifications_constraint.py
+++ b/backend/alembic/versions/8405ca81cc83_notifications_constraint.py
@@ -8,7 +8,6 @@ Create Date: 2026-01-07 16:43:44.855156
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "8405ca81cc83"
down_revision = "a3c1a7904cd0"
diff --git a/backend/alembic/versions/856bcbe14d79_add_missing_fk_indexes_for_hot_tables.py b/backend/alembic/versions/856bcbe14d79_add_missing_fk_indexes_for_hot_tables.py
index dd3a300503..e748990de4 100644
--- a/backend/alembic/versions/856bcbe14d79_add_missing_fk_indexes_for_hot_tables.py
+++ b/backend/alembic/versions/856bcbe14d79_add_missing_fk_indexes_for_hot_tables.py
@@ -30,7 +30,6 @@ Create Date: 2026-04-19 18:00:00.000000
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "856bcbe14d79"
down_revision = "91d150c361f6"
diff --git a/backend/alembic/versions/87c52ec39f84_update_default_system_prompt.py b/backend/alembic/versions/87c52ec39f84_update_default_system_prompt.py
index 57e31b8c6f..f9e690219e 100644
--- a/backend/alembic/versions/87c52ec39f84_update_default_system_prompt.py
+++ b/backend/alembic/versions/87c52ec39f84_update_default_system_prompt.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-05 15:54:06.002452
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "87c52ec39f84"
down_revision = "7bd55f264e1b"
diff --git a/backend/alembic/versions/8e1ac4f39a9f_enable_contextual_retrieval.py b/backend/alembic/versions/8e1ac4f39a9f_enable_contextual_retrieval.py
index 2eed73a0a2..41e74ef277 100644
--- a/backend/alembic/versions/8e1ac4f39a9f_enable_contextual_retrieval.py
+++ b/backend/alembic/versions/8e1ac4f39a9f_enable_contextual_retrieval.py
@@ -9,7 +9,6 @@ Create Date: 2024-12-20 13:29:09.918661
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "8e1ac4f39a9f"
down_revision = "9aadf32dfeb4"
diff --git a/backend/alembic/versions/8e26726b7683_chat_context_addition.py b/backend/alembic/versions/8e26726b7683_chat_context_addition.py
index 23c8d4a8bf..3021eed450 100644
--- a/backend/alembic/versions/8e26726b7683_chat_context_addition.py
+++ b/backend/alembic/versions/8e26726b7683_chat_context_addition.py
@@ -9,7 +9,6 @@ Create Date: 2023-09-13 18:34:31.327944
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "8e26726b7683"
down_revision = "5809c0787398"
diff --git a/backend/alembic/versions/8f43500ee275_add_index.py b/backend/alembic/versions/8f43500ee275_add_index.py
index c99a229883..927bc38e74 100644
--- a/backend/alembic/versions/8f43500ee275_add_index.py
+++ b/backend/alembic/versions/8f43500ee275_add_index.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-24 17:35:33.072714
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "8f43500ee275"
down_revision = "da42808081e3"
diff --git a/backend/alembic/versions/8ffcc2bcfc11_add_needs_persona_sync_to_user_file.py b/backend/alembic/versions/8ffcc2bcfc11_add_needs_persona_sync_to_user_file.py
index 864dfa560d..197b5701a2 100644
--- a/backend/alembic/versions/8ffcc2bcfc11_add_needs_persona_sync_to_user_file.py
+++ b/backend/alembic/versions/8ffcc2bcfc11_add_needs_persona_sync_to_user_file.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-23 10:48:48.343826
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "8ffcc2bcfc11"
down_revision = "7616121f6e97"
diff --git a/backend/alembic/versions/9087b548dd69_seed_default_image_gen_config.py b/backend/alembic/versions/9087b548dd69_seed_default_image_gen_config.py
index fe3c72f245..11d70261c4 100644
--- a/backend/alembic/versions/9087b548dd69_seed_default_image_gen_config.py
+++ b/backend/alembic/versions/9087b548dd69_seed_default_image_gen_config.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-05 00:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "9087b548dd69"
down_revision = "2b90f3af54b8"
diff --git a/backend/alembic/versions/90b409d06e50_add_chat_compression_fields.py b/backend/alembic/versions/90b409d06e50_add_chat_compression_fields.py
index 56b9709e17..3eb854b01a 100644
--- a/backend/alembic/versions/90b409d06e50_add_chat_compression_fields.py
+++ b/backend/alembic/versions/90b409d06e50_add_chat_compression_fields.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-26 09:13:09.635427
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "90b409d06e50"
down_revision = "f220515df7b4"
diff --git a/backend/alembic/versions/90e3b9af7da4_tag_fix.py b/backend/alembic/versions/90e3b9af7da4_tag_fix.py
index 02a03c877f..4fcc2e3ea2 100644
--- a/backend/alembic/versions/90e3b9af7da4_tag_fix.py
+++ b/backend/alembic/versions/90e3b9af7da4_tag_fix.py
@@ -165,7 +165,7 @@ def remove_old_tags() -> None:
)
)
n_deleted += result.rowcount
- logger.info(f"Processed {len(batch)} documents and deleted {n_deleted} tags")
+ logger.info("Processed %s documents and deleted %s tags", len(batch), n_deleted)
def active_search_settings() -> tuple[SearchSettings, SearchSettings | None]:
diff --git a/backend/alembic/versions/93a2e195e25c_add_voice_provider_and_user_voice_prefs.py b/backend/alembic/versions/93a2e195e25c_add_voice_provider_and_user_voice_prefs.py
index 8480387a43..95fdf66f83 100644
--- a/backend/alembic/versions/93a2e195e25c_add_voice_provider_and_user_voice_prefs.py
+++ b/backend/alembic/versions/93a2e195e25c_add_voice_provider_and_user_voice_prefs.py
@@ -12,7 +12,6 @@ from sqlalchemy import column
from sqlalchemy import true
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "93a2e195e25c"
down_revision = "27fb147a843f"
diff --git a/backend/alembic/versions/93c15d6a6fbb_add_chunk_error_and_vespa_count_columns_.py b/backend/alembic/versions/93c15d6a6fbb_add_chunk_error_and_vespa_count_columns_.py
index 4667ad3835..a3fde16f29 100644
--- a/backend/alembic/versions/93c15d6a6fbb_add_chunk_error_and_vespa_count_columns_.py
+++ b/backend/alembic/versions/93c15d6a6fbb_add_chunk_error_and_vespa_count_columns_.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-11 23:07:34.576725
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "93c15d6a6fbb"
down_revision = "d3fd499c829c"
diff --git a/backend/alembic/versions/949b4a92a401_remove_rt.py b/backend/alembic/versions/949b4a92a401_remove_rt.py
index 5ef6d5a22e..8ddd09d4a7 100644
--- a/backend/alembic/versions/949b4a92a401_remove_rt.py
+++ b/backend/alembic/versions/949b4a92a401_remove_rt.py
@@ -18,7 +18,6 @@ from onyx.db.models import (
IndexAttempt,
)
-
# revision identifiers, used by Alembic.
revision = "949b4a92a401"
down_revision = "1b10e1fda030"
diff --git a/backend/alembic/versions/94dc3d0236f8_make_document_set_description_optional.py b/backend/alembic/versions/94dc3d0236f8_make_document_set_description_optional.py
index 2db6589ba9..af738a6ffc 100644
--- a/backend/alembic/versions/94dc3d0236f8_make_document_set_description_optional.py
+++ b/backend/alembic/versions/94dc3d0236f8_make_document_set_description_optional.py
@@ -9,7 +9,6 @@ Create Date: 2024-12-11 11:26:10.616722
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "94dc3d0236f8"
down_revision = "bf7a81109301"
diff --git a/backend/alembic/versions/96a5702df6aa_mcp_tool_enabled.py b/backend/alembic/versions/96a5702df6aa_mcp_tool_enabled.py
index 43508814bf..af7579bf11 100644
--- a/backend/alembic/versions/96a5702df6aa_mcp_tool_enabled.py
+++ b/backend/alembic/versions/96a5702df6aa_mcp_tool_enabled.py
@@ -9,7 +9,6 @@ Create Date: 2025-10-09 12:10:21.733097
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "96a5702df6aa"
down_revision = "40926a4dab77"
diff --git a/backend/alembic/versions/977e834c1427_seed_default_groups.py b/backend/alembic/versions/977e834c1427_seed_default_groups.py
index 75fce18483..4b002c102b 100644
--- a/backend/alembic/versions/977e834c1427_seed_default_groups.py
+++ b/backend/alembic/versions/977e834c1427_seed_default_groups.py
@@ -12,7 +12,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import insert as pg_insert
-
# revision identifiers, used by Alembic.
revision = "977e834c1427"
down_revision = "8188861f4e92"
diff --git a/backend/alembic/versions/9a0296d7421e_add_is_auto_mode_to_llm_provider.py b/backend/alembic/versions/9a0296d7421e_add_is_auto_mode_to_llm_provider.py
index e05b5d53b9..fc2bd0ded6 100644
--- a/backend/alembic/versions/9a0296d7421e_add_is_auto_mode_to_llm_provider.py
+++ b/backend/alembic/versions/9a0296d7421e_add_is_auto_mode_to_llm_provider.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-17 18:14:29.620981
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "9a0296d7421e"
down_revision = "7206234e012a"
diff --git a/backend/alembic/versions/9aadf32dfeb4_add_user_files.py b/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
index aa781de39e..1c2b8d2a2f 100644
--- a/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
+++ b/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
@@ -10,7 +10,6 @@ import sqlalchemy as sa
import datetime
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "9aadf32dfeb4"
down_revision = "3781a5eb12cb"
diff --git a/backend/alembic/versions/9b66d3156fc6_user_file_schema_additions.py b/backend/alembic/versions/9b66d3156fc6_user_file_schema_additions.py
index 531c6402d5..c28a576659 100644
--- a/backend/alembic/versions/9b66d3156fc6_user_file_schema_additions.py
+++ b/backend/alembic/versions/9b66d3156fc6_user_file_schema_additions.py
@@ -255,7 +255,7 @@ def downgrade() -> None:
for col in columns_to_drop:
if col in columns:
op.drop_column("user_file", col)
- logger.info(f"Dropped {col} from user_file")
+ logger.info("Dropped %s from user_file", col)
if "new_id" in columns:
op.drop_constraint("uq_user_file_new_id", "user_file", type_="unique")
diff --git a/backend/alembic/versions/9c00a2bccb83_chat_message_agentic.py b/backend/alembic/versions/9c00a2bccb83_chat_message_agentic.py
index cec3b99931..a5e735ac44 100644
--- a/backend/alembic/versions/9c00a2bccb83_chat_message_agentic.py
+++ b/backend/alembic/versions/9c00a2bccb83_chat_message_agentic.py
@@ -9,7 +9,6 @@ Create Date: 2025-02-17 11:15:43.081150
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "9c00a2bccb83"
down_revision = "b7a7eee5aa15"
diff --git a/backend/alembic/versions/a01bf2971c5d_update_default_tool_descriptions.py b/backend/alembic/versions/a01bf2971c5d_update_default_tool_descriptions.py
index 8dae3da513..57b5eac4f3 100644
--- a/backend/alembic/versions/a01bf2971c5d_update_default_tool_descriptions.py
+++ b/backend/alembic/versions/a01bf2971c5d_update_default_tool_descriptions.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-16 15:21:25.656375
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "a01bf2971c5d"
down_revision = "18b5b2524446"
diff --git a/backend/alembic/versions/a3b8d9e2f1c4_make_scim_external_id_nullable.py b/backend/alembic/versions/a3b8d9e2f1c4_make_scim_external_id_nullable.py
index 1d9cf7c3d7..777b631103 100644
--- a/backend/alembic/versions/a3b8d9e2f1c4_make_scim_external_id_nullable.py
+++ b/backend/alembic/versions/a3b8d9e2f1c4_make_scim_external_id_nullable.py
@@ -8,7 +8,6 @@ Create Date: 2026-03-02
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "a3b8d9e2f1c4"
down_revision = "2664261bfaab"
diff --git a/backend/alembic/versions/a4f23d6b71c8_add_llm_provider_persona_restrictions.py b/backend/alembic/versions/a4f23d6b71c8_add_llm_provider_persona_restrictions.py
index ee8df4c3c1..abd8e4e738 100644
--- a/backend/alembic/versions/a4f23d6b71c8_add_llm_provider_persona_restrictions.py
+++ b/backend/alembic/versions/a4f23d6b71c8_add_llm_provider_persona_restrictions.py
@@ -9,7 +9,6 @@ Create Date: 2025-10-21 00:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "a4f23d6b71c8"
down_revision = "5e1c073d48a3"
diff --git a/backend/alembic/versions/a6fcd3d631f9_replace_document_sync_index_with_partial.py b/backend/alembic/versions/a6fcd3d631f9_replace_document_sync_index_with_partial.py
index 0080f32b35..0ac54de1d5 100644
--- a/backend/alembic/versions/a6fcd3d631f9_replace_document_sync_index_with_partial.py
+++ b/backend/alembic/versions/a6fcd3d631f9_replace_document_sync_index_with_partial.py
@@ -21,7 +21,6 @@ Create Date: 2026-04-17 16:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "a6fcd3d631f9"
down_revision = "d129f37b3d87"
diff --git a/backend/alembic/versions/a8c2065484e6_add_auto_scroll_to_user_model.py b/backend/alembic/versions/a8c2065484e6_add_auto_scroll_to_user_model.py
index b72ee45107..de5fd3b426 100644
--- a/backend/alembic/versions/a8c2065484e6_add_auto_scroll_to_user_model.py
+++ b/backend/alembic/versions/a8c2065484e6_add_auto_scroll_to_user_model.py
@@ -9,7 +9,6 @@ Create Date: 2024-11-22 17:34:09.690295
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "a8c2065484e6"
down_revision = "abe7378b8217"
diff --git a/backend/alembic/versions/b30353be4eec_add_mcp_auth_performer.py b/backend/alembic/versions/b30353be4eec_add_mcp_auth_performer.py
index e17b0f87dd..f881632300 100644
--- a/backend/alembic/versions/b30353be4eec_add_mcp_auth_performer.py
+++ b/backend/alembic/versions/b30353be4eec_add_mcp_auth_performer.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from onyx.db.enums import MCPAuthenticationPerformer, MCPTransport
-
# revision identifiers, used by Alembic.
revision = "b30353be4eec"
down_revision = "2b75d0a8ffcb"
diff --git a/backend/alembic/versions/b388730a2899_nullable_preferences.py b/backend/alembic/versions/b388730a2899_nullable_preferences.py
index c796e9d82e..b44806a93a 100644
--- a/backend/alembic/versions/b388730a2899_nullable_preferences.py
+++ b/backend/alembic/versions/b388730a2899_nullable_preferences.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-17 18:49:22.643902
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "b388730a2899"
down_revision = "1a03d2c2856b"
diff --git a/backend/alembic/versions/b4b7e1028dfd_grant_basic_to_existing_groups.py b/backend/alembic/versions/b4b7e1028dfd_grant_basic_to_existing_groups.py
index 9065beeaef..fd6a25593e 100644
--- a/backend/alembic/versions/b4b7e1028dfd_grant_basic_to_existing_groups.py
+++ b/backend/alembic/versions/b4b7e1028dfd_grant_basic_to_existing_groups.py
@@ -15,7 +15,6 @@ from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "b4b7e1028dfd"
down_revision = "b7bcc991d722"
diff --git a/backend/alembic/versions/b4ef3ae0bf6e_add_user_oauth_token_to_slack_bot.py b/backend/alembic/versions/b4ef3ae0bf6e_add_user_oauth_token_to_slack_bot.py
index cbc40996af..d58877035c 100644
--- a/backend/alembic/versions/b4ef3ae0bf6e_add_user_oauth_token_to_slack_bot.py
+++ b/backend/alembic/versions/b4ef3ae0bf6e_add_user_oauth_token_to_slack_bot.py
@@ -9,7 +9,6 @@ Create Date: 2025-08-26 17:47:41.788462
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "b4ef3ae0bf6e"
down_revision = "505c488f6662"
diff --git a/backend/alembic/versions/b51c6844d1df_seed_memory_tool.py b/backend/alembic/versions/b51c6844d1df_seed_memory_tool.py
index d387061fc4..c35d0b8fc6 100644
--- a/backend/alembic/versions/b51c6844d1df_seed_memory_tool.py
+++ b/backend/alembic/versions/b51c6844d1df_seed_memory_tool.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-11 00:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "b51c6844d1df"
down_revision = "93c15d6a6fbb"
diff --git a/backend/alembic/versions/b558f51620b4_pause_finished_user_file_connectors.py b/backend/alembic/versions/b558f51620b4_pause_finished_user_file_connectors.py
index 48bfb9e9b9..8615176549 100644
--- a/backend/alembic/versions/b558f51620b4_pause_finished_user_file_connectors.py
+++ b/backend/alembic/versions/b558f51620b4_pause_finished_user_file_connectors.py
@@ -8,7 +8,6 @@ Create Date: 2025-08-15 17:17:02.456704
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "b558f51620b4"
down_revision = "90e3b9af7da4"
diff --git a/backend/alembic/versions/b728689f45b1_rename_persona_is_visible_to_is_listed_.py b/backend/alembic/versions/b728689f45b1_rename_persona_is_visible_to_is_listed_.py
index 70751ca4ff..a4784325f4 100644
--- a/backend/alembic/versions/b728689f45b1_rename_persona_is_visible_to_is_listed_.py
+++ b/backend/alembic/versions/b728689f45b1_rename_persona_is_visible_to_is_listed_.py
@@ -8,7 +8,6 @@ Create Date: 2026-03-23 12:36:26.607305
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "b728689f45b1"
down_revision = "689433b0d8de"
diff --git a/backend/alembic/versions/b72ed7a5db0e_remove_description_from_starter_messages.py b/backend/alembic/versions/b72ed7a5db0e_remove_description_from_starter_messages.py
index cda2785bb8..96c597a96f 100644
--- a/backend/alembic/versions/b72ed7a5db0e_remove_description_from_starter_messages.py
+++ b/backend/alembic/versions/b72ed7a5db0e_remove_description_from_starter_messages.py
@@ -9,7 +9,6 @@ Create Date: 2024-11-03 15:55:28.944408
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "b72ed7a5db0e"
down_revision = "33cb72ea4d80"
diff --git a/backend/alembic/versions/b7bcc991d722_assign_users_to_default_groups.py b/backend/alembic/versions/b7bcc991d722_assign_users_to_default_groups.py
index a767f6bcd6..1979a1b991 100644
--- a/backend/alembic/versions/b7bcc991d722_assign_users_to_default_groups.py
+++ b/backend/alembic/versions/b7bcc991d722_assign_users_to_default_groups.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import insert as pg_insert
-
# revision identifiers, used by Alembic.
revision = "b7bcc991d722"
down_revision = "03d085c5c38d"
diff --git a/backend/alembic/versions/b7c2b63c4a03_add_background_reindex_enabled_field.py b/backend/alembic/versions/b7c2b63c4a03_add_background_reindex_enabled_field.py
index ec3ac29380..57209cde16 100644
--- a/backend/alembic/versions/b7c2b63c4a03_add_background_reindex_enabled_field.py
+++ b/backend/alembic/versions/b7c2b63c4a03_add_background_reindex_enabled_field.py
@@ -11,7 +11,6 @@ import sqlalchemy as sa
from onyx.db.enums import EmbeddingPrecision
-
# revision identifiers, used by Alembic.
revision = "b7c2b63c4a03"
down_revision = "f11b408e39d3"
diff --git a/backend/alembic/versions/b7ec9b5b505f_adjust_prompt_length.py b/backend/alembic/versions/b7ec9b5b505f_adjust_prompt_length.py
index 37e6313ee8..983b5e557a 100644
--- a/backend/alembic/versions/b7ec9b5b505f_adjust_prompt_length.py
+++ b/backend/alembic/versions/b7ec9b5b505f_adjust_prompt_length.py
@@ -9,7 +9,6 @@ Create Date: 2025-09-10 18:51:15.629197
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "b7ec9b5b505f"
down_revision = "abbfec3a5ac5"
diff --git a/backend/alembic/versions/b896bbd0d5a7_backfill_is_internet_data_to_false.py b/backend/alembic/versions/b896bbd0d5a7_backfill_is_internet_data_to_false.py
index abb21fe169..9115d28428 100644
--- a/backend/alembic/versions/b896bbd0d5a7_backfill_is_internet_data_to_false.py
+++ b/backend/alembic/versions/b896bbd0d5a7_backfill_is_internet_data_to_false.py
@@ -8,7 +8,6 @@ Create Date: 2024-07-16 15:21:05.718571
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "b896bbd0d5a7"
down_revision = "44f856ae2a4a"
diff --git a/backend/alembic/versions/ba98eba0f66a_add_support_for_litellm_proxy_in_.py b/backend/alembic/versions/ba98eba0f66a_add_support_for_litellm_proxy_in_.py
index 719e606dae..82f7852c0f 100644
--- a/backend/alembic/versions/ba98eba0f66a_add_support_for_litellm_proxy_in_.py
+++ b/backend/alembic/versions/ba98eba0f66a_add_support_for_litellm_proxy_in_.py
@@ -9,7 +9,6 @@ Create Date: 2024-09-06 10:36:04.507332
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "ba98eba0f66a"
down_revision = "bceb1e139447"
diff --git a/backend/alembic/versions/bceb1e139447_add_base_url_to_cloudembeddingprovider.py b/backend/alembic/versions/bceb1e139447_add_base_url_to_cloudembeddingprovider.py
index 50bec01890..ecb73191c6 100644
--- a/backend/alembic/versions/bceb1e139447_add_base_url_to_cloudembeddingprovider.py
+++ b/backend/alembic/versions/bceb1e139447_add_base_url_to_cloudembeddingprovider.py
@@ -9,7 +9,6 @@ Create Date: 2024-08-28 17:00:52.554580
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "bceb1e139447"
down_revision = "a3795dce87be"
diff --git a/backend/alembic/versions/bd2921608c3a_non_nullable_default_persona.py b/backend/alembic/versions/bd2921608c3a_non_nullable_default_persona.py
index 15f653351f..51fcb3fad2 100644
--- a/backend/alembic/versions/bd2921608c3a_non_nullable_default_persona.py
+++ b/backend/alembic/versions/bd2921608c3a_non_nullable_default_persona.py
@@ -9,7 +9,6 @@ Create Date: 2024-09-20 10:28:37.992042
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "bd2921608c3a"
down_revision = "797089dfb4d2"
diff --git a/backend/alembic/versions/bd7c3bf8beba_migrate_agent_responses_to_research_.py b/backend/alembic/versions/bd7c3bf8beba_migrate_agent_responses_to_research_.py
index e7933952ff..764fe3de55 100644
--- a/backend/alembic/versions/bd7c3bf8beba_migrate_agent_responses_to_research_.py
+++ b/backend/alembic/versions/bd7c3bf8beba_migrate_agent_responses_to_research_.py
@@ -9,7 +9,6 @@ Create Date: 2025-08-18 11:33:27.098287
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "bd7c3bf8beba"
down_revision = "f8a9b2c3d4e5"
diff --git a/backend/alembic/versions/be87a654d5af_persona_new_default_model_configuration_.py b/backend/alembic/versions/be87a654d5af_persona_new_default_model_configuration_.py
index d476420806..099935ef55 100644
--- a/backend/alembic/versions/be87a654d5af_persona_new_default_model_configuration_.py
+++ b/backend/alembic/versions/be87a654d5af_persona_new_default_model_configuration_.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-30 11:14:17.306275
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "be87a654d5af"
down_revision = "e7f8a9b0c1d2"
diff --git a/backend/alembic/versions/bf7a81109301_delete_input_prompts.py b/backend/alembic/versions/bf7a81109301_delete_input_prompts.py
index 6bc1330d93..76560c1afe 100644
--- a/backend/alembic/versions/bf7a81109301_delete_input_prompts.py
+++ b/backend/alembic/versions/bf7a81109301_delete_input_prompts.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
import fastapi_users_db_sqlalchemy
-
# revision identifiers, used by Alembic.
revision = "bf7a81109301"
down_revision = "f7a894b06d02"
diff --git a/backend/alembic/versions/c0aab6edb6dd_delete_workspace.py b/backend/alembic/versions/c0aab6edb6dd_delete_workspace.py
index 0ead6dd907..e647f857ab 100644
--- a/backend/alembic/versions/c0aab6edb6dd_delete_workspace.py
+++ b/backend/alembic/versions/c0aab6edb6dd_delete_workspace.py
@@ -8,7 +8,6 @@ Create Date: 2024-12-17 14:37:07.660631
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "c0aab6edb6dd"
down_revision = "35e518e0ddf4"
diff --git a/backend/alembic/versions/c0c937d5c9e5_llm_provider_deprecate_fields.py b/backend/alembic/versions/c0c937d5c9e5_llm_provider_deprecate_fields.py
index 7b82e942a5..86e8fd8976 100644
--- a/backend/alembic/versions/c0c937d5c9e5_llm_provider_deprecate_fields.py
+++ b/backend/alembic/versions/c0c937d5c9e5_llm_provider_deprecate_fields.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-25 17:35:46.125102
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "c0c937d5c9e5"
down_revision = "8ffcc2bcfc11"
diff --git a/backend/alembic/versions/c1d2e3f4a5b6_add_deep_research_tool.py b/backend/alembic/versions/c1d2e3f4a5b6_add_deep_research_tool.py
index 35205d39ea..aeda606ba2 100644
--- a/backend/alembic/versions/c1d2e3f4a5b6_add_deep_research_tool.py
+++ b/backend/alembic/versions/c1d2e3f4a5b6_add_deep_research_tool.py
@@ -9,7 +9,6 @@ Create Date: 2025-12-18 16:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "c1d2e3f4a5b6"
down_revision = "b8c9d0e1f2a3"
diff --git a/backend/alembic/versions/c7e9f4a3b2d1_add_python_tool.py b/backend/alembic/versions/c7e9f4a3b2d1_add_python_tool.py
index 7f4b1c3341..663a94e00d 100644
--- a/backend/alembic/versions/c7e9f4a3b2d1_add_python_tool.py
+++ b/backend/alembic/versions/c7e9f4a3b2d1_add_python_tool.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "c7e9f4a3b2d1"
down_revision = "3c9a65f1207f"
diff --git a/backend/alembic/versions/c8a93a2af083_personalization_user_info.py b/backend/alembic/versions/c8a93a2af083_personalization_user_info.py
index 28d38b3d75..2b32fdad3c 100644
--- a/backend/alembic/versions/c8a93a2af083_personalization_user_info.py
+++ b/backend/alembic/versions/c8a93a2af083_personalization_user_info.py
@@ -10,7 +10,6 @@ from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
-
# revision identifiers, used by Alembic.
revision = "c8a93a2af083"
down_revision = "6f4f86aef280"
diff --git a/backend/alembic/versions/ca04500b9ee8_add_cascade_deletes_to_agent_tables.py b/backend/alembic/versions/ca04500b9ee8_add_cascade_deletes_to_agent_tables.py
index 2846f0f51d..e19b59e326 100644
--- a/backend/alembic/versions/ca04500b9ee8_add_cascade_deletes_to_agent_tables.py
+++ b/backend/alembic/versions/ca04500b9ee8_add_cascade_deletes_to_agent_tables.py
@@ -8,7 +8,6 @@ Create Date: 2025-05-30 16:03:51.112263
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "ca04500b9ee8"
down_revision = "238b84885828"
diff --git a/backend/alembic/versions/cbc03e08d0f3_add_opensearch_migration_tables.py b/backend/alembic/versions/cbc03e08d0f3_add_opensearch_migration_tables.py
index 810cb1ddcb..d47b6f3ee5 100644
--- a/backend/alembic/versions/cbc03e08d0f3_add_opensearch_migration_tables.py
+++ b/backend/alembic/versions/cbc03e08d0f3_add_opensearch_migration_tables.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-31 17:00:45.176604
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "cbc03e08d0f3"
down_revision = "be87a654d5af"
diff --git a/backend/alembic/versions/cec7ec36c505_kgentity_parent.py b/backend/alembic/versions/cec7ec36c505_kgentity_parent.py
index 895abf87ba..0497147983 100644
--- a/backend/alembic/versions/cec7ec36c505_kgentity_parent.py
+++ b/backend/alembic/versions/cec7ec36c505_kgentity_parent.py
@@ -9,7 +9,6 @@ Create Date: 2025-06-07 20:07:46.400770
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "cec7ec36c505"
down_revision = "495cb26ce93e"
diff --git a/backend/alembic/versions/cf90764725d8_larger_refresh_tokens.py b/backend/alembic/versions/cf90764725d8_larger_refresh_tokens.py
index 05a5683d74..7c32612efa 100644
--- a/backend/alembic/versions/cf90764725d8_larger_refresh_tokens.py
+++ b/backend/alembic/versions/cf90764725d8_larger_refresh_tokens.py
@@ -9,7 +9,6 @@ Create Date: 2025-04-04 10:56:39.769294
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "cf90764725d8"
down_revision = "4794bc13e484"
diff --git a/backend/alembic/versions/d09fc20a3c66_seed_builtin_tools.py b/backend/alembic/versions/d09fc20a3c66_seed_builtin_tools.py
index 2b0d1cf29f..6c10cd821d 100644
--- a/backend/alembic/versions/d09fc20a3c66_seed_builtin_tools.py
+++ b/backend/alembic/versions/d09fc20a3c66_seed_builtin_tools.py
@@ -9,7 +9,6 @@ Create Date: 2025-09-09 19:32:16.824373
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d09fc20a3c66"
down_revision = "b7ec9b5b505f"
diff --git a/backend/alembic/versions/d129f37b3d87_add_error_tracking_fields_to_index_.py b/backend/alembic/versions/d129f37b3d87_add_error_tracking_fields_to_index_.py
index 6aa3a5c08b..0ecb433423 100644
--- a/backend/alembic/versions/d129f37b3d87_add_error_tracking_fields_to_index_.py
+++ b/backend/alembic/versions/d129f37b3d87_add_error_tracking_fields_to_index_.py
@@ -9,7 +9,6 @@ Create Date: 2026-04-06 19:11:18.261800
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d129f37b3d87"
down_revision = "503883791c39"
diff --git a/backend/alembic/versions/d1b637d7050a_sync_exa_api_key_to_content_provider.py b/backend/alembic/versions/d1b637d7050a_sync_exa_api_key_to_content_provider.py
index fe2f95933a..4d106e7023 100644
--- a/backend/alembic/versions/d1b637d7050a_sync_exa_api_key_to_content_provider.py
+++ b/backend/alembic/versions/d1b637d7050a_sync_exa_api_key_to_content_provider.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-09 15:54:15.646249
from alembic import op
from sqlalchemy import text
-
# revision identifiers, used by Alembic.
revision = "d1b637d7050a"
down_revision = "d25168c2beee"
diff --git a/backend/alembic/versions/d25168c2beee_tool_name_consistency.py b/backend/alembic/versions/d25168c2beee_tool_name_consistency.py
index c33d4d6e5a..216562a18a 100644
--- a/backend/alembic/versions/d25168c2beee_tool_name_consistency.py
+++ b/backend/alembic/versions/d25168c2beee_tool_name_consistency.py
@@ -9,7 +9,6 @@ Create Date: 2026-01-11 17:54:40.135777
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d25168c2beee"
down_revision = "8405ca81cc83"
diff --git a/backend/alembic/versions/d3fd499c829c_add_file_reader_tool.py b/backend/alembic/versions/d3fd499c829c_add_file_reader_tool.py
index 218a3d2fd4..df83f5ef59 100644
--- a/backend/alembic/versions/d3fd499c829c_add_file_reader_tool.py
+++ b/backend/alembic/versions/d3fd499c829c_add_file_reader_tool.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-07 19:28:22.452337
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d3fd499c829c"
down_revision = "114a638452db"
diff --git a/backend/alembic/versions/d56ffa94ca32_add_file_content.py b/backend/alembic/versions/d56ffa94ca32_add_file_content.py
index f788cdb700..e9ef84eab5 100644
--- a/backend/alembic/versions/d56ffa94ca32_add_file_content.py
+++ b/backend/alembic/versions/d56ffa94ca32_add_file_content.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-06 15:29:34.192960
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d56ffa94ca32"
down_revision = "01f8e6d95a33"
diff --git a/backend/alembic/versions/d5c86e2c6dc6_add_cascade_delete_to_search_query_user_.py b/backend/alembic/versions/d5c86e2c6dc6_add_cascade_delete_to_search_query_user_.py
index 09898bae6a..0964d93da8 100644
--- a/backend/alembic/versions/d5c86e2c6dc6_add_cascade_delete_to_search_query_user_.py
+++ b/backend/alembic/versions/d5c86e2c6dc6_add_cascade_delete_to_search_query_user_.py
@@ -8,7 +8,6 @@ Create Date: 2026-02-04 16:05:04.749804
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "d5c86e2c6dc6"
down_revision = "90b409d06e50"
diff --git a/backend/alembic/versions/d8cdfee5df80_add_skipped_to_userfilestatus.py b/backend/alembic/versions/d8cdfee5df80_add_skipped_to_userfilestatus.py
index ab547288d2..1bb075b070 100644
--- a/backend/alembic/versions/d8cdfee5df80_add_skipped_to_userfilestatus.py
+++ b/backend/alembic/versions/d8cdfee5df80_add_skipped_to_userfilestatus.py
@@ -9,7 +9,6 @@ Create Date: 2026-04-01 10:47:12.593950
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d8cdfee5df80"
down_revision = "1d78c0ca7853"
diff --git a/backend/alembic/versions/d929f0c1c6af_feedback_feature.py b/backend/alembic/versions/d929f0c1c6af_feedback_feature.py
index 52860552ec..5b2215f9a8 100644
--- a/backend/alembic/versions/d929f0c1c6af_feedback_feature.py
+++ b/backend/alembic/versions/d929f0c1c6af_feedback_feature.py
@@ -10,7 +10,6 @@ import fastapi_users_db_sqlalchemy
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d929f0c1c6af"
down_revision = "8aabb57f3b49"
diff --git a/backend/alembic/versions/d961aca62eb3_update_status_length.py b/backend/alembic/versions/d961aca62eb3_update_status_length.py
index 58de115f7d..a9dd81a8fd 100644
--- a/backend/alembic/versions/d961aca62eb3_update_status_length.py
+++ b/backend/alembic/versions/d961aca62eb3_update_status_length.py
@@ -9,7 +9,6 @@ Create Date: 2025-03-23 16:10:05.683965
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "d961aca62eb3"
down_revision = "cf90764725d8"
diff --git a/backend/alembic/versions/d9ec13955951_remove__dim_suffix_from_model_name.py b/backend/alembic/versions/d9ec13955951_remove__dim_suffix_from_model_name.py
index 0e84d5fe85..cd51742d5c 100644
--- a/backend/alembic/versions/d9ec13955951_remove__dim_suffix_from_model_name.py
+++ b/backend/alembic/versions/d9ec13955951_remove__dim_suffix_from_model_name.py
@@ -8,7 +8,6 @@ Create Date: 2024-08-20 16:31:32.955686
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "d9ec13955951"
down_revision = "da4c21c69164"
diff --git a/backend/alembic/versions/da42808081e3_migrate_jira_connectors_to_new_format.py b/backend/alembic/versions/da42808081e3_migrate_jira_connectors_to_new_format.py
index 92897f54c0..0aee6342ea 100644
--- a/backend/alembic/versions/da42808081e3_migrate_jira_connectors_to_new_format.py
+++ b/backend/alembic/versions/da42808081e3_migrate_jira_connectors_to_new_format.py
@@ -13,7 +13,6 @@ import json
from onyx.configs.constants import DocumentSource
from onyx.connectors.jira.utils import extract_jira_project
-
# revision identifiers, used by Alembic.
revision = "da42808081e3"
down_revision = "f13db29f3101"
diff --git a/backend/alembic/versions/dab04867cd88_add_composite_index_to_document_by_.py b/backend/alembic/versions/dab04867cd88_add_composite_index_to_document_by_.py
index 7424c9666a..b6db5a9393 100644
--- a/backend/alembic/versions/dab04867cd88_add_composite_index_to_document_by_.py
+++ b/backend/alembic/versions/dab04867cd88_add_composite_index_to_document_by_.py
@@ -8,7 +8,6 @@ Create Date: 2024-12-13 22:43:20.119990
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "dab04867cd88"
down_revision = "54a74a0417fc"
diff --git a/backend/alembic/versions/dba7f71618f5_onyx_custom_tool_flow.py b/backend/alembic/versions/dba7f71618f5_onyx_custom_tool_flow.py
index d19f60c7bc..5bfda7e0b9 100644
--- a/backend/alembic/versions/dba7f71618f5_onyx_custom_tool_flow.py
+++ b/backend/alembic/versions/dba7f71618f5_onyx_custom_tool_flow.py
@@ -9,7 +9,6 @@ Create Date: 2023-09-18 15:18:37.370972
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "dba7f71618f5"
down_revision = "d5645c915d0e"
diff --git a/backend/alembic/versions/df0c7ad8a076_added_deletion_attempt_table.py b/backend/alembic/versions/df0c7ad8a076_added_deletion_attempt_table.py
index 7ba81a490d..c92f3b6f25 100644
--- a/backend/alembic/versions/df0c7ad8a076_added_deletion_attempt_table.py
+++ b/backend/alembic/versions/df0c7ad8a076_added_deletion_attempt_table.py
@@ -9,7 +9,6 @@ Create Date: 2023-08-05 13:35:39.609619
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "df0c7ad8a076"
down_revision = "d7111c1238cd"
diff --git a/backend/alembic/versions/df46c75b714e_add_default_vision_provider_to_llm_.py b/backend/alembic/versions/df46c75b714e_add_default_vision_provider_to_llm_.py
index b42fe24145..173722af6b 100644
--- a/backend/alembic/versions/df46c75b714e_add_default_vision_provider_to_llm_.py
+++ b/backend/alembic/versions/df46c75b714e_add_default_vision_provider_to_llm_.py
@@ -9,7 +9,6 @@ Create Date: 2025-03-11 16:20:19.038945
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "df46c75b714e"
down_revision = "3934b1bc7b62"
diff --git a/backend/alembic/versions/e4334d5b33ba_add_deployment_name_to_llmprovider.py b/backend/alembic/versions/e4334d5b33ba_add_deployment_name_to_llmprovider.py
index 75cca33c57..eac6944f6e 100644
--- a/backend/alembic/versions/e4334d5b33ba_add_deployment_name_to_llmprovider.py
+++ b/backend/alembic/versions/e4334d5b33ba_add_deployment_name_to_llmprovider.py
@@ -9,7 +9,6 @@ Create Date: 2024-10-04 09:52:34.896867
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "e4334d5b33ba"
down_revision = "ac5eaac849f9"
diff --git a/backend/alembic/versions/e6a4bbc13fe4_add_index_for_retrieving_latest_index_.py b/backend/alembic/versions/e6a4bbc13fe4_add_index_for_retrieving_latest_index_.py
index 3c3e7d8a31..d02d240ab7 100644
--- a/backend/alembic/versions/e6a4bbc13fe4_add_index_for_retrieving_latest_index_.py
+++ b/backend/alembic/versions/e6a4bbc13fe4_add_index_for_retrieving_latest_index_.py
@@ -8,7 +8,6 @@ Create Date: 2023-08-10 12:37:23.335471
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "e6a4bbc13fe4"
down_revision = "b082fec533f0"
diff --git a/backend/alembic/versions/e7f8a9b0c1d2_create_anonymous_user.py b/backend/alembic/versions/e7f8a9b0c1d2_create_anonymous_user.py
index 4ef03b3537..a6a33307e1 100644
--- a/backend/alembic/versions/e7f8a9b0c1d2_create_anonymous_user.py
+++ b/backend/alembic/versions/e7f8a9b0c1d2_create_anonymous_user.py
@@ -13,7 +13,6 @@ Create Date: 2026-01-15 14:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "e7f8a9b0c1d2"
down_revision = "f7ca3e2f45d9"
diff --git a/backend/alembic/versions/eaa3b5593925_add_default_slack_channel_config.py b/backend/alembic/versions/eaa3b5593925_add_default_slack_channel_config.py
index 62d1bb46a6..9f2bc4a070 100644
--- a/backend/alembic/versions/eaa3b5593925_add_default_slack_channel_config.py
+++ b/backend/alembic/versions/eaa3b5593925_add_default_slack_channel_config.py
@@ -9,7 +9,6 @@ Create Date: 2025-02-03 18:07:56.552526
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "eaa3b5593925"
down_revision = "98a5008d8711"
diff --git a/backend/alembic/versions/ee3f4b47fad5_added_alternate_model_to_chat_message.py b/backend/alembic/versions/ee3f4b47fad5_added_alternate_model_to_chat_message.py
index 64ffdad25f..9feb777d90 100644
--- a/backend/alembic/versions/ee3f4b47fad5_added_alternate_model_to_chat_message.py
+++ b/backend/alembic/versions/ee3f4b47fad5_added_alternate_model_to_chat_message.py
@@ -9,7 +9,6 @@ Create Date: 2024-08-12 00:11:50.915845
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "ee3f4b47fad5"
down_revision = "2d2304e27d8c"
diff --git a/backend/alembic/versions/f17bf3b0d9f1_embedding_provider_by_provider_type.py b/backend/alembic/versions/f17bf3b0d9f1_embedding_provider_by_provider_type.py
index a141f946d2..aaf0be3f01 100644
--- a/backend/alembic/versions/f17bf3b0d9f1_embedding_provider_by_provider_type.py
+++ b/backend/alembic/versions/f17bf3b0d9f1_embedding_provider_by_provider_type.py
@@ -9,7 +9,6 @@ Create Date: 2024-08-21 13:13:31.120460
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "f17bf3b0d9f1"
down_revision = "351faebd379d"
diff --git a/backend/alembic/versions/f1ca58b2f2ec_add_passthrough_auth_to_tool.py b/backend/alembic/versions/f1ca58b2f2ec_add_passthrough_auth_to_tool.py
index 7a8b9b3b60..55679efdaa 100644
--- a/backend/alembic/versions/f1ca58b2f2ec_add_passthrough_auth_to_tool.py
+++ b/backend/alembic/versions/f1ca58b2f2ec_add_passthrough_auth_to_tool.py
@@ -11,7 +11,6 @@ from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision: str = "f1ca58b2f2ec"
down_revision: Union[str, None] = "c7bf5721733e"
diff --git a/backend/alembic/versions/f220515df7b4_add_flow_mapping_table.py b/backend/alembic/versions/f220515df7b4_add_flow_mapping_table.py
index afd32a0ecd..76fc587b95 100644
--- a/backend/alembic/versions/f220515df7b4_add_flow_mapping_table.py
+++ b/backend/alembic/versions/f220515df7b4_add_flow_mapping_table.py
@@ -10,7 +10,6 @@ from onyx.db.enums import LLMModelFlowType
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "f220515df7b4"
down_revision = "9d1543a37106"
diff --git a/backend/alembic/versions/f5437cc136c5_delete_non_search_assistants.py b/backend/alembic/versions/f5437cc136c5_delete_non_search_assistants.py
index f6d5f4a41b..c44b8fccdc 100644
--- a/backend/alembic/versions/f5437cc136c5_delete_non_search_assistants.py
+++ b/backend/alembic/versions/f5437cc136c5_delete_non_search_assistants.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-04 16:17:15.677256
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "f5437cc136c5"
down_revision = "eaa3b5593925"
diff --git a/backend/alembic/versions/f7505c5b0284_updated_constraints_for_ccpairs.py b/backend/alembic/versions/f7505c5b0284_updated_constraints_for_ccpairs.py
index 88b3f46e7a..30a7a3cd2d 100644
--- a/backend/alembic/versions/f7505c5b0284_updated_constraints_for_ccpairs.py
+++ b/backend/alembic/versions/f7505c5b0284_updated_constraints_for_ccpairs.py
@@ -8,7 +8,6 @@ Create Date: 2025-04-01 17:50:42.504818
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "f7505c5b0284"
down_revision = "f71470ba9274"
diff --git a/backend/alembic/versions/f7a894b06d02_non_nullbale_slack_bot_id_in_channel_.py b/backend/alembic/versions/f7a894b06d02_non_nullbale_slack_bot_id_in_channel_.py
index 370ab1f0d8..5bf1d7b2e2 100644
--- a/backend/alembic/versions/f7a894b06d02_non_nullbale_slack_bot_id_in_channel_.py
+++ b/backend/alembic/versions/f7a894b06d02_non_nullbale_slack_bot_id_in_channel_.py
@@ -9,7 +9,6 @@ Create Date: 2024-12-06 12:55:42.845723
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "f7a894b06d02"
down_revision = "9f696734098f"
diff --git a/backend/alembic/versions/f7ca3e2f45d9_migrate_no_auth_data_to_placeholder.py b/backend/alembic/versions/f7ca3e2f45d9_migrate_no_auth_data_to_placeholder.py
index 96a45ec394..5c4b7cd635 100644
--- a/backend/alembic/versions/f7ca3e2f45d9_migrate_no_auth_data_to_placeholder.py
+++ b/backend/alembic/versions/f7ca3e2f45d9_migrate_no_auth_data_to_placeholder.py
@@ -20,7 +20,6 @@ import sqlalchemy as sa
from shared_configs.configs import MULTI_TENANT
-
# revision identifiers, used by Alembic.
revision = "f7ca3e2f45d9"
down_revision = "78ebc66946a0"
diff --git a/backend/alembic/versions/f8a9b2c3d4e5_add_research_answer_purpose_to_chat_message.py b/backend/alembic/versions/f8a9b2c3d4e5_add_research_answer_purpose_to_chat_message.py
index 1aa4bb046f..d26320f39f 100644
--- a/backend/alembic/versions/f8a9b2c3d4e5_add_research_answer_purpose_to_chat_message.py
+++ b/backend/alembic/versions/f8a9b2c3d4e5_add_research_answer_purpose_to_chat_message.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-27 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "f8a9b2c3d4e5"
down_revision = "5ae8240accb3"
diff --git a/backend/alembic/versions/f9b8c7d6e5a4_update_parent_question_id_foreign_key_to_research_agent_iteration.py b/backend/alembic/versions/f9b8c7d6e5a4_update_parent_question_id_foreign_key_to_research_agent_iteration.py
index 18ea4e349f..b521b344da 100644
--- a/backend/alembic/versions/f9b8c7d6e5a4_update_parent_question_id_foreign_key_to_research_agent_iteration.py
+++ b/backend/alembic/versions/f9b8c7d6e5a4_update_parent_question_id_foreign_key_to_research_agent_iteration.py
@@ -9,7 +9,6 @@ Create Date: 2025-01-27 12:00:00.000000
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "f9b8c7d6e5a4"
down_revision = "bd7c3bf8beba"
diff --git a/backend/alembic/versions/febe9eaa0644_add_document_set_persona_relationship_.py b/backend/alembic/versions/febe9eaa0644_add_document_set_persona_relationship_.py
index c1a6b23a4a..268b6abc3e 100644
--- a/backend/alembic/versions/febe9eaa0644_add_document_set_persona_relationship_.py
+++ b/backend/alembic/versions/febe9eaa0644_add_document_set_persona_relationship_.py
@@ -9,7 +9,6 @@ Create Date: 2023-09-24 13:06:24.018610
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "febe9eaa0644"
down_revision = "57b53544726e"
diff --git a/backend/alembic/versions/feead2911109_add_opensearch_tenant_migration_columns.py b/backend/alembic/versions/feead2911109_add_opensearch_tenant_migration_columns.py
index c05e22a552..e7f06ffdce 100644
--- a/backend/alembic/versions/feead2911109_add_opensearch_tenant_migration_columns.py
+++ b/backend/alembic/versions/feead2911109_add_opensearch_tenant_migration_columns.py
@@ -9,7 +9,6 @@ Create Date: 2026-02-10 17:46:34.029937
from alembic import op
import sqlalchemy as sa
-
# revision identifiers, used by Alembic.
revision = "feead2911109"
down_revision = "175ea04c7087"
diff --git a/backend/alembic_tenants/versions/34e3630c7f32_lowercase_multi_tenant_user_auth.py b/backend/alembic_tenants/versions/34e3630c7f32_lowercase_multi_tenant_user_auth.py
index 217fae1f71..94f789a964 100644
--- a/backend/alembic_tenants/versions/34e3630c7f32_lowercase_multi_tenant_user_auth.py
+++ b/backend/alembic_tenants/versions/34e3630c7f32_lowercase_multi_tenant_user_auth.py
@@ -8,7 +8,6 @@ Create Date: 2025-02-26 15:03:01.211894
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "34e3630c7f32"
down_revision = "a4f6ee863c47"
diff --git a/backend/alembic_tenants/versions/3b45e0018bf1_add_new_available_tenant_table.py b/backend/alembic_tenants/versions/3b45e0018bf1_add_new_available_tenant_table.py
index ac21fa6ef4..3c1aff6f36 100644
--- a/backend/alembic_tenants/versions/3b45e0018bf1_add_new_available_tenant_table.py
+++ b/backend/alembic_tenants/versions/3b45e0018bf1_add_new_available_tenant_table.py
@@ -10,7 +10,6 @@ import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "3b45e0018bf1"
down_revision = "ac842f85f932"
diff --git a/backend/alembic_tenants/versions/3b9f09038764_add_read_only_kg_user.py b/backend/alembic_tenants/versions/3b9f09038764_add_read_only_kg_user.py
index a91e0f8a58..c0607c1d74 100644
--- a/backend/alembic_tenants/versions/3b9f09038764_add_read_only_kg_user.py
+++ b/backend/alembic_tenants/versions/3b9f09038764_add_read_only_kg_user.py
@@ -12,7 +12,6 @@ from alembic import op
from onyx.configs.app_configs import DB_READONLY_PASSWORD
from onyx.configs.app_configs import DB_READONLY_USER
-
# revision identifiers, used by Alembic.
revision = "3b9f09038764"
down_revision = "3b45e0018bf1"
diff --git a/backend/alembic_tenants/versions/a4f6ee863c47_mapping_for_anonymous_user_path.py b/backend/alembic_tenants/versions/a4f6ee863c47_mapping_for_anonymous_user_path.py
index d90eddee93..6e51bff28d 100644
--- a/backend/alembic_tenants/versions/a4f6ee863c47_mapping_for_anonymous_user_path.py
+++ b/backend/alembic_tenants/versions/a4f6ee863c47_mapping_for_anonymous_user_path.py
@@ -10,7 +10,6 @@ import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "a4f6ee863c47"
down_revision = "14a83a331951"
diff --git a/backend/alembic_tenants/versions/ac842f85f932_new_column_user_tenant_mapping.py b/backend/alembic_tenants/versions/ac842f85f932_new_column_user_tenant_mapping.py
index 6fbad31fc1..5b523b4ea6 100644
--- a/backend/alembic_tenants/versions/ac842f85f932_new_column_user_tenant_mapping.py
+++ b/backend/alembic_tenants/versions/ac842f85f932_new_column_user_tenant_mapping.py
@@ -10,7 +10,6 @@ import sqlalchemy as sa
from alembic import op
-
# revision identifiers, used by Alembic.
revision = "ac842f85f932"
down_revision = "34e3630c7f32"
diff --git a/backend/ee/onyx/access/access.py b/backend/ee/onyx/access/access.py
index 358d5d3c96..200478c8f4 100644
--- a/backend/ee/onyx/access/access.py
+++ b/backend/ee/onyx/access/access.py
@@ -74,7 +74,7 @@ def _get_access_for_documents(
document = doc_id_map[document_id]
source = doc_id_to_source_map.get(document_id)
if source is None:
- logger.error(f"Document {document_id} has no source")
+ logger.error("Document %s has no source", document_id)
continue
perm_sync_config = get_source_perm_sync_config(source)
diff --git a/backend/ee/onyx/auth/users.py b/backend/ee/onyx/auth/users.py
index 3d625666ab..bc50271d4d 100644
--- a/backend/ee/onyx/auth/users.py
+++ b/backend/ee/onyx/auth/users.py
@@ -28,7 +28,7 @@ def verify_auth_setting() -> None:
logger.warning(
"AUTH_TYPE='disabled' is no longer supported. Using 'basic' instead. Please update your configuration."
)
- logger.notice(f"Using Auth Type: {AUTH_TYPE.value}")
+ logger.notice("Using Auth Type: %s", AUTH_TYPE.value)
def get_default_admin_user_emails_() -> list[str]:
diff --git a/backend/ee/onyx/background/celery/tasks/cleanup/tasks.py b/backend/ee/onyx/background/celery/tasks/cleanup/tasks.py
index b2ae1e502f..0e1b5b03bc 100644
--- a/backend/ee/onyx/background/celery/tasks/cleanup/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/cleanup/tasks.py
@@ -34,6 +34,7 @@ def export_query_history_cleanup_task(*, tenant_id: str) -> None:
continue
logger.error(
- f"Task with {task.task_id=} failed; it is being deleted now"
+ "Task with task.task_id=%r failed; it is being deleted now",
+ task.task_id,
)
delete_task_with_id(db_session=db_session, task_id=task.task_id)
diff --git a/backend/ee/onyx/background/celery/tasks/doc_permission_syncing/tasks.py b/backend/ee/onyx/background/celery/tasks/doc_permission_syncing/tasks.py
index 3a1ec6103e..1c549e3bb2 100644
--- a/backend/ee/onyx/background/celery/tasks/doc_permission_syncing/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/doc_permission_syncing/tasks.py
@@ -146,11 +146,11 @@ def _is_external_doc_permissions_sync_due(cc_pair: ConnectorCredentialPair) -> b
sync_config = get_source_perm_sync_config(cc_pair.connector.source)
if sync_config is None:
- logger.error(f"No sync config found for {cc_pair.connector.source}")
+ logger.error("No sync config found for %s", cc_pair.connector.source)
return False
if sync_config.doc_sync_config is None:
- logger.error(f"No doc sync config found for {cc_pair.connector.source}")
+ logger.error("No doc sync config found for %s", cc_pair.connector.source)
return False
# if indexing also does perm sync, don't start running doc_sync until at
@@ -446,7 +446,8 @@ def connector_permission_sync_generator_task(
if payload.celery_task_id is None:
logger.info(
- f"connector_permission_sync_generator_task - Waiting for fence: fence={redis_connector.permissions.fence_key}"
+ "connector_permission_sync_generator_task - Waiting for fence: fence=%s",
+ redis_connector.permissions.fence_key,
)
sleep(1)
continue
@@ -454,9 +455,9 @@ def connector_permission_sync_generator_task(
payload_id = payload.id
logger.info(
- f"connector_permission_sync_generator_task - Fence found, continuing...: "
- f"fence={redis_connector.permissions.fence_key} "
- f"payload_id={payload.id}"
+ "connector_permission_sync_generator_task - Fence found, continuing...: fence=%s payload_id=%s",
+ redis_connector.permissions.fence_key,
+ payload.id,
)
break
@@ -529,7 +530,7 @@ def connector_permission_sync_generator_task(
f"No doc sync func found for {source_type} with cc_pair={cc_pair_id}"
)
- logger.info(f"Syncing docs for {source_type} with cc_pair={cc_pair_id}")
+ logger.info("Syncing docs for %s with cc_pair=%s", source_type, cc_pair_id)
mark_doc_permission_sync_attempt_in_progress(attempt_id, db_session)
@@ -978,9 +979,10 @@ class PermissionSyncCallback(IndexingHeartbeatInterface):
elapsed = time.monotonic() - self.start_monotonic
if elapsed > self.timeout_seconds:
logger.warning(
- f"PermissionSyncCallback - task timeout exceeded: "
- f"elapsed={elapsed:.0f}s timeout={self.timeout_seconds}s "
- f"cc_pair={self.redis_connector.cc_pair_id}"
+ "PermissionSyncCallback - task timeout exceeded: elapsed=%ss timeout=%ss cc_pair=%s",
+ format(elapsed, ".0f"),
+ self.timeout_seconds,
+ self.redis_connector.cc_pair_id,
)
return True
@@ -1001,12 +1003,12 @@ class PermissionSyncCallback(IndexingHeartbeatInterface):
self.last_tag = tag
except LockError:
logger.exception(
- f"PermissionSyncCallback - lock.reacquire exceptioned: "
- f"lock_timeout={self.redis_lock.timeout} "
- f"start={self.started} "
- f"last_tag={self.last_tag} "
- f"last_reacquired={self.last_lock_reacquire} "
- f"now={datetime.now(timezone.utc)}"
+ "PermissionSyncCallback - lock.reacquire exceptioned: lock_timeout=%s start=%s last_tag=%s last_reacquired=%s now=%s",
+ self.redis_lock.timeout,
+ self.started,
+ self.last_tag,
+ self.last_lock_reacquire,
+ datetime.now(timezone.utc),
)
redis_lock_dump(self.redis_lock, self.redis_client)
diff --git a/backend/ee/onyx/background/celery/tasks/external_group_syncing/tasks.py b/backend/ee/onyx/background/celery/tasks/external_group_syncing/tasks.py
index 8edcd4a3ce..bba54691d9 100644
--- a/backend/ee/onyx/background/celery/tasks/external_group_syncing/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/external_group_syncing/tasks.py
@@ -274,7 +274,8 @@ def try_creating_external_group_sync_task(
# Dont kick off a new sync if the previous one is still running
if redis_connector.external_group_sync.fenced:
logger.warning(
- f"Skipping external group sync for CC Pair {cc_pair_id} - already running."
+ "Skipping external group sync for CC Pair %s - already running.",
+ cc_pair_id,
)
return None
@@ -388,16 +389,16 @@ def connector_external_group_sync_generator_task(
if payload.celery_task_id is None:
logger.info(
- f"connector_external_group_sync_generator_task - Waiting for fence: "
- f"fence={redis_connector.external_group_sync.fence_key}"
+ "connector_external_group_sync_generator_task - Waiting for fence: fence=%s",
+ redis_connector.external_group_sync.fence_key,
)
time.sleep(1)
continue
logger.info(
- f"connector_external_group_sync_generator_task - Fence found, continuing...: "
- f"fence={redis_connector.external_group_sync.fence_key} "
- f"payload_id={payload.id}"
+ "connector_external_group_sync_generator_task - Fence found, continuing...: fence=%s payload_id=%s",
+ redis_connector.external_group_sync.fence_key,
+ payload.id,
)
break
@@ -479,7 +480,9 @@ def _perform_external_group_sync(
db_session=db_session,
)
logger.info(
- f"Created external group sync attempt: {attempt_id} for cc_pair={cc_pair_id}"
+ "Created external group sync attempt: %s for cc_pair=%s",
+ attempt_id,
+ cc_pair_id,
)
try:
@@ -532,22 +535,25 @@ def _timed_perform_external_group_sync(
# idle_in_transaction_session_timeout during long API calls), stale
# rows would accumulate indefinitely.
logger.info(
- f"Removing stale external groups from prior cycle for {source_type} "
- f"for cc_pair: {cc_pair_id}"
+ "Removing stale external groups from prior cycle for %s for cc_pair: %s",
+ source_type,
+ cc_pair_id,
)
remove_stale_external_groups(db_session, cc_pair_id)
logger.info(
- f"Marking old external groups as stale for {source_type} for cc_pair: {cc_pair_id}"
+ "Marking old external groups as stale for %s for cc_pair: %s",
+ source_type,
+ cc_pair_id,
)
mark_old_external_groups_as_stale(db_session, cc_pair_id)
# Mark attempt as in progress
mark_external_group_sync_attempt_in_progress(attempt_id, db_session)
- logger.info(f"Marked external group sync attempt {attempt_id} as in progress")
+ logger.info("Marked external group sync attempt %s as in progress", attempt_id)
logger.info(
- f"Syncing external groups for {source_type} for cc_pair: {cc_pair_id}"
+ "Syncing external groups for %s for cc_pair: %s", source_type, cc_pair_id
)
external_user_group_batch: list[ExternalUserGroup] = []
seen_users: set[str] = set() # Track unique users across all groups
@@ -580,7 +586,7 @@ def _timed_perform_external_group_sync(
if len(external_user_group_batch) >= _EXTERNAL_GROUP_BATCH_SIZE:
logger.debug(
- f"New external user groups: {external_user_group_batch}"
+ "New external user groups: %s", external_user_group_batch
)
upsert_start = time.monotonic()
upsert_external_groups(
@@ -593,7 +599,7 @@ def _timed_perform_external_group_sync(
external_user_group_batch = []
if external_user_group_batch:
- logger.debug(f"New external user groups: {external_user_group_batch}")
+ logger.debug("New external user groups: %s", external_user_group_batch)
upsert_start = time.monotonic()
upsert_external_groups(
db_session=db_session,
@@ -613,14 +619,19 @@ def _timed_perform_external_group_sync(
# TODO: add some notification to the admins here
inc_group_sync_errors(connector_type)
logger.exception(
- f"Error syncing external groups for {source_type} for cc_pair: {cc_pair_id} {e}"
+ "Error syncing external groups for %s for cc_pair: %s %s",
+ source_type,
+ cc_pair_id,
+ e,
)
raise e
observe_group_sync_upsert_duration(cumulative_upsert_time, connector_type)
logger.info(
- f"Removing stale external groups for {source_type} for cc_pair: {cc_pair_id}"
+ "Removing stale external groups for %s for cc_pair: %s",
+ source_type,
+ cc_pair_id,
)
remove_stale_external_groups(db_session, cc_pair_id)
@@ -637,9 +648,11 @@ def _timed_perform_external_group_sync(
errors_encountered=0,
)
logger.info(
- f"Completed external group sync attempt {attempt_id}: "
- f"{total_groups_processed} groups, {total_users_processed} users, "
- f"{total_group_memberships_synced} memberships"
+ "Completed external group sync attempt %s: %s groups, %s users, %s memberships",
+ attempt_id,
+ total_groups_processed,
+ total_users_processed,
+ total_group_memberships_synced,
)
inc_group_sync_groups_processed(connector_type, total_groups_processed)
diff --git a/backend/ee/onyx/background/celery/tasks/hooks/tasks.py b/backend/ee/onyx/background/celery/tasks/hooks/tasks.py
index 17283a5142..23dea9fbeb 100644
--- a/backend/ee/onyx/background/celery/tasks/hooks/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/hooks/tasks.py
@@ -27,8 +27,9 @@ def hook_execution_log_cleanup_task(*, tenant_id: str) -> None: # noqa: ARG001
db_session.commit()
if deleted:
logger.info(
- f"Deleted {deleted} hook execution log(s) older than "
- f"{_HOOK_EXECUTION_LOG_RETENTION_DAYS} days."
+ "Deleted %s hook execution log(s) older than %s days.",
+ deleted,
+ _HOOK_EXECUTION_LOG_RETENTION_DAYS,
)
except Exception:
logger.exception("Failed to clean up hook execution logs")
diff --git a/backend/ee/onyx/background/celery/tasks/query_history/tasks.py b/backend/ee/onyx/background/celery/tasks/query_history/tasks.py
index 44ed89c2cc..e759f254b2 100644
--- a/backend/ee/onyx/background/celery/tasks/query_history/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/query_history/tasks.py
@@ -78,7 +78,7 @@ def export_query_history_task(
)
except Exception:
- logger.exception(f"Failed to export query history with {task_id=}")
+ logger.exception("Failed to export query history with task_id=%r", task_id)
mark_task_as_finished_with_id(
db_session=db_session,
task_id=task_id,
@@ -109,7 +109,7 @@ def export_query_history_task(
)
except Exception:
logger.exception(
- f"Failed to save query history export file; {report_name=}"
+ "Failed to save query history export file; report_name=%r", report_name
)
mark_task_as_finished_with_id(
db_session=db_session,
diff --git a/backend/ee/onyx/background/celery/tasks/ttl_management/tasks.py b/backend/ee/onyx/background/celery/tasks/ttl_management/tasks.py
index 85ba73ff35..9c6e6fd61c 100644
--- a/backend/ee/onyx/background/celery/tasks/ttl_management/tasks.py
+++ b/backend/ee/onyx/background/celery/tasks/ttl_management/tasks.py
@@ -50,14 +50,16 @@ def perform_ttl_management_task(
)
except Exception:
logger.exception(
- "Failed to delete chat session "
- f"user_id={user_id} session_id={session_id}, "
- "continuing with remaining sessions"
+ "Failed to delete chat session user_id=%s session_id=%s, continuing with remaining sessions",
+ user_id,
+ session_id,
)
except Exception:
logger.exception(
- f"delete_chat_session exceptioned. user_id={user_id} session_id={session_id}"
+ "delete_chat_session exceptioned. user_id=%s session_id=%s",
+ user_id,
+ session_id,
)
raise
diff --git a/backend/ee/onyx/background/celery_utils.py b/backend/ee/onyx/background/celery_utils.py
index 9ed8e20e51..b401c15854 100644
--- a/backend/ee/onyx/background/celery_utils.py
+++ b/backend/ee/onyx/background/celery_utils.py
@@ -21,6 +21,6 @@ def should_perform_chat_ttl_check(
return True
if check_task_is_live_and_not_timed_out(latest_task, db_session):
- logger.debug(f"{task_name} is already being performed. Skipping.")
+ logger.debug("%s is already being performed. Skipping.", task_name)
return False
return True
diff --git a/backend/ee/onyx/db/external_perm.py b/backend/ee/onyx/db/external_perm.py
index 28af141b7b..b8019fd1c0 100644
--- a/backend/ee/onyx/db/external_perm.py
+++ b/backend/ee/onyx/db/external_perm.py
@@ -132,8 +132,9 @@ def upsert_external_groups(
user_id = email_id_map.get(user_email.lower())
if user_id is None:
logger.warning(
- f"User in group {external_group.id}"
- f" with email {user_email} not found"
+ "User in group %s with email %s not found",
+ external_group.id,
+ user_email,
)
continue
diff --git a/backend/ee/onyx/db/license.py b/backend/ee/onyx/db/license.py
index b46c83e473..d7f8f50f58 100644
--- a/backend/ee/onyx/db/license.py
+++ b/backend/ee/onyx/db/license.py
@@ -163,7 +163,7 @@ def get_cached_license_metadata(tenant_id: str | None = None) -> LicenseMetadata
)
return LicenseMetadata.model_validate_json(cached_str)
except Exception as e:
- logger.warning(f"Failed to parse cached license metadata: {e}")
+ logger.warning("Failed to parse cached license metadata: %s", e)
return None
@@ -234,7 +234,9 @@ def update_license_cache(
ex=LICENSE_CACHE_TTL_SECONDS,
)
- logger.info(f"License cache updated: {metadata.seats} seats, status={status.value}")
+ logger.info(
+ "License cache updated: %s seats, status=%s", metadata.seats, status.value
+ )
return metadata
@@ -273,7 +275,7 @@ def refresh_license_cache(
tenant_id=tenant_id,
)
except ValueError as e:
- logger.error(f"Failed to verify license during cache refresh: {e}")
+ logger.error("Failed to verify license during cache refresh: %s", e)
invalidate_license_cache(tenant_id)
return None
diff --git a/backend/ee/onyx/db/standard_answer.py b/backend/ee/onyx/db/standard_answer.py
index 45ddd02611..f39902f3d4 100644
--- a/backend/ee/onyx/db/standard_answer.py
+++ b/backend/ee/onyx/db/standard_answer.py
@@ -19,7 +19,7 @@ def check_category_validity(category_name: str) -> bool:
Additionally, extremely long categories are not really usable / useful."""
if len(category_name) > 255:
logger.error(
- f"Category with name '{category_name}' is too long, cannot be used"
+ "Category with name '%s' is too long, cannot be used", category_name
)
return False
diff --git a/backend/ee/onyx/db/user_group.py b/backend/ee/onyx/db/user_group.py
index 280f2c4e00..75560ffc61 100644
--- a/backend/ee/onyx/db/user_group.py
+++ b/backend/ee/onyx/db/user_group.py
@@ -666,9 +666,11 @@ def update_user_curator_relationship(
)
logger.info(
- f"user_making_change={user_making_change.email if user_making_change else 'None'} is "
- f"updating the curator relationship for user={target_user.email} "
- f"in group={user_group_id} to is_curator={set_curator_request.is_curator}"
+ "user_making_change=%s is updating the curator relationship for user=%s in group=%s to is_curator=%s",
+ user_making_change.email if user_making_change else "None",
+ target_user.email,
+ user_group_id,
+ set_curator_request.is_curator,
)
relationship_to_update = (
diff --git a/backend/ee/onyx/external_permissions/confluence/group_sync.py b/backend/ee/onyx/external_permissions/confluence/group_sync.py
index f0f570e550..54bc571aba 100644
--- a/backend/ee/onyx/external_permissions/confluence/group_sync.py
+++ b/backend/ee/onyx/external_permissions/confluence/group_sync.py
@@ -22,7 +22,7 @@ def _build_group_member_email_map(
) -> dict[str, set[str]]:
group_member_emails: dict[str, set[str]] = {}
for user in confluence_client.paginated_cql_user_retrieval():
- logger.info(f"Processing groups for user: {user}")
+ logger.info("Processing groups for user: %s", user)
email = user.email
if not email:
@@ -35,7 +35,7 @@ def _build_group_member_email_map(
user_name=user_name,
)
else:
- logger.error(f"user result missing username field: {user}")
+ logger.error("user result missing username field: %s", user)
if not email:
# If we still don't have an email, skip this user
@@ -59,7 +59,9 @@ def _build_group_member_email_map(
emit_background_error(msg, cc_pair_id=cc_pair_id)
logger.error(msg)
else:
- logger.debug(f"Found groups {all_users_groups} for user with email {email}")
+ logger.debug(
+ "Found groups %s for user with email %s", all_users_groups, email
+ )
if not group_member_emails:
msg = "No groups found for any users."
@@ -91,13 +93,13 @@ def _build_group_member_email_map_from_onyx_users(
group_member_emails: dict[str, set[str]] = {}
for email in user_emails:
- logger.info(f"Processing groups for user with email: {email}")
+ logger.info("Processing groups for user with email: %s", email)
try:
user_name = _infer_username_from_email(email)
response = confluence_client.get_user_details_by_username(user_name)
user_key = response.get("userKey")
if not user_key:
- logger.error(f"User key not found for user with email {email}")
+ logger.error("User key not found for user with email %s", email)
continue
all_users_groups: set[str] = set()
@@ -112,10 +114,10 @@ def _build_group_member_email_map_from_onyx_users(
logger.error(msg)
else:
logger.info(
- f"Found groups {all_users_groups} for user with email {email}"
+ "Found groups %s for user with email %s", all_users_groups, email
)
except Exception:
- logger.exception(f"Error getting user details for user with email {email}")
+ logger.exception("Error getting user details for user with email %s", email)
return group_member_emails
diff --git a/backend/ee/onyx/external_permissions/confluence/page_access.py b/backend/ee/onyx/external_permissions/confluence/page_access.py
index 19b3b65fc5..47cd7cf1d4 100644
--- a/backend/ee/onyx/external_permissions/confluence/page_access.py
+++ b/backend/ee/onyx/external_permissions/confluence/page_access.py
@@ -42,16 +42,16 @@ def _extract_read_access_restrictions(
read_access_user_emails.append(email)
else:
logger.warning(
- f"Email for user {user['username']} not found in Confluence"
+ "Email for user %s not found in Confluence", user["username"]
)
else:
if user.get("email") is not None:
- logger.warning(f"Cant find email for user {user.get('displayName')}")
+ logger.warning("Cant find email for user %s", user.get("displayName"))
logger.warning(
"This user needs to make their email accessible in Confluence Settings"
)
- logger.warning(f"no user email or username for {user}")
+ logger.warning("no user email or username for %s", user)
# Extract the groups with read access
read_access_group = read_access_restrictions.get("group", {})
@@ -135,8 +135,11 @@ def get_page_restrictions(
# should be applied (the reason why we'd traverse more than one ancestor is if
# the ancestor also is in "inherit" mode.)
logger.debug(
- f"Found user restrictions {ancestor_user_emails} and group restrictions {ancestor_group_names}"
- f"for document {page_id} based on ancestor {ancestor}"
+ "Found user restrictions %s and group restrictions %sfor document %s based on ancestor %s",
+ ancestor_user_emails,
+ ancestor_group_names,
+ page_id,
+ ancestor,
)
return ExternalAccess(
external_user_emails=ancestor_user_emails,
diff --git a/backend/ee/onyx/external_permissions/confluence/space_access.py b/backend/ee/onyx/external_permissions/confluence/space_access.py
index 1f6afd283b..29a8ac0343 100644
--- a/backend/ee/onyx/external_permissions/confluence/space_access.py
+++ b/backend/ee/onyx/external_permissions/confluence/space_access.py
@@ -58,13 +58,15 @@ def _get_server_space_permissions(
if user_email:
user_emails.add(user_email)
else:
- logger.warning(f"Email for user {user_name} not found in Confluence")
+ logger.warning("Email for user %s not found in Confluence", user_name)
if not user_emails and not group_names:
logger.warning(
"No user emails or group names found in Confluence space permissions"
- f"\nSpace key: {space_key}"
- f"\nSpace permissions: {space_permissions}"
+ "\nSpace key: %s"
+ "\nSpace permissions: %s",
+ space_key,
+ space_permissions,
)
return ExternalAccess(
@@ -126,10 +128,12 @@ def get_space_permission(
and not space_permissions.external_user_group_ids
):
logger.warning(
- f"No permissions found for space '{space_key}'. This is very unlikely "
+ "No permissions found for space '%s'. This is very unlikely "
"to be correct and is more likely caused by an access token with "
"insufficient permissions. Make sure that the access token has Admin "
- f"permissions for space '{space_key}'"
+ "permissions for space '%s'",
+ space_key,
+ space_key,
)
# Prefix group IDs with source type if requested (for indexing path)
@@ -169,7 +173,7 @@ def get_all_space_permissions(
]
# Gets the permissions for each space
- logger.debug(f"Got {len(all_space_keys)} spaces from confluence")
+ logger.debug("Got %s spaces from confluence", len(all_space_keys))
space_permissions_by_space_key: dict[str, ExternalAccess] = {}
for space_key in all_space_keys:
space_permissions = get_space_permission(
diff --git a/backend/ee/onyx/external_permissions/github/doc_sync.py b/backend/ee/onyx/external_permissions/github/doc_sync.py
index 031cbebe0e..f377d58f60 100644
--- a/backend/ee/onyx/external_permissions/github/doc_sync.py
+++ b/backend/ee/onyx/external_permissions/github/doc_sync.py
@@ -43,7 +43,7 @@ def github_doc_sync(
This function checks each repository for visibility/team changes and updates
document permissions accordingly without using checkpoints.
"""
- logger.info(f"Starting GitHub document sync for CC pair ID: {cc_pair.id}")
+ logger.info("Starting GitHub document sync for CC pair ID: %s", cc_pair.id)
# Initialize GitHub connector with credentials
github_connector: GithubConnector = GithubConnector(
@@ -67,9 +67,9 @@ def github_doc_sync(
try:
repos = github_connector.fetch_configured_repos()
- logger.info(f"Found {len(repos)} repositories to check")
+ logger.info("Found %s repositories to check", len(repos))
except Exception as e:
- logger.error(f"Failed to fetch repositories: {e}")
+ logger.error("Failed to fetch repositories: %s", e)
raise
repo_to_doc_list_map: dict[str, list[DocumentRow]] = {}
@@ -77,7 +77,7 @@ def github_doc_sync(
existing_docs: list[DocumentRow] = fetch_all_existing_docs_fn(
sort_order=SortOrder.ASC
)
- logger.info(f"Found {len(existing_docs)} documents to check")
+ logger.info("Found %s documents to check", len(existing_docs))
for doc in existing_docs:
try:
doc_metadata = DocMetadata.model_validate_json(json.dumps(doc.doc_metadata))
@@ -85,19 +85,19 @@ def github_doc_sync(
repo_to_doc_list_map[doc_metadata.repo] = []
repo_to_doc_list_map[doc_metadata.repo].append(doc)
except Exception as e:
- logger.error(f"Failed to parse doc metadata: {e} for doc {doc.id}")
+ logger.error("Failed to parse doc metadata: %s for doc %s", e, doc.id)
continue
- logger.info(f"Found {len(repo_to_doc_list_map)} documents to check")
+ logger.info("Found %s documents to check", len(repo_to_doc_list_map))
# Process each repository individually
for repo in repos:
try:
- logger.info(f"Processing repository: {repo.id} (name: {repo.name})")
+ logger.info("Processing repository: %s (name: %s)", repo.id, repo.name)
repo_doc_list: list[DocumentRow] = repo_to_doc_list_map.get(
repo.full_name, []
)
if not repo_doc_list:
logger.warning(
- f"No documents found for repository {repo.id} ({repo.name})"
+ "No documents found for repository %s (%s)", repo.id, repo.name
)
continue
@@ -111,7 +111,9 @@ def github_doc_sync(
if has_changes:
logger.info(
- f"Repository {repo.id} ({repo.name}) has changes, updating documents"
+ "Repository %s (%s) has changes, updating documents",
+ repo.id,
+ repo.name,
)
# Get new external access permissions for this repository
@@ -120,7 +122,9 @@ def github_doc_sync(
)
logger.info(
- f"Found {len(repo_doc_list)} documents for repository {repo.full_name}"
+ "Found %s documents for repository %s",
+ len(repo_doc_list),
+ repo.full_name,
)
# Yield updated external access for each document
@@ -134,12 +138,14 @@ def github_doc_sync(
)
else:
logger.info(
- f"Repository {repo.id} ({repo.name}) has no changes, skipping"
+ "Repository %s (%s) has no changes, skipping", repo.id, repo.name
)
except Exception as e:
- logger.error(f"Error processing repository {repo.id} ({repo.name}): {e}")
+ logger.error(
+ "Error processing repository %s (%s): %s", repo.id, repo.name, e
+ )
- logger.info(f"GitHub document sync completed for CC pair ID: {cc_pair.id}")
+ logger.info("GitHub document sync completed for CC pair ID: %s", cc_pair.id)
def _check_repository_for_changes(
@@ -150,14 +156,14 @@ def _check_repository_for_changes(
"""
Check if repository has any permission changes (visibility or team updates).
"""
- logger.info(f"Checking repository {repo.id} ({repo.name}) for changes")
+ logger.info("Checking repository %s (%s) for changes", repo.id, repo.name)
# Check for repository visibility changes using the sample document data
if _is_repo_visibility_changed_from_groups(
repo=repo,
current_external_group_ids=current_external_group_ids,
):
- logger.info(f"Repository {repo.id} ({repo.name}) has visibility changes")
+ logger.info("Repository %s (%s) has visibility changes", repo.id, repo.name)
return True
# Check for team membership changes if repository is private
@@ -168,10 +174,10 @@ def _check_repository_for_changes(
github_client=github_client,
current_external_group_ids=current_external_group_ids,
):
- logger.info(f"Repository {repo.id} ({repo.name}) has team changes")
+ logger.info("Repository %s (%s) has team changes", repo.id, repo.name)
return True
- logger.info(f"Repository {repo.id} ({repo.name}) has no changes")
+ logger.info("Repository %s (%s) has no changes", repo.id, repo.name)
return False
@@ -190,7 +196,7 @@ def _is_repo_visibility_changed_from_groups(
True if visibility has changed
"""
current_repo_visibility = get_repository_visibility(repo)
- logger.info(f"Current repository visibility: {current_repo_visibility.value}")
+ logger.info("Current repository visibility: %s", current_repo_visibility.value)
# Build expected group IDs for current visibility
collaborators_group_id = build_ext_group_name_for_onyx(
@@ -216,13 +222,16 @@ def _is_repo_visibility_changed_from_groups(
else:
existing_repo_visibility = GitHubVisibility.PUBLIC
- logger.info(f"Inferred existing visibility: {existing_repo_visibility.value}")
+ logger.info("Inferred existing visibility: %s", existing_repo_visibility.value)
visibility_changed = existing_repo_visibility != current_repo_visibility
if visibility_changed:
logger.info(
- f"Visibility changed for repo {repo.id} ({repo.name}): "
- f"{existing_repo_visibility.value} -> {current_repo_visibility.value}"
+ "Visibility changed for repo %s (%s): %s -> %s",
+ repo.id,
+ repo.name,
+ existing_repo_visibility.value,
+ current_repo_visibility.value,
)
return visibility_changed
@@ -239,7 +248,10 @@ def _teams_updated_from_groups(
# Fetch current team slugs for the repository
current_teams = fetch_repository_team_slugs(repo=repo, github_client=github_client)
logger.info(
- f"Current teams for repository {repo.id} (name: {repo.name}): {current_teams}"
+ "Current teams for repository %s (name: %s): %s",
+ repo.id,
+ repo.name,
+ current_teams,
)
# Build group IDs to exclude from team comparison (non-team groups)
@@ -271,15 +283,20 @@ def _teams_updated_from_groups(
current_team_ids.add(team_group_id)
logger.info(
- f"Existing team IDs: {existing_team_ids}, Current team IDs: {current_team_ids}"
+ "Existing team IDs: %s, Current team IDs: %s",
+ existing_team_ids,
+ current_team_ids,
)
# Compare actual team IDs to detect changes
teams_changed = current_team_ids != existing_team_ids
if teams_changed:
logger.info(
- f"Team changes detected for repo {repo.id} (name: {repo.name}): "
- f"existing={existing_team_ids}, current={current_team_ids}"
+ "Team changes detected for repo %s (name: %s): existing=%s, current=%s",
+ repo.id,
+ repo.name,
+ existing_team_ids,
+ current_team_ids,
)
return teams_changed
diff --git a/backend/ee/onyx/external_permissions/github/group_sync.py b/backend/ee/onyx/external_permissions/github/group_sync.py
index 66a40ff64f..7577a1f710 100644
--- a/backend/ee/onyx/external_permissions/github/group_sync.py
+++ b/backend/ee/onyx/external_permissions/github/group_sync.py
@@ -45,7 +45,9 @@ def github_group_sync(
for external_group in get_external_user_group(
repo, github_connector.github_client
):
- logger.info(f"External group: {external_group}")
+ logger.info("External group: %s", external_group)
yield external_group
except Exception as e:
- logger.error(f"Error processing repository {repo.id} ({repo.name}): {e}")
+ logger.error(
+ "Error processing repository %s (%s): %s", repo.id, repo.name, e
+ )
diff --git a/backend/ee/onyx/external_permissions/github/utils.py b/backend/ee/onyx/external_permissions/github/utils.py
index f9f9952da4..5f6eee1e95 100644
--- a/backend/ee/onyx/external_permissions/github/utils.py
+++ b/backend/ee/onyx/external_permissions/github/utils.py
@@ -47,16 +47,19 @@ def _run_with_retry(
retry_count: int = 0,
) -> Optional[T]:
"""Execute a GitHub operation with retry on rate limit and exception handling."""
- logger.debug(f"Starting operation '{description}', attempt {retry_count + 1}")
+ logger.debug("Starting operation '%s', attempt %s", description, retry_count + 1)
try:
result = operation()
- logger.debug(f"Operation '{description}' completed successfully")
+ logger.debug("Operation '%s' completed successfully", description)
return result
except RateLimitExceededException:
if retry_count < MAX_RETRY_COUNT:
sleep_after_rate_limit_exception(github_client)
logger.warning(
- f"Rate limit exceeded while {description}. Retrying... (attempt {retry_count + 1}/{MAX_RETRY_COUNT})"
+ "Rate limit exceeded while %s. Retrying... (attempt %s/%s)",
+ description,
+ retry_count + 1,
+ MAX_RETRY_COUNT,
)
return _run_with_retry(
operation, description, github_client, retry_count + 1
@@ -66,10 +69,10 @@ def _run_with_retry(
logger.exception(error_msg)
raise RuntimeError(error_msg)
except GithubException as e:
- logger.warning(f"GitHub API error during {description}: {e}")
+ logger.warning("GitHub API error during %s: %s", description, e)
return None
except Exception as e:
- logger.exception(f"Unexpected error during {description}: {e}")
+ logger.exception("Unexpected error during %s: %s", description, e)
return None
@@ -96,7 +99,7 @@ def _fetch_organization_members(
) -> List[UserInfo]:
"""Fetch all organization members including owners and regular members."""
org_members: List[UserInfo] = []
- logger.info(f"Fetching organization members for {org_name}")
+ logger.info("Fetching organization members for %s", org_name)
org = _run_with_retry(
lambda: github_client.get_organization(org_name),
@@ -104,7 +107,7 @@ def _fetch_organization_members(
github_client,
)
if not org:
- logger.error(f"Failed to fetch organization {org_name}")
+ logger.error("Failed to fetch organization %s", org_name)
raise RuntimeError(f"Failed to fetch organization {org_name}")
member_objs: PaginatedList[NamedUser] | list[NamedUser] = (
@@ -120,7 +123,7 @@ def _fetch_organization_members(
user_info = UserInfo(login=member.login, name=member.name, email=member.email)
org_members.append(user_info)
- logger.info(f"Fetched {len(org_members)} members for organization {org_name}")
+ logger.info("Fetched %s members for organization %s", len(org_members), org_name)
return org_members
@@ -131,7 +134,7 @@ def _fetch_repository_teams_detailed(
) -> List[TeamInfo]:
"""Fetch teams with access to the repository and their members."""
teams_data: List[TeamInfo] = []
- logger.info(f"Fetching teams for repository {repo.full_name}")
+ logger.info("Fetching teams for repository %s", repo.full_name)
team_objs: PaginatedList[Team] | list[Team] = (
_run_with_retry(
@@ -144,7 +147,10 @@ def _fetch_repository_teams_detailed(
for team in team_objs:
logger.info(
- f"Processing team {team.name} (slug: {team.slug}) for repository {repo.full_name}"
+ "Processing team %s (slug: %s) for repository %s",
+ team.name,
+ team.slug,
+ repo.full_name,
)
members: PaginatedList[NamedUser] | list[NamedUser] = (
@@ -163,9 +169,9 @@ def _fetch_repository_teams_detailed(
team_info = TeamInfo(name=team.name, slug=team.slug, members=team_members)
teams_data.append(team_info)
- logger.info(f"Team {team.name} has {len(team_members)} members")
+ logger.info("Team %s has %s members", team.name, len(team_members))
- logger.info(f"Fetched {len(teams_data)} teams for repository {repo.full_name}")
+ logger.info("Fetched %s teams for repository %s", len(teams_data), repo.full_name)
return teams_data
@@ -175,7 +181,7 @@ def fetch_repository_team_slugs(
retry_count: int = 0, # noqa: ARG001
) -> List[str]:
"""Fetch team slugs with access to the repository."""
- logger.info(f"Fetching team slugs for repository {repo.full_name}")
+ logger.info("Fetching team slugs for repository %s", repo.full_name)
teams_data: List[str] = []
team_objs: PaginatedList[Team] | list[Team] = (
@@ -190,7 +196,9 @@ def fetch_repository_team_slugs(
for team in team_objs:
teams_data.append(team.slug)
- logger.info(f"Fetched {len(teams_data)} team slugs for repository {repo.full_name}")
+ logger.info(
+ "Fetched %s team slugs for repository %s", len(teams_data), repo.full_name
+ )
return teams_data
@@ -201,7 +209,7 @@ def _get_collaborators_and_outside_collaborators(
"""Fetch and categorize collaborators into regular and outside collaborators."""
collaborators: List[UserInfo] = []
outside_collaborators: List[UserInfo] = []
- logger.info(f"Fetching collaborators for repository {repo.full_name}")
+ logger.info("Fetching collaborators for repository %s", repo.full_name)
repo_collaborators: PaginatedList[NamedUser] | list[NamedUser] = (
_run_with_retry(
@@ -241,7 +249,10 @@ def _get_collaborators_and_outside_collaborators(
collaborators.append(info)
logger.info(
- f"Categorized {len(collaborators)} regular and {len(outside_collaborators)} outside collaborators for {repo.full_name}"
+ "Categorized %s regular and %s outside collaborators for %s",
+ len(collaborators),
+ len(outside_collaborators),
+ repo.full_name,
)
return collaborators, outside_collaborators
@@ -285,17 +296,19 @@ def get_repository_visibility(repo: Repository) -> GitHubVisibility:
if hasattr(repo, "visibility"):
visibility = repo.visibility
logger.info(
- f"Repository {repo.full_name} visibility from attribute: {visibility}"
+ "Repository %s visibility from attribute: %s", repo.full_name, visibility
)
try:
return GitHubVisibility(visibility)
except ValueError:
logger.warning(
- f"Unknown visibility '{visibility}' for repo {repo.full_name}, defaulting to private"
+ "Unknown visibility '%s' for repo %s, defaulting to private",
+ visibility,
+ repo.full_name,
)
return GitHubVisibility.PRIVATE
- logger.info(f"Repository {repo.full_name} is private")
+ logger.info("Repository %s is private", repo.full_name)
return GitHubVisibility.PRIVATE
@@ -320,12 +333,14 @@ def get_external_access_permission(
repo_visibility = get_repository_visibility(repo)
logger.info(
- f"Generating ExternalAccess for {repo.full_name}: visibility={repo_visibility.value}"
+ "Generating ExternalAccess for %s: visibility=%s",
+ repo.full_name,
+ repo_visibility.value,
)
if repo_visibility == GitHubVisibility.PUBLIC:
logger.info(
- f"Repository {repo.full_name} is public - allowing access to all users"
+ "Repository %s is public - allowing access to all users", repo.full_name
)
return ExternalAccess(
external_user_emails=set(),
@@ -334,7 +349,7 @@ def get_external_access_permission(
)
elif repo_visibility == GitHubVisibility.PRIVATE:
logger.info(
- f"Repository {repo.full_name} is private - setting up restricted access"
+ "Repository %s is private - setting up restricted access", repo.full_name
)
collaborators_group_id = form_collaborators_group_id(repo.id)
@@ -361,7 +376,7 @@ def get_external_access_permission(
]
group_ids.update(team_slugs)
- logger.info(f"ExternalAccess groups for {repo.full_name}: {group_ids}")
+ logger.info("ExternalAccess groups for %s: %s", repo.full_name, group_ids)
return ExternalAccess(
external_user_emails=set(),
external_user_group_ids=group_ids,
@@ -370,7 +385,7 @@ def get_external_access_permission(
else:
# Internal repositories - accessible to organization members
logger.info(
- f"Repository {repo.full_name} is internal - accessible to org members"
+ "Repository %s is internal - accessible to org members", repo.full_name
)
org_group_id = form_organization_group_id(repo.organization.id)
if add_prefix:
@@ -379,7 +394,7 @@ def get_external_access_permission(
ext_group_name=org_group_id,
)
group_ids = {org_group_id}
- logger.info(f"ExternalAccess groups for {repo.full_name}: {group_ids}")
+ logger.info("ExternalAccess groups for %s: %s", repo.full_name, group_ids)
return ExternalAccess(
external_user_emails=set(),
external_user_group_ids=group_ids,
@@ -396,11 +411,13 @@ def get_external_user_group(
"""
repo_visibility = get_repository_visibility(repo)
logger.info(
- f"Generating ExternalUserGroups for {repo.full_name}: visibility={repo_visibility.value}"
+ "Generating ExternalUserGroups for %s: visibility=%s",
+ repo.full_name,
+ repo_visibility.value,
)
if repo_visibility == GitHubVisibility.PRIVATE:
- logger.info(f"Processing private repository {repo.full_name}")
+ logger.info("Processing private repository %s", repo.full_name)
collaborators, outside_collaborators = (
_get_collaborators_and_outside_collaborators(github_client, repo)
@@ -416,7 +433,7 @@ def get_external_user_group(
# Expected per-user condition (login without a public email);
# skip and warn so the login in the message doesn't explode
# Sentry fingerprinting.
- logger.warning(f"Collaborator {collab.login} has no email")
+ logger.warning("Collaborator %s has no email", collab.login)
if user_emails:
collaborators_group = ExternalUserGroup(
@@ -424,7 +441,7 @@ def get_external_user_group(
user_emails=list(user_emails),
)
external_user_groups.append(collaborators_group)
- logger.info(f"Created collaborators group with {len(user_emails)} emails")
+ logger.info("Created collaborators group with %s emails", len(user_emails))
# Create group for outside collaborators
user_emails = set()
@@ -432,7 +449,7 @@ def get_external_user_group(
if collab.email:
user_emails.add(collab.email)
else:
- logger.warning(f"Outside collaborator {collab.login} has no email")
+ logger.warning("Outside collaborator %s has no email", collab.login)
if user_emails:
outside_collaborators_group = ExternalUserGroup(
@@ -441,7 +458,7 @@ def get_external_user_group(
)
external_user_groups.append(outside_collaborators_group)
logger.info(
- f"Created outside collaborators group with {len(user_emails)} emails"
+ "Created outside collaborators group with %s emails", len(user_emails)
)
# Create groups for teams
@@ -451,7 +468,7 @@ def get_external_user_group(
if member.email:
user_emails.add(member.email)
else:
- logger.warning(f"Team member {member.login} has no email")
+ logger.warning("Team member %s has no email", member.login)
if user_emails:
team_group = ExternalUserGroup(
@@ -460,16 +477,18 @@ def get_external_user_group(
)
external_user_groups.append(team_group)
logger.info(
- f"Created team group {team.name} with {len(user_emails)} emails"
+ "Created team group %s with %s emails", team.name, len(user_emails)
)
logger.info(
- f"Created {len(external_user_groups)} ExternalUserGroups for private repository {repo.full_name}"
+ "Created %s ExternalUserGroups for private repository %s",
+ len(external_user_groups),
+ repo.full_name,
)
return external_user_groups
if repo_visibility == GitHubVisibility.INTERNAL:
- logger.info(f"Processing internal repository {repo.full_name}")
+ logger.info("Processing internal repository %s", repo.full_name)
org_group_id = form_organization_group_id(repo.organization.id)
org_members = _fetch_organization_members(
@@ -481,16 +500,18 @@ def get_external_user_group(
if member.email:
user_emails.add(member.email)
else:
- logger.warning(f"Org member {member.login} has no email")
+ logger.warning("Org member %s has no email", member.login)
org_group = ExternalUserGroup(
id=org_group_id,
user_emails=list(user_emails),
)
logger.info(
- f"Created organization group with {len(user_emails)} emails for internal repository {repo.full_name}"
+ "Created organization group with %s emails for internal repository %s",
+ len(user_emails),
+ repo.full_name,
)
return [org_group]
- logger.info(f"Repository {repo.full_name} is public - no user groups needed")
+ logger.info("Repository %s is public - no user groups needed", repo.full_name)
return []
diff --git a/backend/ee/onyx/external_permissions/gmail/doc_sync.py b/backend/ee/onyx/external_permissions/gmail/doc_sync.py
index 1dccd5e11d..7a870332d4 100644
--- a/backend/ee/onyx/external_permissions/gmail/doc_sync.py
+++ b/backend/ee/onyx/external_permissions/gmail/doc_sync.py
@@ -79,7 +79,7 @@ def gmail_doc_sync(
)
continue
if slim_doc.external_access is None:
- logger.warning(f"No permissions found for document {slim_doc.id}")
+ logger.warning("No permissions found for document %s", slim_doc.id)
continue
yield DocExternalAccess(
diff --git a/backend/ee/onyx/external_permissions/google_drive/doc_sync.py b/backend/ee/onyx/external_permissions/google_drive/doc_sync.py
index 042d6ca746..f8661f7948 100644
--- a/backend/ee/onyx/external_permissions/google_drive/doc_sync.py
+++ b/backend/ee/onyx/external_permissions/google_drive/doc_sync.py
@@ -115,7 +115,8 @@ def get_external_access_for_raw_gdrive_file(
)
if len(permissions_list) != len(permission_ids) and retriever_drive_service:
logger.warning(
- f"Failed to get all permissions for file {doc_id} with retriever service, trying admin service"
+ "Failed to get all permissions for file %s with retriever service, trying admin service",
+ doc_id,
)
backup_permissions_list = _get_permissions(admin_drive_service)
permissions_list = _merge_permissions_lists(
@@ -132,9 +133,11 @@ def get_external_access_for_raw_gdrive_file(
# but the actual fetch can still return empty due to a 403.
if not permissions_list:
logger.info(
- f"No permission info available for file {doc_id} "
- f"(likely owned by a user outside of your organization). "
- f"Falling back to granting access to retriever user: {fallback_user_email}"
+ "No permission info available for file %s "
+ "(likely owned by a user outside of your organization). "
+ "Falling back to granting access to retriever user: %s",
+ doc_id,
+ fallback_user_email,
)
return ExternalAccess(
external_user_emails={fallback_user_email},
@@ -170,7 +173,9 @@ def get_external_access_for_raw_gdrive_file(
# skip the permission — warn instead of error so the doc_id
# in the message doesn't explode Sentry fingerprinting.
logger.warning(
- f"Permission is type `user` but no email address is provided for document {doc_id}\n {permission}"
+ "Permission is type `user` but no email address is provided for document %s\n %s",
+ doc_id,
+ permission,
)
elif permission.type == PermissionType.GROUP:
# groups are represented as email addresses within Drive
@@ -178,14 +183,17 @@ def get_external_access_for_raw_gdrive_file(
group_emails.add(permission.email_address)
else:
logger.warning(
- f"Permission is type `group` but no email address is provided for document {doc_id}\n {permission}"
+ "Permission is type `group` but no email address is provided for document %s\n %s",
+ doc_id,
+ permission,
)
elif permission.type == PermissionType.DOMAIN and company_domain:
if permission.domain == company_domain:
public = True
else:
logger.warning(
- f"Permission is type domain but does not match company domain:\n {permission}"
+ "Permission is type domain but does not match company domain:\n %s",
+ permission,
)
elif permission.type == PermissionType.ANYONE:
public = True
@@ -244,7 +252,7 @@ def get_external_access_for_folder(
# Get permission IDs from folder metadata
permission_ids = folder.get("permissionIds") or []
if not permission_ids:
- logger.debug(f"No permissionIds found for folder {folder_id}")
+ logger.debug("No permissionIds found for folder %s", folder_id)
return ExternalAccess(
external_user_emails=set(),
external_user_group_ids=set(),
@@ -267,13 +275,15 @@ def get_external_access_for_folder(
if permission.email_address:
user_emails.add(permission.email_address)
else:
- logger.warning(f"User permission without email for folder {folder_id}")
+ logger.warning("User permission without email for folder %s", folder_id)
elif permission.type == PermissionType.GROUP:
# Groups are represented as email addresses in Google Drive
if permission.email_address:
group_emails.add(permission.email_address)
else:
- logger.warning(f"Group permission without email for folder {folder_id}")
+ logger.warning(
+ "Group permission without email for folder %s", folder_id
+ )
elif permission.type == PermissionType.DOMAIN:
# Domain permission - check if it matches company domain
if permission.domain == google_domain:
@@ -282,8 +292,11 @@ def get_external_access_for_folder(
is_public = permission.allow_file_discovery is not False
else:
logger.debug(
- f"Domain permission for {permission.domain} does not match "
- f"company domain {google_domain} for folder {folder_id}"
+ "Domain permission for %s does not match "
+ "company domain %s for folder %s",
+ permission.domain,
+ google_domain,
+ folder_id,
)
elif permission.type == PermissionType.ANYONE:
# Only public if discoverable (allowFileDiscovery is not False)
@@ -331,7 +344,7 @@ def gdrive_doc_sync(
total_processed = 0
for slim_doc_batch in slim_doc_generator:
- logger.info(f"Drive perm sync: Processing {len(slim_doc_batch)} documents")
+ logger.info("Drive perm sync: Processing %s documents", len(slim_doc_batch))
for slim_doc in slim_doc_batch:
if callback:
if callback.should_stop():
@@ -357,4 +370,4 @@ def gdrive_doc_sync(
doc_id=slim_doc.id,
)
total_processed += len(slim_doc_batch)
- logger.info(f"Drive perm sync: Processed {total_processed} total documents")
+ logger.info("Drive perm sync: Processed %s total documents", total_processed)
diff --git a/backend/ee/onyx/external_permissions/google_drive/group_sync.py b/backend/ee/onyx/external_permissions/google_drive/group_sync.py
index dcd78d65d2..521094387b 100644
--- a/backend/ee/onyx/external_permissions/google_drive/group_sync.py
+++ b/backend/ee/onyx/external_permissions/google_drive/group_sync.py
@@ -65,7 +65,7 @@ def _get_all_folders(
):
folder_id = folder["id"]
if folder_id in seen_folder_ids:
- logger.debug(f"Folder {folder_id} has already been seen. Skipping.")
+ logger.debug("Folder %s has already been seen. Skipping.", folder_id)
continue
seen_folder_ids.add(folder_id)
@@ -94,7 +94,7 @@ def _get_all_folders(
]
if not permissions and skip_folders_without_permissions:
- logger.debug(f"Folder {folder_id} has no permissions. Skipping.")
+ logger.debug("Folder %s has no permissions. Skipping.", folder_id)
continue
all_folders.append(
@@ -116,11 +116,12 @@ def _get_all_folders(
# expired), not a bug — surface as a warning instead of an error.
if isinstance(e, HttpError) and e.status_code == 401:
logger.warning(
- f"Google Drive returned 401 for user {user_email}; "
- f"credentials may need to be reconnected. {e}"
+ "Google Drive returned 401 for user %s; credentials may need to be reconnected. %s",
+ user_email,
+ e,
)
else:
- logger.exception(f"Error getting folders for user {user_email}")
+ logger.exception("Error getting folders for user %s", user_email)
failed_count += 1
if failed_count > MAX_FAILED_PERCENTAGE * len(user_emails):
@@ -143,14 +144,18 @@ def _drive_folder_to_onyx_group(
if permission.type == PermissionType.USER:
if permission.email_address is None:
logger.warning(
- f"User email is None for folder {folder.id} permission {permission}"
+ "User email is None for folder %s permission %s",
+ folder.id,
+ permission,
)
continue
folder_member_emails.add(permission.email_address)
elif permission.type == PermissionType.GROUP:
if permission.email_address not in group_email_to_member_emails_map:
logger.warning(
- f"Group email {permission.email_address} for folder {folder.id} not found in group_email_to_member_emails_map"
+ "Group email %s for folder %s not found in group_email_to_member_emails_map",
+ permission.email_address,
+ folder.id,
)
continue
folder_member_emails.update(
@@ -238,10 +243,11 @@ def _get_drive_members(
except HttpError as e:
if e.status_code in (403, 404):
logger.warning(
- f"Error getting permissions for drive id {drive_id}. "
- f"User '{google_drive_connector.primary_admin_email}' likely "
- f"does not have access to this drive (status={e.status_code}). "
- f"Exception: {e}"
+ "Error getting permissions for drive id %s. User '%s' likely does not have access to this drive (status=%s). Exception: %s",
+ drive_id,
+ google_drive_connector.primary_admin_email,
+ e.status_code,
+ e,
)
else:
raise e
@@ -261,7 +267,9 @@ def _drive_member_map_to_onyx_groups(
for group_email in group_emails:
if group_email not in group_email_to_member_emails_map:
logger.warning(
- f"Group email {group_email} for drive {drive_id} not found in group_email_to_member_emails_map"
+ "Group email %s for drive %s not found in group_email_to_member_emails_map",
+ group_email,
+ drive_id,
)
continue
drive_member_emails.update(group_email_to_member_emails_map[group_email])
@@ -348,7 +356,9 @@ def _build_onyx_groups(
for group_email in group_emails:
if group_email not in group_email_to_member_emails_map:
logger.warning(
- f"Group email {group_email} for drive {drive_id} not found in group_email_to_member_emails_map"
+ "Group email %s for drive %s not found in group_email_to_member_emails_map",
+ group_email,
+ drive_id,
)
continue
drive_member_emails.update(group_email_to_member_emails_map[group_email])
@@ -367,15 +377,18 @@ def _build_onyx_groups(
if permission.type == PermissionType.USER:
if permission.email_address is None:
logger.warning(
- f"User email is None for folder {folder.id} permission {permission}"
+ "User email is None for folder %s permission %s",
+ folder.id,
+ permission,
)
continue
folder_member_emails.add(permission.email_address)
elif permission.type == PermissionType.GROUP:
if permission.email_address not in group_email_to_member_emails_map:
logger.warning(
- f"Group email {permission.email_address} for folder {folder.id} "
- "not found in group_email_to_member_emails_map"
+ "Group email %s for folder %s not found in group_email_to_member_emails_map",
+ permission.email_address,
+ folder.id,
)
continue
folder_member_emails.update(
diff --git a/backend/ee/onyx/external_permissions/google_drive/permission_retrieval.py b/backend/ee/onyx/external_permissions/google_drive/permission_retrieval.py
index 310f1f12d9..0163c962be 100644
--- a/backend/ee/onyx/external_permissions/google_drive/permission_retrieval.py
+++ b/backend/ee/onyx/external_permissions/google_drive/permission_retrieval.py
@@ -55,7 +55,9 @@ def get_permissions_by_ids(
if len(filtered_permissions) < len(permission_ids):
missing_ids = permission_id_set - {p.id for p in filtered_permissions if p.id}
logger.warning(
- f"Could not find all requested permission IDs for document {doc_id}. Missing IDs: {missing_ids}"
+ "Could not find all requested permission IDs for document %s. Missing IDs: %s",
+ doc_id,
+ missing_ids,
)
return filtered_permissions
diff --git a/backend/ee/onyx/external_permissions/jira/group_sync.py b/backend/ee/onyx/external_permissions/jira/group_sync.py
index def0efd8ce..c20a4a0e55 100644
--- a/backend/ee/onyx/external_permissions/jira/group_sync.py
+++ b/backend/ee/onyx/external_permissions/jira/group_sync.py
@@ -73,7 +73,7 @@ def _get_group_member_emails(
try:
page = _fetch_group_member_page(jira_client, group_name, start_at)
except Exception as e:
- logger.error(f"Error fetching members for group {group_name}: {e}")
+ logger.error("Error fetching members for group %s: %s", group_name, e)
raise
members: list[dict[str, Any]] = page.get("values", [])
@@ -89,7 +89,9 @@ def _get_group_member_emails(
emails.add(email)
else:
logger.warning(
- f"Atlassian user {member.get('accountId', 'unknown')} in group {group_name} has no visible email address"
+ "Atlassian user %s in group %s has no visible email address",
+ member.get("accountId", "unknown"),
+ group_name,
)
if page.get("isLast", True) or not members:
@@ -130,7 +132,7 @@ def jira_group_sync(
if not group_names:
raise ValueError(f"No groups found for cc_pair_id={cc_pair.id}")
- logger.info(f"Found {len(group_names)} groups in Jira")
+ logger.info("Found %s groups in Jira", len(group_names))
for group_name in group_names:
if not group_name:
@@ -141,10 +143,10 @@ def jira_group_sync(
group_name=group_name,
)
if not member_emails:
- logger.debug(f"No members found for group {group_name}")
+ logger.debug("No members found for group %s", group_name)
continue
- logger.debug(f"Found {len(member_emails)} members for group {group_name}")
+ logger.debug("Found %s members for group %s", len(member_emails), group_name)
yield ExternalUserGroup(
id=group_name,
user_emails=list(member_emails),
diff --git a/backend/ee/onyx/external_permissions/jira/page_access.py b/backend/ee/onyx/external_permissions/jira/page_access.py
index 301b008cdc..fc430d4695 100644
--- a/backend/ee/onyx/external_permissions/jira/page_access.py
+++ b/backend/ee/onyx/external_permissions/jira/page_access.py
@@ -65,7 +65,9 @@ def _build_holder_map(permissions: list[dict]) -> dict[str, list[Holder]]:
for raw_perm in permissions:
if not hasattr(raw_perm, "raw"):
- logger.warning(f"Expected a 'raw' field, but none was found: {raw_perm=}")
+ logger.warning(
+ "Expected a 'raw' field, but none was found: raw_perm=%r", raw_perm
+ )
continue
permission = Permission(**raw_perm.raw) # ty: ignore[invalid-argument-type]
@@ -78,14 +80,16 @@ def _build_holder_map(permissions: list[dict]) -> dict[str, list[Holder]]:
# If this doesn't exist, then we cannot associate this permission to anyone; just skip.
if not permission.holder:
logger.warning(
- f"Expected to find a permission holder, but none was found: {permission=}"
+ "Expected to find a permission holder, but none was found: permission=%r",
+ permission,
)
continue
type = permission.holder.get("type")
if not type:
logger.warning(
- f"Expected to find the type of permission holder, but none was found: {permission=}"
+ "Expected to find the type of permission holder, but none was found: permission=%r",
+ permission,
)
continue
@@ -106,8 +110,8 @@ def _get_user_emails(user_holders: list[Holder]) -> list[str]:
user_model = User.model_validate(raw_user_dict)
except ValidationError:
logger.error(
- "Expected to be able to serialize the raw-user-dict into an instance of `User`, but validation failed;"
- f"{raw_user_dict=}"
+ "Expected to be able to serialize the raw-user-dict into an instance of `User`, but validation failed;raw_user_dict=%r",
+ raw_user_dict,
)
continue
@@ -132,7 +136,7 @@ def _get_user_emails_and_groups_from_project_roles(
if role_id:
role_ids.append(role_id)
else:
- logger.warning(f"No value or parameter in projectRole holder: {holder}")
+ logger.warning("No value or parameter in projectRole holder: %s", holder)
roles = [
jira_client.project_role(project=jira_project, id=role_id)
@@ -144,7 +148,7 @@ def _get_user_emails_and_groups_from_project_roles(
for role in roles:
if not hasattr(role, "actors"):
- logger.warning(f"Project role {role} has no actors attribute")
+ logger.warning("Project role %s has no actors attribute", role)
continue
for actor in role.actors:
@@ -161,13 +165,14 @@ def _get_user_emails_and_groups_from_project_roles(
if hasattr(actor, "actorUser"):
account_id = getattr(actor.actorUser, "accountId", None)
if not account_id:
- logger.error(f"No accountId in actorUser: {actor.actorUser}")
+ logger.error("No accountId in actorUser: %s", actor.actorUser)
continue
user = jira_client.user(id=account_id)
if not hasattr(user, "accountType") or user.accountType != "atlassian":
logger.info(
- f"Skipping user {account_id} because it is not an atlassian user"
+ "Skipping user %s because it is not an atlassian user",
+ account_id,
)
continue
@@ -181,7 +186,7 @@ def _get_user_emails_and_groups_from_project_roles(
emails.append(user.emailAddress)
continue
- logger.debug(f"Skipping actor type: {actor}")
+ logger.debug("Skipping actor type: %s", actor)
return emails, groups
@@ -239,7 +244,7 @@ def _build_external_access_from_holder_map(
if group_name:
direct_groups.append(group_name)
else:
- logger.error(f"No parameter/value in group holder: {group_holder}")
+ logger.error("No parameter/value in group holder: %s", group_holder)
external_user_emails = set(user_emails + project_role_user_emails)
external_user_group_ids = set(project_role_groups + direct_groups)
@@ -267,11 +272,11 @@ def get_project_permissions(
)
if not hasattr(project_permissions, "permissions"):
- logger.error(f"Project {jira_project} has no permissions attribute")
+ logger.error("Project %s has no permissions attribute", jira_project)
return None
if not isinstance(project_permissions.permissions, list):
- logger.error(f"Project {jira_project} permissions is not a list")
+ logger.error("Project %s permissions is not a list", jira_project)
return None
holder_map = _build_holder_map(permissions=project_permissions.permissions)
diff --git a/backend/ee/onyx/external_permissions/post_query_censoring.py b/backend/ee/onyx/external_permissions/post_query_censoring.py
index 384bcf3ccd..74b15c4db8 100644
--- a/backend/ee/onyx/external_permissions/post_query_censoring.py
+++ b/backend/ee/onyx/external_permissions/post_query_censoring.py
@@ -69,7 +69,9 @@ def _post_query_chunk_censoring(
censored_chunks = censor_chunks_for_source(chunks_for_source, user.email)
except Exception as e:
logger.exception(
- f"Failed to censor chunks for source {source} so throwing out all chunks for this source and continuing: {e}"
+ "Failed to censor chunks for source %s so throwing out all chunks for this source and continuing: %s",
+ source,
+ e,
)
continue
diff --git a/backend/ee/onyx/external_permissions/salesforce/postprocessing.py b/backend/ee/onyx/external_permissions/salesforce/postprocessing.py
index 5c99feb72d..6f02e8f823 100644
--- a/backend/ee/onyx/external_permissions/salesforce/postprocessing.py
+++ b/backend/ee/onyx/external_permissions/salesforce/postprocessing.py
@@ -57,10 +57,10 @@ def _get_objects_access_for_user_email_from_salesforce(
user_id = get_salesforce_user_id_from_email(salesforce_client, user_email)
end_time = time.monotonic()
logger.info(
- f"Time taken to get Salesforce user ID: {end_time - start_time} seconds"
+ "Time taken to get Salesforce user ID: %s seconds", end_time - start_time
)
if user_id is None:
- logger.warning(f"User '{user_email}' not found in Salesforce")
+ logger.warning("User '%s' not found in Salesforce", user_email)
return None
# This is the only query that is not cached in the function
@@ -68,7 +68,7 @@ def _get_objects_access_for_user_email_from_salesforce(
object_id_to_access = get_objects_access_for_user_id(
salesforce_client, user_id, list(object_ids)
)
- logger.debug(f"Object ID to access: {object_id_to_access}")
+ logger.debug("Object ID to access: %s", object_id_to_access)
return object_id_to_access
diff --git a/backend/ee/onyx/external_permissions/sharepoint/group_sync.py b/backend/ee/onyx/external_permissions/sharepoint/group_sync.py
index 15111619ef..6560818d2f 100644
--- a/backend/ee/onyx/external_permissions/sharepoint/group_sync.py
+++ b/backend/ee/onyx/external_permissions/sharepoint/group_sync.py
@@ -45,7 +45,7 @@ def sharepoint_group_sync(
if not site_descriptors:
raise RuntimeError("No SharePoint sites found for group sync")
- logger.info(f"Processing {len(site_descriptors)} sites for group sync")
+ logger.info("Processing %s sites for group sync", len(site_descriptors))
enumerate_all = connector_config.get(
"exhaustive_ad_enumeration", SHAREPOINT_EXHAUSTIVE_AD_ENUMERATION
@@ -55,7 +55,7 @@ def sharepoint_group_sync(
sp_tenant_domain = connector.sp_tenant_domain
sp_domain_suffix = connector.sharepoint_domain_suffix
for site_descriptor in site_descriptors:
- logger.debug(f"Processing site: {site_descriptor.url}")
+ logger.debug("Processing site: %s", site_descriptor.url)
ctx = ClientContext(site_descriptor.url).with_access_token(
lambda: acquire_token_for_rest(msal_app, sp_tenant_domain, sp_domain_suffix)
@@ -72,6 +72,6 @@ def sharepoint_group_sync(
# Yield each group
for group in external_groups:
logger.debug(
- f"Found group: {group.id} with {len(group.user_emails)} members"
+ "Found group: %s with %s members", group.id, len(group.user_emails)
)
yield group
diff --git a/backend/ee/onyx/external_permissions/sharepoint/permission_utils.py b/backend/ee/onyx/external_permissions/sharepoint/permission_utils.py
index 036b283c38..e0fa9044ad 100644
--- a/backend/ee/onyx/external_permissions/sharepoint/permission_utils.py
+++ b/backend/ee/onyx/external_permissions/sharepoint/permission_utils.py
@@ -63,7 +63,11 @@ def _graph_api_get(
):
wait = min(int(resp.headers.get("Retry-After", str(2**attempt))), 60)
logger.warning(
- f"Graph API {resp.status_code} on attempt {attempt + 1}, retrying in {wait}s: {url}"
+ "Graph API %s on attempt %s, retrying in %ss: %s",
+ resp.status_code,
+ attempt + 1,
+ wait,
+ url,
)
time.sleep(wait)
continue
@@ -73,7 +77,10 @@ def _graph_api_get(
if attempt < GRAPH_API_MAX_RETRIES:
wait = min(2**attempt, 60)
logger.warning(
- f"Graph API connection error on attempt {attempt + 1}, retrying in {wait}s: {url}"
+ "Graph API connection error on attempt %s, retrying in %ss: %s",
+ attempt + 1,
+ wait,
+ url,
)
time.sleep(wait)
continue
@@ -132,7 +139,7 @@ def _get_azuread_group_guid_by_name(
return None
except Exception as e:
- logger.error(f"Failed to get Azure AD group GUID for name {group_name}: {e}")
+ logger.error("Failed to get Azure AD group GUID for name %s: %s", group_name, e)
return None
@@ -150,7 +157,7 @@ def _extract_guid_from_claims_token(claims_token: str) -> str | None:
return None
except Exception as e:
- logger.error(f"Failed to extract GUID from claims token {claims_token}: {e}")
+ logger.error("Failed to extract GUID from claims token %s: %s", claims_token, e)
return None
@@ -167,14 +174,14 @@ def _get_group_guid_from_identifier(
if identifier.startswith("c:0") and "|" in identifier:
guid = _extract_guid_from_claims_token(identifier)
if guid:
- logger.info(f"Extracted GUID {guid} from claims token {identifier}")
+ logger.info("Extracted GUID %s from claims token %s", guid, identifier)
return guid
# Try to search by display name as fallback
return _get_azuread_group_guid_by_name(graph_client, identifier)
except Exception as e:
- logger.error(f"Failed to get group GUID from identifier {identifier}: {e}")
+ logger.error("Failed to get group GUID from identifier %s: %s", identifier, e)
return None
@@ -188,7 +195,7 @@ def _get_security_group_owners(graph_client: GraphClient, group_id: str) -> list
)
owner_emails: list[str] = []
- logger.info(f"Owners: {owners}")
+ logger.info("Owners: %s", owners)
for owner in owners:
owner_data = owner.to_json()
@@ -210,12 +217,14 @@ def _get_security_group_owners(graph_client: GraphClient, group_id: str) -> list
owner_emails.append(user_principal_name)
logger.info(
- f"Retrieved {len(owner_emails)} owners from security group {group_id}"
+ "Retrieved %s owners from security group %s", len(owner_emails), group_id
)
return owner_emails
except Exception as e:
- logger.error(f"Failed to get security group owners for group {group_id}: {e}")
+ logger.error(
+ "Failed to get security group owners for group %s: %s", group_id, e
+ )
return []
@@ -247,7 +256,7 @@ def _get_sharepoint_list_item_id(drive_item: DriveItem) -> str | None:
return None
except Exception as e:
logger.error(
- f"Error getting SharePoint list item ID for item {drive_item.id}: {e}"
+ "Error getting SharePoint list item ID for item %s: %s", drive_item.id, e
)
raise e
@@ -271,7 +280,7 @@ def _is_public_item(
return True
return False
except Exception as e:
- logger.error(f"Failed to check if item {drive_item.id} is public: {e}")
+ logger.error("Failed to check if item %s is public: %s", drive_item.id, e)
return False
@@ -285,7 +294,7 @@ def _is_public_login_name(login_name: str) -> bool:
]
for pattern in public_login_patterns:
if pattern in login_name:
- logger.info(f"Login name {login_name} is public")
+ logger.info("Login name %s is public", login_name)
return True
return False
@@ -313,7 +322,7 @@ def _get_sharepoint_groups(
# `_get_next().execute_query()`, which re-fires this `page_loaded` callback
# and recurses until Python hits its max recursion depth.
for user in users.current_page:
- logger.debug(f"User: {user.to_json()}")
+ logger.debug("User: %s", user.to_json())
if user.principal_type == USER_PRINCIPAL_TYPE and hasattr(
user, "user_principal_name"
):
@@ -324,7 +333,7 @@ def _get_sharepoint_groups(
user_emails.add(email)
else:
logger.warning(
- f"User don't have a user principal name: {user.login_name}"
+ "User don't have a user principal name: %s", user.login_name
)
elif user.principal_type in [
AZURE_AD_GROUP_PRINCIPAL_TYPE,
@@ -357,7 +366,7 @@ def _get_azuread_groups(
group_id = _get_group_guid_from_identifier(graph_client, group_name)
if not group_id:
- logger.error(f"Failed to get Azure AD group GUID for name {group_name}")
+ logger.error("Failed to get Azure AD group GUID for name %s", group_name)
return set(), set()
group = graph_client.groups[group_id]
groups: set[SharepointGroup] = set()
@@ -372,7 +381,7 @@ def _get_azuread_groups(
# and recurses until Python hits its max recursion depth.
for member in members.current_page:
member_data = member.to_json()
- logger.debug(f"Member: {member_data}")
+ logger.debug("Member: %s", member_data)
# Check for user-specific attributes
user_principal_name = member_data.get("userPrincipalName")
mail = member_data.get("mail")
@@ -419,10 +428,10 @@ def _get_azuread_groups(
if MICROSOFT_DOMAIN in email:
email = email.replace(MICROSOFT_DOMAIN, "")
user_emails.add(email)
- logger.info(f"Added user: {user_principal_name or mail}")
+ logger.info("Added user: %s", user_principal_name or mail)
elif is_group:
if not display_name:
- logger.error(f"No display name for group: {member_data.get('id')}")
+ logger.error("No display name for group: %s", member_data.get("id"))
continue
name = _get_group_name_with_suffix(
member_data.get("id", ""), display_name, graph_client
@@ -434,10 +443,10 @@ def _get_azuread_groups(
name=name,
)
)
- logger.info(f"Added group: {name}")
+ logger.info("Added group: %s", name)
else:
# Log unidentified members for debugging
- logger.warning(f"Could not identify member type for: {member_data}")
+ logger.warning("Could not identify member type for: %s", member_data)
sleep_and_retry(
group.members.get_all(page_loaded=process_members), "get_azuread_groups"
@@ -469,7 +478,7 @@ def _get_groups_and_members_recursively(
visited_groups.add(group.login_name)
visited_group_name_to_emails[group.name] = set()
logger.info(
- f"Processing group: {group.name} principal type: {group.principal_type}"
+ "Processing group: %s principal type: %s", group.name, group.principal_type
)
if group.principal_type == SHAREPOINT_GROUP_PRINCIPAL_TYPE:
group_info, user_emails = _get_sharepoint_groups(
@@ -501,7 +510,7 @@ def _get_groups_and_members_recursively(
# in sharepoint but it is removed from Azure AD. There is no actual documentation on this, but based on
# our testing we have seen this happen.
if e.response is not None and e.response.status_code == 404:
- logger.warning(f"Group {group.login_name} not found")
+ logger.warning("Group %s not found", group.login_name)
continue
raise e
@@ -537,7 +546,7 @@ def get_external_access_from_sharepoint(
# via `_get_next().execute_query()`, which re-fires this `page_loaded`
# callback and recurses until Python hits its max recursion depth.
for assignment in role_assignments.current_page:
- logger.debug(f"Assignment: {assignment.to_json()}")
+ logger.debug("Assignment: %s", assignment.to_json())
if assignment.role_definition_bindings:
is_limited_access = True
for role_definition_binding in assignment.role_definition_bindings:
@@ -584,7 +593,7 @@ def get_external_access_from_sharepoint(
if drive_item and drive_name:
is_public = _is_public_item(drive_item, treat_sharing_link_as_public)
if is_public:
- logger.info(f"Item {drive_item.id} is public")
+ logger.info("Item %s is public", drive_item.id)
return ExternalAccess(
external_user_emails=set(),
external_user_group_ids=set(),
@@ -652,8 +661,8 @@ def get_external_access_from_sharepoint(
)
group_ids.add(group_name.lower())
- logger.info(f"User emails: {len(user_emails)}")
- logger.info(f"Group IDs: {len(group_ids)}")
+ logger.info("User emails: %s", len(user_emails))
+ logger.info("Group IDs: %s", len(group_ids))
return ExternalAccess(
external_user_emails=user_emails,
@@ -687,9 +696,8 @@ def _enumerate_ad_groups_paginated(
total_groups += 1
if total_groups > AD_GROUP_ENUMERATION_THRESHOLD:
logger.warning(
- f"Azure AD group enumeration exceeded {AD_GROUP_ENUMERATION_THRESHOLD} "
- "groups — stopping to avoid excessive memory/API usage. "
- "Remaining groups will be resolved from role assignments only."
+ "Azure AD group enumeration exceeded %s groups — stopping to avoid excessive memory/API usage. Remaining groups will be resolved from role assignments only.",
+ AD_GROUP_ENUMERATION_THRESHOLD,
)
return
@@ -712,7 +720,7 @@ def _enumerate_ad_groups_paginated(
yield ExternalUserGroup(id=name, user_emails=member_emails)
- logger.info(f"Enumerated {total_groups} Azure AD groups via paginated Graph API")
+ logger.info("Enumerated %s Azure AD groups via paginated Graph API", total_groups)
def get_sharepoint_external_groups(
diff --git a/backend/ee/onyx/external_permissions/utils.py b/backend/ee/onyx/external_permissions/utils.py
index 6538c90d8e..e9152249a5 100644
--- a/backend/ee/onyx/external_permissions/utils.py
+++ b/backend/ee/onyx/external_permissions/utils.py
@@ -39,7 +39,7 @@ def generic_doc_sync(
A `Generator` which yields existing and newly fetched external-access permissions.
"""
- logger.info(f"Starting {doc_source} doc sync for CC Pair ID: {cc_pair.id}")
+ logger.info("Starting %s doc sync for CC Pair ID: %s", doc_source, cc_pair.id)
indexing_start: SecondsSinceUnixEpoch | None = (
cc_pair.connector.indexing_start.timestamp()
@@ -49,12 +49,12 @@ def generic_doc_sync(
newly_fetched_doc_ids: set[str] = set()
- logger.info(f"Fetching all slim documents from {doc_source}")
+ logger.info("Fetching all slim documents from %s", doc_source)
for doc_batch in slim_connector.retrieve_all_slim_docs_perm_sync(
start=indexing_start,
callback=callback,
):
- logger.info(f"Got {len(doc_batch)} slim documents from {doc_source}")
+ logger.info("Got %s slim documents from %s", len(doc_batch), doc_source)
if callback:
if callback.should_stop():
@@ -83,7 +83,9 @@ def generic_doc_sync(
external_access=doc.external_access,
)
- logger.info(f"Querying existing document IDs for CC Pair ID: {cc_pair.id=}")
+ logger.info(
+ "Querying existing document IDs for CC Pair ID: cc_pair.id=%r", cc_pair.id
+ )
existing_doc_ids: list[str] = fetch_all_existing_docs_ids_fn()
missing_doc_ids = set(existing_doc_ids) - newly_fetched_doc_ids
@@ -92,14 +94,15 @@ def generic_doc_sync(
return
logger.warning(
- f"Found {len(missing_doc_ids)=} documents that are in the DB but not present in fetch. Making them inaccessible."
+ "Found len(missing_doc_ids)=%r documents that are in the DB but not present in fetch. Making them inaccessible.",
+ len(missing_doc_ids),
)
for missing_id in missing_doc_ids:
- logger.warning(f"Removing access for {missing_id=}")
+ logger.warning("Removing access for missing_id=%r", missing_id)
yield DocExternalAccess(
doc_id=missing_id,
external_access=ExternalAccess.empty(),
)
- logger.info(f"Finished {doc_source} doc sync")
+ logger.info("Finished %s doc sync", doc_source)
diff --git a/backend/ee/onyx/feature_flags/posthog_provider.py b/backend/ee/onyx/feature_flags/posthog_provider.py
index 341d6fc62b..9c00323878 100644
--- a/backend/ee/onyx/feature_flags/posthog_provider.py
+++ b/backend/ee/onyx/feature_flags/posthog_provider.py
@@ -52,6 +52,6 @@ class PostHogFeatureFlagProvider(FeatureFlagProvider):
except Exception as e:
logger.error(
- f"Error checking feature flag {flag_key} for user {user_id}: {e}"
+ "Error checking feature flag %s for user %s: %s", flag_key, user_id, e
)
return False
diff --git a/backend/ee/onyx/hooks/executor.py b/backend/ee/onyx/hooks/executor.py
index f3802253d4..87e26745da 100644
--- a/backend/ee/onyx/hooks/executor.py
+++ b/backend/ee/onyx/hooks/executor.py
@@ -243,7 +243,7 @@ def _persist_result(
log_session.commit()
except Exception:
logger.exception(
- f"Failed to persist hook execution log for hook_id={hook_id}"
+ "Failed to persist hook execution log for hook_id=%s", hook_id
)
# Update is_reachable separately — best-effort, non-critical.
@@ -260,7 +260,7 @@ def _persist_result(
)
reachable_session.commit()
except Exception:
- logger.warning(f"Failed to update is_reachable for hook_id={hook_id}")
+ logger.warning("Failed to update is_reachable for hook_id=%s", hook_id)
# ---------------------------------------------------------------------------
@@ -342,7 +342,9 @@ def _execute_hook_inner(
outcome.error_message or "Hook execution failed.",
)
logger.warning(
- f"Hook execution failed (soft fail) for hook_id={hook_id}: {outcome.error_message}"
+ "Hook execution failed (soft fail) for hook_id=%s: %s",
+ hook_id,
+ outcome.error_message,
)
return HookSoftFailed()
@@ -379,7 +381,7 @@ def _execute_hook_impl(
except Exception:
if fail_strategy == HookFailStrategy.SOFT:
logger.exception(
- f"Unexpected error in hook execution (soft fail) for hook_id={hook_id}"
+ "Unexpected error in hook execution (soft fail) for hook_id=%s", hook_id
)
return HookSoftFailed()
raise
diff --git a/backend/ee/onyx/onyxbot/slack/handlers/handle_standard_answers.py b/backend/ee/onyx/onyxbot/slack/handlers/handle_standard_answers.py
index 73d562818b..e875111622 100644
--- a/backend/ee/onyx/onyxbot/slack/handlers/handle_standard_answers.py
+++ b/backend/ee/onyx/onyxbot/slack/handlers/handle_standard_answers.py
@@ -232,7 +232,7 @@ def _handle_standard_answers(
return True
except Exception as e:
- logger.exception(f"Unable to send standard answer message: {e}")
+ logger.exception("Unable to send standard answer message: %s", e)
return False
else:
return False
diff --git a/backend/ee/onyx/search/process_search_query.py b/backend/ee/onyx/search/process_search_query.py
index 63a80a0eff..fec0f874d4 100644
--- a/backend/ee/onyx/search/process_search_query.py
+++ b/backend/ee/onyx/search/process_search_query.py
@@ -94,10 +94,11 @@ def stream_search_query(
)
if keyword_expansions:
logger.debug(
- f"Query expansion generated {len(keyword_expansions)} keyword queries"
+ "Query expansion generated %s keyword queries",
+ len(keyword_expansions),
)
except Exception as e:
- logger.warning(f"Query expansion failed: {e}; using original query only.")
+ logger.warning("Query expansion failed: %s; using original query only.", e)
keyword_expansions = []
# Build list of all executed queries for tracking
@@ -218,12 +219,14 @@ def stream_search_query(
)
)
logger.debug(
- f"LLM document selection evaluated {len(sections_to_evaluate)} sections, "
- f"selected {len(selected_sections)} sections with doc IDs: {llm_selected_doc_ids}"
+ "LLM document selection evaluated %s sections, selected %s sections with doc IDs: %s",
+ len(sections_to_evaluate),
+ len(selected_sections),
+ llm_selected_doc_ids,
)
except Exception as e:
# Allowing a blanket exception here as this step is not critical and the rest of the results are still valid
- logger.warning(f"LLM document selection failed: {e}")
+ logger.warning("LLM document selection failed: %s", e)
llm_selection_failed = True
elif run_llm_selection and not sections:
# LLM selection requested but no sections to evaluate
diff --git a/backend/ee/onyx/secondary_llm_flows/query_expansion.py b/backend/ee/onyx/secondary_llm_flows/query_expansion.py
index 80ca1b66c9..2bb52b117d 100644
--- a/backend/ee/onyx/secondary_llm_flows/query_expansion.py
+++ b/backend/ee/onyx/secondary_llm_flows/query_expansion.py
@@ -84,9 +84,9 @@ def expand_keywords(
seen_lower.add(query_lower)
expanded_queries.append(query)
- logger.debug(f"Keyword expansion generated {len(expanded_queries)} queries")
+ logger.debug("Keyword expansion generated %s queries", len(expanded_queries))
return expanded_queries
except Exception as e:
- logger.warning(f"Keyword expansion failed: {e}")
+ logger.warning("Keyword expansion failed: %s", e)
return []
diff --git a/backend/ee/onyx/server/billing/api.py b/backend/ee/onyx/server/billing/api.py
index 41f2610794..26ed206b43 100644
--- a/backend/ee/onyx/server/billing/api.py
+++ b/backend/ee/onyx/server/billing/api.py
@@ -89,11 +89,13 @@ def _is_billing_circuit_open() -> bool:
redis_client = get_shared_redis_client()
is_open = bool(redis_client.exists(BILLING_CIRCUIT_BREAKER_KEY))
logger.debug(
- f"Circuit breaker check: key={BILLING_CIRCUIT_BREAKER_KEY}, is_open={is_open}"
+ "Circuit breaker check: key=%s, is_open=%s",
+ BILLING_CIRCUIT_BREAKER_KEY,
+ is_open,
)
return is_open
except Exception as e:
- logger.error(f"Failed to check circuit breaker: {e}")
+ logger.error("Failed to check circuit breaker: %s", e)
return False
@@ -111,11 +113,12 @@ def _open_billing_circuit() -> None:
# Verify it was set
exists = redis_client.exists(BILLING_CIRCUIT_BREAKER_KEY)
logger.warning(
- f"Billing circuit breaker opened (TTL={BILLING_CIRCUIT_BREAKER_TTL_SECONDS}s, "
- f"verified={exists}). Stripe billing requests are disabled until manually reset."
+ "Billing circuit breaker opened (TTL=%ss, verified=%s). Stripe billing requests are disabled until manually reset.",
+ BILLING_CIRCUIT_BREAKER_TTL_SECONDS,
+ exists,
)
except Exception as e:
- logger.error(f"Failed to open circuit breaker: {e}")
+ logger.error("Failed to open circuit breaker: %s", e)
def _close_billing_circuit() -> None:
@@ -129,7 +132,7 @@ def _close_billing_circuit() -> None:
"Billing circuit breaker closed. Stripe billing requests re-enabled."
)
except Exception as e:
- logger.error(f"Failed to close circuit breaker: {e}")
+ logger.error("Failed to close circuit breaker: %s", e)
def _get_license_data(db_session: Session) -> str | None:
diff --git a/backend/ee/onyx/server/billing/service.py b/backend/ee/onyx/server/billing/service.py
index 819128c8ff..f0c18c0bcf 100644
--- a/backend/ee/onyx/server/billing/service.py
+++ b/backend/ee/onyx/server/billing/service.py
@@ -122,7 +122,7 @@ async def _make_billing_request(
detail = error_data.get("detail", detail)
except Exception:
pass
- logger.error(f"{error_message}: {e.response.status_code} - {detail}")
+ logger.error("%s: %s - %s", error_message, e.response.status_code, detail)
raise OnyxError(
OnyxErrorCode.BAD_GATEWAY,
detail,
diff --git a/backend/ee/onyx/server/documents/cc_pair.py b/backend/ee/onyx/server/documents/cc_pair.py
index fb66a75fb8..bfe242358b 100644
--- a/backend/ee/onyx/server/documents/cc_pair.py
+++ b/backend/ee/onyx/server/documents/cc_pair.py
@@ -81,10 +81,11 @@ def sync_cc_pair(
)
logger.info(
- f"Permissions sync cc_pair={cc_pair_id} "
- f"connector_id={cc_pair.connector_id} "
- f"credential_id={cc_pair.credential_id} "
- f"{cc_pair.connector.name} connector."
+ "Permissions sync cc_pair=%s connector_id=%s credential_id=%s %s connector.",
+ cc_pair_id,
+ cc_pair.connector_id,
+ cc_pair.credential_id,
+ cc_pair.connector.name,
)
payload_id = try_creating_permissions_sync_task(
client_app, cc_pair_id, r, tenant_id
@@ -95,7 +96,7 @@ def sync_cc_pair(
detail="Permissions sync task creation failed.",
)
- logger.info(f"Permissions sync queued: cc_pair={cc_pair_id} id={payload_id}")
+ logger.info("Permissions sync queued: cc_pair=%s id=%s", cc_pair_id, payload_id)
return StatusResponse(
success=True,
@@ -155,10 +156,11 @@ def sync_cc_pair_groups(
)
logger.info(
- f"External group sync cc_pair={cc_pair_id} "
- f"connector_id={cc_pair.connector_id} "
- f"credential_id={cc_pair.credential_id} "
- f"{cc_pair.connector.name} connector."
+ "External group sync cc_pair=%s connector_id=%s credential_id=%s %s connector.",
+ cc_pair_id,
+ cc_pair.connector_id,
+ cc_pair.credential_id,
+ cc_pair.connector.name,
)
payload_id = try_creating_external_group_sync_task(
client_app, cc_pair_id, r, tenant_id
@@ -169,7 +171,7 @@ def sync_cc_pair_groups(
detail="External group sync task creation failed.",
)
- logger.info(f"External group sync queued: cc_pair={cc_pair_id} id={payload_id}")
+ logger.info("External group sync queued: cc_pair=%s id=%s", cc_pair_id, payload_id)
return StatusResponse(
success=True,
diff --git a/backend/ee/onyx/server/enterprise_settings/api.py b/backend/ee/onyx/server/enterprise_settings/api.py
index 0e969c8035..6c3f9c6ac6 100644
--- a/backend/ee/onyx/server/enterprise_settings/api.py
+++ b/backend/ee/onyx/server/enterprise_settings/api.py
@@ -70,7 +70,7 @@ async def refresh_access_token(
user_manager: UserManager = Depends(get_user_manager),
) -> None:
try:
- logger.debug(f"Received response from Meechum auth URL for user {user.id}")
+ logger.debug("Received response from Meechum auth URL for user %s", user.id)
# Extract new tokens
new_access_token = refresh_token.access_token
@@ -81,7 +81,7 @@ async def refresh_access_token(
)
expires_at_timestamp = int(new_expiry.timestamp())
- logger.debug(f"Access token has been refreshed for user {user.id}")
+ logger.debug("Access token has been refreshed for user %s", user.id)
await user_manager.oauth_callback(
oauth_name="custom",
@@ -93,17 +93,19 @@ async def refresh_access_token(
associate_by_email=True,
)
- logger.info(f"Successfully refreshed tokens for user {user.id}")
+ logger.info("Successfully refreshed tokens for user %s", user.id)
except httpx.HTTPStatusError as e:
if e.response.status_code == 401:
- logger.warning(f"Full authentication required for user {user.id}")
+ logger.warning("Full authentication required for user %s", user.id)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Full authentication required",
)
logger.error(
- f"HTTP error occurred while refreshing token for user {user.id}: {str(e)}"
+ "HTTP error occurred while refreshing token for user %s: %s",
+ user.id,
+ str(e),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
@@ -111,7 +113,9 @@ async def refresh_access_token(
)
except Exception as e:
logger.error(
- f"Unexpected error occurred while refreshing token for user {user.id}: {str(e)}"
+ "Unexpected error occurred while refreshing token for user %s: %s",
+ user.id,
+ str(e),
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
diff --git a/backend/ee/onyx/server/enterprise_settings/store.py b/backend/ee/onyx/server/enterprise_settings/store.py
index 54f377719f..2ff446d2e3 100644
--- a/backend/ee/onyx/server/enterprise_settings/store.py
+++ b/backend/ee/onyx/server/enterprise_settings/store.py
@@ -101,7 +101,7 @@ def upload_logo(file: UploadFile | str, is_logotype: bool = False) -> bool:
content: IO[Any]
if isinstance(file, str):
- logger.notice(f"Uploading logo from local path {file}")
+ logger.notice("Uploading logo from local path %s", file)
if not os.path.isfile(file) or not is_valid_file_type(file):
logger.error(
"Invalid file type- only .png, .jpg, and .jpeg files are allowed"
diff --git a/backend/ee/onyx/server/license/api.py b/backend/ee/onyx/server/license/api.py
index a26e38668a..b9b8e0870f 100644
--- a/backend/ee/onyx/server/license/api.py
+++ b/backend/ee/onyx/server/license/api.py
@@ -187,10 +187,12 @@ async def claim_license(
try:
update_license_cache(payload, source=LicenseSource.AUTO_FETCH)
except Exception as cache_error:
- logger.warning(f"Failed to update license cache: {cache_error}")
+ logger.warning("Failed to update license cache: %s", cache_error)
logger.info(
- f"License claimed: seats={payload.seats}, expires={payload.expires_at.date()}"
+ "License claimed: seats=%s, expires=%s",
+ payload.seats,
+ payload.expires_at.date(),
)
return LicenseResponse(success=True, license=payload)
@@ -254,7 +256,7 @@ async def upload_license(
try:
update_license_cache(payload, source=LicenseSource.MANUAL_UPLOAD)
except Exception as cache_error:
- logger.warning(f"Failed to update license cache: {cache_error}")
+ logger.warning("Failed to update license cache: %s", cache_error)
return LicenseUploadResponse(
success=True,
@@ -310,7 +312,7 @@ async def delete_license(
try:
invalidate_license_cache()
except Exception as cache_error:
- logger.warning(f"Failed to invalidate license cache: {cache_error}")
+ logger.warning("Failed to invalidate license cache: %s", cache_error)
deleted = db_delete_license(db_session)
diff --git a/backend/ee/onyx/server/middleware/license_enforcement.py b/backend/ee/onyx/server/middleware/license_enforcement.py
index 03a73c4367..3458d528ab 100644
--- a/backend/ee/onyx/server/middleware/license_enforcement.py
+++ b/backend/ee/onyx/server/middleware/license_enforcement.py
@@ -113,7 +113,8 @@ def add_license_enforcement_middleware(
)
except SQLAlchemyError as db_error:
logger.warning(
- f"[license_enforcement] Failed to check database for license: {db_error}"
+ "[license_enforcement] Failed to check database for license: %s",
+ db_error,
)
if metadata:
@@ -129,8 +130,9 @@ def add_license_enforcement_middleware(
# when users are added/removed
if metadata.used_seats > metadata.seats:
logger.info(
- f"[license_enforcement] Blocking request: "
- f"seat limit exceeded ({metadata.used_seats}/{metadata.seats})"
+ "[license_enforcement] Blocking request: seat limit exceeded (%s/%s)",
+ metadata.used_seats,
+ metadata.seats,
)
return JSONResponse(
status_code=402,
@@ -148,7 +150,8 @@ def add_license_enforcement_middleware(
# Allow community features, but block EE-only features
if _is_ee_only_path(path):
logger.info(
- f"[license_enforcement] Blocking EE-only path (no license): {path}"
+ "[license_enforcement] Blocking EE-only path (no license): %s",
+ path,
)
return JSONResponse(
status_code=402,
@@ -165,13 +168,13 @@ def add_license_enforcement_middleware(
)
is_gated = False
except CACHE_TRANSIENT_ERRORS as e:
- logger.warning(f"Failed to check license metadata: {e}")
+ logger.warning("Failed to check license metadata: %s", e)
# Fail open - don't block users due to cache connectivity issues
is_gated = False
if is_gated:
logger.info(
- f"[license_enforcement] Blocking request (license expired): {path}"
+ "[license_enforcement] Blocking request (license expired): %s", path
)
return JSONResponse(
diff --git a/backend/ee/onyx/server/middleware/tenant_tracking.py b/backend/ee/onyx/server/middleware/tenant_tracking.py
index 6bdebef94f..bf171d3200 100644
--- a/backend/ee/onyx/server/middleware/tenant_tracking.py
+++ b/backend/ee/onyx/server/middleware/tenant_tracking.py
@@ -40,7 +40,7 @@ def add_api_server_tenant_id_middleware(
return await call_next(request)
except Exception as e:
- logger.exception(f"Error in tenant ID middleware: {str(e)}")
+ logger.exception("Error in tenant ID middleware: %s", str(e))
raise
@@ -97,7 +97,7 @@ async def _get_tenant_id_from_request(
return tenant_id
except Exception as e:
- logger.error(f"Error decoding anonymous user cookie: {str(e)}")
+ logger.error("Error decoding anonymous user cookie: %s", str(e))
# Continue and attempt to authenticate
logger.debug(
@@ -110,7 +110,7 @@ async def _get_tenant_id_from_request(
return POSTGRES_DEFAULT_SCHEMA
except Exception as e:
- logger.error(f"Unexpected error in _get_tenant_id_from_request: {str(e)}")
+ logger.error("Unexpected error in _get_tenant_id_from_request: %s", str(e))
raise HTTPException(status_code=500, detail="Internal server error")
finally:
diff --git a/backend/ee/onyx/server/query_and_chat/query_backend.py b/backend/ee/onyx/server/query_and_chat/query_backend.py
index 66569137f1..8b866ac49a 100644
--- a/backend/ee/onyx/server/query_and_chat/query_backend.py
+++ b/backend/ee/onyx/server/query_and_chat/query_backend.py
@@ -33,5 +33,5 @@ def get_standard_answer(
)
return StandardAnswerResponse(standard_answers=standard_answers)
except Exception as e:
- logger.error(f"Error in get_standard_answer: {str(e)}", exc_info=True)
+ logger.error("Error in get_standard_answer: %s", str(e), exc_info=True)
raise HTTPException(status_code=500, detail="An internal server error occurred")
diff --git a/backend/ee/onyx/server/query_and_chat/search_backend.py b/backend/ee/onyx/server/query_and_chat/search_backend.py
index c1aa7d8225..d6e579dce8 100644
--- a/backend/ee/onyx/server/query_and_chat/search_backend.py
+++ b/backend/ee/onyx/server/query_and_chat/search_backend.py
@@ -92,7 +92,7 @@ def handle_send_search_message(
Returns:
StreamingResponse with SSE if stream=True, otherwise SearchFullResponse.
"""
- logger.debug(f"Received search query: {request.search_query}")
+ logger.debug("Received search query: %s", request.search_query)
if request.hybrid_alpha is None and ONYX_SEARCH_UI_USES_OPENSEARCH_KEYWORD_SEARCH:
request.hybrid_alpha = 0.0
diff --git a/backend/ee/onyx/server/scim/api.py b/backend/ee/onyx/server/scim/api.py
index 99bf0ae674..dc770a8030 100644
--- a/backend/ee/onyx/server/scim/api.py
+++ b/backend/ee/onyx/server/scim/api.py
@@ -569,7 +569,7 @@ def create_user(
assign_user_to_default_groups__no_commit(db_session, user)
except Exception:
dal.rollback()
- logger.exception(f"Failed to assign SCIM user {email} to default groups")
+ logger.exception("Failed to assign SCIM user %s to default groups", email)
return _scim_error_response(
500, f"Failed to assign user {email} to default group"
)
diff --git a/backend/ee/onyx/server/seeding.py b/backend/ee/onyx/server/seeding.py
index 2e2347539f..b21a6dcb1c 100644
--- a/backend/ee/onyx/server/seeding.py
+++ b/backend/ee/onyx/server/seeding.py
@@ -79,8 +79,8 @@ def _seed_custom_tools(db_session: Session, tools: List[CustomToolSeed]) -> None
logger.notice("Seeding Custom Tools")
for tool in tools:
try:
- logger.debug(f"Attempting to seed tool: {tool.name}")
- logger.debug(f"Reading definition from: {tool.definition_path}")
+ logger.debug("Attempting to seed tool: %s", tool.name)
+ logger.debug("Reading definition from: %s", tool.definition_path)
with open(tool.definition_path, "r") as file:
file_content = file.read()
if not file_content.strip():
@@ -96,19 +96,21 @@ def _seed_custom_tools(db_session: Session, tools: List[CustomToolSeed]) -> None
user_id=tool.user_id,
)
db_session.add(db_tool)
- logger.debug(f"Successfully added tool: {tool.name}")
+ logger.debug("Successfully added tool: %s", tool.name)
except FileNotFoundError:
logger.error(
- f"Definition file not found for tool {tool.name}: {tool.definition_path}"
+ "Definition file not found for tool %s: %s",
+ tool.name,
+ tool.definition_path,
)
except json.JSONDecodeError as e:
logger.error(
- f"Invalid JSON in definition file for tool {tool.name}: {str(e)}"
+ "Invalid JSON in definition file for tool %s: %s", tool.name, str(e)
)
except Exception as e:
- logger.error(f"Failed to seed tool {tool.name}: {str(e)}")
+ logger.error("Failed to seed tool %s: %s", tool.name, str(e))
db_session.commit()
- logger.notice(f"Successfully seeded {len(tools)} Custom Tools")
+ logger.notice("Successfully seeded %s Custom Tools", len(tools))
def _seed_llms(
@@ -189,7 +191,7 @@ def _seed_settings(settings: Settings) -> None:
store_base_settings(settings)
logger.notice("Successfully seeded Settings")
except ValueError as e:
- logger.error(f"Failed to seed Settings: {str(e)}")
+ logger.error("Failed to seed Settings: %s", str(e))
def _seed_enterprise_settings(seed_config: SeedConfiguration) -> None:
@@ -243,10 +245,10 @@ def _seed_analytics_script(seed_config: SeedConfiguration) -> None:
store_analytics_script(analytics_script)
except FileNotFoundError:
logger.error(
- f"Analytics script file not found: {seed_config.analytics_script_path}"
+ "Analytics script file not found: %s", seed_config.analytics_script_path
)
except ValueError as e:
- logger.error(f"Failed to seed analytics script: {str(e)}")
+ logger.error("Failed to seed analytics script: %s", str(e))
def get_seed_config() -> SeedConfiguration | None:
diff --git a/backend/ee/onyx/server/settings/api.py b/backend/ee/onyx/server/settings/api.py
index a79eb54629..9125e3892a 100644
--- a/backend/ee/onyx/server/settings/api.py
+++ b/backend/ee/onyx/server/settings/api.py
@@ -51,13 +51,13 @@ def check_ee_features_enabled() -> bool:
with get_session_with_current_tenant() as db_session:
metadata = refresh_license_cache(db_session, tenant_id)
except SQLAlchemyError as db_error:
- logger.warning(f"Failed to load license from DB: {db_error}")
+ logger.warning("Failed to load license from DB: %s", db_error)
if metadata and metadata.status != _BLOCKING_STATUS:
# Has a valid license (GRACE_PERIOD/PAYMENT_REMINDER still allow EE features)
return True
except RedisError as e:
- logger.warning(f"Failed to check license for EE features: {e}")
+ logger.warning("Failed to check license for EE features: %s", e)
# Fail closed - if Redis is down, other things will break anyway
return False
@@ -103,7 +103,7 @@ def apply_license_status_to_settings(settings: Settings) -> Settings:
metadata = refresh_license_cache(db_session, tenant_id)
except SQLAlchemyError as db_error:
logger.warning(
- f"Failed to load license from DB for settings: {db_error}"
+ "Failed to load license from DB for settings: %s", db_error
)
if metadata:
@@ -127,7 +127,7 @@ def apply_license_status_to_settings(settings: Settings) -> Settings:
settings.application_status = _BLOCKING_STATUS
settings.ee_features_enabled = False
except CACHE_TRANSIENT_ERRORS as e:
- logger.warning(f"Failed to check license metadata for settings: {e}")
+ logger.warning("Failed to check license metadata for settings: %s", e)
# Fail closed - disable EE features if we can't verify license
settings.ee_features_enabled = False
diff --git a/backend/ee/onyx/server/tenant_usage_limits.py b/backend/ee/onyx/server/tenant_usage_limits.py
index 827595c88f..60eb3ce86f 100644
--- a/backend/ee/onyx/server/tenant_usage_limits.py
+++ b/backend/ee/onyx/server/tenant_usage_limits.py
@@ -49,7 +49,9 @@ def fetch_usage_limit_overrides() -> dict[str, TenantUsageLimitOverrides] | None
result[tenant_id] = TenantUsageLimitOverrides(**override_data)
except Exception as e:
logger.warning(
- f"Failed to parse usage limit overrides for tenant {tenant_id}: {e}"
+ "Failed to parse usage limit overrides for tenant %s: %s",
+ tenant_id,
+ e,
)
return (
@@ -57,10 +59,12 @@ def fetch_usage_limit_overrides() -> dict[str, TenantUsageLimitOverrides] | None
) # if empty dictionary, something went wrong and we shouldn't enforce limits
except requests.exceptions.RequestException as e:
- logger.warning(f"Failed to fetch usage limit overrides from control plane: {e}")
+ logger.warning(
+ "Failed to fetch usage limit overrides from control plane: %s", e
+ )
return None
except Exception as e:
- logger.error(f"Error parsing usage limit overrides: {e}")
+ logger.error("Error parsing usage limit overrides: %s", e)
return None
@@ -81,7 +85,7 @@ def load_usage_limit_overrides() -> None:
_tenant_usage_limit_overrides = overrides or _tenant_usage_limit_overrides
if overrides:
- logger.info(f"Loaded usage limit overrides for {len(overrides)} tenants")
+ logger.info("Loaded usage limit overrides for %s tenants", len(overrides))
else:
logger.info("No tenant-specific usage limit overrides found")
@@ -122,7 +126,9 @@ def get_tenant_usage_limit_overrides(
_tenant_usage_limit_overrides is None and time_since > _ERROR_FETCH_INTERVAL
) or (time_since > _FETCH_INTERVAL):
logger.debug(
- f"Last fetch time: {_last_fetch_time}, time since last fetch: {time_since}"
+ "Last fetch time: %s, time since last fetch: %s",
+ _last_fetch_time,
+ time_since,
)
load_usage_limit_overrides()
diff --git a/backend/ee/onyx/server/tenants/anonymous_users_api.py b/backend/ee/onyx/server/tenants/anonymous_users_api.py
index 54194fd516..8a0c552d34 100644
--- a/backend/ee/onyx/server/tenants/anonymous_users_api.py
+++ b/backend/ee/onyx/server/tenants/anonymous_users_api.py
@@ -62,7 +62,7 @@ async def set_anonymous_user_path_api(
detail="The anonymous user path is already in use. Please choose a different path.",
)
except Exception as e:
- logger.exception(f"Failed to modify anonymous user path: {str(e)}")
+ logger.exception("Failed to modify anonymous user path: %s", str(e))
raise HTTPException(
status_code=500,
detail="An unexpected error occurred while modifying the anonymous user path",
diff --git a/backend/ee/onyx/server/tenants/provisioning.py b/backend/ee/onyx/server/tenants/provisioning.py
index 2d932e2e54..55b88cc719 100644
--- a/backend/ee/onyx/server/tenants/provisioning.py
+++ b/backend/ee/onyx/server/tenants/provisioning.py
@@ -109,16 +109,21 @@ async def get_or_provision_tenant(
# The tenant was already dequeued from the pool — roll it back so
# it doesn't end up orphaned (schema exists, but not assigned to anyone).
logger.exception(
- f"Migration failed for pre-provisioned tenant {_tenant_id}; rolling back"
+ "Migration failed for pre-provisioned tenant %s; rolling back",
+ _tenant_id,
)
try:
await rollback_tenant_provisioning(_tenant_id)
except Exception:
- logger.exception(f"Failed to rollback orphaned tenant {_tenant_id}")
+ logger.exception(
+ "Failed to rollback orphaned tenant %s", _tenant_id
+ )
raise
# If we have a pre-provisioned tenant, assign it to the user
await assign_tenant_to_user(tenant_id, email, referral_source)
- logger.info(f"Assigned pre-provisioned tenant {tenant_id} to user {email}")
+ logger.info(
+ "Assigned pre-provisioned tenant %s to user %s", tenant_id, email
+ )
else:
# If no pre-provisioned tenant is available, create a new one on-demand
tenant_id = await create_tenant(email, referral_source)
@@ -149,19 +154,19 @@ async def create_tenant(
"""
tenant_id = TENANT_ID_PREFIX + str(uuid.uuid4())
- logger.info(f"Creating new tenant {tenant_id} for user {email}")
+ logger.info("Creating new tenant %s for user %s", tenant_id, email)
try:
# Provision tenant on data plane
await provision_tenant(tenant_id, email)
except Exception as e:
- logger.exception(f"Tenant provisioning failed: {str(e)}")
+ logger.exception("Tenant provisioning failed: %s", str(e))
# Attempt to rollback the tenant provisioning
try:
await rollback_tenant_provisioning(tenant_id)
except Exception:
- logger.exception(f"Failed to rollback tenant provisioning for {tenant_id}")
+ logger.exception("Failed to rollback tenant provisioning for %s", tenant_id)
raise HTTPException(status_code=500, detail="Failed to provision tenant.")
return tenant_id
@@ -176,14 +181,14 @@ async def provision_tenant(tenant_id: str, email: str) -> None:
status_code=409, detail="User already belongs to an organization"
)
- logger.debug(f"Provisioning tenant {tenant_id} for user {email}")
+ logger.debug("Provisioning tenant %s for user %s", tenant_id, email)
try:
# Create the schema for the tenant
if not create_schema_if_not_exists(tenant_id):
- logger.debug(f"Created schema for tenant {tenant_id}")
+ logger.debug("Created schema for tenant %s", tenant_id)
else:
- logger.debug(f"Schema already exists for tenant {tenant_id}")
+ logger.debug("Schema already exists for tenant %s", tenant_id)
# Set up the tenant with all necessary configurations
await setup_tenant(tenant_id)
@@ -192,7 +197,7 @@ async def provision_tenant(tenant_id: str, email: str) -> None:
await assign_tenant_to_user(tenant_id, email)
except Exception as e:
- logger.exception(f"Failed to create tenant {tenant_id}")
+ logger.exception("Failed to create tenant %s", tenant_id)
raise HTTPException(
status_code=500, detail=f"Failed to create tenant: {str(e)}"
)
@@ -219,7 +224,7 @@ async def notify_control_plane(
) as response:
if response.status != 200:
error_text = await response.text()
- logger.error(f"Control plane tenant creation failed: {error_text}")
+ logger.error("Control plane tenant creation failed: %s", error_text)
raise Exception(
f"Failed to create tenant on control plane: {error_text}"
)
@@ -230,7 +235,7 @@ async def rollback_tenant_provisioning(tenant_id: str) -> None:
Logic to rollback tenant provisioning on data plane.
Handles each step independently to ensure maximum cleanup even if some steps fail.
"""
- logger.info(f"Rolling back tenant provisioning for tenant_id: {tenant_id}")
+ logger.info("Rolling back tenant provisioning for tenant_id: %s", tenant_id)
# Track if any part of the rollback fails
rollback_errors = []
@@ -238,7 +243,7 @@ async def rollback_tenant_provisioning(tenant_id: str) -> None:
# 1. Try to drop the tenant's schema
try:
drop_schema(tenant_id)
- logger.info(f"Successfully dropped schema for tenant {tenant_id}")
+ logger.info("Successfully dropped schema for tenant %s", tenant_id)
except Exception as e:
error_msg = f"Failed to drop schema for tenant {tenant_id}: {str(e)}"
logger.error(error_msg)
@@ -254,7 +259,7 @@ async def rollback_tenant_provisioning(tenant_id: str) -> None:
).delete()
db_session.commit()
logger.info(
- f"Successfully removed user mappings for tenant {tenant_id}"
+ "Successfully removed user mappings for tenant %s", tenant_id
)
except Exception as e:
db_session.rollback()
@@ -279,7 +284,7 @@ async def rollback_tenant_provisioning(tenant_id: str) -> None:
db_session.delete(available_tenant)
db_session.commit()
logger.info(
- f"Removed tenant {tenant_id} from available tenants table"
+ "Removed tenant %s from available tenants table", tenant_id
)
except Exception as e:
db_session.rollback()
@@ -291,9 +296,9 @@ async def rollback_tenant_provisioning(tenant_id: str) -> None:
# Log summary of rollback operation
if rollback_errors:
- logger.error(f"Tenant rollback completed with {len(rollback_errors)} errors")
+ logger.error("Tenant rollback completed with %s errors", len(rollback_errors))
else:
- logger.info(f"Tenant rollback completed successfully for tenant {tenant_id}")
+ logger.info("Tenant rollback completed successfully for tenant %s", tenant_id)
def _build_model_configuration_upsert_requests(
@@ -334,14 +339,14 @@ def configure_default_api_keys(db_session: Session) -> None:
update_default_provider(provider.id, default_model, db_session)
has_set_default_provider = True
except Exception as e:
- logger.error(f"Failed to configure {request.provider} provider: {e}")
+ logger.error("Failed to configure %s provider: %s", request.provider, e)
# Configure OpenAI provider
if OPENAI_DEFAULT_API_KEY:
default_model = recommendations.get_default_model(OPENAI_PROVIDER_NAME)
if default_model is None:
logger.error(
- f"No default model found for {OPENAI_PROVIDER_NAME} in recommendations"
+ "No default model found for %s in recommendations", OPENAI_PROVIDER_NAME
)
default_model_name = default_model.name if default_model else "gpt-5.2"
@@ -363,7 +368,7 @@ def configure_default_api_keys(db_session: Session) -> None:
db_session, OPENAI_DEFAULT_API_KEY
)
except Exception as e:
- logger.error(f"Failed to create default image gen config: {e}")
+ logger.error("Failed to create default image gen config: %s", e)
else:
logger.info(
"OPENAI_DEFAULT_API_KEY not set, skipping OpenAI provider configuration"
@@ -374,7 +379,8 @@ def configure_default_api_keys(db_session: Session) -> None:
default_model = recommendations.get_default_model(ANTHROPIC_PROVIDER_NAME)
if default_model is None:
logger.error(
- f"No default model found for {ANTHROPIC_PROVIDER_NAME} in recommendations"
+ "No default model found for %s in recommendations",
+ ANTHROPIC_PROVIDER_NAME,
)
default_model_name = (
default_model.name if default_model else "claude-sonnet-4-5"
@@ -401,7 +407,8 @@ def configure_default_api_keys(db_session: Session) -> None:
default_model = recommendations.get_default_model(VERTEXAI_PROVIDER_NAME)
if default_model is None:
logger.error(
- f"No default model found for {VERTEXAI_PROVIDER_NAME} in recommendations"
+ "No default model found for %s in recommendations",
+ VERTEXAI_PROVIDER_NAME,
)
default_model_name = default_model.name if default_model else "gemini-2.5-pro"
@@ -432,7 +439,8 @@ def configure_default_api_keys(db_session: Session) -> None:
default_model = recommendations.get_default_model(OPENROUTER_PROVIDER_NAME)
if default_model is None:
logger.error(
- f"No default model found for {OPENROUTER_PROVIDER_NAME} in recommendations"
+ "No default model found for %s in recommendations",
+ OPENROUTER_PROVIDER_NAME,
)
default_model_name = default_model.name if default_model else "z-ai/glm-4.7"
@@ -549,7 +557,7 @@ async def submit_to_hubspot(
response = await client.post(HUBSPOT_TRACKING_URL, json=data)
if response.status_code != 200:
- logger.error(f"Failed to submit to HubSpot: {response.text}")
+ logger.error("Failed to submit to HubSpot: %s", response.text)
async def delete_user_from_control_plane(tenant_id: str, email: str) -> None:
@@ -568,7 +576,7 @@ async def delete_user_from_control_plane(tenant_id: str, email: str) -> None:
) as response:
if response.status != 200:
error_text = await response.text()
- logger.error(f"Control plane tenant creation failed: {error_text}")
+ logger.error("Control plane tenant creation failed: %s", error_text)
raise Exception(
f"Failed to delete tenant on control plane: {error_text}"
)
@@ -601,7 +609,7 @@ def get_tenant_by_domain_from_control_plane(
)
if response.status_code != 200:
- logger.error(f"Control plane tenant lookup failed: {response.text}")
+ logger.error("Control plane tenant lookup failed: %s", response.text)
return None
response_data = response.json()
@@ -614,7 +622,7 @@ def get_tenant_by_domain_from_control_plane(
creator_email=response_data.get("creator_email"),
)
except Exception as e:
- logger.error(f"Error fetching tenant by domain: {str(e)}")
+ logger.error("Error fetching tenant by domain: %s", str(e))
return None
@@ -645,7 +653,7 @@ async def get_available_tenant() -> str | None:
# Remove the tenant from the available tenants table
db_session.delete(available_tenant)
db_session.commit()
- logger.info(f"Using pre-provisioned tenant {tenant_id}")
+ logger.info("Using pre-provisioned tenant %s", tenant_id)
return tenant_id
else:
db_session.rollback()
@@ -689,7 +697,7 @@ async def setup_tenant(tenant_id: str) -> None:
setup_onyx(db_session, tenant_id, cohere_enabled=cohere_enabled)
except Exception as e:
- logger.exception(f"Failed to set up tenant {tenant_id}")
+ logger.exception("Failed to set up tenant %s", tenant_id)
raise e
finally:
if token is not None:
@@ -711,5 +719,5 @@ async def assign_tenant_to_user(
try:
add_users_to_tenant([email], tenant_id)
except Exception:
- logger.exception(f"Failed to assign tenant {tenant_id} to user {email}")
+ logger.exception("Failed to assign tenant %s to user %s", tenant_id, email)
raise Exception("Failed to assign tenant to user")
diff --git a/backend/ee/onyx/server/tenants/proxy.py b/backend/ee/onyx/server/tenants/proxy.py
index 6cdfb37ae5..c0a6fc5f50 100644
--- a/backend/ee/onyx/server/tenants/proxy.py
+++ b/backend/ee/onyx/server/tenants/proxy.py
@@ -196,7 +196,7 @@ async def forward_to_control_plane(
detail = error_data.get("detail", detail)
except Exception:
pass
- logger.error(f"Control plane returned {status_code}: {detail}")
+ logger.error("Control plane returned %s: %s", status_code, detail)
raise HTTPException(status_code=status_code, detail=detail)
except httpx.RequestError:
logger.exception("Failed to connect to control plane")
@@ -293,7 +293,7 @@ async def proxy_claim_license(
license_data = result.get("license")
if not tenant_id or not license_data:
- logger.error(f"Control plane returned incomplete claim response: {result}")
+ logger.error("Control plane returned incomplete claim response: %s", result)
raise HTTPException(
status_code=502,
detail="Control plane returned incomplete license data",
@@ -410,7 +410,7 @@ async def proxy_license_fetch(
license_data = result.get("license")
if not license_data:
- logger.error(f"Control plane returned incomplete license response: {result}")
+ logger.error("Control plane returned incomplete license response: %s", result)
raise HTTPException(
status_code=502,
detail="Control plane returned incomplete license data",
diff --git a/backend/ee/onyx/server/tenants/schema_management.py b/backend/ee/onyx/server/tenants/schema_management.py
index 1bc6eb8cf9..5078a39683 100644
--- a/backend/ee/onyx/server/tenants/schema_management.py
+++ b/backend/ee/onyx/server/tenants/schema_management.py
@@ -37,7 +37,7 @@ def validate_tenant_id(tenant_id: str) -> bool:
def run_alembic_migrations(schema_name: str) -> None:
- logger.info(f"Starting Alembic migrations for schema: {schema_name}")
+ logger.info("Starting Alembic migrations for schema: %s", schema_name)
try:
current_dir = os.path.dirname(os.path.abspath(__file__))
@@ -65,11 +65,13 @@ def run_alembic_migrations(schema_name: str) -> None:
# Run migrations programmatically
logger.info(
- f"Alembic migrations completed successfully for schema: {schema_name}"
+ "Alembic migrations completed successfully for schema: %s", schema_name
)
except Exception as e:
- logger.exception(f"Alembic migration failed for schema {schema_name}: {str(e)}")
+ logger.exception(
+ "Alembic migration failed for schema %s: %s", schema_name, str(e)
+ )
raise
diff --git a/backend/ee/onyx/server/tenants/team_membership_api.py b/backend/ee/onyx/server/tenants/team_membership_api.py
index 06ddf71f7c..d325087164 100644
--- a/backend/ee/onyx/server/tenants/team_membership_api.py
+++ b/backend/ee/onyx/server/tenants/team_membership_api.py
@@ -54,7 +54,9 @@ async def leave_organization(
logger.debug("User deleted from control plane")
except Exception as e:
logger.exception(
- f"Failed to delete user from control plane for tenant {tenant_id}: {e}"
+ "Failed to delete user from control plane for tenant %s: %s",
+ tenant_id,
+ e,
)
raise HTTPException(
status_code=500,
diff --git a/backend/ee/onyx/server/tenants/user_invitations_api.py b/backend/ee/onyx/server/tenants/user_invitations_api.py
index efd077e46a..f47b007001 100644
--- a/backend/ee/onyx/server/tenants/user_invitations_api.py
+++ b/backend/ee/onyx/server/tenants/user_invitations_api.py
@@ -30,7 +30,7 @@ async def request_invite(
invite_self_to_tenant(user.email, invite_request.tenant_id)
except Exception as e:
logger.exception(
- f"Failed to invite self to tenant {invite_request.tenant_id}: {e}"
+ "Failed to invite self to tenant %s: %s", invite_request.tenant_id, e
)
raise HTTPException(status_code=500, detail=str(e))
@@ -63,7 +63,7 @@ async def accept_invite(
try:
accept_user_invite(user.email, invite_request.tenant_id)
except Exception as e:
- logger.exception(f"Failed to accept invite: {str(e)}")
+ logger.exception("Failed to accept invite: %s", str(e))
raise HTTPException(status_code=500, detail="Failed to accept invitation")
@@ -78,5 +78,5 @@ async def deny_invite(
try:
deny_user_invite(user.email, invite_request.tenant_id)
except Exception as e:
- logger.exception(f"Failed to deny invite: {str(e)}")
+ logger.exception("Failed to deny invite: %s", str(e))
raise HTTPException(status_code=500, detail="Failed to deny invitation")
diff --git a/backend/ee/onyx/server/tenants/user_mapping.py b/backend/ee/onyx/server/tenants/user_mapping.py
index 67389beec7..0482cc253b 100644
--- a/backend/ee/onyx/server/tenants/user_mapping.py
+++ b/backend/ee/onyx/server/tenants/user_mapping.py
@@ -48,7 +48,7 @@ def get_tenant_id_for_email(email: str) -> str:
db_session.commit()
tenant_id = mapping.tenant_id
except Exception as e:
- logger.exception(f"Error getting tenant id for email {email}: {e}")
+ logger.exception("Error getting tenant id for email %s: %s", email, e)
raise exceptions.UserNotExists()
if tenant_id is None:
@@ -126,10 +126,10 @@ def add_users_to_tenant(emails: list[str], tenant_id: str) -> None:
# Commit the transaction
db_session.commit()
- logger.info(f"Successfully added users {emails} to tenant {tenant_id}")
+ logger.info("Successfully added users %s to tenant %s", emails, tenant_id)
except Exception:
- logger.exception(f"Failed to add users to tenant {tenant_id}")
+ logger.exception("Failed to add users to tenant %s", tenant_id)
db_session.rollback()
raise
@@ -152,7 +152,7 @@ def remove_users_from_tenant(emails: list[str], tenant_id: str) -> None:
db_session.commit()
except Exception as e:
logger.exception(
- f"Failed to remove users from tenant {tenant_id}: {str(e)}"
+ "Failed to remove users from tenant %s: %s", tenant_id, str(e)
)
db_session.rollback()
@@ -229,7 +229,9 @@ def accept_user_invite(email: str, tenant_id: str) -> None:
if active_mapping:
db_session.delete(active_mapping)
logger.info(
- f"Deleted existing active mapping for user {email} in tenant {tenant_id}"
+ "Deleted existing active mapping for user %s in tenant %s",
+ email,
+ tenant_id,
)
# Find the inactive mapping for this user and tenant
@@ -253,16 +255,21 @@ def accept_user_invite(email: str, tenant_id: str) -> None:
# Activate this mapping
mapping.active = True
db_session.commit()
- logger.info(f"User {email} accepted invitation to tenant {tenant_id}")
+ logger.info(
+ "User %s accepted invitation to tenant %s", email, tenant_id
+ )
else:
logger.warning(
- f"No invitation found for user {email} in tenant {tenant_id}"
+ "No invitation found for user %s in tenant %s", email, tenant_id
)
except Exception as e:
db_session.rollback()
logger.exception(
- f"Failed to accept invitation for user {email} to tenant {tenant_id}: {str(e)}"
+ "Failed to accept invitation for user %s to tenant %s: %s",
+ email,
+ tenant_id,
+ str(e),
)
raise
@@ -273,7 +280,7 @@ def accept_user_invite(email: str, tenant_id: str) -> None:
if email in invited_users:
invited_users.remove(email)
write_invited_users(invited_users)
- logger.info(f"Removed {email} from invited users list after acceptance")
+ logger.info("Removed %s from invited users list after acceptance", email)
finally:
CURRENT_TENANT_ID_CONTEXTVAR.reset(token)
@@ -297,10 +304,10 @@ def deny_user_invite(email: str, tenant_id: str) -> None:
db_session.commit()
if result:
- logger.info(f"User {email} denied invitation to tenant {tenant_id}")
+ logger.info("User %s denied invitation to tenant %s", email, tenant_id)
else:
logger.warning(
- f"No invitation found for user {email} in tenant {tenant_id}"
+ "No invitation found for user %s in tenant %s", email, tenant_id
)
token = CURRENT_TENANT_ID_CONTEXTVAR.set(tenant_id)
try:
diff --git a/backend/ee/onyx/server/usage_limits.py b/backend/ee/onyx/server/usage_limits.py
index 8170c1a129..d98a5f9e63 100644
--- a/backend/ee/onyx/server/usage_limits.py
+++ b/backend/ee/onyx/server/usage_limits.py
@@ -33,6 +33,6 @@ def is_tenant_on_trial(tenant_id: str) -> bool:
return False
except Exception as e:
- logger.warning(f"Failed to fetch billing info for trial check: {e}")
+ logger.warning("Failed to fetch billing info for trial check: %s", e)
# Default to trial limits on error (more restrictive = safer)
return True
diff --git a/backend/ee/onyx/server/user_group/api.py b/backend/ee/onyx/server/user_group/api.py
index 0ca381a805..e7b8e80070 100644
--- a/backend/ee/onyx/server/user_group/api.py
+++ b/backend/ee/onyx/server/user_group/api.py
@@ -236,7 +236,7 @@ def set_user_curator(
user_making_change=user,
)
except ValueError as e:
- logger.error(f"Error setting user curator: {e}")
+ logger.error("Error setting user curator: %s", e)
raise HTTPException(status_code=404, detail=str(e))
diff --git a/backend/ee/onyx/utils/license.py b/backend/ee/onyx/utils/license.py
index 076af1fba5..138f0e3b1a 100644
--- a/backend/ee/onyx/utils/license.py
+++ b/backend/ee/onyx/utils/license.py
@@ -91,11 +91,11 @@ def verify_license_signature(license_data: str) -> LicensePayload:
logger.error("[verify_license] FAILED: Signature verification failed")
raise ValueError("Invalid license signature")
except json.JSONDecodeError as e:
- logger.error(f"[verify_license] FAILED: JSON decode error: {e}")
+ logger.error("[verify_license] FAILED: JSON decode error: %s", e)
raise ValueError("Invalid license format: not valid JSON")
except (ValueError, KeyError, TypeError) as e:
logger.error(
- f"[verify_license] FAILED: Validation error: {type(e).__name__}: {e}"
+ "[verify_license] FAILED: Validation error: %s: %s", type(e).__name__, e
)
raise ValueError(f"Invalid license format: {type(e).__name__}: {e}")
except Exception:
diff --git a/backend/ee/onyx/utils/posthog_client.py b/backend/ee/onyx/utils/posthog_client.py
index 4fa14fec7a..e87c74212a 100644
--- a/backend/ee/onyx/utils/posthog_client.py
+++ b/backend/ee/onyx/utils/posthog_client.py
@@ -16,7 +16,7 @@ logger = setup_logger()
def posthog_on_error(error: Any, items: Any) -> None:
"""Log any PostHog delivery errors."""
- logger.error(f"PostHog error: {error}, items: {items}")
+ logger.error("PostHog error: %s, items: %s", error, items)
posthog: Posthog | None = None
@@ -65,7 +65,7 @@ def capture_and_sync_with_alternate_posthog(
marketing_posthog.capture(alternate_distinct_id, event, props)
marketing_posthog.flush()
except Exception as e:
- logger.error(f"Error capturing marketing posthog event: {e}")
+ logger.error("Error capturing marketing posthog event: %s", e)
try:
if posthog and (cloud_user_id := props.get("onyx_cloud_user_id")):
@@ -77,7 +77,7 @@ def capture_and_sync_with_alternate_posthog(
properties=cloud_props,
)
except Exception as e:
- logger.error(f"Error identifying cloud posthog user: {e}")
+ logger.error("Error identifying cloud posthog user: %s", e)
def alias_user(distinct_id: str, anonymous_id: str) -> None:
@@ -93,7 +93,7 @@ def alias_user(distinct_id: str, anonymous_id: str) -> None:
posthog.alias(previous_id=anonymous_id, distinct_id=distinct_id)
posthog.flush()
except Exception as e:
- logger.error(f"Error aliasing PostHog user: {e}")
+ logger.error("Error aliasing PostHog user: %s", e)
def get_anon_id_from_request(request: Any) -> str | None:
@@ -137,5 +137,5 @@ def parse_posthog_cookie(cookie_value: str) -> dict[str, Any] | None:
return cookie_data
except (json.JSONDecodeError, KeyError, TypeError, AttributeError) as e:
- logger.warning(f"Failed to parse cookie: {e}")
+ logger.warning("Failed to parse cookie: %s", e)
return None
diff --git a/backend/ee/onyx/utils/telemetry.py b/backend/ee/onyx/utils/telemetry.py
index da265c9aa1..d691d11619 100644
--- a/backend/ee/onyx/utils/telemetry.py
+++ b/backend/ee/onyx/utils/telemetry.py
@@ -39,12 +39,12 @@ def event_telemetry(
# Log the pre-enrichment properties so the real client IP (PII) never
# reaches the application log aggregator. PostHog itself still receives
# the enriched payload via the capture call below.
- logger.info(f"Capturing PostHog event: {distinct_id} {event} {properties}")
+ logger.info("Capturing PostHog event: %s %s %s", distinct_id, event, properties)
try:
posthog.capture(distinct_id, event, enriched)
posthog.flush()
except Exception as e:
- logger.error(f"Error capturing PostHog event: {e}")
+ logger.error("Error capturing PostHog event: %s", e)
def identify_user(
@@ -60,4 +60,4 @@ def identify_user(
posthog.identify(distinct_id, enriched)
posthog.flush()
except Exception as e:
- logger.error(f"Error identifying PostHog user: {e}")
+ logger.error("Error identifying PostHog user: %s", e)
diff --git a/backend/model_server/encoders.py b/backend/model_server/encoders.py
index df3fd6b221..528ab60753 100644
--- a/backend/model_server/encoders.py
+++ b/backend/model_server/encoders.py
@@ -54,12 +54,12 @@ def get_embedding_model(
)
logger.info("RoPE pre-warm successful")
except Exception as e:
- logger.warning(f"RoPE pre-warm skipped/failed: {e}")
+ logger.warning("RoPE pre-warm skipped/failed: %s", e)
global _GLOBAL_MODELS_DICT
if model_name not in _GLOBAL_MODELS_DICT:
- logger.notice(f"Loading {model_name}")
+ logger.notice("Loading %s", model_name)
model = SentenceTransformer(
model_name_or_path=model_name,
trust_remote_code=True,
@@ -94,7 +94,7 @@ def _concurrent_embedding(
# the model to fail to encode texts. It's pretty rare and we want to allow
# concurrent embedding, hence we retry (the specific error is
# "RuntimeError: Already borrowed" and occurs in the transformers library)
- logger.warning(f"Error encoding texts, retrying: {e}")
+ logger.warning("Error encoding texts, retrying: %s", e)
time.sleep(ENCODING_RETRY_DELAY)
return model.encode(texts, normalize_embeddings=normalize_embeddings)
@@ -127,7 +127,10 @@ async def embed_text(
if model_name is not None:
logger.info(
- f"Embedding {len(texts)} texts with {total_chars} total characters with local model: {model_name}"
+ "Embedding %s texts with %s total characters with local model: %s",
+ len(texts),
+ total_chars,
+ model_name,
)
prefixed_texts = [f"{prefix}{text}" for text in texts] if prefix else texts
@@ -149,16 +152,19 @@ async def embed_text(
elapsed = time.monotonic() - start
logger.info(
- f"Successfully embedded {len(texts)} texts with {total_chars} total characters "
- f"with local model {model_name} in {elapsed:.2f}"
+ "Successfully embedded %s texts with %s total characters with local model %s in %s",
+ len(texts),
+ total_chars,
+ model_name,
+ format(elapsed, ".2f"),
)
logger.info(
- f"event=embedding_model "
- f"texts={len(texts)} "
- f"chars={total_chars} "
- f"model={model_name} "
- f"gpu={gpu_type} "
- f"elapsed={elapsed:.2f}"
+ "event=embedding_model texts=%s chars=%s model=%s gpu=%s elapsed=%s",
+ len(texts),
+ total_chars,
+ model_name,
+ gpu_type,
+ format(elapsed, ".2f"),
)
else:
logger.error("Model name not specified for embedding")
@@ -217,7 +223,9 @@ async def process_embed_request(
)
except Exception as e:
logger.exception(
- f"Error during embedding process: provider={embed_request.provider_type} model={embed_request.model_name}"
+ "Error during embedding process: provider=%s model=%s",
+ embed_request.provider_type,
+ embed_request.model_name,
)
raise HTTPException(
status_code=500, detail=f"Error during embedding process: {e}"
diff --git a/backend/model_server/main.py b/backend/model_server/main.py
index b0f6b9126d..79777fb582 100644
--- a/backend/model_server/main.py
+++ b/backend/model_server/main.py
@@ -70,7 +70,7 @@ def _move_files_recursively(source: Path, dest: Path, overwrite: bool = False) -
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator:
gpu_type = get_gpu_type()
- logger.notice(f"Torch GPU Detection: gpu_type={gpu_type}")
+ logger.notice("Torch GPU Detection: gpu_type=%s", gpu_type)
app.state.gpu_type = gpu_type
@@ -82,12 +82,12 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
logger.notice("Moved contents of temp_huggingface to huggingface cache.")
except Exception as e:
logger.warning(
- f"Error moving contents of temp_huggingface to huggingface cache: {e}. "
- "This is not a critical error and the model server will continue to run."
+ "Error moving contents of temp_huggingface to huggingface cache: %s. This is not a critical error and the model server will continue to run.",
+ e,
)
torch.set_num_threads(max(MIN_THREADS_ML_MODELS, torch.get_num_threads()))
- logger.notice(f"Torch Threads: {torch.get_num_threads()}")
+ logger.notice("Torch Threads: %s", torch.get_num_threads())
yield
@@ -131,7 +131,9 @@ app = get_model_app()
if __name__ == "__main__":
logger.notice(
- f"Starting Onyx Model Server on http://{MODEL_SERVER_ALLOWED_HOST}:{str(MODEL_SERVER_PORT)}/"
+ "Starting Onyx Model Server on http://%s:%s/",
+ MODEL_SERVER_ALLOWED_HOST,
+ str(MODEL_SERVER_PORT),
)
- logger.notice(f"Model Server Version: {__version__}")
+ logger.notice("Model Server Version: %s", __version__)
uvicorn.run(app, host=MODEL_SERVER_ALLOWED_HOST, port=MODEL_SERVER_PORT)
diff --git a/backend/onyx/auth/captcha.py b/backend/onyx/auth/captcha.py
index f5437b61e5..f6a5ff7fad 100644
--- a/backend/onyx/auth/captcha.py
+++ b/backend/onyx/auth/captcha.py
@@ -132,7 +132,7 @@ async def _reserve_token_or_raise(token: str) -> None:
except CaptchaVerificationError:
raise
except Exception as e:
- logger.error(f"Captcha replay cache error (failing open): {e}")
+ logger.error("Captcha replay cache error (failing open): %s", e)
async def _release_token(token: str) -> None:
@@ -143,7 +143,7 @@ async def _release_token(token: str) -> None:
redis = await get_async_redis_connection()
await redis.delete(_replay_cache_key(token))
except Exception as e:
- logger.error(f"Captcha replay cache release error (ignored): {e}")
+ logger.error("Captcha replay cache release error (ignored): %s", e)
def _check_token_freshness(create_time: str | None) -> None:
@@ -154,13 +154,13 @@ def _check_token_freshness(create_time: str | None) -> None:
try:
ts = datetime.fromisoformat(create_time.replace("Z", "+00:00"))
except ValueError:
- logger.warning(f"Captcha createTime unparseable: {create_time!r}")
+ logger.warning("Captcha createTime unparseable: %r", create_time)
raise CaptchaVerificationError(
"Captcha verification failed: malformed createTime"
)
age_seconds = (datetime.now(timezone.utc) - ts).total_seconds()
if age_seconds > _TOKEN_MAX_AGE_SECONDS:
- logger.warning(f"Captcha token stale: age={age_seconds:.1f}s")
+ logger.warning("Captcha token stale: age=%ss", format(age_seconds, ".1f"))
raise CaptchaVerificationError("Captcha verification failed: token expired")
@@ -172,40 +172,49 @@ def _evaluate_assessment(
if not tp.valid:
reason = tp.invalid_reason or "INVALID"
- logger.warning(f"Captcha token invalid: reason={reason}")
+ logger.warning("Captcha token invalid: reason=%s", reason)
raise CaptchaVerificationError(f"Captcha verification failed: {reason}")
if RECAPTCHA_HOSTNAME_ALLOWLIST and (
tp.hostname is None or tp.hostname not in RECAPTCHA_HOSTNAME_ALLOWLIST
):
- logger.warning(f"Captcha hostname mismatch: {tp.hostname!r}")
+ logger.warning("Captcha hostname mismatch: %r", tp.hostname)
raise CaptchaVerificationError("Captcha verification failed: hostname mismatch")
_check_token_freshness(tp.create_time)
if tp.action != action.value:
logger.warning(
- f"Captcha action mismatch: got={tp.action!r} expected={action.value!r}"
+ "Captcha action mismatch: got=%r expected=%r", tp.action, action.value
)
raise CaptchaVerificationError("Captcha verification failed: action mismatch")
hard = _HARD_REJECT_REASONS.intersection(ra.reasons)
if hard:
- logger.warning(f"Captcha hard reject: reasons={sorted(hard)} score={ra.score}")
+ logger.warning(
+ "Captcha hard reject: reasons=%s score=%s", sorted(hard), ra.score
+ )
raise CaptchaVerificationError(
f"Captcha verification failed: {', '.join(sorted(hard))}"
)
if ra.score < RECAPTCHA_SCORE_THRESHOLD:
logger.warning(
- f"Captcha score below threshold: {ra.score} < {RECAPTCHA_SCORE_THRESHOLD} reasons={ra.reasons}"
+ "Captcha score below threshold: %s < %s reasons=%s",
+ ra.score,
+ RECAPTCHA_SCORE_THRESHOLD,
+ ra.reasons,
)
raise CaptchaVerificationError(
"Captcha verification failed: suspicious activity detected"
)
logger.info(
- f"Captcha verification passed: action={tp.action} score={ra.score} reasons={ra.reasons} hostname={tp.hostname}"
+ "Captcha verification passed: action=%s score=%s reasons=%s hostname=%s",
+ tp.action,
+ ra.score,
+ ra.reasons,
+ tp.hostname,
)
@@ -246,7 +255,7 @@ async def verify_captcha_token(token: str, action: CaptchaAction) -> None:
except CaptchaVerificationError:
raise
except Exception as e:
- logger.error(f"Captcha verification failed unexpectedly: {e}")
+ logger.error("Captcha verification failed unexpectedly: %s", e)
await _release_token(token)
raise CaptchaVerificationError("Captcha verification service unavailable")
diff --git a/backend/onyx/auth/disposable_email_validator.py b/backend/onyx/auth/disposable_email_validator.py
index ce05e02a6e..02f7dd5373 100644
--- a/backend/onyx/auth/disposable_email_validator.py
+++ b/backend/onyx/auth/disposable_email_validator.py
@@ -83,7 +83,8 @@ class DisposableEmailValidator:
try:
logger.info(
- f"Fetching disposable email domains from {DISPOSABLE_EMAIL_DOMAINS_URL}"
+ "Fetching disposable email domains from %s",
+ DISPOSABLE_EMAIL_DOMAINS_URL,
)
with httpx.Client(timeout=10.0) as client:
response = client.get(DISPOSABLE_EMAIL_DOMAINS_URL)
@@ -93,7 +94,8 @@ class DisposableEmailValidator:
if not isinstance(domains_list, list):
logger.error(
- f"Expected list from disposable domains URL, got {type(domains_list)}"
+ "Expected list from disposable domains URL, got %s",
+ type(domains_list),
)
return self._fallback_domains.copy()
@@ -104,14 +106,14 @@ class DisposableEmailValidator:
domains.update(self._fallback_domains)
logger.info(
- f"Successfully fetched {len(domains)} disposable email domains"
+ "Successfully fetched %s disposable email domains", len(domains)
)
return domains
except httpx.HTTPError as e:
- logger.warning(f"Failed to fetch disposable domains (HTTP error): {e}")
+ logger.warning("Failed to fetch disposable domains (HTTP error): %s", e)
except Exception as e:
- logger.warning(f"Failed to fetch disposable domains: {e}")
+ logger.warning("Failed to fetch disposable domains: %s", e)
# On error, return fallback domains
return self._fallback_domains.copy()
diff --git a/backend/onyx/auth/email_utils.py b/backend/onyx/auth/email_utils.py
index a123ead4b8..fa02d91fbd 100644
--- a/backend/onyx/auth/email_utils.py
+++ b/backend/onyx/auth/email_utils.py
@@ -243,7 +243,7 @@ def send_email_with_sendgrid(
sg = sendgrid.SendGridAPIClient(api_key=SENDGRID_API_KEY)
response = sg.client.mail.send.post(request_body=mail_json) # can raise
if response.status_code != 202:
- logger.warning(f"Unexpected status code {response.status_code}")
+ logger.warning("Unexpected status code %s", response.status_code)
def send_email_with_smtplib(
diff --git a/backend/onyx/auth/jwt.py b/backend/onyx/auth/jwt.py
index afbfe8c507..4622dd5682 100644
--- a/backend/onyx/auth/jwt.py
+++ b/backend/onyx/auth/jwt.py
@@ -37,7 +37,7 @@ def _fetch_public_key_payload() -> tuple[str | dict[str, Any], PublicKeyFormat]
response = requests.get(JWT_PUBLIC_KEY_URL)
response.raise_for_status()
except requests.RequestException as exc:
- logger.error(f"Failed to fetch JWT public key: {str(exc)}")
+ logger.error("Failed to fetch JWT public key: %s", str(exc))
return None
content_type = response.headers.get("Content-Type", "").lower()
raw_body = response.text
@@ -88,7 +88,7 @@ def _resolve_public_key_from_jwks(
try:
header = jwt.get_unverified_header(token)
except PyJWTError as e:
- logger.error(f"Unable to parse JWT header: {str(e)}")
+ logger.error("Unable to parse JWT header: %s", str(e))
return None
keys = jwks_payload.get("keys", []) if isinstance(jwks_payload, dict) else []
@@ -123,7 +123,7 @@ def _resolve_public_key_from_jwks(
try:
return cast(RSAPublicKey, RSAAlgorithm.from_jwk(json.dumps(jwk)))
except ValueError as e:
- logger.error(f"Failed to construct RSA key from JWK: {str(e)}")
+ logger.error("Failed to construct RSA key from JWK: %s", str(e))
return None
@@ -145,13 +145,13 @@ async def verify_jwt_token(token: str) -> dict[str, Any] | None:
options={"verify_aud": False},
)
except InvalidTokenError as e:
- logger.error(f"Invalid JWT token: {str(e)}")
+ logger.error("Invalid JWT token: %s", str(e))
if attempt < _PUBLIC_KEY_FETCH_ATTEMPTS - 1:
_fetch_public_key_payload.cache_clear()
continue
return None
except PyJWTError as e:
- logger.error(f"JWT decoding error: {str(e)}")
+ logger.error("JWT decoding error: %s", str(e))
if attempt < _PUBLIC_KEY_FETCH_ATTEMPTS - 1:
_fetch_public_key_payload.cache_clear()
continue
diff --git a/backend/onyx/auth/oauth_refresher.py b/backend/onyx/auth/oauth_refresher.py
index 3b9b192a82..b4e39ca826 100644
--- a/backend/onyx/auth/oauth_refresher.py
+++ b/backend/onyx/auth/oauth_refresher.py
@@ -54,7 +54,7 @@ async def _test_expire_oauth_token(
return True
except Exception as e:
- logger.exception(f"Error setting artificial expiration: {str(e)}")
+ logger.exception("Error setting artificial expiration: %s", str(e))
return False
@@ -70,17 +70,19 @@ async def refresh_oauth_token(
"""
if not oauth_account.refresh_token:
logger.warning(
- f"No refresh token available for {user.email}'s {oauth_account.oauth_name} account"
+ "No refresh token available for %s's %s account",
+ user.email,
+ oauth_account.oauth_name,
)
return False
provider = oauth_account.oauth_name
if provider not in REFRESH_ENDPOINTS:
- logger.warning(f"Refresh endpoint not configured for provider: {provider}")
+ logger.warning("Refresh endpoint not configured for provider: %s", provider)
return False
try:
- logger.info(f"Refreshing OAuth token for {user.email}'s {provider} account")
+ logger.info("Refreshing OAuth token for %s's %s account", user.email, provider)
async with httpx.AsyncClient() as client:
response = await client.post(
@@ -96,7 +98,7 @@ async def refresh_oauth_token(
if response.status_code != 200:
logger.error(
- f"Failed to refresh OAuth token: Status {response.status_code}"
+ "Failed to refresh OAuth token: Status %s", response.status_code
)
return False
@@ -140,11 +142,11 @@ async def refresh_oauth_token(
updated_data,
)
- logger.info(f"Successfully refreshed OAuth token for {user.email}")
+ logger.info("Successfully refreshed OAuth token for %s", user.email)
return True
except Exception as e:
- logger.exception(f"Error refreshing OAuth token: {str(e)}")
+ logger.exception("Error refreshing OAuth token: %s", str(e))
return False
@@ -174,7 +176,9 @@ async def check_and_refresh_oauth_tokens(
oauth_account.expires_at
and oauth_account.expires_at - now_timestamp < buffer_seconds
):
- logger.info(f"OAuth token for {user.email} is about to expire - refreshing")
+ logger.info(
+ "OAuth token for %s is about to expire - refreshing", user.email
+ )
success = await refresh_oauth_token(
user, oauth_account, db_session, user_manager
)
diff --git a/backend/onyx/auth/oauth_token_manager.py b/backend/onyx/auth/oauth_token_manager.py
index ab2a113e4b..0c83c2d0b2 100644
--- a/backend/onyx/auth/oauth_token_manager.py
+++ b/backend/onyx/auth/oauth_token_manager.py
@@ -45,7 +45,7 @@ class OAuthTokenManager:
try:
return self.refresh_token(user_token)
except Exception as e:
- logger.warning(f"Failed to refresh token: {e}")
+ logger.warning("Failed to refresh token: %s", e)
return None
else:
return None
diff --git a/backend/onyx/auth/permissions.py b/backend/onyx/auth/permissions.py
index 2316f2f7d9..badf1894f7 100644
--- a/backend/onyx/auth/permissions.py
+++ b/backend/onyx/auth/permissions.py
@@ -89,7 +89,7 @@ def get_effective_permissions(user: User) -> set[Permission]:
try:
granted.add(Permission(p))
except ValueError:
- logger.warning(f"Skipping unknown permission '{p}' for user {user.id}")
+ logger.warning("Skipping unknown permission '%s' for user %s", p, user.id)
if Permission.FULL_ADMIN_PANEL_ACCESS in granted:
return set(Permission)
expanded = resolve_effective_permissions({p.value for p in granted})
diff --git a/backend/onyx/auth/signup_rate_limit.py b/backend/onyx/auth/signup_rate_limit.py
index 04f3eab9ef..80ffdf453c 100644
--- a/backend/onyx/auth/signup_rate_limit.py
+++ b/backend/onyx/auth/signup_rate_limit.py
@@ -52,11 +52,11 @@ async def enforce_signup_rate_limit(request: Request) -> None:
incr_result, _ = await pipe.execute()
count = int(incr_result)
except Exception as e:
- logger.error(f"Signup rate-limit Redis error: {e}")
+ logger.error("Signup rate-limit Redis error: %s", e)
return
if count > _PER_IP_PER_HOUR:
- logger.warning(f"Signup rate limit exceeded for ip={ip} count={count}")
+ logger.warning("Signup rate limit exceeded for ip=%s count=%s", ip, count)
raise OnyxError(
OnyxErrorCode.RATE_LIMITED,
"Too many signup attempts from this network. Please wait before trying again.",
diff --git a/backend/onyx/auth/users.py b/backend/onyx/auth/users.py
index 1d15abb4ff..20ca59393d 100644
--- a/backend/onyx/auth/users.py
+++ b/backend/onyx/auth/users.py
@@ -180,7 +180,7 @@ def verify_auth_setting() -> None:
"AUTH_TYPE='disabled' is no longer supported. Using 'basic' instead. Please update your configuration."
)
- logger.notice(f"Using Auth Type: {AUTH_TYPE.value}")
+ logger.notice("Using Auth Type: %s", AUTH_TYPE.value)
def get_display_email(email: str | None, space_less: bool = False) -> str:
@@ -394,7 +394,8 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
else "unknown"
)
logger.warning(
- f"Blocked disposable email registration attempt: {domain}",
+ "Blocked disposable email registration attempt: %s",
+ domain,
extra={"email_domain": domain},
)
raise
@@ -850,7 +851,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
domain=None,
secure=WEB_DOMAIN.startswith("https"),
)
- logger.debug(f"Deleted anonymous user cookie for user {user.email}")
+ logger.debug("Deleted anonymous user cookie for user %s", user.email)
except Exception:
logger.exception("Error deleting anonymous user cookie")
@@ -882,7 +883,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
token = CURRENT_TENANT_ID_CONTEXTVAR.set(tenant_id)
try:
user_count = await get_user_count()
- logger.debug(f"Current tenant user count: {user_count}")
+ logger.debug("Current tenant user count: %s", user_count)
# Link the anonymous PostHog session to the identified user so
# that pre-signup session recordings merge into one person profile.
@@ -979,7 +980,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
properties=properties,
)
- logger.debug(f"User {user.id} has registered.")
+ logger.debug("User %s has registered.", user.id)
optional_telemetry(
record_type=RecordType.SIGN_UP,
data={"action": "create"},
@@ -1017,7 +1018,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
verify_email_domain(user.email)
logger.notice(
- f"Verification requested for user {user.id}. Verification token: {token}"
+ "Verification requested for user %s. Verification token: %s", user.id, token
)
user_count = await get_user_count()
send_user_verification_email(
@@ -1041,7 +1042,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
)
except Exception as e:
logger.warning(
- f"User attempted to login with invalid credentials: {str(e)}"
+ "User attempted to login with invalid credentials: %s", str(e)
)
if not tenant_id:
@@ -1436,7 +1437,7 @@ class FastAPIUserWithLogoutRouter(FastAPIUsers[models.UP, models.ID]):
) -> Response:
try:
user, token = user_token
- logger.info(f"Processing token refresh request for user {user.email}")
+ logger.info("Processing token refresh request for user %s", user.email)
# Check if user has OAuth accounts that need refreshing
await check_and_refresh_oauth_tokens(
@@ -1455,11 +1456,12 @@ class FastAPIUserWithLogoutRouter(FastAPIUsers[models.UP, models.ID]):
refresh_method = getattr(strategy, "refresh_token")
new_token = await refresh_method(token, user)
logger.info(
- f"Successfully refreshed session token for user {user.email}"
+ "Successfully refreshed session token for user %s",
+ user.email,
)
return await backend.transport.get_login_response(new_token)
except Exception as e:
- logger.error(f"Error refreshing session token: {str(e)}")
+ logger.error("Error refreshing session token: %s", str(e))
# Fallback to logout and login if refresh fails
await backend.logout(strategy, user, token)
return await backend.login(strategy, user)
@@ -1471,7 +1473,7 @@ class FastAPIUserWithLogoutRouter(FastAPIUsers[models.UP, models.ID]):
await backend.logout(strategy, user, token)
return await backend.login(strategy, user)
except Exception as e:
- logger.error(f"Unexpected error in refresh endpoint: {str(e)}")
+ logger.error("Unexpected error in refresh endpoint: %s", str(e))
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Token refresh failed: {str(e)}",
@@ -1807,7 +1809,9 @@ async def current_user_from_websocket(
raise BasicAuthenticationError(detail="Access denied. Missing origin.")
if not _is_same_origin(origin, WEB_DOMAIN):
- logger.warning(f"WS auth: origin mismatch. Expected {WEB_DOMAIN}, got {origin}")
+ logger.warning(
+ "WS auth: origin mismatch. Expected %s, got %s", WEB_DOMAIN, origin
+ )
raise BasicAuthenticationError(detail="Access denied. Invalid origin.")
# Validate WS token in Redis (single-use, deleted after retrieval)
@@ -1820,7 +1824,7 @@ async def current_user_from_websocket(
except BasicAuthenticationError:
raise
except Exception as e:
- logger.error(f"WS auth: error during token validation: {e}")
+ logger.error("WS auth: error during token validation: %s", e)
raise BasicAuthenticationError(
detail="Authentication verification failed."
) from e
@@ -1828,7 +1832,7 @@ async def current_user_from_websocket(
# Get user from token data
user = await _get_user_from_token_data(token_data)
if user is None:
- logger.warning(f"WS auth: user not found for id={token_data.get('sub')}")
+ logger.warning("WS auth: user not found for id=%s", token_data.get("sub"))
raise BasicAuthenticationError(
detail="Access denied. User not found or inactive."
)
@@ -1838,12 +1842,12 @@ async def current_user_from_websocket(
# Block limited users (same as current_user)
if is_limited_user(user):
- logger.warning(f"WS auth: user {user.email} is limited")
+ logger.warning("WS auth: user %s is limited", user.email)
raise BasicAuthenticationError(
detail="Access denied. User has limited permissions.",
)
- logger.debug(f"WS auth: authenticated {user.email}")
+ logger.debug("WS auth: authenticated %s", user.email)
return user
diff --git a/backend/onyx/background/celery/apps/app_base.py b/backend/onyx/background/celery/apps/app_base.py
index b0d0cffa41..840b5c35db 100644
--- a/backend/onyx/background/celery/apps/app_base.py
+++ b/backend/onyx/background/celery/apps/app_base.py
@@ -151,7 +151,9 @@ def on_task_postrun(
if not task:
return
- task_logger.debug(f"Task {task.name} (ID: {task_id}) completed with state: {state}")
+ task_logger.debug(
+ "Task %s (ID: %s) completed with state: %s", task.name, task_id, state
+ )
if state not in READY_STATES:
return
@@ -165,13 +167,17 @@ def on_task_postrun(
# Get tenant_id directly from kwargs- each celery task has a tenant_id kwarg
if not kwargs:
- logger.error(f"Task {task.name} (ID: {task_id}) is missing kwargs")
+ logger.error("Task %s (ID: %s) is missing kwargs", task.name, task_id)
tenant_id = POSTGRES_DEFAULT_SCHEMA
else:
tenant_id = cast(str, kwargs.get("tenant_id", POSTGRES_DEFAULT_SCHEMA))
task_logger.debug(
- f"Task {task.name} (ID: {task_id}) completed with state: {state} {f'for tenant_id={tenant_id}' if tenant_id else ''}"
+ "Task %s (ID: %s) completed with state: %s %s",
+ task.name,
+ task_id,
+ state,
+ f"for tenant_id={tenant_id}" if tenant_id else "",
)
r = get_redis_client(tenant_id=tenant_id)
@@ -238,7 +244,7 @@ def on_celeryd_init(
# force=True. so we use force=True as a fallback.
all_start_methods: list[str] = multiprocessing.get_all_start_methods()
- logger.info(f"Multiprocessing all start methods: {all_start_methods}")
+ logger.info("Multiprocessing all start methods: %s", all_start_methods)
try:
multiprocessing.set_start_method("spawn") # fork is unsafe, set to spawn
@@ -256,7 +262,7 @@ def on_celeryd_init(
)
logger.info(
- f"Multiprocessing selected start method: {multiprocessing.get_start_method()}"
+ "Multiprocessing selected start method: %s", multiprocessing.get_start_method()
)
# Initialize tracing in workers if credentials are available.
@@ -289,7 +295,9 @@ def wait_for_redis(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
break
logger.info(
- f"Redis: Readiness probe ongoing. elapsed={time_elapsed:.1f} timeout={WAIT_LIMIT:.1f}"
+ "Redis: Readiness probe ongoing. elapsed=%s timeout=%s",
+ format(time_elapsed, ".1f"),
+ format(WAIT_LIMIT, ".1f"),
)
time.sleep(WAIT_INTERVAL)
@@ -328,7 +336,9 @@ def wait_for_db(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
break
logger.info(
- f"Database: Readiness probe ongoing. elapsed={time_elapsed:.1f} timeout={WAIT_LIMIT:.1f}"
+ "Database: Readiness probe ongoing. elapsed=%s timeout=%s",
+ format(time_elapsed, ".1f"),
+ format(WAIT_LIMIT, ".1f"),
)
time.sleep(WAIT_INTERVAL)
@@ -343,7 +353,7 @@ def wait_for_db(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
def on_secondary_worker_init(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
- logger.info(f"Running as a secondary celery worker: pid={os.getpid()}")
+ logger.info("Running as a secondary celery worker: pid=%s", os.getpid())
# Set up variables for waiting on primary worker
WAIT_INTERVAL = 5
@@ -358,7 +368,9 @@ def on_secondary_worker_init(sender: Any, **kwargs: Any) -> None: # noqa: ARG00
time_elapsed = time.monotonic() - time_start
logger.info(
- f"Primary worker is not ready yet. elapsed={time_elapsed:.1f} timeout={WAIT_LIMIT:.1f}"
+ "Primary worker is not ready yet. elapsed=%s timeout=%s",
+ format(time_elapsed, ".1f"),
+ format(WAIT_LIMIT, ".1f"),
)
if time_elapsed > WAIT_LIMIT:
msg = f"Primary worker was not ready within the timeout. ({WAIT_LIMIT} seconds). Exiting..."
@@ -381,7 +393,7 @@ def on_worker_ready(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
hostname: str = cast(str, sender.hostname)
path = make_probe_path("readiness", hostname)
path.touch()
- logger.info(f"Readiness signal touched at {path}.")
+ logger.info("Readiness signal touched at %s.", path)
def on_worker_shutdown(sender: Any, **kwargs: Any) -> None: # noqa: ARG001
diff --git a/backend/onyx/background/celery/apps/beat.py b/backend/onyx/background/celery/apps/beat.py
index 0e58608bad..8b858974db 100644
--- a/backend/onyx/background/celery/apps/beat.py
+++ b/backend/onyx/background/celery/apps/beat.py
@@ -43,7 +43,8 @@ class DynamicTenantScheduler(PersistentScheduler):
# Let the parent class handle store initialization
self.setup_schedule()
task_logger.info(
- f"DynamicTenantScheduler initialized: reload_interval={self._reload_interval}"
+ "DynamicTenantScheduler initialized: reload_interval=%s",
+ self._reload_interval,
)
self._liveness_probe_path = make_probe_path("liveness", "beat@hostname")
@@ -103,7 +104,9 @@ class DynamicTenantScheduler(PersistentScheduler):
"kwargs": task.get("kwargs", {}),
}
if options := task.get("options"):
- task_logger.debug(f"Adding options to task {task_name}: {options}")
+ task_logger.debug(
+ "Adding options to task %s: %s", task_name, options
+ )
cloud_task["options"] = options
new_schedule[task_name] = cloud_task
@@ -120,7 +123,8 @@ class DynamicTenantScheduler(PersistentScheduler):
for tenant_id in tenant_ids:
if IGNORED_SYNCING_TENANT_LIST and tenant_id in IGNORED_SYNCING_TENANT_LIST:
task_logger.debug(
- f"Skipping tenant {tenant_id} as it is in the ignored syncing list"
+ "Skipping tenant %s as it is in the ignored syncing list",
+ tenant_id,
)
continue
@@ -128,7 +132,9 @@ class DynamicTenantScheduler(PersistentScheduler):
task_name = task["name"]
tenant_task_name = f"{task['name']}-{tenant_id}"
- task_logger.debug(f"Creating task configuration for {tenant_task_name}")
+ task_logger.debug(
+ "Creating task configuration for %s", tenant_task_name
+ )
tenant_task = {
"task": task["task"],
"schedule": task["schedule"],
@@ -136,7 +142,9 @@ class DynamicTenantScheduler(PersistentScheduler):
}
if options := task.get("options"):
task_logger.debug(
- f"Adding options to task {tenant_task_name}: {options}"
+ "Adding options to task %s: %s",
+ tenant_task_name,
+ options,
)
tenant_task["options"] = options
@@ -151,7 +159,7 @@ class DynamicTenantScheduler(PersistentScheduler):
task_logger.debug("_try_updating_schedule starting")
tenant_ids = get_all_tenant_ids()
- task_logger.debug(f"Found {len(tenant_ids)} IDs")
+ task_logger.debug("Found %s IDs", len(tenant_ids))
# get current schedule and extract current tenants
current_schedule = self.schedule.items()
@@ -181,7 +189,9 @@ class DynamicTenantScheduler(PersistentScheduler):
if not do_update:
# exit early if nothing changed
task_logger.info(
- f"_try_updating_schedule - Schedule unchanged: tasks={len(new_schedule)} beat_multiplier={beat_multiplier}"
+ "_try_updating_schedule - Schedule unchanged: tasks=%s beat_multiplier=%s",
+ len(new_schedule),
+ beat_multiplier,
)
return
@@ -214,11 +224,15 @@ class DynamicTenantScheduler(PersistentScheduler):
self.sync()
task_logger.info(
- f"_try_updating_schedule - Schedule updated: "
- f"prev_num_tasks={len(current_schedule)} "
- f"prev_beat_multiplier={self.last_beat_multiplier} "
- f"tasks={len(new_schedule)} "
- f"beat_multiplier={beat_multiplier}"
+ "_try_updating_schedule - Schedule updated: "
+ "prev_num_tasks=%s "
+ "prev_beat_multiplier=%s "
+ "tasks=%s "
+ "beat_multiplier=%s",
+ len(current_schedule),
+ self.last_beat_multiplier,
+ len(new_schedule),
+ beat_multiplier,
)
self.last_beat_multiplier = beat_multiplier
@@ -243,7 +257,7 @@ def on_beat_init(sender: Any, **kwargs: Any) -> None:
app_base.wait_for_redis(sender, **kwargs)
path = make_probe_path("readiness", "beat@hostname")
path.touch()
- task_logger.info(f"Readiness signal touched at {path}.")
+ task_logger.info("Readiness signal touched at %s.", path)
# first time init of the scheduler after db has been init'ed
scheduler: DynamicTenantScheduler = sender.scheduler
diff --git a/backend/onyx/background/celery/apps/light.py b/backend/onyx/background/celery/apps/light.py
index 2660d40002..c586125e47 100644
--- a/backend/onyx/background/celery/apps/light.py
+++ b/backend/onyx/background/celery/apps/light.py
@@ -96,7 +96,7 @@ def on_worker_init(sender: Worker, **kwargs: Any) -> None:
logger.info("worker_init signal received.")
logger.info(
- f"Concurrency: {sender.concurrency}" # ty: ignore[unresolved-attribute]
+ "Concurrency: %s", sender.concurrency # ty: ignore[unresolved-attribute]
)
SqlEngine.set_app_name(POSTGRES_CELERY_WORKER_LIGHT_APP_NAME)
diff --git a/backend/onyx/background/celery/apps/monitoring.py b/backend/onyx/background/celery/apps/monitoring.py
index bdfa7c7942..ae852fdd3d 100644
--- a/backend/onyx/background/celery/apps/monitoring.py
+++ b/backend/onyx/background/celery/apps/monitoring.py
@@ -62,7 +62,7 @@ def on_worker_init(sender: Any, **kwargs: Any) -> None:
global _prometheus_collectors_ok
logger.info("worker_init signal received.")
- logger.info(f"Multiprocessing start method: {multiprocessing.get_start_method()}")
+ logger.info("Multiprocessing start method: %s", multiprocessing.get_start_method())
SqlEngine.set_app_name(POSTGRES_CELERY_WORKER_MONITORING_APP_NAME)
SqlEngine.init_engine(pool_size=sender.concurrency, max_overflow=3)
diff --git a/backend/onyx/background/celery/apps/primary.py b/backend/onyx/background/celery/apps/primary.py
index 546ac6cc60..e0035e8766 100644
--- a/backend/onyx/background/celery/apps/primary.py
+++ b/backend/onyx/background/celery/apps/primary.py
@@ -126,7 +126,7 @@ def on_worker_init(sender: Worker, **kwargs: Any) -> None:
app_base.wait_for_db(sender, **kwargs)
app_base.wait_for_document_index_or_shutdown()
- logger.info(f"Running as the primary celery worker: pid={os.getpid()}")
+ logger.info("Running as the primary celery worker: pid=%s", os.getpid())
# Less startup checks in multi-tenant case
if MULTI_TENANT:
@@ -142,13 +142,13 @@ def on_worker_init(sender: Worker, **kwargs: Any) -> None:
connected_slaves: int = replication_info.get("connected_slaves", 0)
logger.info(
- f"Redis INFO REPLICATION: role={role} connected_slaves={connected_slaves}"
+ "Redis INFO REPLICATION: role=%s connected_slaves=%s", role, connected_slaves
)
memory_info: dict[str, Any] = cast(dict, r.info("memory"))
maxmemory_policy: str = cast(str, memory_info.get("maxmemory_policy", ""))
- logger.info(f"Redis INFO MEMORY: maxmemory_policy={maxmemory_policy}")
+ logger.info("Redis INFO MEMORY: maxmemory_policy=%s", maxmemory_policy)
# For the moment, we're assuming that we are the only primary worker
# that should be running.
@@ -238,7 +238,9 @@ def on_worker_init(sender: Worker, **kwargs: Any) -> None:
except Exception:
# If we can't check the task status, be conservative and continue
logger.warning(
- f"Could not verify Celery task status on startup for attempt {attempt.id}, task_id={attempt.celery_task_id}"
+ "Could not verify Celery task status on startup for attempt %s, task_id=%s",
+ attempt.id,
+ attempt.celery_task_id,
)
diff --git a/backend/onyx/background/celery/celery_utils.py b/backend/onyx/background/celery/celery_utils.py
index 799cbce299..a281b281fa 100644
--- a/backend/onyx/background/celery/celery_utils.py
+++ b/backend/onyx/background/celery/celery_utils.py
@@ -120,7 +120,7 @@ def _extract_from_batch(
if failed_id:
ids[failed_id] = None
logger.warning(
- f"Failed to retrieve document {failed_id}: {item.failure_message}"
+ "Failed to retrieve document %s: %s", failed_id, item.failure_message
)
else:
ids[item.id] = item.parent_hierarchy_raw_node_id
diff --git a/backend/onyx/background/celery/memory_monitoring.py b/backend/onyx/background/celery/memory_monitoring.py
index 2403077728..817866ec60 100644
--- a/backend/onyx/background/celery/memory_monitoring.py
+++ b/backend/onyx/background/celery/memory_monitoring.py
@@ -64,10 +64,16 @@ def emit_process_memory(
metadata_str = f" {metadata_str}" if metadata_str else ""
memory_logger.info(
- f"PROCESS_MEMORY process_name={process_name} pid={pid} "
- f"rss_mb={memory_info.rss / (1024 * 1024):.2f} "
- f"vms_mb={memory_info.vms / (1024 * 1024):.2f} "
- f"cpu={cpu_percent:.2f}{metadata_str}"
+ "PROCESS_MEMORY process_name=%s pid=%s "
+ "rss_mb=%s "
+ "vms_mb=%s "
+ "cpu=%s%s",
+ process_name,
+ pid,
+ format(memory_info.rss / (1024 * 1024), ".2f"),
+ format(memory_info.vms / (1024 * 1024), ".2f"),
+ format(cpu_percent, ".2f"),
+ metadata_str,
)
except Exception:
logger.exception("Error monitoring process memory.")
diff --git a/backend/onyx/background/celery/tasks/docfetching/tasks.py b/backend/onyx/background/celery/tasks/docfetching/tasks.py
index d63e2d4867..5a046b2d73 100644
--- a/backend/onyx/background/celery/tasks/docfetching/tasks.py
+++ b/backend/onyx/background/celery/tasks/docfetching/tasks.py
@@ -93,10 +93,10 @@ def _verify_indexing_attempt(
)
logger.info(
- f"docfetching_task - IndexAttempt verified: "
- f"attempt_id={index_attempt_id} "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id}"
+ "docfetching_task - IndexAttempt verified: attempt_id=%s cc_pair=%s search_settings=%s",
+ index_attempt_id,
+ cc_pair_id,
+ search_settings_id,
)
@@ -151,11 +151,11 @@ def _docfetching_task(
logger.debug("Sentry DSN not provided, skipping Sentry initialization")
logger.info(
- f"Indexing spawned task starting: "
- f"attempt={index_attempt_id} "
- f"tenant={tenant_id} "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id}"
+ "Indexing spawned task starting: attempt=%s tenant=%s cc_pair=%s search_settings=%s",
+ index_attempt_id,
+ tenant_id,
+ cc_pair_id,
+ search_settings_id,
)
redis_connector = RedisConnector(tenant_id, cc_pair_id)
@@ -209,10 +209,11 @@ def _docfetching_task(
)
logger.info(
- f"Indexing spawned task running entrypoint: attempt={index_attempt_id} "
- f"tenant={tenant_id} "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id}"
+ "Indexing spawned task running entrypoint: attempt=%s tenant=%s cc_pair=%s search_settings=%s",
+ index_attempt_id,
+ tenant_id,
+ cc_pair_id,
+ search_settings_id,
)
# This is where the heavy/real work happens
@@ -236,10 +237,11 @@ def _docfetching_task(
except Exception as e:
logger.exception(
- f"Indexing spawned task failed: attempt={index_attempt_id} "
- f"tenant={tenant_id} "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id}"
+ "Indexing spawned task failed: attempt=%s tenant=%s cc_pair=%s search_settings=%s",
+ index_attempt_id,
+ tenant_id,
+ cc_pair_id,
+ search_settings_id,
)
# special bulletproofing ... truncate long exception messages
@@ -253,7 +255,10 @@ def _docfetching_task(
raise e
logger.info(
- f"Indexing spawned task finished: attempt={index_attempt_id} cc_pair={cc_pair_id} search_settings={search_settings_id}"
+ "Indexing spawned task finished: attempt=%s cc_pair=%s search_settings=%s",
+ index_attempt_id,
+ cc_pair_id,
+ search_settings_id,
)
os._exit(0) # ensure process exits cleanly
@@ -627,7 +632,8 @@ def docfetching_proxy_task(
try:
with get_session_with_current_tenant() as db_session:
logger.exception(
- f"Marking attempt {index_attempt_id} as canceled due to termination signal"
+ "Marking attempt %s as canceled due to termination signal",
+ index_attempt_id,
)
mark_attempt_canceled(
index_attempt_id,
diff --git a/backend/onyx/background/celery/tasks/docprocessing/tasks.py b/backend/onyx/background/celery/tasks/docprocessing/tasks.py
index 26754c9607..04761c9cf0 100644
--- a/backend/onyx/background/celery/tasks/docprocessing/tasks.py
+++ b/backend/onyx/background/celery/tasks/docprocessing/tasks.py
@@ -368,7 +368,9 @@ def monitor_indexing_attempt_progress(
)
except Exception as e:
logger.exception(
- f"Failed to monitor document processing completion: attempt={attempt.id} error={str(e)}"
+ "Failed to monitor document processing completion: attempt=%s error=%s",
+ attempt.id,
+ str(e),
)
# Mark the attempt as failed if monitoring fails
@@ -386,7 +388,7 @@ def monitor_indexing_attempt_progress(
# Try to clean up storage
try:
- logger.info(f"Cleaning up storage after monitoring failure: {storage}")
+ logger.info("Cleaning up storage after monitoring failure: %s", storage)
storage.cleanup_all_batches()
except Exception:
logger.exception("Failed to cleanup storage after monitoring failure")
@@ -416,7 +418,9 @@ def check_indexing_completion(
task: Task,
) -> None:
logger.info(
- f"Checking for indexing completion: attempt={index_attempt_id} tenant={tenant_id}"
+ "Checking for indexing completion: attempt=%s tenant=%s",
+ index_attempt_id,
+ tenant_id,
)
# Check if indexing is complete and all batches are processed
@@ -427,12 +431,13 @@ def check_indexing_completion(
)
logger.info(
- f"Indexing status: "
- f"indexing_completed={indexing_completed} "
- f"batches_processed={batches_processed}/{batches_total if batches_total is not None else '?'} "
- f"total_docs={coordination_status.total_docs} "
- f"total_chunks={coordination_status.total_chunks} "
- f"total_failures={coordination_status.total_failures}"
+ "Indexing status: indexing_completed=%s batches_processed=%s/%s total_docs=%s total_chunks=%s total_failures=%s",
+ indexing_completed,
+ batches_processed,
+ batches_total if batches_total is not None else "?",
+ coordination_status.total_docs,
+ coordination_status.total_chunks,
+ coordination_status.total_failures,
)
# Update progress tracking and check for stalls
@@ -465,9 +470,10 @@ def check_indexing_completion(
if attempt and timed_out:
if attempt.status == IndexingStatus.IN_PROGRESS:
logger.error(
- f"Indexing attempt {index_attempt_id} has been indexing for "
- f"{stalled_timeout_hours // 2}-{stalled_timeout_hours} hours without progress. "
- f"Marking it as failed."
+ "Indexing attempt %s has been indexing for %s-%s hours without progress. Marking it as failed.",
+ index_attempt_id,
+ stalled_timeout_hours // 2,
+ stalled_timeout_hours,
)
mark_attempt_failed(
index_attempt_id, db_session, failure_reason="Stalled indexing"
@@ -496,9 +502,9 @@ def check_indexing_completion(
attempt = get_index_attempt(db_session, index_attempt_id)
if attempt and attempt.status == IndexingStatus.NOT_STARTED:
logger.error(
- f"Task {attempt.celery_task_id} attached to indexing attempt "
- f"{index_attempt_id} does not exist in the queue. "
- f"Marking indexing attempt as failed."
+ "Task %s attached to indexing attempt %s does not exist in the queue. Marking indexing attempt as failed.",
+ attempt.celery_task_id,
+ index_attempt_id,
)
mark_attempt_failed(
index_attempt_id,
@@ -507,9 +513,11 @@ def check_indexing_completion(
)
else:
logger.info(
- f"Indexing attempt {index_attempt_id} is {attempt.status}. "
- f"{stalled_timeout_hours // 2}-{stalled_timeout_hours} hours without heartbeat "
- "but task is in the queue. Likely underprovisioned docfetching worker."
+ "Indexing attempt %s is %s. %s-%s hours without heartbeat but task is in the queue. Likely underprovisioned docfetching worker.",
+ index_attempt_id,
+ attempt.status,
+ stalled_timeout_hours // 2,
+ stalled_timeout_hours,
)
# Update last progress time so we won't time out again for
# another `stalled_timeout_hours / 2` window.
@@ -528,7 +536,7 @@ def check_indexing_completion(
return
# If processing is complete, handle completion
- logger.info(f"Connector indexing finished for index attempt {index_attempt_id}.")
+ logger.info("Connector indexing finished for index attempt %s.", index_attempt_id)
# All processing is complete
total_failures = coordination_status.total_failures
@@ -536,11 +544,13 @@ def check_indexing_completion(
with get_session_with_current_tenant() as db_session:
if total_failures == 0:
attempt = mark_attempt_succeeded(index_attempt_id, db_session)
- logger.info(f"Index attempt {index_attempt_id} completed successfully")
+ logger.info("Index attempt %s completed successfully", index_attempt_id)
else:
attempt = mark_attempt_partially_succeeded(index_attempt_id, db_session)
logger.info(
- f"Index attempt {index_attempt_id} completed with {total_failures} failures"
+ "Index attempt %s completed with %s failures",
+ index_attempt_id,
+ total_failures,
)
# Update CC pair status if successful
@@ -622,7 +632,7 @@ def check_indexing_completion(
if attempt.status == IndexingStatus.SUCCESS:
logger.info(
- f"Resolving indexing entity errors for attempt {index_attempt_id}"
+ "Resolving indexing entity errors for attempt %s", index_attempt_id
)
_resolve_indexing_entity_errors(
cc_pair_id=attempt.connector_credential_pair_id,
@@ -631,7 +641,7 @@ def check_indexing_completion(
# Clean up FileStore storage (still needed for document batches during transition)
try:
- logger.info(f"Cleaning up storage after indexing completion: {storage}")
+ logger.info("Cleaning up storage after indexing completion: %s", storage)
storage.cleanup_all_batches()
except Exception:
logger.exception("Failed to clean up document batches - continuing")
@@ -653,7 +663,7 @@ def check_indexing_completion(
"caught by the next attempt's start-of-run sweep."
)
- logger.info(f"Database coordination completed for attempt {index_attempt_id}")
+ logger.info("Database coordination completed for attempt %s", index_attempt_id)
def active_indexing_attempt(
@@ -871,7 +881,7 @@ def check_for_indexing(self: Task, *, tenant_id: str) -> int | None:
if is_fence(key_bytes) and not redis_client.sismember(
OnyxRedisConstants.ACTIVE_FENCES, key_bytes
):
- logger.warning(f"Adding {key_bytes} to the lookup table.")
+ logger.warning("Adding %s to the lookup table.", key_bytes)
redis_client.sadd(OnyxRedisConstants.ACTIVE_FENCES, key_bytes)
redis_client.set(
@@ -1377,7 +1387,9 @@ def _check_failure_threshold(
FAILURE_RATIO_THRESHOLD = 0.1
if total_failures > FAILURE_THRESHOLD and failure_ratio > FAILURE_RATIO_THRESHOLD:
logger.error(
- f"Connector run failed with '{total_failures}' errors after '{batch_num}' batches."
+ "Connector run failed with '%s' errors after '%s' batches.",
+ total_failures,
+ batch_num,
)
if last_failure and last_failure.exception:
raise last_failure.exception from last_failure.exception
@@ -1421,7 +1433,7 @@ def _resolve_indexing_document_errors(
if document_id not in doc_id_to_unresolved_errors:
continue
- logger.info(f"Resolving IndexAttemptError for document '{document_id}'")
+ logger.info("Resolving IndexAttemptError for document '%s'", document_id)
for error in doc_id_to_unresolved_errors[document_id]:
error.is_resolved = True
db_session_temp.add(error)
diff --git a/backend/onyx/background/celery/tasks/docprocessing/utils.py b/backend/onyx/background/celery/tasks/docprocessing/utils.py
index a79900d43f..98e0bfba01 100644
--- a/backend/onyx/background/celery/tasks/docprocessing/utils.py
+++ b/backend/onyx/background/celery/tasks/docprocessing/utils.py
@@ -68,9 +68,10 @@ class IndexingCallbackBase(IndexingHeartbeatInterface):
elapsed = time.monotonic() - self.start_monotonic
if elapsed > self.timeout_seconds:
logger.warning(
- f"IndexingCallback Docprocessing - task timeout exceeded: "
- f"elapsed={elapsed:.0f}s timeout={self.timeout_seconds}s "
- f"cc_pair={self.redis_connector.cc_pair_id}"
+ "IndexingCallback Docprocessing - task timeout exceeded: elapsed=%ss timeout=%ss cc_pair=%s",
+ format(elapsed, ".0f"),
+ self.timeout_seconds,
+ self.redis_connector.cc_pair_id,
)
return True
@@ -107,12 +108,13 @@ class IndexingCallbackBase(IndexingHeartbeatInterface):
self.last_tag = tag
except LockError:
logger.exception(
- f"{self.__class__.__name__} - lock.reacquire exceptioned: "
- f"lock_timeout={self.redis_lock.timeout} "
- f"start={self.started} "
- f"last_tag={self.last_tag} "
- f"last_reacquired={self.last_lock_reacquire} "
- f"now={datetime.now(timezone.utc)}"
+ "%s - lock.reacquire exceptioned: lock_timeout=%s start=%s last_tag=%s last_reacquired=%s now=%s",
+ self.__class__.__name__,
+ self.redis_lock.timeout,
+ self.started,
+ self.last_tag,
+ self.last_lock_reacquire,
+ datetime.now(timezone.utc),
)
redis_lock_dump(self.redis_lock, self.redis_client)
diff --git a/backend/onyx/background/celery/tasks/evals/tasks.py b/backend/onyx/background/celery/tasks/evals/tasks.py
index f897aad96d..bce3132eb7 100644
--- a/backend/onyx/background/celery/tasks/evals/tasks.py
+++ b/backend/onyx/background/celery/tasks/evals/tasks.py
@@ -84,7 +84,10 @@ def scheduled_eval_task(self: Task, **kwargs: Any) -> None: # noqa: ARG001
run_timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d")
logger.info(
- f"Starting scheduled eval pipeline for project '{project_name}' with {len(dataset_names)} dataset(s): {dataset_names}"
+ "Starting scheduled eval pipeline for project '%s' with %s dataset(s): %s",
+ project_name,
+ len(dataset_names),
+ dataset_names,
)
pipeline_start = datetime.now(timezone.utc)
@@ -100,7 +103,9 @@ def scheduled_eval_task(self: Task, **kwargs: Any) -> None: # noqa: ARG001
try:
logger.info(
- f"Running scheduled eval for dataset: {dataset_name} (project: {project_name})"
+ "Running scheduled eval for dataset: %s (project: %s)",
+ dataset_name,
+ project_name,
)
configuration = EvalConfigurationOptions(
@@ -116,10 +121,10 @@ def scheduled_eval_task(self: Task, **kwargs: Any) -> None: # noqa: ARG001
remote_dataset_name=dataset_name,
)
success = result.success
- logger.info(f"Completed eval for {dataset_name}: success={success}")
+ logger.info("Completed eval for %s: success=%s", dataset_name, success)
except Exception as e:
- logger.exception(f"Failed to run scheduled eval for {dataset_name}")
+ logger.exception("Failed to run scheduled eval for %s", dataset_name)
error_message = str(e)
success = False
@@ -140,5 +145,8 @@ def scheduled_eval_task(self: Task, **kwargs: Any) -> None: # noqa: ARG001
passed_count = sum(1 for r in results if r["success"])
logger.info(
- f"Scheduled eval pipeline completed: {passed_count}/{len(results)} passed in {total_duration:.1f}s"
+ "Scheduled eval pipeline completed: %s/%s passed in %ss",
+ passed_count,
+ len(results),
+ format(total_duration, ".1f"),
)
diff --git a/backend/onyx/background/celery/tasks/opensearch_migration/transformer.py b/backend/onyx/background/celery/tasks/opensearch_migration/transformer.py
index ecd0e1e96c..e395b3ee43 100644
--- a/backend/onyx/background/celery/tasks/opensearch_migration/transformer.py
+++ b/backend/onyx/background/celery/tasks/opensearch_migration/transformer.py
@@ -202,9 +202,9 @@ def transform_vespa_chunks_to_opensearch_chunks(
# function.
if vespa_document_id in sanitized_to_original_doc_id_mapping:
logger.warning(
- f"Migration warning: Vespa document ID {vespa_document_id} does not match the document ID supplied "
- f"{sanitized_to_original_doc_id_mapping[vespa_document_id]}. "
- "The Vespa ID will be discarded."
+ "Migration warning: Vespa document ID %s does not match the document ID supplied %s. The Vespa ID will be discarded.",
+ vespa_document_id,
+ sanitized_to_original_doc_id_mapping[vespa_document_id],
)
document_id = sanitized_to_original_doc_id_mapping.get(
vespa_document_id, vespa_document_id
@@ -287,9 +287,9 @@ def transform_vespa_chunks_to_opensearch_chunks(
)
if not is_public and not acl_list:
logger.warning(
- f"Migration warning: Vespa chunk with document ID {vespa_document_id} and chunk index {chunk_index} has no "
- "public ACL and no access control list. This does not make sense as it implies the document is never "
- "searchable. Continuing with the migration..."
+ "Migration warning: Vespa chunk with document ID %s and chunk index %s has no public ACL and no access control list. This does not make sense as it implies the document is never searchable. Continuing with the migration...",
+ vespa_document_id,
+ chunk_index,
)
chunk_tenant_id: str | None = vespa_chunk.get(TENANT_ID)
@@ -338,9 +338,9 @@ def transform_vespa_chunks_to_opensearch_chunks(
except Exception:
traceback.print_exc()
logger.exception(
- f"Migration error: Error transforming Vespa chunk with document ID {vespa_chunk.get(DOCUMENT_ID)} "
- f"and chunk index {vespa_chunk.get(CHUNK_ID)} into an OpenSearch chunk. Continuing with "
- "the migration..."
+ "Migration error: Error transforming Vespa chunk with document ID %s and chunk index %s into an OpenSearch chunk. Continuing with the migration...",
+ vespa_chunk.get(DOCUMENT_ID),
+ vespa_chunk.get(CHUNK_ID),
)
errored_chunks.append(vespa_chunk)
diff --git a/backend/onyx/background/celery/tasks/pruning/tasks.py b/backend/onyx/background/celery/tasks/pruning/tasks.py
index 03695ab967..baa4a1af15 100644
--- a/backend/onyx/background/celery/tasks/pruning/tasks.py
+++ b/backend/onyx/background/celery/tasks/pruning/tasks.py
@@ -238,18 +238,18 @@ def check_for_pruning(self: Task, *, tenant_id: str) -> bool | None:
cc_pair_id=cc_pair_id,
)
if not cc_pair:
- logger.error(f"CC pair not found: {cc_pair_id}")
+ logger.error("CC pair not found: %s", cc_pair_id)
continue
if not _is_pruning_due(cc_pair):
- logger.info(f"CC pair not due for pruning: {cc_pair_id}")
+ logger.info("CC pair not due for pruning: %s", cc_pair_id)
continue
payload_id = try_creating_prune_generator_task(
self.app, cc_pair, db_session, r, tenant_id
)
if not payload_id:
- logger.info(f"Pruning not created: {cc_pair_id}")
+ logger.info("Pruning not created: %s", cc_pair_id)
continue
prune_dispatched = True
@@ -328,7 +328,7 @@ def try_creating_prune_generator_task(
is used to trigger prunes immediately, e.g. via the web ui.
"""
- logger.info(f"try_creating_prune_generator_task: cc_pair={cc_pair.id}")
+ logger.info("try_creating_prune_generator_task: cc_pair=%s", cc_pair.id)
redis_connector = RedisConnector(tenant_id, cc_pair.id)
@@ -336,7 +336,8 @@ def try_creating_prune_generator_task(
count = redis_connector.prune.get_active_task_count()
if count > 0:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} no simultaneous pruning allowed"
+ "try_creating_prune_generator_task: cc_pair=%s no simultaneous pruning allowed",
+ cc_pair.id,
)
return None
@@ -352,7 +353,8 @@ def try_creating_prune_generator_task(
acquired = lock.acquire(blocking_timeout=LOCK_TIMEOUT / 2)
if not acquired:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} lock not acquired"
+ "try_creating_prune_generator_task: cc_pair=%s lock not acquired",
+ cc_pair.id,
)
return None
@@ -360,28 +362,30 @@ def try_creating_prune_generator_task(
# skip pruning if already pruning
if redis_connector.prune.fenced:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} already pruning"
+ "try_creating_prune_generator_task: cc_pair=%s already pruning",
+ cc_pair.id,
)
return None
# skip pruning if the cc_pair is deleting
if redis_connector.delete.fenced:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} deleting"
+ "try_creating_prune_generator_task: cc_pair=%s deleting", cc_pair.id
)
return None
# skip pruning if doc permissions sync is running
if redis_connector.permissions.fenced:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} permissions sync running"
+ "try_creating_prune_generator_task: cc_pair=%s permissions sync running",
+ cc_pair.id,
)
return None
db_session.refresh(cc_pair)
if cc_pair.status == ConnectorCredentialPairStatus.DELETING:
logger.info(
- f"try_creating_prune_generator_task: cc_pair={cc_pair.id} deleting"
+ "try_creating_prune_generator_task: cc_pair=%s deleting", cc_pair.id
)
return None
@@ -507,7 +511,8 @@ def connector_pruning_generator_task(
if payload.celery_task_id is None:
logger.info(
- f"connector_prune_generator_task - Waiting for fence: fence={redis_connector.prune.fence_key}"
+ "connector_prune_generator_task - Waiting for fence: fence=%s",
+ redis_connector.prune.fence_key,
)
time.sleep(1)
continue
@@ -515,9 +520,9 @@ def connector_pruning_generator_task(
payload_id = payload.id
logger.info(
- f"connector_prune_generator_task - Fence found, continuing...: "
- f"fence={redis_connector.prune.fence_key} "
- f"payload_id={payload.id}"
+ "connector_prune_generator_task - Fence found, continuing...: fence=%s payload_id=%s",
+ redis_connector.prune.fence_key,
+ payload.id,
)
break
diff --git a/backend/onyx/background/celery/tasks/vespa/document_sync.py b/backend/onyx/background/celery/tasks/vespa/document_sync.py
index a1c2c0df1f..94ebabafd5 100644
--- a/backend/onyx/background/celery/tasks/vespa/document_sync.py
+++ b/backend/onyx/background/celery/tasks/vespa/document_sync.py
@@ -156,7 +156,8 @@ def try_generate_stale_document_sync_tasks(
maybe_mark_tenant_active(tenant_id, caller="vespa_sync")
logger.info(
- f"Stale documents found (at least {stale_doc_count}). Generating sync tasks in one batch."
+ "Stale documents found (at least %s). Generating sync tasks in one batch.",
+ stale_doc_count,
)
logger.info("generate_document_sync_tasks starting for all documents.")
@@ -173,13 +174,15 @@ def try_generate_stale_document_sync_tasks(
if tasks_generated >= max_tasks:
logger.info(
- f"generate_document_sync_tasks reached the task generation limit: "
- f"tasks_generated={tasks_generated} max_tasks={max_tasks}"
+ "generate_document_sync_tasks reached the task generation limit: tasks_generated=%s max_tasks=%s",
+ tasks_generated,
+ max_tasks,
)
else:
logger.info(
- f"generate_document_sync_tasks finished for all documents. "
- f"tasks_generated={tasks_generated} total_docs_found={total_docs}"
+ "generate_document_sync_tasks finished for all documents. tasks_generated=%s total_docs_found=%s",
+ tasks_generated,
+ total_docs,
)
set_document_sync_fence(r, tasks_generated)
diff --git a/backend/onyx/background/indexing/checkpointing_utils.py b/backend/onyx/background/indexing/checkpointing_utils.py
index 3f27e22308..8b6be2df35 100644
--- a/backend/onyx/background/indexing/checkpointing_utils.py
+++ b/backend/onyx/background/indexing/checkpointing_utils.py
@@ -98,9 +98,9 @@ def get_latest_valid_checkpoint(
if not had_any_progress:
logger.warning(
- f"{_NUM_RECENT_ATTEMPTS_TO_CONSIDER} consecutive failed attempts without progress "
- f"found for cc_pair={cc_pair_id}. Ignoring checkpoint to let the run start "
- "from scratch."
+ "%s consecutive failed attempts without progress found for cc_pair=%s. Ignoring checkpoint to let the run start from scratch.",
+ _NUM_RECENT_ATTEMPTS_TO_CONSIDER,
+ cc_pair_id,
)
return connector.build_dummy_checkpoint(), False
@@ -141,7 +141,8 @@ def get_latest_valid_checkpoint(
checkpoint = connector.build_dummy_checkpoint()
if latest_valid_checkpoint_candidate is None:
logger.info(
- f"No valid checkpoint found for cc_pair={cc_pair_id}. Starting from scratch."
+ "No valid checkpoint found for cc_pair=%s. Starting from scratch.",
+ cc_pair_id,
)
return checkpoint, False
@@ -152,15 +153,15 @@ def get_latest_valid_checkpoint(
)
except Exception:
logger.exception(
- f"Failed to load checkpoint from previous failed attempt with ID "
- f"{latest_valid_checkpoint_candidate.id}. Falling back to default checkpoint."
+ "Failed to load checkpoint from previous failed attempt with ID %s. Falling back to default checkpoint.",
+ latest_valid_checkpoint_candidate.id,
)
return checkpoint, False
logger.info(
- f"Using checkpoint from previous failed attempt with ID "
- f"{latest_valid_checkpoint_candidate.id}. Previous checkpoint: "
- f"{previous_checkpoint}"
+ "Using checkpoint from previous failed attempt with ID %s. Previous checkpoint: %s",
+ latest_valid_checkpoint_candidate.id,
+ previous_checkpoint,
)
return previous_checkpoint, True
diff --git a/backend/onyx/background/indexing/dask_utils.py b/backend/onyx/background/indexing/dask_utils.py
index 1f1ccb566c..c11377ba78 100644
--- a/backend/onyx/background/indexing/dask_utils.py
+++ b/backend/onyx/background/indexing/dask_utils.py
@@ -28,6 +28,9 @@ class ResourceLogger(WorkerPlugin):
memory_available_gb = psutil.virtual_memory().available / (1024.0**3)
# You can now log these values or send them to a monitoring service
logger.debug(
- f"Worker {self.worker.address}: CPU usage {cpu_percent}%, Memory available {memory_available_gb}GB"
+ "Worker %s: CPU usage %s%%, Memory available %sGB",
+ self.worker.address,
+ cpu_percent,
+ memory_available_gb,
)
await asyncio.sleep(self.log_interval)
diff --git a/backend/onyx/background/indexing/job_client.py b/backend/onyx/background/indexing/job_client.py
index 934a45c081..eb06055c7b 100644
--- a/backend/onyx/background/indexing/job_client.py
+++ b/backend/onyx/background/indexing/job_client.py
@@ -140,15 +140,19 @@ class SimpleJob:
pid = self.process.pid
logger.warning(
- f"SimpleJob.terminate_and_wait - sending SIGTERM to job: id={self.id} pid={pid}"
+ "SimpleJob.terminate_and_wait - sending SIGTERM to job: id=%s pid=%s",
+ self.id,
+ pid,
)
self.process.terminate()
self.process.join(timeout=sigterm_grace_seconds)
if self.process.is_alive():
logger.warning(
- f"SimpleJob.terminate_and_wait - SIGTERM grace exceeded, sending SIGKILL: "
- f"id={self.id} pid={pid} grace={sigterm_grace_seconds}s"
+ "SimpleJob.terminate_and_wait - SIGTERM grace exceeded, sending SIGKILL: id=%s pid=%s grace=%ss",
+ self.id,
+ pid,
+ sigterm_grace_seconds,
)
self.process.kill()
self.process.join()
@@ -201,7 +205,7 @@ class SimpleJobClient:
for job_id in current_job_ids:
job = self.jobs.get(job_id)
if job and job.done():
- logger.debug(f"Cleaning up job with id: '{job.id}'")
+ logger.debug("Cleaning up job with id: '%s'", job.id)
del self.jobs[job.id]
def submit(
@@ -214,7 +218,9 @@ class SimpleJobClient:
self._cleanup_completed_jobs()
if len(self.jobs) >= self.n_workers:
logger.debug(
- f"No available workers to run job. Currently running '{len(self.jobs)}' jobs, with a limit of '{self.n_workers}'."
+ "No available workers to run job. Currently running '%s' jobs, with a limit of '%s'.",
+ len(self.jobs),
+ self.n_workers,
)
return None
diff --git a/backend/onyx/background/indexing/memory_tracer.py b/backend/onyx/background/indexing/memory_tracer.py
index a23af2e922..05e21d82fd 100644
--- a/backend/onyx/background/indexing/memory_tracer.py
+++ b/backend/onyx/background/indexing/memory_tracer.py
@@ -19,7 +19,7 @@ class MemoryTracer:
def start(self) -> None:
"""Start the memory tracer if interval is greater than 0."""
if self.interval > 0:
- logger.debug(f"Memory tracer starting: interval={self.interval}")
+ logger.debug("Memory tracer starting: interval=%s", self.interval)
tracemalloc.start(DANSWER_TRACEMALLOC_FRAMES)
self._take_snapshot()
@@ -56,9 +56,9 @@ class MemoryTracer:
"""Log the memory difference between two snapshots."""
stats = current.compare_to(previous, "traceback")
for s in stats[: self.num_print_entries]:
- logger.debug(f"Tracer diff: {s}")
+ logger.debug("Tracer diff: %s", s)
for line in s.traceback.format():
- logger.debug(f"* {line}")
+ logger.debug("* %s", line)
def increment_and_maybe_trace(self) -> None:
"""Increment counter and perform trace if interval is hit."""
@@ -68,7 +68,9 @@ class MemoryTracer:
self.counter += 1
if self.counter % self.interval == 0:
logger.debug(
- f"Running trace comparison for batch {self.counter}. interval={self.interval}"
+ "Running trace comparison for batch %s. interval=%s",
+ self.counter,
+ self.interval,
)
self._take_snapshot()
if self.snapshot and self.snapshot_prev:
@@ -80,7 +82,8 @@ class MemoryTracer:
return
logger.debug(
- f"Running trace comparison between start and end of indexing. {self.counter} batches processed."
+ "Running trace comparison between start and end of indexing. %s batches processed.",
+ self.counter,
)
self._take_snapshot()
if self.snapshot and self.snapshot_first:
diff --git a/backend/onyx/background/indexing/run_docfetching.py b/backend/onyx/background/indexing/run_docfetching.py
index bd5ea1de53..246c2a9d3a 100644
--- a/backend/onyx/background/indexing/run_docfetching.py
+++ b/backend/onyx/background/indexing/run_docfetching.py
@@ -220,7 +220,7 @@ def strip_null_characters(doc_batch: list[Document]) -> list[Document]:
for doc in doc_batch:
if sys.getsizeof(doc) > MAX_FILE_SIZE_BYTES:
logger.warning(
- f"doc {doc.id} too large, Document size: {sys.getsizeof(doc)}"
+ "doc %s too large, Document size: %s", doc.id, sys.getsizeof(doc)
)
cleaned_batch.append(sanitize_document_for_postgres(doc))
@@ -289,7 +289,9 @@ def _check_failure_threshold(
FAILURE_RATIO_THRESHOLD = 0.1
if total_failures > FAILURE_THRESHOLD and failure_ratio > FAILURE_RATIO_THRESHOLD:
logger.error(
- f"Connector run failed with '{total_failures}' errors after '{batch_num}' batches."
+ "Connector run failed with '%s' errors after '%s' batches.",
+ total_failures,
+ batch_num,
)
if last_failure and last_failure.exception:
raise last_failure.exception from last_failure.exception
@@ -331,10 +333,11 @@ def run_docfetching_entrypoint(
credential_id = attempt.connector_credential_pair.credential_id
logger.info(
- f"Docfetching starting{tenant_str}: "
- f"connector='{connector_name}' "
- f"config='{connector_config}' "
- f"credentials='{credential_id}'"
+ "Docfetching starting%s: connector='%s' config='%s' credentials='%s'",
+ tenant_str,
+ connector_name,
+ connector_config,
+ credential_id,
)
raw_file_callback = build_raw_file_callback(
@@ -366,10 +369,11 @@ def run_docfetching_entrypoint(
)
logger.info(
- f"Docfetching finished{tenant_str}: "
- f"connector='{connector_name}' "
- f"config='{connector_config}' "
- f"credentials='{credential_id}'"
+ "Docfetching finished%s: connector='%s' config='%s' credentials='%s'",
+ tenant_str,
+ connector_name,
+ connector_config,
+ credential_id,
)
INDEX_ATTEMPT_INFO_CONTEXTVAR.reset(token)
@@ -393,11 +397,11 @@ def connector_document_extraction(
start_time = time.monotonic()
logger.info(
- f"Document extraction starting: "
- f"attempt={index_attempt_id} "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id} "
- f"tenant={tenant_id}"
+ "Document extraction starting: attempt=%s cc_pair=%s search_settings=%s tenant=%s",
+ index_attempt_id,
+ cc_pair_id,
+ search_settings_id,
+ tenant_id,
)
# Get batch storage (transition to IN_PROGRESS is handled by run_indexing_entrypoint)
@@ -427,9 +431,9 @@ def connector_document_extraction(
# Clear the indexing trigger if it was set, to prevent duplicate indexing attempts
if index_attempt.connector_credential_pair.indexing_trigger is not None:
logger.info(
- "Clearing indexing trigger: "
- f"cc_pair={index_attempt.connector_credential_pair.id} "
- f"trigger={index_attempt.connector_credential_pair.indexing_trigger}"
+ "Clearing indexing trigger: cc_pair=%s trigger=%s",
+ index_attempt.connector_credential_pair.id,
+ index_attempt.connector_credential_pair.indexing_trigger,
)
mark_ccpair_with_indexing_trigger(
index_attempt.connector_credential_pair.id, None, db_session
@@ -546,13 +550,15 @@ def connector_document_extraction(
most_recent_attempt and most_recent_attempt.status.is_successful()
):
logger.info(
- f"Cleaning up all old batches for index attempt {index_attempt_id} before starting new run"
+ "Cleaning up all old batches for index attempt %s before starting new run",
+ index_attempt_id,
)
batch_storage.cleanup_all_batches()
checkpoint = connector_runner.connector.build_dummy_checkpoint()
else:
logger.info(
- f"Getting latest valid checkpoint for index attempt {index_attempt_id}"
+ "Getting latest valid checkpoint for index attempt %s",
+ index_attempt_id,
)
checkpoint, resuming_from_checkpoint = get_latest_valid_checkpoint(
db_session=db_session,
@@ -586,7 +592,8 @@ def connector_document_extraction(
db_session.commit()
else:
logger.info(
- f"Cleaning up all batches for index attempt {index_attempt_id} before starting new run"
+ "Cleaning up all batches for index attempt %s before starting new run",
+ index_attempt_id,
)
# for non-checkpointed connectors, throw out batches from previous unsuccessful attempts
# because we'll be getting those documents again anyways.
@@ -615,7 +622,9 @@ def connector_document_extraction(
# Main extraction loop
while checkpoint.has_more:
logger.info(
- f"Running '{db_connector.source.value}' connector with checkpoint: {checkpoint}"
+ "Running '%s' connector with checkpoint: %s",
+ db_connector.source.value,
+ checkpoint,
)
for (
document_batch,
@@ -718,7 +727,9 @@ def connector_document_extraction(
)
logger.debug(
- f"Persisted and cached {len(hierarchy_node_batch_cleaned)} hierarchy nodes for attempt={index_attempt_id}"
+ "Persisted and cached %s hierarchy nodes for attempt=%s",
+ len(hierarchy_node_batch_cleaned),
+ index_attempt_id,
)
# below is all document processing task, so if no batch we can just continue
@@ -762,12 +773,13 @@ def connector_document_extraction(
if doc_size > INDEXING_SIZE_WARNING_THRESHOLD:
logger.warning(
- f"Document size: doc='{doc.to_short_descriptor()}' "
- f"size={doc_size} "
- f"threshold={INDEXING_SIZE_WARNING_THRESHOLD}"
+ "Document size: doc='%s' size=%s threshold=%s",
+ doc.to_short_descriptor(),
+ doc_size,
+ INDEXING_SIZE_WARNING_THRESHOLD,
)
- logger.debug(f"Indexing batch of documents: {batch_description}")
+ logger.debug("Indexing batch of documents: %s", batch_description)
memory_tracer.increment_and_maybe_trace()
if processing_mode == ProcessingMode.FILE_SYSTEM:
@@ -835,10 +847,10 @@ def connector_document_extraction(
total_doc_batches_queued += 1
logger.info(
- f"Wrote documents to file system: "
- f"batch_num={batch_num} "
- f"docs={len(written_paths)} "
- f"attempt={index_attempt_id}"
+ "Wrote documents to file system: batch_num=%s docs=%s attempt=%s",
+ batch_num,
+ len(written_paths),
+ index_attempt_id,
)
else:
# REGULAR mode (default): Full pipeline - store and queue docprocessing
@@ -873,10 +885,10 @@ def connector_document_extraction(
total_doc_batches_queued += 1
logger.info(
- f"Queued document processing batch: "
- f"batch_num={batch_num} "
- f"docs={len(doc_batch_cleaned)} "
- f"attempt={index_attempt_id}"
+ "Queued document processing batch: batch_num=%s docs=%s attempt=%s",
+ batch_num,
+ len(doc_batch_cleaned),
+ index_attempt_id,
)
# Check checkpoint size periodically
@@ -898,10 +910,10 @@ def connector_document_extraction(
elapsed_time = time.monotonic() - start_time
logger.info(
- f"Document extraction completed: "
- f"attempt={index_attempt_id} "
- f"batches_queued={total_doc_batches_queued} "
- f"elapsed={elapsed_time:.2f}s"
+ "Document extraction completed: attempt=%s batches_queued=%s elapsed=%ss",
+ index_attempt_id,
+ total_doc_batches_queued,
+ format(elapsed_time, ".2f"),
)
# Set total batches in database to signal extraction completion.
@@ -929,12 +941,14 @@ def connector_document_extraction(
queue=OnyxCeleryQueues.SANDBOX,
)
logger.info(
- f"Triggered sandbox file sync for user {creator_id} source={source_value} after indexing complete"
+ "Triggered sandbox file sync for user %s source=%s after indexing complete",
+ creator_id,
+ source_value,
)
except Exception as e:
logger.exception(
- f"Document extraction failed: attempt={index_attempt_id} error={str(e)}"
+ "Document extraction failed: attempt=%s error=%s", index_attempt_id, str(e)
)
# Do NOT clean up batches on failure; future runs will use those batches
@@ -946,7 +960,8 @@ def connector_document_extraction(
# used in the future until the credentials are updated.
with get_session_with_current_tenant() as db_session_temp:
logger.exception(
- f"Marking attempt {index_attempt_id} as canceled due to validation error."
+ "Marking attempt %s as canceled due to validation error.",
+ index_attempt_id,
)
mark_attempt_canceled(
index_attempt_id,
@@ -980,8 +995,9 @@ def connector_document_extraction(
if num_validation_errors >= VALIDATION_ERROR_THRESHOLD:
logger.warning(
- f"Connector {db_connector.id} has {num_validation_errors} consecutive validation"
- f" errors. Marking the CC Pair as invalid."
+ "Connector %s has %s consecutive validation errors. Marking the CC Pair as invalid.",
+ db_connector.id,
+ num_validation_errors,
)
update_connector_credential_pair(
db_session=db_session_temp,
@@ -993,7 +1009,8 @@ def connector_document_extraction(
elif isinstance(e, ConnectorStopSignal):
with get_session_with_current_tenant() as db_session_temp:
logger.exception(
- f"Marking attempt {index_attempt_id} as canceled due to stop signal."
+ "Marking attempt %s as canceled due to stop signal.",
+ index_attempt_id,
)
mark_attempt_canceled(
index_attempt_id,
@@ -1010,7 +1027,8 @@ def connector_document_extraction(
IndexingStatus.FAILED,
]:
logger.info(
- f"Attempt {index_attempt_id} is already failed/canceled, skipping marking as failed."
+ "Attempt %s is already failed/canceled, skipping marking as failed.",
+ index_attempt_id,
)
raise e
@@ -1042,12 +1060,14 @@ def reissue_old_batches(
batch_storage.update_old_batches_to_new_index_attempt(old_batches)
for batch_id in old_batches:
logger.info(
- f"Re-issuing docprocessing task for batch {batch_id} for index attempt {index_attempt_id}"
+ "Re-issuing docprocessing task for batch %s for index attempt %s",
+ batch_id,
+ index_attempt_id,
)
path_info = batch_storage.extract_path_info(batch_id)
if path_info is None:
logger.warning(
- f"Could not extract path info from batch {batch_id}, skipping"
+ "Could not extract path info from batch %s, skipping", batch_id
)
continue
if path_info.cc_pair_id != cc_pair_id:
@@ -1074,6 +1094,9 @@ def reissue_old_batches(
# is still in the filestore waiting for processing or not.
last_batch_num = len(old_batches) + recent_batches
logger.info(
- f"Starting from batch {last_batch_num} due to re-issued batches: {old_batches}, completed batches: {recent_batches}"
+ "Starting from batch %s due to re-issued batches: %s, completed batches: %s",
+ last_batch_num,
+ old_batches,
+ recent_batches,
)
return len(old_batches), recent_batches
diff --git a/backend/onyx/background/periodic_poller.py b/backend/onyx/background/periodic_poller.py
index a7e1493d54..80414d827e 100644
--- a/backend/onyx/background/periodic_poller.py
+++ b/backend/onyx/background/periodic_poller.py
@@ -102,7 +102,7 @@ def _run_scheduled_eval() -> None:
)
except Exception:
logger.exception(
- f"Periodic poller - Failed scheduled eval for dataset {dataset_name}"
+ "Periodic poller - Failed scheduled eval for dataset %s", dataset_name
)
@@ -208,7 +208,7 @@ def _try_run_periodic_task(task_def: _PeriodicTaskDef) -> None:
task_def.last_run_at = now
except Exception:
logger.exception(
- f"Periodic poller - Error running periodic task {task_def.name}"
+ "Periodic poller - Error running periodic task %s", task_def.name
)
@@ -259,7 +259,9 @@ def _poller_loop(tenant_id: str) -> None:
periodic_tasks = _build_periodic_tasks()
logger.info(
- f"Periodic poller started with {len(periodic_tasks)} periodic task(s): {[t.name for t in periodic_tasks]}"
+ "Periodic poller started with %s periodic task(s): %s",
+ len(periodic_tasks),
+ [t.name for t in periodic_tasks],
)
while not _shutdown_event.is_set():
@@ -273,7 +275,7 @@ def _poller_loop(tenant_id: str) -> None:
_try_run_periodic_task(task_def)
except Exception:
logger.exception(
- f"Periodic poller - Unhandled error checking task {task_def.name}"
+ "Periodic poller - Unhandled error checking task %s", task_def.name
)
_shutdown_event.wait(RECOVERY_INTERVAL_SECONDS)
diff --git a/backend/onyx/background/task_utils.py b/backend/onyx/background/task_utils.py
index 191f048614..e30814fffb 100644
--- a/backend/onyx/background/task_utils.py
+++ b/backend/onyx/background/task_utils.py
@@ -155,7 +155,7 @@ def drain_processing_loop(tenant_id: str) -> None:
redis_locking=False,
)
except Exception:
- logger.exception(f"Failed to process user file {file_id}")
+ logger.exception("Failed to process user file %s", file_id)
def drain_delete_loop(tenant_id: str) -> None:
@@ -178,7 +178,7 @@ def drain_delete_loop(tenant_id: str) -> None:
redis_locking=False,
)
except Exception:
- logger.exception(f"Failed to delete user file {file_id}")
+ logger.exception("Failed to delete user file %s", file_id)
failed.add(file_id)
@@ -202,5 +202,5 @@ def drain_project_sync_loop(tenant_id: str) -> None:
redis_locking=False,
)
except Exception:
- logger.exception(f"Failed to sync user file {file_id}")
+ logger.exception("Failed to sync user file %s", file_id)
failed.add(file_id)
diff --git a/backend/onyx/chat/chat_utils.py b/backend/onyx/chat/chat_utils.py
index efd79d290c..38f600c208 100644
--- a/backend/onyx/chat/chat_utils.py
+++ b/backend/onyx/chat/chat_utils.py
@@ -382,7 +382,7 @@ def _get_or_extract_plaintext(
plaintext_io = file_store.read_file(plaintext_key, mode="b")
return plaintext_io.read().decode("utf-8")
except Exception:
- logger.info(f"Cache miss for file with id={file_id}")
+ logger.info("Cache miss for file with id=%s", file_id)
# Cache miss — extract and store.
content_text = extract_fn()
@@ -424,7 +424,9 @@ def load_chat_file(
content_text = _get_or_extract_plaintext(cache_key, _extract)
except Exception as e:
logger.warning(
- f"Failed to retrieve content for file {file_descriptor['id']}: {str(e)}"
+ "Failed to retrieve content for file %s: %s",
+ file_descriptor["id"],
+ str(e),
)
# Get token count from UserFile if available
@@ -440,7 +442,7 @@ def load_chat_file(
token_count = user_file.token_count
except (ValueError, TypeError) as e:
logger.warning(
- f"Failed to get token count for file {file_descriptor['id']}: {e}"
+ "Failed to get token count for file %s: %s", file_descriptor["id"], e
)
return ChatLoadedFile(
@@ -902,7 +904,7 @@ def build_python_chat_files_from_search_docs(
record = file_store.read_file_record(doc.file_id)
except Exception as e:
logger.warning(
- f"file_id={doc.file_id!r} not found in file store ({e}); skipping."
+ "file_id=%r not found in file store (%s); skipping.", doc.file_id, e
)
continue
@@ -911,8 +913,9 @@ def build_python_chat_files_from_search_docs(
FileOrigin.CONNECTOR_FILE_UPLOAD,
):
logger.warning(
- f"file_id={doc.file_id!r} has origin={record.file_origin!r}, "
- "not eligible for code-interpreter staging; skipping."
+ "file_id=%r has origin=%r, not eligible for code-interpreter staging; skipping.",
+ doc.file_id,
+ record.file_origin,
)
continue
@@ -920,7 +923,7 @@ def build_python_chat_files_from_search_docs(
content = file_store.read_file(doc.file_id, mode="b").read()
except Exception as e:
logger.warning(
- f"Failed to read bytes for file_id={doc.file_id!r}: {e}; skipping."
+ "Failed to read bytes for file_id=%r: %s; skipping.", doc.file_id, e
)
continue
diff --git a/backend/onyx/chat/citation_processor.py b/backend/onyx/chat/citation_processor.py
index 3ed9df696f..bf933102b4 100644
--- a/backend/onyx/chat/citation_processor.py
+++ b/backend/onyx/chat/citation_processor.py
@@ -466,13 +466,15 @@ class DynamicCitationProcessor:
num = int(num_str)
except ValueError:
# Invalid citation, skip it
- logger.warning(f"Invalid citation number format: {num_str}")
+ logger.warning("Invalid citation number format: %s", num_str)
continue
# Check if we have a mapping for this citation number
if num not in self.citation_to_doc:
logger.warning(
- f"Citation number {num} not found in mapping. Available: {list(self.citation_to_doc.keys())}"
+ "Citation number %s not found in mapping. Available: %s",
+ num,
+ list(self.citation_to_doc.keys()),
)
continue
diff --git a/backend/onyx/chat/compression.py b/backend/onyx/chat/compression.py
index 89a049e2b1..2ad4a3bcc2 100644
--- a/backend/onyx/chat/compression.py
+++ b/backend/onyx/chat/compression.py
@@ -369,8 +369,10 @@ def compress_chat_history(
chat_session_id = chat_history[0].chat_session_id
logger.info(
- f"Starting compression for session {chat_session_id}, "
- f"history_len={len(chat_history)}, tokens_for_recent={compression_params.tokens_for_recent}"
+ "Starting compression for session %s, history_len=%s, tokens_for_recent=%s",
+ chat_session_id,
+ len(chat_history),
+ compression_params.tokens_for_recent,
)
with ensure_trace(
@@ -412,7 +414,9 @@ def compress_chat_history(
tokenizer = get_tokenizer(None, None)
summary_token_count = len(tokenizer.encode(summary_text))
logger.debug(
- f"Generated summary ({summary_token_count} tokens): {summary_text[:200]}..."
+ "Generated summary (%s tokens): %s...",
+ summary_token_count,
+ summary_text[:200],
)
# Create new summary as a ChatMessage
@@ -429,9 +433,10 @@ def compress_chat_history(
db_session.commit()
logger.info(
- f"Compressed {len(summary_content.older_messages)} messages into summary "
- f"(session_id={chat_session_id}, "
- f"summary_tokens={summary_token_count})"
+ "Compressed %s messages into summary (session_id=%s, summary_tokens=%s)",
+ len(summary_content.older_messages),
+ chat_session_id,
+ summary_token_count,
)
return CompressionResult(
@@ -440,7 +445,9 @@ def compress_chat_history(
)
except Exception as e:
- logger.exception(f"Compression failed for session {chat_session_id}: {e}")
+ logger.exception(
+ "Compression failed for session %s: %s", chat_session_id, e
+ )
db_session.rollback()
return CompressionResult(
summary_created=False,
diff --git a/backend/onyx/chat/llm_loop.py b/backend/onyx/chat/llm_loop.py
index 4773d3266f..ef6d4f4843 100644
--- a/backend/onyx/chat/llm_loop.py
+++ b/backend/onyx/chat/llm_loop.py
@@ -218,7 +218,8 @@ def _try_fallback_tool_extraction(
)
if extracted_tool_calls:
logger.info(
- f"Extracted {len(extracted_tool_calls)} tool call(s) from response text as fallback"
+ "Extracted %s tool call(s) from response text as fallback",
+ len(extracted_tool_calls),
)
return (
LlmStepResult(
@@ -457,7 +458,8 @@ def construct_message_history(
]
if forgotten_meta:
logger.debug(
- f"FileReader: building forgotten-files message for {[(m.file_id, m.filename) for m in forgotten_meta]}"
+ "FileReader: building forgotten-files message for %s",
+ [(m.file_id, m.filename) for m in forgotten_meta],
)
forgotten_files_message = _create_file_tool_metadata_message(
forgotten_meta, token_counter
diff --git a/backend/onyx/chat/llm_step.py b/backend/onyx/chat/llm_step.py
index 97bb19638f..efbe5a6264 100644
--- a/backend/onyx/chat/llm_step.py
+++ b/backend/onyx/chat/llm_step.py
@@ -483,7 +483,8 @@ def extract_tool_calls_from_response_text(
)
logger.info(
- f"Extracted {len(tool_calls)} tool call(s) from response text as fallback"
+ "Extracted %s tool call(s) from response text as fallback",
+ len(tool_calls),
)
return tool_calls
@@ -843,7 +844,9 @@ def translate_history_to_llm_format(
content_parts.append(image_part)
except Exception as e:
logger.warning(
- f"Failed to process image file {img_file.file_id}: {e}. Skipping image."
+ "Failed to process image file %s: %s. Skipping image.",
+ img_file.file_id,
+ e,
)
user_msg = UserMessage(
role="user",
@@ -876,7 +879,8 @@ def translate_history_to_llm_format(
else:
logger.warning(
- f"Unknown message type {msg.message_type} in history. Skipping message."
+ "Unknown message type %s in history. Skipping message.",
+ msg.message_type,
)
# Apply model-specific formatting when translating to LLM format (e.g. OpenAI
@@ -1010,7 +1014,8 @@ def run_llm_step_pkt_generator(
if LOG_ONYX_MODEL_INTERACTIONS:
logger.debug(
- f"Message history:\n{_format_message_history_for_logging(llm_msg_history)}"
+ "Message history:\n%s",
+ _format_message_history_for_logging(llm_msg_history),
)
id_to_tool_call_map: dict[int, dict[str, Any]] = {}
@@ -1181,7 +1186,9 @@ def run_llm_step_pkt_generator(
empty_chunk_count += 1
logger.warning(
"LLM packet is empty (no content, reasoning, or tool calls). "
- f"finish_reason={finish_reason}. Skipping: {packet}"
+ "finish_reason=%s. Skipping: %s",
+ finish_reason,
+ packet,
)
continue
@@ -1315,25 +1322,32 @@ def run_llm_step_pkt_generator(
# Note: Content (AgentResponseDelta) doesn't need an explicit end packet - OverallStop handles it
# Tool calls are handled by tool execution code and emit their own packets (e.g., SectionEnd)
if LOG_ONYX_MODEL_INTERACTIONS:
- logger.debug(f"Accumulated reasoning: {accumulated_reasoning}")
- logger.debug(f"Accumulated answer: {accumulated_answer}")
+ logger.debug("Accumulated reasoning: %s", accumulated_reasoning)
+ logger.debug("Accumulated answer: %s", accumulated_answer)
if tool_calls:
tool_calls_str = "\n".join(
f" - {tc.tool_name}: {json.dumps(tc.tool_args, indent=4)}"
for tc in tool_calls
)
- logger.debug(f"Tool calls:\n{tool_calls_str}")
+ logger.debug("Tool calls:\n%s", tool_calls_str)
else:
logger.debug("Tool calls: []")
if actionable_chunk_count == 0:
logger.warning(
"LLM stream completed with no actionable deltas. "
- f"chunks={stream_chunk_count}, empty_chunks={empty_chunk_count}, "
- f"finish_reasons={sorted(finish_reasons)}, "
- f"provider={llm.config.model_provider}, model={llm.config.model_name}, "
- f"tool_choice={tool_choice}, tools_sent={len(tool_definitions)}"
+ "chunks=%s, empty_chunks=%s, "
+ "finish_reasons=%s, "
+ "provider=%s, model=%s, "
+ "tool_choice=%s, tools_sent=%s",
+ stream_chunk_count,
+ empty_chunk_count,
+ sorted(finish_reasons),
+ llm.config.model_provider,
+ llm.config.model_name,
+ tool_choice,
+ len(tool_definitions),
)
return (
diff --git a/backend/onyx/chat/process_message.py b/backend/onyx/chat/process_message.py
index 5804fff31f..e040d8cac4 100644
--- a/backend/onyx/chat/process_message.py
+++ b/backend/onyx/chat/process_message.py
@@ -277,7 +277,8 @@ def _fetch_cached_image_captions(
)
except Exception:
logger.warning(
- f"Failed to fetch cached captions for user_file {user_file.id}",
+ "Failed to fetch cached captions for user_file %s",
+ user_file.id,
exc_info=True,
)
return []
@@ -354,7 +355,7 @@ def _extract_text_from_in_memory_file(
return "\n\n".join(parts).strip() or None
except Exception:
- logger.warning(f"Failed to extract text from file {f.file_id}", exc_info=True)
+ logger.warning("Failed to extract text from file %s", f.file_id, exc_info=True)
return None
@@ -466,7 +467,8 @@ def extract_context_files(
# Only the metadata is provided, with LLM using tools
if not uf:
logger.error(
- f"File with id={f.file_id} in metadata-only path with no associated user file"
+ "File with id=%s in metadata-only path with no associated user file",
+ f.file_id,
)
continue
tool_metadata.append(_build_tool_metadata(uf))
@@ -477,7 +479,7 @@ def extract_context_files(
if not text_content:
continue
if not uf:
- logger.warning(f"No user file for file_id={f.file_id}")
+ logger.warning("No user file for file_id=%s", f.file_id)
continue
file_texts.append(text_content)
file_metadata.append(
@@ -980,7 +982,8 @@ def build_chat_turn(
if all_injected_file_metadata:
logger.debug(
- f"FileReader: file metadata for LLM: {[(fid, m.filename) for fid, m in all_injected_file_metadata.items()]}"
+ "FileReader: file metadata for LLM: %s",
+ [(fid, m.filename) for fid, m in all_injected_file_metadata.items()],
)
if summary_message is not None:
@@ -1506,7 +1509,10 @@ def _stream_chat_turn(
except EmptyLLMResponseError as e:
stack_trace = traceback.format_exc()
logger.warning(
- f"LLM returned an empty response (provider={e.provider}, model={e.model}, tool_choice={e.tool_choice})"
+ "LLM returned an empty response (provider=%s, model=%s, tool_choice=%s)",
+ e.provider,
+ e.model,
+ e.tool_choice,
)
yield StreamingError(
error=e.client_error_msg,
@@ -1522,7 +1528,7 @@ def _stream_chat_turn(
db_session.rollback()
except Exception as e:
- logger.exception(f"Failed to process chat message due to {e}")
+ logger.exception("Failed to process chat message due to %s", e)
stack_trace = traceback.format_exc()
llm = setup.llms[0] if setup else None
@@ -1689,7 +1695,7 @@ def llm_loop_completion_handle(
final_answer = answer_tokens
else:
# Stopped by user - append stop message
- logger.debug(f"Chat session {chat_session_id} stopped by user")
+ logger.debug("Chat session %s stopped by user", chat_session_id)
if answer_tokens:
final_answer = (
answer_tokens + " ... \n\nGeneration was stopped by the user."
diff --git a/backend/onyx/chat/save_chat.py b/backend/onyx/chat/save_chat.py
index 9bb3791d91..5a6393152e 100644
--- a/backend/onyx/chat/save_chat.py
+++ b/backend/onyx/chat/save_chat.py
@@ -87,7 +87,9 @@ def _create_and_link_tool_calls(
tool_call_tokens = len(default_tokenizer.encode(arguments_json_str))
except Exception as e:
logger.warning(
- f"Failed to tokenize tool call arguments for {tool_call_info.tool_call_id}: {e}. Using length as (over) estimate."
+ "Failed to tokenize tool call arguments for %s: %s. Using length as (over) estimate.",
+ tool_call_info.tool_call_id,
+ e,
)
arguments_json_str = json.dumps(tool_call_info.tool_call_arguments)
tool_call_tokens = len(arguments_json_str)
@@ -143,8 +145,9 @@ def _create_and_link_tool_calls(
else:
# Parent doesn't exist (likely cancelled) - skip this orphaned child
logger.warning(
- f"Skipping tool call '{tool_call_obj.tool_call_id}' with missing parent "
- f"'{tool_call_info.parent_tool_call_id}' (likely cancelled during execution)"
+ "Skipping tool call '%s' with missing parent '%s' (likely cancelled during execution)",
+ tool_call_obj.tool_call_id,
+ tool_call_info.parent_tool_call_id,
)
# Remove from DB session to prevent saving
db_session.delete(tool_call_obj)
@@ -283,11 +286,13 @@ def save_chat_turn(
if is_project_file:
logger.info(
- f"Project file citation {search_doc_py.document_id} not in tool calls, creating it"
+ "Project file citation %s not in tool calls, creating it",
+ search_doc_py.document_id,
)
else:
logger.warning(
- f"Citation doc {search_doc_py.document_id} not found in tool call search_docs, creating it"
+ "Citation doc %s not found in tool call search_docs, creating it",
+ search_doc_py.document_id,
)
# Create the SearchDoc in the database
diff --git a/backend/onyx/configs/app_configs.py b/backend/onyx/configs/app_configs.py
index 23a973a4a5..fe2f311890 100644
--- a/backend/onyx/configs/app_configs.py
+++ b/backend/onyx/configs/app_configs.py
@@ -219,7 +219,8 @@ if _GOOGLE_OAUTH_SCOPE_OVERRIDE:
]
except Exception:
logger.exception(
- f"Error configuring Google OAuth login scopes: {_GOOGLE_OAUTH_SCOPE_OVERRIDE}"
+ "Error configuring Google OAuth login scopes: %s",
+ _GOOGLE_OAUTH_SCOPE_OVERRIDE,
)
# OpenID Connect configuration URL for OIDC integrations
diff --git a/backend/onyx/connectors/airtable/airtable_connector.py b/backend/onyx/connectors/airtable/airtable_connector.py
index 29458140be..ac72c07264 100644
--- a/backend/onyx/connectors/airtable/airtable_connector.py
+++ b/backend/onyx/connectors/airtable/airtable_connector.py
@@ -266,7 +266,7 @@ class AirtableConnector(LoadConnector):
return attachment_response.content
except requests.exceptions.HTTPError as e:
if e.response.status_code == 410:
- logger.info(f"Refreshing attachment for {filename}")
+ logger.info("Refreshing attachment for %s", filename)
# Re-fetch the record to get a fresh URL
refreshed_record = self.airtable_client.table(
base_id, table_id
@@ -283,7 +283,9 @@ class AirtableConnector(LoadConnector):
attachment_response.raise_for_status()
return attachment_response.content
- logger.error(f"Failed to refresh attachment for {filename}")
+ logger.error(
+ "Failed to refresh attachment for %s", filename
+ )
raise
attachment_content = get_attachment_with_retry(url, record_id)
@@ -313,7 +315,7 @@ class AirtableConnector(LoadConnector):
)
except Exception as e:
logger.warning(
- f"Failed to process attachment {filename}: {str(e)}"
+ "Failed to process attachment %s: %s", filename, str(e)
)
return attachment_texts
@@ -439,7 +441,10 @@ class AirtableConnector(LoadConnector):
field_type = field_schema.type
logger.debug(
- f"Processing field '{field_name}' of type '{field_type}' for record '{record_id}'."
+ "Processing field '%s' of type '%s' for record '%s'.",
+ field_name,
+ field_type,
+ record_id,
)
field_sections, field_metadata = self._process_field(
@@ -457,7 +462,7 @@ class AirtableConnector(LoadConnector):
metadata.update(field_metadata)
if not sections:
- logger.warning(f"No sections found for record {record_id}")
+ logger.warning("No sections found for record %s", record_id)
return None
# Include base name in semantic ID only in index_all mode
@@ -505,7 +510,7 @@ class AirtableConnector(LoadConnector):
if base_info.id == base_id:
return base_info.name
except Exception:
- logger.debug(f"Could not resolve base name for {base_id}")
+ logger.debug("Could not resolve base name for %s", base_id)
return None
def _index_table(
@@ -532,7 +537,10 @@ class AirtableConnector(LoadConnector):
break
logger.info(
- f"Processing {len(records)} records from table '{table_schema.name}' in base '{base_name or base_id}'."
+ "Processing %s records from table '%s' in base '%s'.",
+ len(records),
+ table_schema.name,
+ base_name or base_id,
)
if not records:
@@ -572,7 +580,7 @@ class AirtableConnector(LoadConnector):
if document:
record_documents.append(document)
except Exception as e:
- logger.exception(f"Failed to process record {record['id']}")
+ logger.exception("Failed to process record %s", record["id"])
raise e
if record_documents:
@@ -599,23 +607,25 @@ class AirtableConnector(LoadConnector):
def _load_all(self) -> GenerateDocumentsOutput:
"""Discover all bases and tables, then index everything."""
bases = self.airtable_client.bases()
- logger.info(f"Discovered {len(bases)} Airtable base(s).")
+ logger.info("Discovered %s Airtable base(s).", len(bases))
for base_info in bases:
base_id = base_info.id
base_name = base_info.name
- logger.info(f"Listing tables for base '{base_name}' ({base_id}).")
+ logger.info("Listing tables for base '%s' (%s).", base_name, base_id)
try:
base = self.airtable_client.base(base_id)
tables = base.tables()
except Exception:
logger.exception(
- f"Failed to list tables for base '{base_name}' ({base_id}), skipping."
+ "Failed to list tables for base '%s' (%s), skipping.",
+ base_name,
+ base_id,
)
continue
- logger.info(f"Found {len(tables)} table(s) in base '{base_name}'.")
+ logger.info("Found %s table(s) in base '%s'.", len(tables), base_name)
for table in tables:
try:
@@ -626,6 +636,10 @@ class AirtableConnector(LoadConnector):
)
except Exception:
logger.exception(
- f"Failed to index table '{table.name}' ({table.id}) in base '{base_name}' ({base_id}), skipping."
+ "Failed to index table '%s' (%s) in base '%s' (%s), skipping.",
+ table.name,
+ table.id,
+ base_name,
+ base_id,
)
continue
diff --git a/backend/onyx/connectors/asana/asana_api.py b/backend/onyx/connectors/asana/asana_api.py
index fcc59b4d1a..be20f6c709 100755
--- a/backend/onyx/connectors/asana/asana_api.py
+++ b/backend/onyx/connectors/asana/asana_api.py
@@ -75,13 +75,13 @@ class AsanaAPI:
projects_list.append(project_gid)
else:
logger.debug(
- f"Skipping project: {project_gid} - not in accepted project_gids"
+ "Skipping project: %s - not in accepted project_gids", project_gid
)
project_count += 1
if project_count % 100 == 0:
- logger.info(f"Processed {project_count} projects")
+ logger.info("Processed %s projects", project_count)
- logger.info(f"Found {len(projects_list)} projects to process")
+ logger.info("Found %s projects to process", len(projects_list))
# Asana tasks can belong to multiple projects and thus tasks
# can get reported multiple times
seen_task_gids: set[str] = set()
@@ -90,10 +90,10 @@ class AsanaAPI:
project_gid, start_date, start_seconds, seen_task_gids
):
yield task
- logger.info(f"Completed fetching {self.task_count} tasks from Asana")
+ logger.info("Completed fetching %s tasks from Asana", self.task_count)
if self.api_error_count > 0:
logger.warning(
- f"Encountered {self.api_error_count} API errors during task fetching"
+ "Encountered %s API errors during task fetching", self.api_error_count
)
def _get_tasks_for_project(
@@ -109,26 +109,33 @@ class AsanaAPI:
team_gid = team.get("gid")
if project.get("archived"):
- logger.info(f"Skipping archived project: {project_name} ({project_gid})")
+ logger.info("Skipping archived project: %s (%s)", project_name, project_gid)
return
if not team_gid:
logger.info(
- f"Skipping project without a team: {project_name} ({project_gid})"
+ "Skipping project without a team: %s (%s)", project_name, project_gid
)
return
if project.get("privacy_setting") == "private":
if self.team_gid and team_gid != self.team_gid:
logger.info(
- f"Skipping private project not in configured team: {project_name} ({project_gid})"
+ "Skipping private project not in configured team: %s (%s)",
+ project_name,
+ project_gid,
)
return
logger.info(
- f"Processing private project in configured team: {project_name} ({project_gid})"
+ "Processing private project in configured team: %s (%s)",
+ project_name,
+ project_gid,
)
simple_start_date = start_date.split(".")[0].split("+")[0]
logger.info(
- f"Fetching tasks modified since {simple_start_date} for project: {project_name} ({project_gid})"
+ "Fetching tasks modified since %s for project: %s (%s)",
+ simple_start_date,
+ project_name,
+ project_gid,
)
opts = {
@@ -143,8 +150,8 @@ class AsanaAPI:
gid = data["gid"]
if gid in seen_task_gids:
logger.debug(
- f"Skipping duplicate Asana task {gid} "
- f"(already yielded for another project)"
+ "Skipping duplicate Asana task %s (already yielded for another project)",
+ gid,
)
continue
seen_task_gids.add(gid)
@@ -155,11 +162,13 @@ class AsanaAPI:
runtime_seconds = end_seconds - start_seconds
if runtime_seconds > 0:
logger.info(
- f"Processed {self.task_count} tasks in {runtime_seconds:.0f} seconds "
- f"({self.task_count / runtime_seconds:.2f} tasks/second)"
+ "Processed %s tasks in %s seconds (%s tasks/second)",
+ self.task_count,
+ format(runtime_seconds, ".0f"),
+ format(self.task_count / runtime_seconds, ".2f"),
)
- logger.debug(f"Processing Asana task: {data['name']}")
+ logger.debug("Processing Asana task: %s", data["name"])
text = self._construct_task_text(data)
@@ -181,7 +190,9 @@ class AsanaAPI:
yield task
except Exception:
logger.error(
- f"Error processing task {data['gid']} in project {project_gid}",
+ "Error processing task %s in project %s",
+ data["gid"],
+ project_gid,
exc_info=True,
)
self.api_error_count += 1
@@ -229,7 +240,10 @@ class AsanaAPI:
story_duration = time.time() - story_start
logger.debug(
- f"Processed {story_count} stories (including {comment_count} comments) in {story_duration:.2f} seconds"
+ "Processed %s stories (including %s comments) in %s seconds",
+ story_count,
+ comment_count,
+ format(story_duration, ".2f"),
)
return text
@@ -240,7 +254,9 @@ class AsanaAPI:
self._user = self.users_api.get_user(user_gid, {"opt_fields": "name,email"})
if not self._user:
- logger.warning(f"Unable to fetch user information for user_gid: {user_gid}")
+ logger.warning(
+ "Unable to fetch user information for user_gid: %s", user_gid
+ )
return {"name": "Unknown"}
return self._user
diff --git a/backend/onyx/connectors/asana/connector.py b/backend/onyx/connectors/asana/connector.py
index 34169eb3a3..94cb0e1a49 100755
--- a/backend/onyx/connectors/asana/connector.py
+++ b/backend/onyx/connectors/asana/connector.py
@@ -40,7 +40,7 @@ class AsanaConnector(LoadConnector, PollConnector):
self.batch_size = batch_size
self.continue_on_failure = continue_on_failure
logger.info(
- f"AsanaConnector initialized with workspace_id: {asana_workspace_id}"
+ "AsanaConnector initialized with workspace_id: %s", asana_workspace_id
)
def load_credentials(self, credentials: dict[str, Any]) -> dict[str, Any] | None:
@@ -59,7 +59,7 @@ class AsanaConnector(LoadConnector, PollConnector):
end: SecondsSinceUnixEpoch | None, # noqa: ARG002
) -> GenerateDocumentsOutput:
start_time = datetime.datetime.fromtimestamp(start).isoformat()
- logger.info(f"Starting Asana poll from {start_time}")
+ logger.info("Starting Asana poll from %s", start_time)
asana = asana_api.AsanaAPI(
api_token=self.api_token,
workspace_gid=self.workspace_id,
@@ -73,12 +73,12 @@ class AsanaConnector(LoadConnector, PollConnector):
docs_batch.append(doc)
if len(docs_batch) >= self.batch_size:
- logger.info(f"Yielding batch of {len(docs_batch)} documents")
+ logger.info("Yielding batch of %s documents", len(docs_batch))
yield docs_batch
docs_batch = []
if docs_batch:
- logger.info(f"Yielding final batch of {len(docs_batch)} documents")
+ logger.info("Yielding final batch of %s documents", len(docs_batch))
yield docs_batch
logger.info("Asana poll completed")
@@ -88,7 +88,7 @@ class AsanaConnector(LoadConnector, PollConnector):
return self.poll_source(start=0, end=None)
def _message_to_doc(self, task: asana_api.AsanaTask) -> Document:
- logger.debug(f"Converting Asana task {task.id} to Document")
+ logger.debug("Converting Asana task %s to Document", task.id)
return Document(
id=task.id,
sections=[TextSection(link=task.link, text=task.text)],
diff --git a/backend/onyx/connectors/axero/connector.py b/backend/onyx/connectors/axero/connector.py
index bc462e60b7..20dc4e2537 100644
--- a/backend/onyx/connectors/axero/connector.py
+++ b/backend/onyx/connectors/axero/connector.py
@@ -84,7 +84,7 @@ def _get_entities(
total_records = data["TotalRecords"]
contents = data["ResponseData"]
pages_fetched += len(contents)
- logger.debug(f"Fetched {pages_fetched} {ENTITY_NAME_MAP[entity_type]}")
+ logger.debug("Fetched %s %s", pages_fetched, ENTITY_NAME_MAP[entity_type])
for page in contents:
update_time = time_str_to_utc(page["DateUpdated"])
@@ -138,7 +138,7 @@ def _map_post_to_parent(
for ind, post in enumerate(posts):
if (ind + 1) % 25 == 0:
- logger.debug(f"Processed {ind + 1} posts or responses")
+ logger.debug("Processed %s posts or responses", ind + 1)
post_time = time_str_to_utc(
post.get("DateUpdated") or post.get("DateCreated") or epoch_str
@@ -200,7 +200,7 @@ def _get_forums(
total_records = data["TotalRecords"]
contents = data["ResponseData"]
pages_fetched += len(contents)
- logger.debug(f"Fetched {pages_fetched} forums")
+ logger.debug("Fetched %s forums", pages_fetched)
for page in contents:
pages_to_return.append(page)
diff --git a/backend/onyx/connectors/blob/connector.py b/backend/onyx/connectors/blob/connector.py
index f1b5463a4c..6d5c6ebd6a 100644
--- a/backend/onyx/connectors/blob/connector.py
+++ b/backend/onyx/connectors/blob/connector.py
@@ -84,7 +84,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
self, allow_images: bool
) -> None:
"""Set whether to process images in this connector."""
- logger.info(f"Setting allow_images to {allow_images}.")
+ logger.info("Setting allow_images to %s.", allow_images)
self._allow_images = allow_images
def _detect_bucket_region(self) -> None:
@@ -103,11 +103,11 @@ class BlobStorageConnector(LoadConnector, PollConnector):
).get("HTTPHeaders", {}).get("x-amz-bucket-region")
if self.bucket_region:
- logger.debug(f"Detected bucket region: {self.bucket_region}")
+ logger.debug("Detected bucket region: %s", self.bucket_region)
else:
logger.warning("Bucket region not found in head_bucket response")
except Exception as e:
- logger.warning(f"Failed to detect bucket region via head_bucket: {e}")
+ logger.warning("Failed to detect bucket region via head_bucket: %s", e)
def load_credentials(self, credentials: dict[str, Any]) -> dict[str, Any] | None:
"""Checks for boto3 credentials based on the bucket type.
@@ -127,7 +127,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
"""
logger.debug(
- f"Loading credentials for {self.bucket_name} or type {self.bucket_type}"
+ "Loading credentials for %s or type %s", self.bucket_name, self.bucket_type
)
if self.bucket_type == BlobType.R2:
@@ -156,7 +156,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
"authentication_method", "access_key"
)
logger.debug(
- f"Using authentication method: {authentication_method} for S3 bucket."
+ "Using authentication method: %s for S3 bucket.", authentication_method
)
if authentication_method == "access_key":
logger.debug("Using access key authentication for S3 bucket.")
@@ -283,7 +283,9 @@ class BlobStorageConnector(LoadConnector, PollConnector):
if bytes_read > self.size_threshold + SIZE_THRESHOLD_BUFFER:
logger.warning(
- f"{key} exceeds size threshold of {self.size_threshold}. Skipping."
+ "%s exceeds size threshold of %s. Skipping.",
+ key,
+ self.size_threshold,
)
return None
@@ -418,7 +420,9 @@ class BlobStorageConnector(LoadConnector, PollConnector):
and size_bytes > self.size_threshold
):
logger.warning(
- f"{file_name} exceeds size threshold of {self.size_threshold}. Skipping."
+ "%s exceeds size threshold of %s. Skipping.",
+ file_name,
+ self.size_threshold,
)
continue
@@ -426,7 +430,8 @@ class BlobStorageConnector(LoadConnector, PollConnector):
if file_ext in OnyxFileExtensions.IMAGE_EXTENSIONS:
if not self._allow_images:
logger.debug(
- f"Skipping image file: {key} (image processing not enabled)"
+ "Skipping image file: %s (image processing not enabled)",
+ key,
)
continue
@@ -461,7 +466,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
yield batch
batch = []
except Exception:
- logger.exception(f"Error processing image {key}")
+ logger.exception("Error processing image %s", key)
continue
# Handle tabular files (xlsx, csv, tsv) — produce one
@@ -510,7 +515,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
yield batch
batch = []
except Exception:
- logger.exception(f"Error processing tabular file {key}")
+ logger.exception("Error processing tabular file %s", key)
continue
# Handle text and document files
@@ -537,7 +542,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
sections: list[TextSection | ImageSection] = []
if extraction_result.text_content.strip():
logger.debug(
- f"Creating TextSection for {file_name} with link: {link}"
+ "Creating TextSection for %s with link: %s", file_name, link
)
sections.append(
TextSection(
@@ -567,7 +572,7 @@ class BlobStorageConnector(LoadConnector, PollConnector):
batch = []
except Exception:
- logger.exception(f"Error decoding object {key} as UTF-8")
+ logger.exception("Error decoding object %s as UTF-8", key)
if batch:
yield batch
diff --git a/backend/onyx/connectors/canvas/connector.py b/backend/onyx/connectors/canvas/connector.py
index fe9605d5f9..9a95615e88 100644
--- a/backend/onyx/connectors/canvas/connector.py
+++ b/backend/onyx/connectors/canvas/connector.py
@@ -283,7 +283,7 @@ class CanvasConnector(
@retry(tries=3, delay=1, backoff=2)
def _list_pages(self, course_id: int) -> list[CanvasPage]:
"""Fetch all pages for a given course."""
- logger.debug(f"Fetching pages for course {course_id}")
+ logger.debug("Fetching pages for course %s", course_id)
pages: list[CanvasPage] = []
for page in self.canvas_client.paginate(
@@ -296,7 +296,7 @@ class CanvasConnector(
@retry(tries=3, delay=1, backoff=2)
def _list_assignments(self, course_id: int) -> list[CanvasAssignment]:
"""Fetch all assignments for a given course."""
- logger.debug(f"Fetching assignments for course {course_id}")
+ logger.debug("Fetching assignments for course %s", course_id)
assignments: list[CanvasAssignment] = []
for page in self.canvas_client.paginate(
@@ -311,7 +311,7 @@ class CanvasConnector(
@retry(tries=3, delay=1, backoff=2)
def _list_announcements(self, course_id: int) -> list[CanvasAnnouncement]:
"""Fetch all announcements for a given course."""
- logger.debug(f"Fetching announcements for course {course_id}")
+ logger.debug("Fetching announcements for course %s", course_id)
announcements: list[CanvasAnnouncement] = []
for page in self.canvas_client.paginate(
@@ -529,8 +529,9 @@ class CanvasConnector(
)
if not announcement.posted_at:
logger.debug(
- f"Skipping announcement {announcement.id} in "
- f"course {course_id}: no posted_at"
+ "Skipping announcement %s in course %s: no posted_at",
+ announcement.id,
+ course_id,
)
continue
if not _in_time_window(announcement.posted_at, start, end):
@@ -596,7 +597,7 @@ class CanvasConnector(
_handle_canvas_api_error(e) # NoReturn — always raises
raise
new_checkpoint.course_ids = [c.id for c in courses]
- logger.info(f"Found {len(courses)} Canvas courses to process")
+ logger.info("Found %s Canvas courses to process", len(courses))
new_checkpoint.has_more = len(new_checkpoint.course_ids) > 0
return new_checkpoint
@@ -648,8 +649,9 @@ class CanvasConnector(
# the whole course rather than burning API calls on each stage.
if oe.status_code == 404:
logger.warning(
- f"Canvas course {course_id} not found while fetching "
- f"{stage} (HTTP 404). Skipping course."
+ "Canvas course %s not found while fetching %s (HTTP 404). Skipping course.",
+ course_id,
+ stage,
)
yield ConnectorFailure(
failed_entity=EntityFailure(
@@ -661,8 +663,10 @@ class CanvasConnector(
new_checkpoint.advance_course()
else:
logger.warning(
- f"Failed to fetch {stage} for course {course_id}: {oe}. "
- f"Skipping remainder of this stage."
+ "Failed to fetch %s for course %s: %s. Skipping remainder of this stage.",
+ stage,
+ course_id,
+ oe,
)
yield ConnectorFailure(
failed_entity=EntityFailure(
@@ -681,8 +685,10 @@ class CanvasConnector(
except Exception as e:
# Unknown error — skip the stage and try to continue.
logger.warning(
- f"Failed to fetch {stage} for course {course_id}: {e}. "
- f"Skipping remainder of this stage."
+ "Failed to fetch %s for course %s: %s. Skipping remainder of this stage.",
+ stage,
+ course_id,
+ e,
)
yield ConnectorFailure(
failed_entity=EntityFailure(
diff --git a/backend/onyx/connectors/coda/connector.py b/backend/onyx/connectors/coda/connector.py
index ac6e1b1900..2c56098721 100644
--- a/backend/onyx/connectors/coda/connector.py
+++ b/backend/onyx/connectors/coda/connector.py
@@ -145,7 +145,7 @@ class CodaConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _get_doc(self, doc_id: str) -> CodaDoc:
"""Fetch a specific Coda document by its ID."""
- logger.debug(f"Fetching Coda doc with ID: {doc_id}")
+ logger.debug("Fetching Coda doc with ID: %s", doc_id)
try:
response = self.coda_client.get(f"docs/{doc_id}")
except CodaClientRequestFailedError as e:
@@ -169,7 +169,7 @@ class CodaConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _get_page(self, doc_id: str, page_id: str) -> CodaPage:
"""Fetch a specific page from a Coda document."""
- logger.debug(f"Fetching Coda page with ID: {page_id}")
+ logger.debug("Fetching Coda page with ID: %s", page_id)
try:
response = self.coda_client.get(f"docs/{doc_id}/pages/{page_id}")
except CodaClientRequestFailedError as e:
@@ -193,7 +193,7 @@ class CodaConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _get_table(self, doc_id: str, table_id: str) -> CodaTable:
"""Fetch a specific table from a Coda document."""
- logger.debug(f"Fetching Coda table with ID: {table_id}")
+ logger.debug("Fetching Coda table with ID: %s", table_id)
try:
response = self.coda_client.get(f"docs/{doc_id}/tables/{table_id}")
except CodaClientRequestFailedError as e:
@@ -216,7 +216,7 @@ class CodaConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _get_row(self, doc_id: str, table_id: str, row_id: str) -> CodaRow:
"""Fetch a specific row from a Coda table."""
- logger.debug(f"Fetching Coda row with ID: {row_id}")
+ logger.debug("Fetching Coda row with ID: %s", row_id)
try:
response = self.coda_client.get(
f"docs/{doc_id}/tables/{table_id}/rows/{row_id}"
@@ -291,13 +291,13 @@ class CodaConnector(LoadConnector, PollConnector):
if not next_page_token:
break
- logger.debug(f"Found {len(all_docs)} docs")
+ logger.debug("Found %s docs", len(all_docs))
return all_docs
@retry(tries=3, delay=1, backoff=2)
def _list_pages_in_doc(self, doc_id: str) -> List[CodaPage]:
"""List all pages in a Coda document."""
- logger.debug(f"Listing pages in Coda doc with ID: {doc_id}")
+ logger.debug("Listing pages in Coda doc with ID: %s", doc_id)
pages: List[CodaPage] = []
endpoint = f"docs/{doc_id}/pages"
@@ -340,13 +340,13 @@ class CodaConnector(LoadConnector, PollConnector):
if not next_page_token:
break
- logger.debug(f"Found {len(pages)} pages in doc {doc_id}")
+ logger.debug("Found %s pages in doc %s", len(pages), doc_id)
return pages
@retry(tries=3, delay=1, backoff=2)
def _fetch_page_content(self, doc_id: str, page_id: str) -> str:
"""Fetch the content of a Coda page."""
- logger.debug(f"Fetching content for page {page_id} in doc {doc_id}")
+ logger.debug("Fetching content for page %s in doc %s", page_id, doc_id)
content_parts = []
next_page_token: str | None = None
@@ -362,7 +362,7 @@ class CodaConnector(LoadConnector, PollConnector):
)
except CodaClientRequestFailedError as e:
if e.status_code == 404:
- logger.debug(f"No content available for page {page_id}")
+ logger.debug("No content available for page %s", page_id)
return ""
raise
@@ -384,7 +384,7 @@ class CodaConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _list_tables(self, doc_id: str) -> List[CodaTable]:
"""List all tables in a Coda document."""
- logger.debug(f"Listing tables in Coda doc with ID: {doc_id}")
+ logger.debug("Listing tables in Coda doc with ID: %s", doc_id)
tables: List[CodaTable] = []
endpoint = f"docs/{doc_id}/tables"
@@ -422,13 +422,13 @@ class CodaConnector(LoadConnector, PollConnector):
if not next_page_token:
break
- logger.debug(f"Found {len(tables)} tables in doc {doc_id}")
+ logger.debug("Found %s tables in doc %s", len(tables), doc_id)
return tables
@retry(tries=3, delay=1, backoff=2)
def _list_rows_and_values(self, doc_id: str, table_id: str) -> List[CodaRow]:
"""List all rows and their values in a table."""
- logger.debug(f"Listing rows in Coda table: {table_id} in Coda doc: {doc_id}")
+ logger.debug("Listing rows in Coda table: %s in Coda doc: %s", table_id, doc_id)
rows: List[CodaRow] = []
endpoint = f"docs/{doc_id}/tables/{table_id}/rows"
@@ -473,7 +473,7 @@ class CodaConnector(LoadConnector, PollConnector):
if not next_page_token:
break
- logger.debug(f"Found {len(rows)} rows in table {table_id}")
+ logger.debug("Found %s rows in table %s", len(rows), table_id)
return rows
def _convert_page_to_document(self, page: CodaPage, content: str = "") -> Document:
@@ -556,10 +556,10 @@ class CodaConnector(LoadConnector, PollConnector):
def _iter_documents() -> Generator[Document, None, None]:
docs = self._list_all_docs()
- logger.info(f"Found {len(docs)} Coda docs to process")
+ logger.info("Found %s Coda docs to process", len(docs))
for doc in docs:
- logger.debug(f"Processing doc: {doc.name} ({doc.id})")
+ logger.debug("Processing doc: %s (%s)", doc.name, doc.id)
try:
pages = self._list_pages_in_doc(doc.id)
@@ -570,11 +570,13 @@ class CodaConnector(LoadConnector, PollConnector):
content = self._fetch_page_content(doc.id, page.id)
except Exception as e:
logger.warning(
- f"Failed to fetch content for page {page.id}: {e}"
+ "Failed to fetch content for page %s: %s",
+ page.id,
+ e,
)
yield self._convert_page_to_document(page, content)
except ConnectorValidationError as e:
- logger.warning(f"Failed to list pages for doc {doc.id}: {e}")
+ logger.warning("Failed to list pages for doc %s: %s", doc.id, e)
try:
tables = self._list_tables(doc.id)
@@ -584,11 +586,11 @@ class CodaConnector(LoadConnector, PollConnector):
yield self._convert_table_with_rows_to_document(table, rows)
except ConnectorValidationError as e:
logger.warning(
- f"Failed to list rows for table {table.id}: {e}"
+ "Failed to list rows for table %s: %s", table.id, e
)
yield self._convert_table_with_rows_to_document(table, [])
except ConnectorValidationError as e:
- logger.warning(f"Failed to list tables for doc {doc.id}: {e}")
+ logger.warning("Failed to list tables for doc %s: %s", doc.id, e)
return batch_generator(_iter_documents(), self.batch_size)
@@ -603,7 +605,10 @@ class CodaConnector(LoadConnector, PollConnector):
def _iter_documents() -> Generator[Document, None, None]:
docs = self._list_all_docs()
logger.info(
- f"Polling {len(docs)} Coda docs for updates between {start} and {end}"
+ "Polling %s Coda docs for updates between %s and %s",
+ len(docs),
+ start,
+ end,
)
for doc in docs:
@@ -622,11 +627,13 @@ class CodaConnector(LoadConnector, PollConnector):
content = self._fetch_page_content(doc.id, page.id)
except Exception as e:
logger.warning(
- f"Failed to fetch content for page {page.id}: {e}"
+ "Failed to fetch content for page %s: %s",
+ page.id,
+ e,
)
yield self._convert_page_to_document(page, content)
except ConnectorValidationError as e:
- logger.warning(f"Failed to list pages for doc {doc.id}: {e}")
+ logger.warning("Failed to list pages for doc %s: %s", doc.id, e)
try:
tables = self._list_tables(doc.id)
@@ -659,7 +666,7 @@ class CodaConnector(LoadConnector, PollConnector):
except ConnectorValidationError as e:
logger.warning(
- f"Failed to list rows for table {table.id}: {e}"
+ "Failed to list rows for table %s: %s", table.id, e
)
if table_timestamp > start and table_timestamp <= end:
yield self._convert_table_with_rows_to_document(
@@ -667,7 +674,7 @@ class CodaConnector(LoadConnector, PollConnector):
)
except ConnectorValidationError as e:
- logger.warning(f"Failed to list tables for doc {doc.id}: {e}")
+ logger.warning("Failed to list tables for doc %s: %s", doc.id, e)
return batch_generator(_iter_documents(), self.batch_size)
@@ -676,13 +683,13 @@ class CodaConnector(LoadConnector, PollConnector):
try:
response = self.coda_client.get("whoami")
logger.info(
- f"Coda connector validated for user: {response.get('name', 'Unknown')}"
+ "Coda connector validated for user: %s", response.get("name", "Unknown")
)
if self.workspace_id:
params = {"workspaceId": self.workspace_id, "limit": "1"}
self.coda_client.get("docs", params=params)
- logger.info(f"Validated access to workspace: {self.workspace_id}")
+ logger.info("Validated access to workspace: %s", self.workspace_id)
except CodaClientRequestFailedError as e:
if e.status_code == 401:
diff --git a/backend/onyx/connectors/confluence/connector.py b/backend/onyx/connectors/confluence/connector.py
index 606f86a7aa..e4405f91e2 100644
--- a/backend/onyx/connectors/confluence/connector.py
+++ b/backend/onyx/connectors/confluence/connector.py
@@ -186,7 +186,7 @@ class ConfluenceConnector(
self.continue_on_failure = continue_on_failure
def set_allow_images(self, value: bool) -> None:
- logger.info(f"Setting allow_images to {value}.")
+ logger.info("Setting allow_images to %s.", value)
self.allow_images = value
def _yield_space_hierarchy_nodes(
@@ -470,7 +470,7 @@ class ConfluenceConnector(
# Extract basic page information
page_id = _get_page_id(page)
page_title = page["title"]
- logger.info(f"Converting page {page_title} to document")
+ logger.info("Converting page %s to document", page_title)
page_url = build_confluence_document_id(
self.wiki_base, page["_links"]["webui"], self.is_cloud
)
@@ -532,7 +532,7 @@ class ConfluenceConnector(
parent_hierarchy_raw_node_id=parent_hierarchy_raw_node_id,
)
except Exception as e:
- logger.error(f"Error converting page {page.get('id', 'unknown')}: {e}")
+ logger.error("Error converting page %s: %s", page.get("id", "unknown"), e)
if is_atlassian_date_error(e): # propagate error to be caught and retried
raise
return ConnectorFailure(
@@ -579,7 +579,8 @@ class ConfluenceConnector(
if not self.allow_images:
if media_type.startswith("image/"):
logger.info(
- f"Skipping attachment because allow images is False: {attachment['title']}"
+ "Skipping attachment because allow images is False: %s",
+ attachment["title"],
)
continue
@@ -587,12 +588,15 @@ class ConfluenceConnector(
attachment,
):
logger.info(
- f"Skipping attachment because it is not an accepted file type: {attachment['title']}"
+ "Skipping attachment because it is not an accepted file type: %s",
+ attachment["title"],
)
continue
logger.info(
- f"Processing attachment: {attachment['title']} attached to page {page['title']}"
+ "Processing attachment: %s attached to page %s",
+ attachment["title"],
+ page["title"],
)
# Attachment document id: use the download URL for stable identity
try:
@@ -601,9 +605,9 @@ class ConfluenceConnector(
)
except Exception as e:
logger.warning(
- f"Invalid attachment url for id {attachment['id']}, skipping"
+ "Invalid attachment url for id %s, skipping", attachment["id"]
)
- logger.debug(f"Error building attachment url: {e}")
+ logger.debug("Error building attachment url: %s", e)
continue
try:
response = convert_attachment_to_content(
@@ -691,7 +695,8 @@ class ConfluenceConnector(
attachment_docs.append(attachment_doc)
except Exception as e:
logger.error(
- f"Failed to extract/summarize attachment {attachment['title']}",
+ "Failed to extract/summarize attachment %s",
+ attachment["title"],
exc_info=e,
)
if is_atlassian_date_error(e):
@@ -773,7 +778,7 @@ class ConfluenceConnector(
page_query_url = checkpoint.next_page_url or self._build_page_retrieval_url(
start_ts, end, self.batch_size
)
- logger.debug(f"page_query_url: {page_query_url}")
+ logger.debug("page_query_url: %s", page_query_url)
# store the next page start for confluence server, cursor for confluence cloud
def store_next_page_url(next_page_url: str) -> None:
@@ -842,9 +847,8 @@ class ConfluenceConnector(
except Exception as e:
if is_atlassian_date_error(e) and start is not None:
logger.warning(
- "Confluence says we provided an invalid 'updated' field. This may indicate"
- "a real issue, but can also appear during edge cases like daylight"
- f"savings time changes. Retrying with a 1 hour offset. Error: {e}"
+ "Confluence says we provided an invalid 'updated' field. This may indicatea real issue, but can also appear during edge cases like daylightsavings time changes. Retrying with a 1 hour offset. Error: %s",
+ e,
)
return self._fetch_document_batches(checkpoint, start - ONE_HOUR, end)
raise
diff --git a/backend/onyx/connectors/confluence/onyx_confluence.py b/backend/onyx/connectors/confluence/onyx_confluence.py
index dadd2a7212..787010915c 100644
--- a/backend/onyx/connectors/confluence/onyx_confluence.py
+++ b/backend/onyx/connectors/confluence/onyx_confluence.py
@@ -339,9 +339,10 @@ class OnyxConfluence:
else:
if "WWW-Authenticate" in e.response.headers:
logger.warning(
- f"WWW-Authenticate: {e.response.headers['WWW-Authenticate']}"
+ "WWW-Authenticate: %s",
+ e.response.headers["WWW-Authenticate"],
)
- logger.warning(f"Full error: {e.response.text}")
+ logger.warning("Full error: %s", e.response.text)
raise e
return
@@ -394,7 +395,8 @@ class OnyxConfluence:
confluence = Confluence(url=url, oauth2=oauth2_dict, **kwargs)
else:
logger.info(
- f"Connecting to Confluence with Personal Access Token as user: {credentials['confluence_username']}"
+ "Connecting to Confluence with Personal Access Token as user: %s",
+ credentials["confluence_username"],
)
if self._is_cloud:
confluence = Confluence(
@@ -461,7 +463,8 @@ class OnyxConfluence:
except HTTPError as e:
delay_until = _handle_http_error(e, attempt, MAX_RETRIES)
logger.warning(
- f"HTTPError in confluence call. Retrying in {delay_until} seconds..."
+ "HTTPError in confluence call. Retrying in %s seconds...",
+ delay_until,
)
while time.monotonic() < delay_until:
# in the future, check a signal here to exit
@@ -533,7 +536,7 @@ class OnyxConfluence:
url_suffix, "start", str(initial_start + ind)
)
temp_url_suffix = update_param_in_path(temp_url_suffix, "limit", "1")
- logger.info(f"Making recovery confluence call to {temp_url_suffix}")
+ logger.info("Making recovery confluence call to %s", temp_url_suffix)
raw_response = self.get(path=temp_url_suffix, advanced_mode=True)
raw_response.raise_for_status()
@@ -543,13 +546,15 @@ class OnyxConfluence:
if not latest_results:
# no more results, break out of the loop
logger.info(
- f"No results found for call '{temp_url_suffix}'Stopping pagination."
+ "No results found for call '%s'Stopping pagination.",
+ temp_url_suffix,
)
found_empty_page = True
break
except Exception:
logger.exception(
- f"Error in confluence call to {temp_url_suffix}. Continuing."
+ "Error in confluence call to %s. Continuing.",
+ temp_url_suffix,
)
if found_empty_page:
@@ -576,7 +581,7 @@ class OnyxConfluence:
url_suffix = update_param_in_path(url_suffix, "limit", str(current_limit))
while url_suffix:
- logger.debug(f"Making confluence call to {url_suffix}")
+ logger.debug("Making confluence call to %s", url_suffix)
try:
# Only pass params if they're not already in the URL to avoid duplicate
# params accumulating. Confluence's _links.next already includes these.
@@ -592,20 +597,22 @@ class OnyxConfluence:
params=params,
)
except Exception as e:
- logger.exception(f"Error in confluence call to {url_suffix}")
+ logger.exception("Error in confluence call to %s", url_suffix)
raise e
try:
raw_response.raise_for_status()
except Exception as e:
- logger.warning(f"Error in confluence call to {url_suffix}")
+ logger.warning("Error in confluence call to %s", url_suffix)
# If the problematic expansion is in the url, replace it
# with the replacement expansion and try again
# If that fails, raise the error
if _PROBLEMATIC_EXPANSIONS in url_suffix:
logger.warning(
- f"Replacing {_PROBLEMATIC_EXPANSIONS} with {_REPLACEMENT_EXPANSIONS} and trying again."
+ "Replacing %s with %s and trying again.",
+ _PROBLEMATIC_EXPANSIONS,
+ _REPLACEMENT_EXPANSIONS,
)
url_suffix = url_suffix.replace(
_PROBLEMATIC_EXPANSIONS,
@@ -622,9 +629,12 @@ class OnyxConfluence:
current_limit // 2, _MINIMUM_PAGINATION_LIMIT
)
logger.warning(
- f"Confluence returned {raw_response.status_code}. "
- f"Reducing limit from {old_limit} to {current_limit} "
- f"and retrying."
+ "Confluence returned %s. "
+ "Reducing limit from %s to %s "
+ "and retrying.",
+ raw_response.status_code,
+ old_limit,
+ current_limit,
)
url_suffix = update_param_in_path(
url_suffix, "limit", str(current_limit)
@@ -653,18 +663,26 @@ class OnyxConfluence:
continue
logger.exception(
- f"Error in confluence call to {url_suffix} "
- f"after reducing limit to {current_limit}.\n"
- f"Raw Response Text: {raw_response.text}\n"
- f"Error: {e}\n"
+ "Error in confluence call to %s "
+ "after reducing limit to %s.\n"
+ "Raw Response Text: %s\n"
+ "Error: %s\n",
+ url_suffix,
+ current_limit,
+ raw_response.text,
+ e,
)
raise
logger.exception(
- f"Error in confluence call to {url_suffix} \n"
- f"Raw Response Text: {raw_response.text} \n"
- f"Full Response: {raw_response.__dict__} \n"
- f"Error: {e} \n"
+ "Error in confluence call to %s \n"
+ "Raw Response Text: %s \n"
+ "Full Response: %s \n"
+ "Error: %s \n",
+ url_suffix,
+ raw_response.text,
+ raw_response.__dict__,
+ e,
)
raise
@@ -672,7 +690,8 @@ class OnyxConfluence:
next_response = raw_response.json()
except Exception as e:
logger.exception(
- f"Failed to parse response as JSON. Response: {raw_response.__dict__}"
+ "Failed to parse response as JSON. Response: %s",
+ raw_response.__dict__,
)
raise e
@@ -734,7 +753,8 @@ class OnyxConfluence:
# stop paginating.
if url_suffix and not results:
logger.info(
- f"No results found for call '{old_url_suffix}' despite next link being present. Stopping pagination."
+ "No results found for call '%s' despite next link being present. Stopping pagination.",
+ old_url_suffix,
)
break
@@ -771,7 +791,7 @@ class OnyxConfluence:
cql_url, limit=limit, next_page_callback=next_page_callback
)
except Exception as e:
- logger.exception(f"Error in paginated_page_retrieval: {e}")
+ logger.exception("Error in paginated_page_retrieval: %s", e)
raise e
def cql_paginate_all_expansions(
@@ -953,10 +973,12 @@ class OnyxConfluence:
response=e.response,
) from e
raise
- logger.debug(f"jsonrpc response: {response}")
+ logger.debug("jsonrpc response: %s", response)
if not response.get("result"):
logger.warning(
- f"No jsonrpc response for space permissions for space {space_key}\nResponse: {response}"
+ "No jsonrpc response for space permissions for space %s\nResponse: %s",
+ space_key,
+ response,
)
return response.get("result", [])
@@ -999,14 +1021,20 @@ def get_user_email_from_username__server(
except HTTPError as e:
status_code = e.response.status_code if e.response is not None else "N/A"
logger.warning(
- f"Failed to get confluence email for {user_name}: HTTP {status_code} - {e}"
+ "Failed to get confluence email for %s: HTTP %s - %s",
+ user_name,
+ status_code,
+ e,
)
# For now, we'll just return None and log a warning. This means
# we will keep retrying to get the email every group sync.
email = None
except Exception as e:
logger.warning(
- f"Failed to get confluence email for {user_name}: {type(e).__name__} - {e}"
+ "Failed to get confluence email for %s: %s - %s",
+ user_name,
+ type(e).__name__,
+ e,
)
email = None
_USER_EMAIL_CACHE[user_name] = email
@@ -1083,7 +1111,8 @@ def extract_text_from_confluence_html(
)
if not user_id:
logger.warning(
- f"ri:userkey not found in ri:user element. Found attrs: {user.attrs}"
+ "ri:userkey not found in ri:user element. Found attrs: %s",
+ user.attrs,
)
continue
# Include @ sign for tagging, more clear for LLM
@@ -1097,7 +1126,8 @@ def extract_text_from_confluence_html(
page_data = html_page_reference.find("ri:page")
if not page_data:
logger.warning(
- f"Skipping retrieval of {html_page_reference} because because page data is missing"
+ "Skipping retrieval of %s because because page data is missing",
+ html_page_reference,
)
continue
@@ -1105,13 +1135,14 @@ def extract_text_from_confluence_html(
if not page_title:
# only fetch pages that have a title
logger.warning(
- f"Skipping retrieval of {html_page_reference} because it has no title"
+ "Skipping retrieval of %s because it has no title",
+ html_page_reference,
)
continue
if page_title in fetched_titles:
# prevent recursive fetching of pages
- logger.debug(f"Skipping {page_title} because it has already been fetched")
+ logger.debug("Skipping %s because it has already been fetched", page_title)
continue
fetched_titles.add(page_title)
@@ -1131,7 +1162,9 @@ def extract_text_from_confluence_html(
break
except Exception as e:
logger.warning(
- f"Error getting page contents for object {confluence_object}: {e}"
+ "Error getting page contents for object %s: %s",
+ confluence_object,
+ e,
)
continue
@@ -1153,7 +1186,7 @@ def extract_text_from_confluence_html(
text_from_link = html_link_body.text
html_link_body.replaceWith(f"(LINK TEXT: {text_from_link})")
except Exception as e:
- logger.warning(f"Error processing ac:link-body: {e}")
+ logger.warning("Error processing ac:link-body: %s", e)
for html_attachment in soup.findAll("ri:attachment"):
# This extracts the text from inline attachments in the page so they can be
@@ -1163,7 +1196,7 @@ def extract_text_from_confluence_html(
f"{sanitize_attachment_title(html_attachment.attrs['ri:filename'])}"
) # to be replaced later
except Exception as e:
- logger.warning(f"Error processing ac:attachment: {e}")
+ logger.warning("Error processing ac:attachment: %s", e)
return format_document_soup(soup)
diff --git a/backend/onyx/connectors/confluence/utils.py b/backend/onyx/connectors/confluence/utils.py
index f9992309f0..a84edf3ced 100644
--- a/backend/onyx/connectors/confluence/utils.py
+++ b/backend/onyx/connectors/confluence/utils.py
@@ -145,9 +145,10 @@ def process_attachment(
else:
if attachment_size > CONFLUENCE_CONNECTOR_ATTACHMENT_SIZE_THRESHOLD:
logger.warning(
- f"Skipping {attachment_link} due to size. "
- f"size={attachment_size} "
- f"threshold={CONFLUENCE_CONNECTOR_ATTACHMENT_SIZE_THRESHOLD}"
+ "Skipping %s due to size. size=%s threshold=%s",
+ attachment_link,
+ attachment_size,
+ CONFLUENCE_CONNECTOR_ATTACHMENT_SIZE_THRESHOLD,
)
return AttachmentProcessingResult(
text=None,
@@ -156,14 +157,19 @@ def process_attachment(
)
logger.info(
- f"Downloading attachment: title={attachment['title']} length={attachment_size} link={attachment_link}"
+ "Downloading attachment: title=%s length=%s link=%s",
+ attachment["title"],
+ attachment_size,
+ attachment_link,
)
# Download the attachment
resp: requests.Response = confluence_client._session.get(attachment_link)
if resp.status_code != 200:
logger.warning(
- f"Failed to fetch {attachment_link} with status code {resp.status_code}"
+ "Failed to fetch %s with status code %s",
+ attachment_link,
+ resp.status_code,
)
return AttachmentProcessingResult(
text=None,
@@ -226,7 +232,7 @@ def _process_image_attachment(
media_type=media_type,
file_origin=FileOrigin.CONNECTOR,
)
- logger.info(f"Stored image attachment with file name: {file_name}")
+ logger.info("Stored image attachment with file name: %s", file_name)
# Return empty text but include the file_name for later processing
return AttachmentProcessingResult(text="", file_name=file_name, error=None)
@@ -252,14 +258,16 @@ def convert_attachment_to_content(
# Quick check for unsupported types:
if media_type.startswith("video/") or media_type == "application/gliffy+json":
logger.warning(
- f"Skipping unsupported attachment type: '{media_type}' for {attachment['title']}"
+ "Skipping unsupported attachment type: '%s' for %s",
+ media_type,
+ attachment["title"],
)
return None
result = process_attachment(confluence_client, attachment, page_id, allow_images)
if result.error is not None:
logger.warning(
- f"Attachment {attachment['title']} encountered error: {result.error}"
+ "Attachment %s encountered error: %s", attachment["title"], result.error
)
return None
@@ -367,7 +375,8 @@ def handle_confluence_rate_limit(confluence_call: F) -> F:
except requests.HTTPError as e:
delay_until = _handle_http_error(e, attempt, MAX_RETRIES)
logger.warning(
- f"HTTPError in confluence call. Retrying in {delay_until} seconds..."
+ "HTTPError in confluence call. Retrying in %s seconds...",
+ delay_until,
)
while time.monotonic() < delay_until:
# in the future, check a signal here to exit
@@ -403,8 +412,8 @@ def _handle_http_error(e: requests.HTTPError, attempt: int, max_retries: int) ->
FORBIDDEN_RETRY_DELAY = 10
if attempt < FORBIDDEN_MAX_RETRY_ATTEMPTS:
logger.warning(
- "403 error. This sometimes happens when we hit "
- f"Confluence rate limits. Retrying in {FORBIDDEN_RETRY_DELAY} seconds..."
+ "403 error. This sometimes happens when we hit Confluence rate limits. Retrying in %s seconds...",
+ FORBIDDEN_RETRY_DELAY,
)
return FORBIDDEN_RETRY_DELAY
@@ -416,8 +425,10 @@ def _handle_http_error(e: requests.HTTPError, attempt: int, max_retries: int) ->
delay = min(STARTING_DELAY * (BACKOFF**attempt), MAX_DELAY)
logger.warning(
- f"Server error {e.response.status_code}. "
- f"Retrying in {delay} seconds (attempt {attempt + 1})..."
+ "Server error %s. Retrying in %s seconds (attempt %s)...",
+ e.response.status_code,
+ delay,
+ attempt + 1,
)
return math.ceil(time.monotonic() + delay)
@@ -435,7 +446,9 @@ def _handle_http_error(e: requests.HTTPError, attempt: int, max_retries: int) ->
retry_after = int(retry_after_header)
if retry_after > MAX_DELAY:
logger.warning(
- f"Clamping retry_after from {retry_after} to {MAX_DELAY} seconds..."
+ "Clamping retry_after from %s to %s seconds...",
+ retry_after,
+ MAX_DELAY,
)
retry_after = MAX_DELAY
if retry_after < MIN_DELAY:
@@ -445,7 +458,7 @@ def _handle_http_error(e: requests.HTTPError, attempt: int, max_retries: int) ->
if retry_after is not None:
logger.warning(
- f"Rate limiting with retry header. Retrying after {retry_after} seconds..."
+ "Rate limiting with retry header. Retrying after %s seconds...", retry_after
)
delay = retry_after
else:
diff --git a/backend/onyx/connectors/connector_runner.py b/backend/onyx/connectors/connector_runner.py
index be8b4bf6e9..220de41e25 100644
--- a/backend/onyx/connectors/connector_runner.py
+++ b/backend/onyx/connectors/connector_runner.py
@@ -213,7 +213,8 @@ class ConnectorRunner(Generic[CT]):
yield None, None, None, next_checkpoint
logger.debug(
- f"Connector took {time.monotonic() - start} seconds to get to the next checkpoint."
+ "Connector took %s seconds to get to the next checkpoint.",
+ time.monotonic() - start,
)
else:
@@ -264,7 +265,9 @@ class ConnectorRunner(Generic[CT]):
f"{key}: {value}" for key, value in local_vars.items()
)
logger.error(
- f"Error in connector. type: {exc_type};\nlocal_vars below -> \n{local_vars_str[:1024]}"
+ "Error in connector. type: %s;\nlocal_vars below -> \n%s",
+ exc_type,
+ local_vars_str[:1024],
)
raise
diff --git a/backend/onyx/connectors/cross_connector_utils/miscellaneous_utils.py b/backend/onyx/connectors/cross_connector_utils/miscellaneous_utils.py
index a29883648b..1727ae683c 100644
--- a/backend/onyx/connectors/cross_connector_utils/miscellaneous_utils.py
+++ b/backend/onyx/connectors/cross_connector_utils/miscellaneous_utils.py
@@ -127,7 +127,7 @@ def _parse_document_source(connector_type: Any) -> DocumentSource | None:
return connector_type
if not isinstance(connector_type, str):
- logger.warning(f"Invalid connector_type type: {type(connector_type).__name__}")
+ logger.warning("Invalid connector_type type: %s", type(connector_type).__name__)
return None
normalized = re.sub(r"[\s\-]+", "_", connector_type.strip().lower())
@@ -135,7 +135,9 @@ def _parse_document_source(connector_type: Any) -> DocumentSource | None:
return DocumentSource(normalized)
except ValueError:
logger.warning(
- f"Invalid connector_type value: '{connector_type}' (normalized: '{normalized}')"
+ "Invalid connector_type value: '%s' (normalized: '%s')",
+ connector_type,
+ normalized,
)
return None
diff --git a/backend/onyx/connectors/cross_connector_utils/rate_limit_wrapper.py b/backend/onyx/connectors/cross_connector_utils/rate_limit_wrapper.py
index fe8c1cb1a5..fecfd0e91c 100644
--- a/backend/onyx/connectors/cross_connector_utils/rate_limit_wrapper.py
+++ b/backend/onyx/connectors/cross_connector_utils/rate_limit_wrapper.py
@@ -57,7 +57,9 @@ class _RateLimitDecorator:
while len(self.call_history) == self.max_calls:
sleep_time = self.sleep_time * (self.sleep_backoff**sleep_cnt)
logger.notice(
- f"Rate limit exceeded for function {func.__name__}. Waiting {sleep_time} seconds before retrying."
+ "Rate limit exceeded for function %s. Waiting %s seconds before retrying.",
+ func.__name__,
+ sleep_time,
)
time.sleep(sleep_time)
sleep_cnt += 1
diff --git a/backend/onyx/connectors/cross_connector_utils/tabular_section_utils.py b/backend/onyx/connectors/cross_connector_utils/tabular_section_utils.py
index 7807309282..731b9706ab 100644
--- a/backend/onyx/connectors/cross_connector_utils/tabular_section_utils.py
+++ b/backend/onyx/connectors/cross_connector_utils/tabular_section_utils.py
@@ -67,7 +67,7 @@ def tabular_file_to_sections(
try:
text = file_io_to_text(file).strip()
except Exception:
- logger.exception(f"Failure decoding {file_name}")
+ logger.exception("Failure decoding %s", file_name)
raise
if not text:
diff --git a/backend/onyx/connectors/discord/connector.py b/backend/onyx/connectors/discord/connector.py
index 169754788b..34fa048c98 100644
--- a/backend/onyx/connectors/discord/connector.py
+++ b/backend/onyx/connectors/discord/connector.py
@@ -109,7 +109,7 @@ async def _fetch_filtered_channels(
continue
filtered_channels.append(channel)
- logger.info(f"Found {len(filtered_channels)} channels for the authenticated user")
+ logger.info("Found %s channels for the authenticated user", len(filtered_channels))
return filtered_channels
diff --git a/backend/onyx/connectors/dropbox/connector.py b/backend/onyx/connectors/dropbox/connector.py
index 6c40966001..96e7575be1 100644
--- a/backend/onyx/connectors/dropbox/connector.py
+++ b/backend/onyx/connectors/dropbox/connector.py
@@ -59,7 +59,7 @@ class DropboxConnector(LoadConnector, PollConnector):
)
return link_metadata.url
except ApiError as err:
- logger.exception(f"Failed to create a shared link for {path}: {err}")
+ logger.exception("Failed to create a shared link for %s: %s", path, err)
return ""
def _yield_files_recursive(
@@ -117,7 +117,9 @@ class DropboxConnector(LoadConnector, PollConnector):
)
except Exception as e:
logger.exception(
- f"Error decoding file {entry.path_display} as utf-8 error occurred: {e}"
+ "Error decoding file %s as utf-8 error occurred: %s",
+ entry.path_display,
+ e,
)
elif isinstance(entry, FolderMetadata):
diff --git a/backend/onyx/connectors/drupal_wiki/connector.py b/backend/onyx/connectors/drupal_wiki/connector.py
index 9111da210c..40c856b6f9 100644
--- a/backend/onyx/connectors/drupal_wiki/connector.py
+++ b/backend/onyx/connectors/drupal_wiki/connector.py
@@ -129,7 +129,7 @@ class DrupalWikiConnector(
self._api_token: str | None = None # set by load_credentials
def set_allow_images(self, value: bool) -> None:
- logger.info(f"Setting allow_images to {value}.")
+ logger.info("Setting allow_images to %s.", value)
self.allow_images = value
def _get_page_attachments(self, page_id: int) -> list[dict[str, Any]]:
@@ -144,16 +144,16 @@ class DrupalWikiConnector(
"""
url = f"{self.base_url}/api/rest/scope/api/attachment"
params = {"pageId": str(page_id)}
- logger.debug(f"Fetching attachments for page {page_id} from {url}")
+ logger.debug("Fetching attachments for page %s from %s", page_id, url)
try:
response = rate_limited_get(url, headers=self.headers, params=params)
response.raise_for_status()
attachments = response.json()
- logger.info(f"Found {len(attachments)} attachments for page {page_id}")
+ logger.info("Found %s attachments for page %s", len(attachments), page_id)
return attachments
except Exception as e:
- logger.warning(f"Failed to fetch attachments for page {page_id}: {e}")
+ logger.warning("Failed to fetch attachments for page %s: %s", page_id, e)
return []
def _download_attachment(self, attachment_id: int) -> bytes:
@@ -167,7 +167,7 @@ class DrupalWikiConnector(
Raw bytes of the attachment.
"""
url = f"{self.base_url}/api/rest/scope/api/attachment/{attachment_id}/download"
- logger.info(f"Downloading attachment {attachment_id} from {url}")
+ logger.info("Downloading attachment %s from %s", attachment_id, url)
# Use headers without Accept for binary downloads
download_headers = {"Authorization": f"Bearer {self._api_token}"}
@@ -197,7 +197,7 @@ class DrupalWikiConnector(
if file_extension in OnyxFileExtensions.ALL_ALLOWED_EXTENSIONS:
return True
- logger.warning(f"Unsupported file type: {file_extension} for {file_name}")
+ logger.warning("Unsupported file type: %s for %s", file_extension, file_name)
return False
def _get_media_type_from_filename(self, filename: str) -> str:
@@ -256,7 +256,8 @@ class DrupalWikiConnector(
if media_type.startswith("image/"):
if not self.allow_images:
logger.info(
- f"Skipping image attachment {file_name} because allow_images is False",
+ "Skipping image attachment %s because allow_images is False",
+ file_name,
)
return [], None
@@ -272,7 +273,9 @@ class DrupalWikiConnector(
file_origin=FileOrigin.CONNECTOR,
)
sections.append(image_section)
- logger.debug(f"Stored image attachment with file name: {file_name}")
+ logger.debug(
+ "Stored image attachment with file name: %s", file_name
+ )
except Exception as e:
return [], f"Image storage failed: {e}"
@@ -291,7 +294,7 @@ class DrupalWikiConnector(
)
except Exception:
logger.exception(
- f"Failed to extract tabular sections from {file_name}"
+ "Failed to extract tabular sections from %s", file_name
)
if not sections:
return [], f"No content extracted from tabular file {file_name}"
@@ -311,7 +314,9 @@ class DrupalWikiConnector(
media_for_image = get_image_type_from_bytes(image_data)
except ValueError:
logger.warning(
- f"Unable to determine media type for embedded image {image_name} on attachment {file_name}"
+ "Unable to determine media type for embedded image %s on attachment %s",
+ image_name,
+ file_name,
)
image_counter += 1
@@ -332,7 +337,10 @@ class DrupalWikiConnector(
sections.append(image_section)
except Exception as err:
logger.warning(
- f"Failed to store embedded image {image_name or image_counter} for attachment {file_name}: {err}"
+ "Failed to store embedded image %s for attachment %s: %s",
+ image_name or image_counter,
+ file_name,
+ err,
)
extraction_result = extract_text_and_images(
@@ -346,7 +354,7 @@ class DrupalWikiConnector(
if text_content:
sections.insert(0, TextSection(text=text_content, link=download_url))
logger.info(
- f"Extracted {len(text_content)} characters from {file_name}"
+ "Extracted %s characters from %s", len(text_content), file_name
)
elif not sections:
return [], f"No text extracted for {file_name}"
@@ -355,7 +363,10 @@ class DrupalWikiConnector(
except Exception as e:
logger.error(
- f"Failed to process attachment {attachment.get('name', 'unknown')} on page {page_id}: {e}"
+ "Failed to process attachment %s on page %s: %s",
+ attachment.get("name", "unknown"),
+ page_id,
+ e,
)
return [], f"Failed to process attachment: {e}"
@@ -403,13 +414,13 @@ class DrupalWikiConnector(
while has_more and len(all_space_ids) > last_num_ids:
last_num_ids = len(all_space_ids)
params = {"size": size, "page": page}
- logger.debug(f"Fetching spaces from {url} (page={page}, size={size})")
+ logger.debug("Fetching spaces from %s (page=%s, size=%s)", url, page, size)
response = rate_limited_get(url, headers=self.headers, params=params)
response.raise_for_status()
resp_json = response.json()
space_response = DrupalWikiSpaceResponse.model_validate(resp_json)
- logger.info(f"Fetched {len(space_response.content)} spaces from {page}")
+ logger.info("Fetched %s spaces from %s", len(space_response.content), page)
# Collect ids into the set to deduplicate
for space in space_response.content:
all_space_ids.add(space.id)
@@ -421,7 +432,7 @@ class DrupalWikiConnector(
# Return a deterministic, sorted list of ids
space_id_list = list(sorted(all_space_ids))
- logger.debug(f"Total spaces fetched: {len(space_id_list)}")
+ logger.debug("Total spaces fetched: %s", len(space_id_list))
return space_id_list
def _get_pages_for_space(
@@ -455,7 +466,12 @@ class DrupalWikiConnector(
params["modifiedAfter"] = int(modified_after)
logger.debug(
- f"Fetching pages for space {space_id} from {url} ({page=}, {size=}, {modified_after=})"
+ "Fetching pages for space %s from %s (page=%r, size=%r, modified_after=%r)",
+ space_id,
+ url,
+ page,
+ size,
+ modified_after,
)
response = rate_limited_get(url, headers=self.headers, params=params)
response.raise_for_status()
@@ -464,11 +480,14 @@ class DrupalWikiConnector(
try:
page_response = DrupalWikiPageResponse.model_validate(resp_json)
except Exception as e:
- logger.error(f"Failed to validate Drupal Wiki page response: {e}")
+ logger.error("Failed to validate Drupal Wiki page response: %s", e)
raise ConnectorValidationError(f"Invalid API response format: {e}")
logger.info(
- f"Fetched {len(page_response.content)} pages in space {space_id} (page={page})"
+ "Fetched %s pages in space %s (page=%s)",
+ len(page_response.content),
+ space_id,
+ page,
)
# Pydantic should automatically parse content items as DrupalWikiPage objects
@@ -480,7 +499,7 @@ class DrupalWikiConnector(
page += 1
- logger.debug(f"Total pages fetched for space {space_id}: {len(all_pages)}")
+ logger.debug("Total pages fetched for space %s: %s", space_id, len(all_pages))
return all_pages
def _get_page_content(self, page_id: int) -> DrupalWikiPage:
@@ -530,7 +549,9 @@ class DrupalWikiConnector(
attachments = self._get_page_attachments(page.id)
for attachment in attachments:
logger.info(
- f"Processing attachment: {attachment.get('name', 'Unknown')} (ID: {attachment['id']})"
+ "Processing attachment: %s (ID: %s)",
+ attachment.get("name", "Unknown"),
+ attachment["id"],
)
# Use downloadUrl from API; fallback to page URL
raw_download = attachment.get("downloadUrl")
@@ -548,14 +569,18 @@ class DrupalWikiConnector(
)
if error:
logger.warning(
- f"Error processing attachment {attachment.get('name', 'Unknown')}: {error}"
+ "Error processing attachment %s: %s",
+ attachment.get("name", "Unknown"),
+ error,
)
continue
if attachment_sections:
sections.extend(attachment_sections)
logger.debug(
- f"Added {len(attachment_sections)} section(s) for attachment {attachment.get('name', 'Unknown')}"
+ "Added %s section(s) for attachment %s",
+ len(attachment_sections),
+ attachment.get("name", "Unknown"),
)
# Create metadata
@@ -575,7 +600,7 @@ class DrupalWikiConnector(
doc_updated_at=datetime_from_utc_timestamp(page.lastModified),
)
except Exception as e:
- logger.error(f"Error processing page {page.id}: {e}")
+ logger.error("Error processing page %s: %s", page.id, e)
return ConnectorFailure(
failed_document=DocumentFailure(
document_id=str(page.id),
@@ -609,7 +634,7 @@ class DrupalWikiConnector(
# Initialize page_ids from self.pages if not already set
if not checkpoint.page_ids and self.pages:
- logger.info(f"Initializing page_ids from self.pages: {self.pages}")
+ logger.info("Initializing page_ids from self.pages: %s", self.pages)
checkpoint.page_ids = [int(page_id.strip()) for page_id in self.pages]
# Ensure spaces is not None
@@ -618,7 +643,7 @@ class DrupalWikiConnector(
while checkpoint.current_page_id_index < len(checkpoint.page_ids):
page_id = checkpoint.page_ids[checkpoint.current_page_id_index]
- logger.debug(f"Processing page ID: {page_id}")
+ logger.debug("Processing page ID: %s", page_id)
try:
# Get the page content directly
@@ -626,7 +651,7 @@ class DrupalWikiConnector(
# Skip pages outside the time range
if not self._is_page_in_time_range(page.lastModified, start, end):
- logger.info(f"Skipping page {page_id} - outside time range")
+ logger.info("Skipping page %s - outside time range", page_id)
checkpoint.current_page_id_index += 1
continue
@@ -635,7 +660,7 @@ class DrupalWikiConnector(
yield doc_or_failure
except Exception as e:
- logger.error(f"Error processing page ID {page_id}: {e}")
+ logger.error("Error processing page ID %s: %s", page_id, e)
yield ConnectorFailure(
failed_document=DocumentFailure(
document_id=str(page_id),
@@ -667,17 +692,17 @@ class DrupalWikiConnector(
all_space_ids = self._get_space_ids()
# checkpoint.spaces expects a list of ints; assign returned list
checkpoint.spaces = all_space_ids
- logger.info(f"Found {len(checkpoint.spaces)} spaces to process")
+ logger.info("Found %s spaces to process", len(checkpoint.spaces))
# Otherwise, use provided spaces if checkpoint is empty
elif not checkpoint.spaces:
- logger.info(f"Using provided spaces: {self.spaces}")
+ logger.info("Using provided spaces: %s", self.spaces)
# Use provided spaces
checkpoint.spaces = [int(space_id.strip()) for space_id in self.spaces]
# Process spaces from the checkpoint
while checkpoint.current_space_index < len(checkpoint.spaces):
space_id = checkpoint.spaces[checkpoint.current_space_index]
- logger.debug(f"Processing space ID: {space_id}")
+ logger.debug("Processing space ID: %s", space_id)
# Get pages for the current space, filtered by start time if provided
pages = self._get_pages_for_space(space_id, modified_after=start)
@@ -685,13 +710,13 @@ class DrupalWikiConnector(
# Process pages from the checkpoint
while checkpoint.current_page_index < len(pages):
page = pages[checkpoint.current_page_index]
- logger.debug(f"Processing page: {page.title} (ID: {page.id})")
+ logger.debug("Processing page: %s (ID: %s)", page.title, page.id)
# For space-based pages, we already filtered by modifiedAfter in the API call
# Only need to check the end time boundary
if end and page.lastModified >= end:
logger.info(
- f"Skipping page {page.id} - outside time range (after end)"
+ "Skipping page %s - outside time range (after end)", page.id
)
checkpoint.current_page_index += 1
continue
@@ -767,12 +792,14 @@ class DrupalWikiConnector(
"""
slim_docs: list[SlimDocument | HierarchyNode] = []
logger.info(
- f"Starting retrieve_all_slim_docs with include_all_spaces={self.include_all_spaces}, spaces={self.spaces}"
+ "Starting retrieve_all_slim_docs with include_all_spaces=%s, spaces=%s",
+ self.include_all_spaces,
+ self.spaces,
)
# Process specific page IDs if provided
if self.pages:
- logger.info(f"Processing specific pages: {self.pages}")
+ logger.info("Processing specific pages: %s", self.pages)
for page_id in self.pages:
try:
# Get the page content directly
@@ -782,7 +809,7 @@ class DrupalWikiConnector(
if not self._is_page_in_time_range(
page_content.lastModified, start, end
):
- logger.info(f"Skipping page {page_id} - outside time range")
+ logger.info("Skipping page %s - outside time range", page_id)
continue
# Create slim document for the page
@@ -794,7 +821,7 @@ class DrupalWikiConnector(
id=page_url,
)
)
- logger.debug(f"Added slim document for page {page_content.id}")
+ logger.debug("Added slim document for page %s", page_content.id)
# Process attachments for this page
attachments = self._get_page_attachments(page_content.id)
@@ -807,13 +834,14 @@ class DrupalWikiConnector(
)
)
logger.debug(
- f"Added slim document for attachment {attachment['id']}"
+ "Added slim document for attachment %s",
+ attachment["id"],
)
# Yield batch if it reaches the batch size
if len(slim_docs) >= self.batch_size:
logger.debug(
- f"Yielding batch of {len(slim_docs)} slim documents"
+ "Yielding batch of %s slim documents", len(slim_docs)
)
yield slim_docs
slim_docs = []
@@ -825,7 +853,7 @@ class DrupalWikiConnector(
except Exception as e:
logger.error(
- f"Error processing page ID {page_id} for slim documents: {e}"
+ "Error processing page ID %s for slim documents: %s", page_id, e
)
# Process spaces if include_all_spaces is True or spaces are provided
@@ -838,25 +866,25 @@ class DrupalWikiConnector(
# Fetch all spaces
all_space_ids = self._get_space_ids()
spaces_to_process = all_space_ids
- logger.info(f"Found {len(spaces_to_process)} spaces to process")
+ logger.info("Found %s spaces to process", len(spaces_to_process))
else:
- logger.info(f"Using provided spaces: {self.spaces}")
+ logger.info("Using provided spaces: %s", self.spaces)
# Use provided spaces
spaces_to_process = [int(space_id.strip()) for space_id in self.spaces]
# Process each space
for space_id in spaces_to_process:
- logger.info(f"Processing space ID: {space_id}")
+ logger.info("Processing space ID: %s", space_id)
# Get pages for the current space, filtered by start time if provided
pages = self._get_pages_for_space(space_id, modified_after=start)
# Process each page
for page in pages:
- logger.debug(f"Processing page: {page.title} (ID: {page.id})")
+ logger.debug("Processing page: %s (ID: %s)", page.title, page.id)
# Skip pages outside the time range
if end and page.lastModified >= end:
logger.info(
- f"Skipping page {page.id} - outside time range (after end)"
+ "Skipping page %s - outside time range (after end)", page.id
)
continue
@@ -867,7 +895,7 @@ class DrupalWikiConnector(
id=page_url,
)
)
- logger.info(f"Added slim document for page {page.id}")
+ logger.info("Added slim document for page %s", page.id)
# Process attachments for this page
attachments = self._get_page_attachments(page.id)
@@ -880,13 +908,14 @@ class DrupalWikiConnector(
)
)
logger.info(
- f"Added slim document for attachment {attachment['id']}"
+ "Added slim document for attachment %s",
+ attachment["id"],
)
# Yield batch if it reaches the batch size
if len(slim_docs) >= self.batch_size:
logger.info(
- f"Yielding batch of {len(slim_docs)} slim documents"
+ "Yielding batch of %s slim documents", len(slim_docs)
)
yield slim_docs
slim_docs = []
@@ -898,7 +927,7 @@ class DrupalWikiConnector(
# Yield remaining documents
if slim_docs:
- logger.debug(f"Yielding final batch of {len(slim_docs)} slim documents")
+ logger.debug("Yielding final batch of %s slim documents", len(slim_docs))
yield slim_docs
def validate_connector_settings(self) -> None:
diff --git a/backend/onyx/connectors/egnyte/connector.py b/backend/onyx/connectors/egnyte/connector.py
index b1f648a18b..123345c519 100644
--- a/backend/onyx/connectors/egnyte/connector.py
+++ b/backend/onyx/connectors/egnyte/connector.py
@@ -71,7 +71,7 @@ def _process_egnyte_file(
# Explicitly excluding image extensions here. TODO: consider allowing images
if extension not in OnyxFileExtensions.TEXT_AND_DOCUMENT_EXTENSIONS:
- logger.warning(f"Skipping file '{file_name}' with extension '{extension}'")
+ logger.warning("Skipping file '%s' with extension '%s'", file_name, extension)
return None
# Extract text content based on file type
@@ -283,7 +283,7 @@ class EgnyteConnector(LoadConnector, PollConnector, OAuthConnector):
# Iterate through yielded files and filter them
for file in self._get_files_list(self.folder_path):
if not self._should_index_file(file, start_time, end_time):
- logger.debug(f"Skipping file '{file['path']}'.")
+ logger.debug("Skipping file '%s'.", file["path"])
continue
try:
@@ -302,7 +302,9 @@ class EgnyteConnector(LoadConnector, PollConnector, OAuthConnector):
if not response.ok:
logger.error(
- f"Failed to fetch file content: {file['path']} (status code: {response.status_code})"
+ "Failed to fetch file content: %s (status code: %s)",
+ file["path"],
+ response.status_code,
)
continue
@@ -331,7 +333,7 @@ class EgnyteConnector(LoadConnector, PollConnector, OAuthConnector):
current_batch = []
except Exception:
- logger.exception(f"Failed to process file {file['path']}")
+ logger.exception("Failed to process file %s", file["path"])
continue
if current_batch:
diff --git a/backend/onyx/connectors/file/connector.py b/backend/onyx/connectors/file/connector.py
index 0e6e6482c7..22ff71ba3a 100644
--- a/backend/onyx/connectors/file/connector.py
+++ b/backend/onyx/connectors/file/connector.py
@@ -73,7 +73,7 @@ def _create_image_section(
)
return section, stored_file_name
except Exception as e:
- logger.error(f"Failed to store image {display_name}: {e}")
+ logger.error("Failed to store image %s: %s", display_name, e)
raise e
@@ -98,7 +98,7 @@ def _process_file(
if extension not in OnyxFileExtensions.ALL_ALLOWED_EXTENSIONS:
logger.warning(
- f"Skipping file '{file_name}' with unrecognized extension '{extension}'"
+ "Skipping file '%s' with unrecognized extension '%s'", file_name, extension
)
return []
@@ -121,7 +121,7 @@ def _process_file(
# Read the image data
image_data = file.read()
if not image_data:
- logger.warning(f"Empty image file: {file_name}")
+ logger.warning("Empty image file: %s", file_name)
return []
# Create an ImageSection for the image
@@ -147,7 +147,7 @@ def _process_file(
)
]
except Exception as e:
- logger.error(f"Failed to process image file {file_name}: {e}")
+ logger.error("Failed to process image file %s: %s", file_name, e)
return []
# 2) Otherwise: text-based approach. Possibly with embedded images.
@@ -165,7 +165,9 @@ def _process_file(
# If so, we should add it to any metadata processed so far
if extraction_result.metadata:
logger.debug(
- f"Found file-specific metadata for {file_name}: {extraction_result.metadata}"
+ "Found file-specific metadata for %s: %s",
+ file_name,
+ extraction_result.metadata,
)
onyx_metadata, more_custom_tags = process_onyx_metadata(
extraction_result.metadata
@@ -218,13 +220,13 @@ def _process_file(
)
)
except Exception as e:
- logger.error(f"Failed to process tabular file {file_name}: {e}")
+ logger.error("Failed to process tabular file %s: %s", file_name, e)
return []
if not sections:
- logger.warning(f"No content extracted from tabular file {file_name}")
+ logger.warning("No content extracted from tabular file %s", file_name)
return []
elif extraction_result.text_content.strip():
- logger.debug(f"Creating TextSection for {file_name} with link: {link}")
+ logger.debug("Creating TextSection for %s with link: %s", file_name, link)
sections.append(
TextSection(link=link, text=extraction_result.text_content.strip())
)
@@ -245,11 +247,14 @@ def _process_file(
)
sections.append(image_section)
logger.debug(
- f"Created ImageSection for embedded image {idx} in {file_name}, stored as: {stored_file_name}"
+ "Created ImageSection for embedded image %s in %s, stored as: %s",
+ idx,
+ file_name,
+ stored_file_name,
)
except Exception as e:
logger.warning(
- f"Failed to process embedded image {idx} in {file_name}: {e}"
+ "Failed to process embedded image %s in %s: %s", idx, file_name, e
)
return [
@@ -319,7 +324,7 @@ class LocalFileConnector(LoadConnector):
else:
zip_metadata = loaded_metadata
except Exception as e:
- logger.warning(f"Failed to load metadata from file store: {e}")
+ logger.warning("Failed to load metadata from file store: %s", e)
elif self._zip_metadata_deprecated:
logger.warning(
"Using deprecated inline zip_metadata dict. Re-upload files to use the new file store format."
@@ -333,7 +338,9 @@ class LocalFileConnector(LoadConnector):
file_record = file_store.read_file_record(file_id=file_id)
if not file_record:
# typically an unsupported extension
- logger.warning(f"No file record found for '{file_id}' in PG; skipping.")
+ logger.warning(
+ "No file record found for '%s' in PG; skipping.", file_id
+ )
continue
metadata = zip_metadata.get(
diff --git a/backend/onyx/connectors/fireflies/connector.py b/backend/onyx/connectors/fireflies/connector.py
index 25347cf0c2..0b06e77e61 100644
--- a/backend/onyx/connectors/fireflies/connector.py
+++ b/backend/onyx/connectors/fireflies/connector.py
@@ -190,8 +190,10 @@ class FirefliesConnector(PollConnector, LoadConnector):
if response.status_code < 500 or attempt == _FIREFLIES_MAX_RETRIES - 1:
break
logger.warning(
- f"Fireflies returned {response.status_code} on attempt "
- f"{attempt + 1}/{_FIREFLIES_MAX_RETRIES}, retrying"
+ "Fireflies returned %s on attempt %s/%s, retrying",
+ response.status_code,
+ attempt + 1,
+ _FIREFLIES_MAX_RETRIES,
)
time.sleep(_FIREFLIES_RETRY_BASE_DELAY_SECONDS * (2**attempt))
diff --git a/backend/onyx/connectors/freshdesk/connector.py b/backend/onyx/connectors/freshdesk/connector.py
index f86baea1df..7c390e5ef9 100644
--- a/backend/onyx/connectors/freshdesk/connector.py
+++ b/backend/onyx/connectors/freshdesk/connector.py
@@ -233,7 +233,9 @@ class FreshdeskConnector(PollConnector, LoadConnector):
tickets = json.loads(response.content)
logger.info(
- f"Fetched {len(tickets)} tickets from Freshdesk API (Page {params['page']})"
+ "Fetched %s tickets from Freshdesk API (Page %s)",
+ len(tickets),
+ params["page"],
)
yield tickets
diff --git a/backend/onyx/connectors/gitbook/connector.py b/backend/onyx/connectors/gitbook/connector.py
index 3c795ce5ba..b4480d46b3 100644
--- a/backend/onyx/connectors/gitbook/connector.py
+++ b/backend/onyx/connectors/gitbook/connector.py
@@ -235,9 +235,10 @@ class GitbookConnector(LoadConnector, PollConnector):
pages: list[dict[str, Any]] = content.get("pages", [])
current_batch: list[Document | HierarchyNode] = []
- logger.info(f"Found {len(pages)} root pages.")
+ logger.info("Found %s root pages.", len(pages))
logger.info(
- f"First 20 Page Ids: {[page.get('id', 'Unknown') for page in pages[:20]]}"
+ "First 20 Page Ids: %s",
+ [page.get("id", "Unknown") for page in pages[:20]],
)
while pages:
@@ -268,7 +269,7 @@ class GitbookConnector(LoadConnector, PollConnector):
yield current_batch
except requests.RequestException as e:
- logger.error(f"Error fetching GitBook content: {str(e)}")
+ logger.error("Error fetching GitBook content: %s", str(e))
raise
def load_from_state(self) -> GenerateDocumentsOutput:
diff --git a/backend/onyx/connectors/github/connector.py b/backend/onyx/connectors/github/connector.py
index ada0ede3c9..dd00712774 100644
--- a/backend/onyx/connectors/github/connector.py
+++ b/backend/onyx/connectors/github/connector.py
@@ -140,11 +140,13 @@ def _paginate_until_error(
if num_objs % CURSOR_LOG_FREQUENCY == 0:
logger.info(
- f"Retrieved {num_objs} objects with current cursor url: {get_nextUrl(pag_list, nextUrl_key)}"
+ "Retrieved %s objects with current cursor url: %s",
+ num_objs,
+ get_nextUrl(pag_list, nextUrl_key),
)
except Exception as e:
- logger.exception(f"Error during cursor-based pagination: {e}")
+ logger.exception("Error during cursor-based pagination: %s", e)
if num_objs - prev_num_objs > 0:
raise
@@ -230,7 +232,7 @@ def _get_userinfo(user: NamedUser) -> dict[str, str]:
try:
return cast(str | None, getattr(user, attr_name))
except GithubException:
- logger.debug(f"Error getting {attr_name} for user")
+ logger.debug("Error getting %s for user", attr_name)
return None
return {
@@ -504,7 +506,10 @@ class GithubConnector(
repos.append(repo)
except GithubException as e:
logger.warning(
- f"Could not fetch repo {self.repo_owner}/{repo_name}: {e}"
+ "Could not fetch repo %s/%s: %s",
+ self.repo_owner,
+ repo_name,
+ e,
)
return repos
@@ -609,7 +614,7 @@ class GithubConnector(
repo, self.github_client
)
if self.include_prs and checkpoint.stage == GithubConnectorStage.PRS:
- logger.info(f"Fetching PRs for repo: {repo.name}")
+ logger.info("Fetching PRs for repo: %s", repo.name)
pr_batch = _get_batch_rate_limited(
self._pull_requests_func(repo),
@@ -676,7 +681,7 @@ class GithubConnector(
# In offset mode, while indexing without time constraints, the pr batch
# will be empty when we're done.
used_cursor = checkpoint.cursor_url is not None
- logger.info(f"Fetched {num_prs} PRs for repo: {repo.name}")
+ logger.info("Fetched %s PRs for repo: %s", num_prs, repo.name)
if num_prs > 0 and not done_with_prs and not used_cursor:
return checkpoint
@@ -692,7 +697,7 @@ class GithubConnector(
checkpoint.stage = GithubConnectorStage.ISSUES
if self.include_issues and checkpoint.stage == GithubConnectorStage.ISSUES:
- logger.info(f"Fetching issues for repo: {repo.name}")
+ logger.info("Fetching issues for repo: %s", repo.name)
issue_batch = list(
_get_batch_rate_limited(
@@ -704,7 +709,7 @@ class GithubConnector(
self.github_client,
)
)
- logger.info(f"Fetched {len(issue_batch)} issues for repo: {repo.name}")
+ logger.info("Fetched %s issues for repo: %s", len(issue_batch), repo.name)
checkpoint.curr_page += 1
done_with_issues = False
num_issues = 0
@@ -753,7 +758,7 @@ class GithubConnector(
)
continue
- logger.info(f"Fetched {num_issues} issues for repo: {repo.name}")
+ logger.info("Fetched %s issues for repo: %s", num_issues, repo.name)
# if we found any issues on the page, and we're not done, return the checkpoint.
# don't return if we're using cursor-based pagination to avoid infinite loops
if num_issues > 0 and not done_with_issues and not checkpoint.cursor_url:
@@ -778,7 +783,9 @@ class GithubConnector(
if checkpoint.cached_repo_ids:
logger.info(
- f"{len(checkpoint.cached_repo_ids)} repos remaining (IDs: {checkpoint.cached_repo_ids})"
+ "%s repos remaining (IDs: %s)",
+ len(checkpoint.cached_repo_ids),
+ checkpoint.cached_repo_ids,
)
else:
logger.info("No more repos remaining")
@@ -920,7 +927,9 @@ class GithubConnector(
f"{self.repo_owner}/{repo_name}"
)
logger.info(
- f"Successfully accessed repository: {self.repo_owner}/{repo_name}"
+ "Successfully accessed repository: %s/%s",
+ self.repo_owner,
+ repo_name,
)
test_repo.get_contents("")
valid_repos = True
diff --git a/backend/onyx/connectors/github/rate_limit_utils.py b/backend/onyx/connectors/github/rate_limit_utils.py
index fdb7a5c22e..c58f6c7c8e 100644
--- a/backend/onyx/connectors/github/rate_limit_utils.py
+++ b/backend/onyx/connectors/github/rate_limit_utils.py
@@ -21,5 +21,7 @@ def sleep_after_rate_limit_exception(github_client: Github) -> None:
tzinfo=timezone.utc
) - datetime.now(tz=timezone.utc)
sleep_time += timedelta(minutes=1) # add an extra minute just to be safe
- logger.notice(f"Ran into Github rate-limit. Sleeping {sleep_time.seconds} seconds.")
+ logger.notice(
+ "Ran into Github rate-limit. Sleeping %s seconds.", sleep_time.seconds
+ )
time.sleep(sleep_time.total_seconds())
diff --git a/backend/onyx/connectors/github/utils.py b/backend/onyx/connectors/github/utils.py
index e5029b3a7e..90e31b1500 100644
--- a/backend/onyx/connectors/github/utils.py
+++ b/backend/onyx/connectors/github/utils.py
@@ -57,7 +57,7 @@ def deserialize_repository(
except Exception as e:
# If all else fails, re-fetch the repo directly
logger.warning(
- f"Failed to deserialize repository: {e}. Attempting to re-fetch."
+ "Failed to deserialize repository: %s. Attempting to re-fetch.", e
)
repo_id = cached_repo.id
return github_client.get_repo(repo_id)
diff --git a/backend/onyx/connectors/gmail/connector.py b/backend/onyx/connectors/gmail/connector.py
index 147ba28771..1e827baa41 100644
--- a/backend/onyx/connectors/gmail/connector.py
+++ b/backend/onyx/connectors/gmail/connector.py
@@ -443,7 +443,9 @@ class GmailConnector(
query = _build_time_range_query(time_range_start, time_range_end)
slim_doc_batch: list[SlimDocument | HierarchyNode] = []
logger.info(
- f"Fetching {'slim' if is_slim else 'full'} threads for user: {user_email}"
+ "Fetching %s threads for user: %s",
+ "slim" if is_slim else "full",
+ user_email,
)
gmail_service = get_gmail_service(self.creds, user_email)
try:
diff --git a/backend/onyx/connectors/gong/connector.py b/backend/onyx/connectors/gong/connector.py
index 46191f7484..a3f28b6fd3 100644
--- a/backend/onyx/connectors/gong/connector.py
+++ b/backend/onyx/connectors/gong/connector.py
@@ -183,7 +183,7 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
# detect it before raise_for_status so callers can restart the workspace.
if cursor and "cursor has expired" in response.text.lower():
raise _CursorExpiredError(response.text)
- logger.error(f"Error fetching transcripts: {response.text}")
+ logger.error("Error fetching transcripts: %s", response.text)
response.raise_for_status()
data = response.json()
@@ -248,7 +248,7 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
for workspace in self.workspaces:
workspace_id = workspace_map.get(workspace)
if not workspace_id:
- logger.error(f"Invalid Gong workspace: {workspace}")
+ logger.error("Invalid Gong workspace: %s", workspace)
continue
resolved.append(workspace_id)
@@ -304,12 +304,15 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
call_time_str = call_metadata["started"]
call_title = call_metadata["title"]
logger.info(
- f"Indexing Gong call id {call_id} from {call_time_str.split('T', 1)[0]}: {call_title}"
+ "Indexing Gong call id %s from %s: %s",
+ call_id,
+ call_time_str.split("T", 1)[0],
+ call_title,
)
call_parties = cast(list[dict] | None, call_details.get("parties"))
if call_parties is None:
- logger.error(f"Couldn't get parties for Call ID: {call_id}")
+ logger.error("Couldn't get parties for Call ID: %s", call_id)
call_parties = []
id_to_name_map = self._parse_parties(call_parties)
@@ -395,9 +398,8 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
if newly_stashed:
logger.warning(
- f"Gong call details not yet available (race condition); "
- f"deferring to next checkpoint invocation: "
- f"call_ids={newly_stashed}"
+ "Gong call details not yet available (race condition); deferring to next checkpoint invocation: call_ids=%s",
+ newly_stashed,
)
# First attempt on any newly-stashed transcripts counts as attempt #1.
# pending_call_details_attempts is guaranteed 0 here because
@@ -467,8 +469,11 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
start, end
)
logger.info(
- f"Fetching Gong calls between {start_time} and {end_time} "
- f"(workspace {checkpoint.workspace_index + 1}/{len(workspace_ids)})"
+ "Fetching Gong calls between %s and %s (workspace %s/%s)",
+ start_time,
+ end_time,
+ checkpoint.workspace_index + 1,
+ len(workspace_ids),
)
workspace_id = workspace_ids[checkpoint.workspace_index]
@@ -488,9 +493,9 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
# Document upserts are idempotent (keyed by call_id) so
# reprocessing is safe.
logger.warning(
- f"Gong pagination cursor expired for workspace "
- f"{checkpoint.workspace_index + 1}/{len(workspace_ids)}; "
- f"restarting workspace from beginning of time range."
+ "Gong pagination cursor expired for workspace %s/%s; restarting workspace from beginning of time range.",
+ checkpoint.workspace_index + 1,
+ len(workspace_ids),
)
checkpoint.cursor = None
checkpoint.has_more = True
@@ -560,17 +565,17 @@ class GongConnector(CheckpointedConnector[GongConnectorCheckpoint]):
checkpoint.pending_call_details_attempts += 1
logger.warning(
- f"Gong call details still missing after "
- f"{checkpoint.pending_call_details_attempts}/"
- f"{self.MAX_CALL_DETAILS_ATTEMPTS} attempts: "
- f"missing_call_ids={list(checkpoint.pending_transcripts.keys())}"
+ "Gong call details still missing after %s/%s attempts: missing_call_ids=%s",
+ checkpoint.pending_call_details_attempts,
+ self.MAX_CALL_DETAILS_ATTEMPTS,
+ list(checkpoint.pending_transcripts.keys()),
)
if checkpoint.pending_call_details_attempts >= self.MAX_CALL_DETAILS_ATTEMPTS:
logger.error(
- f"Giving up on missing Gong call details after "
- f"{self.MAX_CALL_DETAILS_ATTEMPTS} attempts: "
- f"missing_call_ids={list(checkpoint.pending_transcripts.keys())}"
+ "Giving up on missing Gong call details after %s attempts: missing_call_ids=%s",
+ self.MAX_CALL_DETAILS_ATTEMPTS,
+ list(checkpoint.pending_transcripts.keys()),
)
for call_id in list(checkpoint.pending_transcripts.keys()):
yield ConnectorFailure(
diff --git a/backend/onyx/connectors/google_drive/connector.py b/backend/onyx/connectors/google_drive/connector.py
index 04c06f6945..d5537118c7 100644
--- a/backend/onyx/connectors/google_drive/connector.py
+++ b/backend/onyx/connectors/google_drive/connector.py
@@ -126,7 +126,7 @@ def _clean_requested_drive_ids(
filtered_folder_ids = requested_folder_ids - all_drive_ids_available
if invalid_requested_drive_ids:
logger.warning(
- f"Some shared drive IDs were not found. IDs: {invalid_requested_drive_ids}"
+ "Some shared drive IDs were not found. IDs: %s", invalid_requested_drive_ids
)
logger.warning("Checking for folder access instead...")
filtered_folder_ids.update(invalid_requested_drive_ids)
@@ -696,7 +696,9 @@ class GoogleDriveConnector(
)
if failed_ids and folder_id in failed_ids:
logger.debug(
- f"Skipping folder {folder_id} using {email} (previously confirmed no parents)"
+ "Skipping folder %s using %s (previously confirmed no parents)",
+ folder_id,
+ email,
)
continue
@@ -704,10 +706,10 @@ class GoogleDriveConnector(
folder = get_folder_metadata(service, folder_id, field_type)
if not folder:
- logger.debug(f"Failed to fetch folder {folder_id} using {email}")
+ logger.debug("Failed to fetch folder %s using %s", folder_id, email)
continue
- logger.debug(f"Successfully fetched folder {folder_id} using {email}")
+ logger.debug("Successfully fetched folder %s using %s", folder_id, email)
# If this folder has parents, use it
if folder.get("parents"):
@@ -722,17 +724,22 @@ class GoogleDriveConnector(
if best_folder is None:
best_folder = folder
logger.debug(
- f"Folder {folder_id} has no parents when fetched by {email}, will try admin to check for parent access"
+ "Folder %s has no parents when fetched by %s, will try admin to check for parent access",
+ folder_id,
+ email,
)
if best_folder:
logger.debug(
- f"Successfully fetched folder {folder_id} but no parents found"
+ "Successfully fetched folder %s but no parents found", folder_id
)
return best_folder
logger.debug(
- f"All attempts failed to fetch folder {folder_id} (tried {retriever_email} and {self.primary_admin_email})"
+ "All attempts failed to fetch folder %s (tried %s and %s)",
+ folder_id,
+ retriever_email,
+ self.primary_admin_email,
)
return None
@@ -752,7 +759,9 @@ class GoogleDriveConnector(
drive_service = get_drive_service(self.creds, user_email)
is_service_account = isinstance(self.creds, ServiceAccountCredentials)
logger.info(
- f"Getting all drives for user {user_email} with service account: {is_service_account}"
+ "Getting all drives for user %s with service account: %s",
+ user_email,
+ is_service_account,
)
all_drive_ids: set[str] = set()
for drive in execute_paginated_retrieval(
@@ -807,7 +816,7 @@ class GoogleDriveConnector(
completion.processed_drive_ids.add(drive_id)
return drive_id
elif status == DriveIdStatus.IN_PROGRESS:
- logger.debug(f"Drive id in progress: {drive_id}")
+ logger.debug("Drive id in progress: %s", drive_id)
future_work = drive_id
if future_work:
@@ -855,9 +864,11 @@ class GoogleDriveConnector(
if curr_stage.stage == DriveRetrievalStage.MY_DRIVE_FILES:
if self.include_my_drives or user_email in self._requested_my_drive_emails:
logger.info(
- f"Getting all files in my drive as '{user_email}. Resuming: {resuming}. "
- f"Stage completed until: {curr_stage.completed_until}. "
- f"Next page token: {curr_stage.next_page_token}"
+ "Getting all files in my drive as '%s. Resuming: %s. Stage completed until: %s. Next page token: %s",
+ user_email,
+ resuming,
+ curr_stage.completed_until,
+ curr_stage.next_page_token,
)
for file_or_token in add_retrieval_info(
@@ -876,7 +887,7 @@ class GoogleDriveConnector(
DriveRetrievalStage.MY_DRIVE_FILES,
):
if isinstance(file_or_token, str):
- logger.debug(f"Done with max num pages for user {user_email}")
+ logger.debug("Done with max num pages for user %s", user_email)
checkpoint.completion_map[user_email].next_page_token = (
file_or_token
)
@@ -928,7 +939,10 @@ class GoogleDriveConnector(
drive_id = get_new_drive_id(user_email)
if drive_id:
logger.info(
- f"Getting files in shared drive '{drive_id}' as '{user_email}. Resuming: {resuming}"
+ "Getting files in shared drive '%s' as '%s. Resuming: %s",
+ drive_id,
+ user_email,
+ resuming,
)
curr_stage.completed_until = 0
curr_stage.current_folder_or_drive_id = drive_id
@@ -975,9 +989,8 @@ class GoogleDriveConnector(
folder_id = curr_stage.current_folder_or_drive_id
if folder_id is None:
logger.warning(
- f"folder id not set in checkpoint for user {user_email}. "
- "This happens occasionally when the connector is interrupted "
- "and resumed."
+ "folder id not set in checkpoint for user %s. This happens occasionally when the connector is interrupted and resumed.",
+ user_email,
)
else:
resume_start = curr_stage.completed_until
@@ -1003,7 +1016,9 @@ class GoogleDriveConnector(
if num_completed_folders >= FOLDERS_PER_CHECKPOINT:
return # resume from this folder on the next run
- logger.info(f"Getting files in folder '{folder_id}' as '{user_email}'")
+ logger.info(
+ "Getting files in folder '%s' as '%s'", folder_id, user_email
+ )
yield from _yield_from_folder_crawl(folder_id, start)
num_completed_folders += 1
@@ -1019,11 +1034,11 @@ class GoogleDriveConnector(
start: SecondsSinceUnixEpoch | None = None,
end: SecondsSinceUnixEpoch | None = None,
) -> Iterator[RetrievedDriveFile]:
- logger.info(f"Impersonating user {user_email}")
+ logger.info("Impersonating user %s", user_email)
curr_stage = checkpoint.completion_map[user_email]
resuming = True
if curr_stage.stage == DriveRetrievalStage.START:
- logger.info(f"Setting stage to {DriveRetrievalStage.MY_DRIVE_FILES.value}")
+ logger.info("Setting stage to %s", DriveRetrievalStage.MY_DRIVE_FILES.value)
curr_stage.stage = DriveRetrievalStage.MY_DRIVE_FILES
resuming = False
drive_service = get_drive_service(self.creds, user_email)
@@ -1034,7 +1049,7 @@ class GoogleDriveConnector(
# validate that the user has access to the drive APIs by performing a simple
# request and checking for a 401
try:
- logger.debug(f"Getting root folder id for user {user_email}")
+ logger.debug("Getting root folder id for user %s", user_email)
# default is ~17mins of retries, don't do that here for cases so we don't
# waste 17mins everytime we run into a user without access to drive APIs
retry_builder(tries=3, delay=1)(get_root_folder_id)(drive_service)
@@ -1043,7 +1058,7 @@ class GoogleDriveConnector(
# fail gracefully, let the other impersonations continue
# one user without access shouldn't block the entire connector
logger.warning(
- f"User '{user_email}' does not have access to the drive APIs."
+ "User '%s' does not have access to the drive APIs.", user_email
)
# mark this user as done so we don't try to retrieve anything for them
# again
@@ -1053,12 +1068,14 @@ class GoogleDriveConnector(
except RefreshError as e:
if is_user_removed():
logger.warning(
- f"User '{user_email}' confirmed removed from workspace, skipping."
+ "User '%s' confirmed removed from workspace, skipping.", user_email
)
curr_stage.stage = DriveRetrievalStage.DONE
return
logger.warning(
- f"User '{user_email}' impersonation failed at validation gate. Error: {e}"
+ "User '%s' impersonation failed at validation gate. Error: %s",
+ user_email,
+ e,
)
curr_stage.stage = DriveRetrievalStage.DONE
yield RetrievedDriveFile(
@@ -1085,12 +1102,12 @@ class GoogleDriveConnector(
except RefreshError as e:
if is_user_removed():
logger.warning(
- f"User '{user_email}' removed mid-run, skipping remaining files."
+ "User '%s' removed mid-run, skipping remaining files.", user_email
)
curr_stage.stage = DriveRetrievalStage.DONE
else:
logger.warning(
- f"User '{user_email}' impersonation failed mid-run. Error: {e}"
+ "User '%s' impersonation failed mid-run. Error: %s", user_email, e
)
curr_stage.stage = DriveRetrievalStage.DONE
yield RetrievedDriveFile(
@@ -1144,12 +1161,12 @@ class GoogleDriveConnector(
# we've found all users and drives, now time to actually start
# fetching stuff
- logger.info(f"Found {len(all_org_emails)} users to impersonate")
- logger.debug(f"Users: {all_org_emails}")
- logger.info(f"Found {len(sorted_drive_ids)} drives to retrieve")
- logger.debug(f"Drives: {sorted_drive_ids}")
- logger.info(f"Found {len(sorted_folder_ids)} folders to retrieve")
- logger.debug(f"Folders: {sorted_folder_ids}")
+ logger.info("Found %s users to impersonate", len(all_org_emails))
+ logger.debug("Users: %s", all_org_emails)
+ logger.info("Found %s drives to retrieve", len(sorted_drive_ids))
+ logger.debug("Drives: %s", sorted_drive_ids)
+ logger.info("Found %s folders to retrieve", len(sorted_folder_ids))
+ logger.debug("Folders: %s", sorted_folder_ids)
drive_id_getter = self.make_drive_id_getter(sorted_drive_ids, checkpoint)
@@ -1160,7 +1177,7 @@ class GoogleDriveConnector(
if stage_completion.stage != DriveRetrievalStage.DONE
]
- logger.debug(f"Non-completed users remaining: {len(non_completed_org_emails)}")
+ logger.debug("Non-completed users remaining: %s", len(non_completed_org_emails))
# don't process too many emails before returning a checkpoint. This is
# to resolve the case where there are a ton of emails that don't have access
@@ -1204,7 +1221,7 @@ class GoogleDriveConnector(
) - self._retrieved_folder_and_drive_ids
if remaining_folders:
logger.warning(
- f"Some folders/drives were not retrieved. IDs: {remaining_folders}"
+ "Some folders/drives were not retrieved. IDs: %s", remaining_folders
)
if any(
checkpoint.completion_map[user_email].stage != DriveRetrievalStage.DONE
@@ -1263,11 +1280,11 @@ class GoogleDriveConnector(
return
logger.info(
- f"Getting shared files/my drive files for OAuth "
- f"with include_files_shared_with_me={self.include_files_shared_with_me}, "
- f"include_my_drives={self.include_my_drives}, "
- f"include_shared_drives={self.include_shared_drives}."
- f"Using '{self.primary_admin_email}' as the account."
+ "Getting shared files/my drive files for OAuth with include_files_shared_with_me=%s, include_my_drives=%s, include_shared_drives=%s.Using '%s' as the account.",
+ self.include_files_shared_with_me,
+ self.include_my_drives,
+ self.include_shared_drives,
+ self.primary_admin_email,
)
yield from add_retrieval_info(
get_all_files_for_oauth(
@@ -1343,11 +1360,13 @@ class GoogleDriveConnector(
for drive_id in drive_ids_to_retrieve:
if drive_id in self._retrieved_folder_and_drive_ids:
logger.info(
- f"Skipping drive '{drive_id}' as it has already been retrieved"
+ "Skipping drive '%s' as it has already been retrieved", drive_id
)
continue
logger.info(
- f"Getting files in shared drive '{drive_id}' as '{self.primary_admin_email}'"
+ "Getting files in shared drive '%s' as '%s'",
+ drive_id,
+ self.primary_admin_email,
)
for file_or_token in _yield_from_drive(drive_id, start):
if isinstance(file_or_token, str):
@@ -1417,7 +1436,9 @@ class GoogleDriveConnector(
# instead, the traversed_parent_ids are used to determine what we have left to retrieve
for folder_id in remaining_folders:
logger.info(
- f"Getting files in folder '{folder_id}' as '{self.primary_admin_email}'"
+ "Getting files in folder '%s' as '%s'",
+ folder_id,
+ self.primary_admin_email,
)
yield from _yield_from_folder_crawl(folder_id, start)
@@ -1426,7 +1447,7 @@ class GoogleDriveConnector(
) - self._retrieved_folder_and_drive_ids
if remaining_folders:
logger.warning(
- f"Some folders/drives were not retrieved. IDs: {remaining_folders}"
+ "Some folders/drives were not retrieved. IDs: %s", remaining_folders
)
def _checkpointed_retrieval(
@@ -1485,8 +1506,9 @@ class GoogleDriveConnector(
continue
logger.debug(
- f"Updating checkpoint for file: {drive_file.get('name')}. "
- f"Seen: {document_id in checkpoint.all_retrieved_file_ids}"
+ "Updating checkpoint for file: %s. Seen: %s",
+ drive_file.get("name"),
+ document_id in checkpoint.all_retrieved_file_ids,
)
if document_id in checkpoint.all_retrieved_file_ids:
continue
@@ -1656,7 +1678,7 @@ class GoogleDriveConnector(
add_prefix=True,
)
if new_ancestors:
- logger.debug(f"Yielding {len(new_ancestors)} new hierarchy nodes")
+ logger.debug("Yielding %s new hierarchy nodes", len(new_ancestors))
yield from new_ancestors
func_with_args = [
@@ -1674,7 +1696,7 @@ class GoogleDriveConnector(
results: list[Document | ConnectorFailure] = [
r for r in raw_results if r is not None
]
- logger.debug(f"batch has {len(results)} docs or failures")
+ logger.debug("batch has %s docs or failures", len(results))
yield from results
checkpoint.retrieved_folder_and_drive_ids = self._retrieved_folder_and_drive_ids
@@ -1700,8 +1722,8 @@ class GoogleDriveConnector(
)
except Exception as e:
logger.exception(
- f"Error extracting document: "
- f"{retrieved_file.drive_file.get('name')} from Google Drive"
+ "Error extracting document: %s from Google Drive",
+ retrieved_file.drive_file.get("name"),
)
return ConnectorFailure(
failed_entity=EntityFailure(
@@ -1730,8 +1752,9 @@ class GoogleDriveConnector(
)
logger.info(
- f"Loading from checkpoint with completion stage: {checkpoint.completion_stage},"
- f"num retrieved ids: {len(checkpoint.all_retrieved_file_ids)}"
+ "Loading from checkpoint with completion stage: %s,num retrieved ids: %s",
+ checkpoint.completion_stage,
+ len(checkpoint.all_retrieved_file_ids),
)
checkpoint = copy.deepcopy(checkpoint)
self._retrieved_folder_and_drive_ids = checkpoint.retrieved_folder_and_drive_ids
@@ -1757,7 +1780,7 @@ class GoogleDriveConnector(
checkpoint.retrieved_folder_and_drive_ids = self._retrieved_folder_and_drive_ids
logger.info(
- f"num drive files retrieved: {len(checkpoint.all_retrieved_file_ids)}"
+ "num drive files retrieved: %s", len(checkpoint.all_retrieved_file_ids)
)
if checkpoint.completion_stage == DriveRetrievalStage.DONE:
checkpoint.has_more = False
@@ -1796,7 +1819,7 @@ class GoogleDriveConnector(
"Credentials missing, should not call this method before calling load_credentials"
)
- logger.info(f"Resolving {len(errors)} errors")
+ logger.info("Resolving %s errors", len(errors))
doc_ids = [
failure.failed_document.document_id
for failure in errors
diff --git a/backend/onyx/connectors/google_drive/doc_conversion.py b/backend/onyx/connectors/google_drive/doc_conversion.py
index ad576c97b2..9b9d6cbb4d 100644
--- a/backend/onyx/connectors/google_drive/doc_conversion.py
+++ b/backend/onyx/connectors/google_drive/doc_conversion.py
@@ -91,7 +91,7 @@ def _get_folder_info(
_folder_cache[folder_id] = (folder_name, parent_id)
return folder_name, parent_id
except HttpError as e:
- logger.warning(f"Failed to get folder info for {folder_id}: {e}")
+ logger.warning("Failed to get folder info for %s: %s", folder_id, e)
_folder_cache[folder_id] = ("Unknown", None)
return "Unknown", None
@@ -112,7 +112,7 @@ def _get_drive_name(service: GoogleDriveService, drive_id: str) -> str:
_folder_cache[cache_key] = (drive_name, None)
return drive_name
except HttpError as e:
- logger.warning(f"Failed to get drive name for {drive_id}: {e}")
+ logger.warning("Failed to get drive name for %s: %s", drive_id, e)
_folder_cache[cache_key] = (f"Shared Drive {drive_id}", None)
return f"Shared Drive {drive_id}"
@@ -289,13 +289,15 @@ def _download_request(request: Any, file_id: str, size_threshold: int) -> bytes:
)
if download_progress.resumable_progress > size_threshold:
logger.warning(
- f"File {file_id} exceeds size threshold of {size_threshold}. Skipping2."
+ "File %s exceeds size threshold of %s. Skipping2.",
+ file_id,
+ size_threshold,
)
return bytes()
response = response_bytes.getvalue()
if not response:
- logger.warning(f"Failed to download {file_id}")
+ logger.warning("Failed to download %s", file_id)
return bytes()
return response
@@ -362,7 +364,7 @@ def _download_and_extract_sections_basic(
)
sections.append(section)
except Exception as e:
- logger.error(f"Failed to process image {file_name}: {e}")
+ logger.error("Failed to process image %s: %s", file_name, e)
return FileExtractionResult(sections=sections)
# For Google Docs, Sheets, and Slides, export via the Drive API
@@ -373,7 +375,7 @@ def _download_and_extract_sections_basic(
)
response = _download_request(request, file_id, size_threshold)
if not response:
- logger.warning(f"Failed to export {file_name} as {export_mime_type}")
+ logger.warning("Failed to export %s as %s", file_name, export_mime_type)
return FileExtractionResult(sections=[])
if export_mime_type in OnyxMimeTypes.TABULAR_MIME_TYPES:
@@ -408,7 +410,7 @@ def _download_and_extract_sections_basic(
text = response_call().decode("utf-8")
return FileExtractionResult(sections=[TextSection(link=link, text=text)])
except UnicodeDecodeError as e:
- logger.warning(f"Failed to extract text from {file_name}: {e}")
+ logger.warning("Failed to extract text from %s: %s", file_name, e)
return FileExtractionResult(sections=[])
elif (
@@ -467,20 +469,20 @@ def _download_and_extract_sections_basic(
)
pdf_sections.append(section)
except Exception as e:
- logger.error(f"Failed to process PDF images in {file_name}: {e}")
+ logger.error("Failed to process PDF images in %s: %s", file_name, e)
return FileExtractionResult(sections=pdf_sections)
# Final attempt at extracting text
file_ext = get_file_ext(file.get("name", ""))
if file_ext not in OnyxFileExtensions.ALL_ALLOWED_EXTENSIONS:
- logger.warning(f"Skipping file {file.get('name')} due to extension.")
+ logger.warning("Skipping file %s due to extension.", file.get("name"))
return FileExtractionResult(sections=[])
try:
text = extract_file_text(io.BytesIO(response_call()), file_name)
return FileExtractionResult(sections=[TextSection(link=link, text=text)])
except Exception as e:
- logger.warning(f"Failed to extract text from {file_name}: {e}")
+ logger.warning("Failed to extract text from %s: %s", file_name, e)
return FileExtractionResult(sections=[])
@@ -522,7 +524,8 @@ def align_basic_advanced(
).strip()
if heading_key == "":
logger.warning(
- f"Cannot match heading: {heading}, its link will come from the following section"
+ "Cannot match heading: %s, its link will come from the following section",
+ heading,
)
continue
heading_offset = heading.find(heading_key)
@@ -537,7 +540,9 @@ def align_basic_advanced(
)
if heading_start < 0:
logger.warning(
- f"Heading key {heading_key} from heading {heading} not found in basic text"
+ "Heading key %s from heading %s not found in basic text",
+ heading_key,
+ heading,
)
heading_start = prev_start
continue
@@ -666,9 +671,11 @@ def convert_drive_item_to_document(
# This SHOULD happen very rarely, and we don't want to break the indexing process when
# a high volume of 403s occurs early. We leave a verbose log to help investigate.
logger.error(
- f"Skipping file id: {file.get('id')} name: {file.get('name')} due to 403 error."
- f"Attempted to retrieve with {retriever_emails},"
- f"got the following errors: {first_error.failure_message}"
+ "Skipping file id: %s name: %s due to 403 error.Attempted to retrieve with %s,got the following errors: %s",
+ file.get("id"),
+ file.get("name"),
+ retriever_emails,
+ first_error.failure_message,
)
return None
return first_error
@@ -711,18 +718,20 @@ def _convert_drive_item_to_document(
try:
size_int = int(size_str)
except ValueError:
- logger.warning(f"Parsing string to int failed: size_str={size_str}")
+ logger.warning("Parsing string to int failed: size_str=%s", size_str)
else:
if size_int > size_threshold:
logger.warning(
- f"{file.get('name')} exceeds size threshold of {size_threshold}. Skipping."
+ "%s exceeds size threshold of %s. Skipping.",
+ file.get("name"),
+ size_threshold,
)
return None
# If it's a Google Doc, we might do advanced parsing
if file.get("mimeType") == GDriveMimeType.DOC.value:
try:
- logger.debug(f"starting advanced parsing for {file.get('name')}")
+ logger.debug("starting advanced parsing for %s", file.get("name"))
# get_document_sections is the advanced approach for Google Docs
doc_sections = get_document_sections(
docs_service=_get_docs_service(),
@@ -734,7 +743,8 @@ def _convert_drive_item_to_document(
)
if any(SMART_CHIP_CHAR in section.text for section in doc_sections):
logger.debug(
- f"found smart chips in {file.get('name')}, aligning with basic sections"
+ "found smart chips in %s, aligning with basic sections",
+ file.get("name"),
)
basic_extraction = _download_and_extract_sections_basic(
file,
@@ -750,7 +760,8 @@ def _convert_drive_item_to_document(
except Exception as e:
logger.warning(
- f"Error in advanced parsing: {e}. Falling back to basic extraction."
+ "Error in advanced parsing: %s. Falling back to basic extraction.",
+ e,
)
# Not Google Doc, attempt basic extraction
else:
@@ -766,7 +777,7 @@ def _convert_drive_item_to_document(
# If we still don't have any sections, skip this file
if not sections:
- logger.warning(f"No content extracted from {file.get('name')}. Skipping.")
+ logger.warning("No content extracted from %s. Skipping.", file.get("name"))
return None
doc_id = onyx_document_id_from_drive_file(file)
@@ -830,7 +841,7 @@ def _convert_drive_item_to_document(
try:
doc_id = onyx_document_id_from_drive_file(file)
except Exception as e2:
- logger.warning(f"Error getting document id from file: {e2}")
+ logger.warning("Error getting document id from file: %s", e2)
file_name = file.get("name")
error_str = (
@@ -838,9 +849,9 @@ def _convert_drive_item_to_document(
)
if isinstance(e, HttpError) and e.status_code == 403:
logger.warning(
- f"Uncommon permissions error while downloading file. User "
- f"{retriever_email} was able to see file {file_name} "
- "but cannot download it."
+ "Uncommon permissions error while downloading file. User %s was able to see file %s but cannot download it.",
+ retriever_email,
+ file_name,
)
logger.warning(error_str)
diff --git a/backend/onyx/connectors/google_drive/file_retrieval.py b/backend/onyx/connectors/google_drive/file_retrieval.py
index f9b65cabe0..292eb250d5 100644
--- a/backend/onyx/connectors/google_drive/file_retrieval.py
+++ b/backend/onyx/connectors/google_drive/file_retrieval.py
@@ -146,11 +146,11 @@ def get_folder_metadata(
)
except HttpError as e:
if e.resp.status in (403, 404):
- logger.debug(f"Cannot access folder {folder_id}: {e}")
+ logger.debug("Cannot access folder %s: %s", folder_id, e)
else:
raise e
except RefreshError:
- logger.debug(f"Cannot access folder {folder_id}: impersonation failed")
+ logger.debug("Cannot access folder %s: impersonation failed", folder_id)
return None
@@ -179,11 +179,11 @@ def get_shared_drive_name(
return drive.get("name")
except HttpError as e:
if e.resp.status in (403, 404):
- logger.debug(f"Cannot access drive {drive_id}: {e}")
+ logger.debug("Cannot access drive %s: %s", drive_id, e)
else:
raise
except RefreshError:
- logger.debug(f"Cannot access drive {drive_id}: impersonation failed")
+ logger.debug("Cannot access drive %s: impersonation failed", drive_id)
return None
@@ -308,7 +308,7 @@ def crawl_folders_for_files(
start=start,
end=end,
):
- logger.info(f"Found file: {file['name']}, user email: {user_email}")
+ logger.info("Found file: %s, user email: %s", file["name"], user_email)
found_files = True
yield RetrievedDriveFile(
drive_file=file,
@@ -327,9 +327,9 @@ def crawl_folders_for_files(
if isinstance(e, HttpError) and e.status_code == 403:
# don't yield an error here because this is expected behavior
# when a user doesn't have access to a folder
- logger.debug(f"Error getting files in parent {parent_id}: {e}")
+ logger.debug("Error getting files in parent %s: %s", parent_id, e)
else:
- logger.error(f"Error getting files in parent {parent_id}: {e}")
+ logger.error("Error getting files in parent %s: %s", parent_id, e)
yield RetrievedDriveFile(
drive_file=file,
user_email=user_email,
@@ -338,7 +338,7 @@ def crawl_folders_for_files(
error=e,
)
else:
- logger.info(f"Skipping subfolder files since already traversed: {parent_id}")
+ logger.info("Skipping subfolder files since already traversed: %s", parent_id)
for subfolder in _get_folders_in_parent(
service=service,
@@ -370,7 +370,7 @@ def get_files_in_shared_drive(
) -> Iterator[GoogleDriveFileType | str]:
kwargs = {ORDER_BY_KEY: GoogleFields.MODIFIED_TIME.value}
if page_token:
- logger.info(f"Using page token: {page_token}")
+ logger.info("Using page token: %s", page_token)
kwargs[PAGE_TOKEN_KEY] = page_token
if cache_folders:
@@ -432,7 +432,7 @@ def get_all_files_in_my_drive_and_shared(
) -> Iterator[GoogleDriveFileType | str]:
kwargs = {ORDER_BY_KEY: GoogleFields.MODIFIED_TIME.value}
if page_token:
- logger.info(f"Using page token: {page_token}")
+ logger.info("Using page token: %s", page_token)
kwargs[PAGE_TOKEN_KEY] = page_token
if cache_folders:
@@ -487,7 +487,7 @@ def get_all_files_for_oauth(
) -> Iterator[GoogleDriveFileType | str]:
kwargs = {ORDER_BY_KEY: GoogleFields.MODIFIED_TIME.value}
if page_token:
- logger.info(f"Using page token: {page_token}")
+ logger.info("Using page token: %s", page_token)
kwargs[PAGE_TOKEN_KEY] = page_token
should_get_all = (
@@ -615,7 +615,7 @@ def _get_files_by_web_view_links_batch(
exception: Exception | None,
) -> None:
if exception:
- logger.warning(f"Error retrieving file {request_id}: {exception}")
+ logger.warning("Error retrieving file %s: %s", request_id, exception)
result.errors[request_id] = exception
else:
result.files[request_id] = response
@@ -637,7 +637,7 @@ def _get_files_by_web_view_links_batch(
)
batch.add(request, request_id=web_view_link)
except ValueError as e:
- logger.warning(f"Failed to extract file ID from {web_view_link}: {e}")
+ logger.warning("Failed to extract file ID from %s: %s", web_view_link, e)
result.errors[web_view_link] = e
batch.execute()
diff --git a/backend/onyx/connectors/google_site/connector.py b/backend/onyx/connectors/google_site/connector.py
index d9ea461a1d..260fc2f83e 100644
--- a/backend/onyx/connectors/google_site/connector.py
+++ b/backend/onyx/connectors/google_site/connector.py
@@ -96,7 +96,7 @@ class GoogleSitesConnector(LoadConnector):
+ "This page will not have a working link.\n\n"
+ f"# of broken links so far - {count}"
)
- logger.info(f"Path to page: {path}")
+ logger.info("Path to page: %s", path)
# cleanup the hidden `Skip to main content` and `Skip to navigation` that
# appears at the top of every page
for div in soup.find_all("div", attrs={"data-is-touch-wrapper": "true"}):
diff --git a/backend/onyx/connectors/google_utils/google_utils.py b/backend/onyx/connectors/google_utils/google_utils.py
index b66c2b8879..8cff3196fc 100644
--- a/backend/onyx/connectors/google_utils/google_utils.py
+++ b/backend/onyx/connectors/google_utils/google_utils.py
@@ -96,14 +96,18 @@ def _execute_with_retry(request: Any) -> Any:
)
else:
logger.error(
- f"No Retry-After header or timestamp found in error message: {error}"
+ "No Retry-After header or timestamp found in error message: %s",
+ error,
)
sleep_time = 60
sleep_time += 3 # Add a buffer to be safe
logger.info(
- f"Rate limit exceeded. Attempt {attempt}/{max_attempts}. Sleeping for {sleep_time} seconds."
+ "Rate limit exceeded. Attempt %s/%s. Sleeping for %s seconds.",
+ attempt,
+ max_attempts,
+ sleep_time,
)
time.sleep(sleep_time)
@@ -146,7 +150,8 @@ def _execute_single_retrieval(
and "pageToken" in str(e)
):
logger.warning(
- f"Invalid page token: {request_kwargs['pageToken']}, retrying from start of request"
+ "Invalid page token: %s, retrying from start of request",
+ request_kwargs["pageToken"],
)
request_kwargs.pop("pageToken")
return _execute_single_retrieval(
@@ -154,13 +159,13 @@ def _execute_single_retrieval(
continue_on_404_or_403,
**request_kwargs,
)
- logger.error(f"Error executing request: {e}")
+ logger.error("Error executing request: %s", e)
raise e
elif _is_rate_limit_error(e):
results = _execute_with_retry(retrieval_function(**request_kwargs))
elif e.resp.status == 404 or e.resp.status == 403:
if continue_on_404_or_403:
- logger.debug(f"Error executing request: {e}")
+ logger.debug("Error executing request: %s", e)
results = {}
else:
raise e
diff --git a/backend/onyx/connectors/highspot/client.py b/backend/onyx/connectors/highspot/client.py
index de72b12ac4..1bc40353cf 100644
--- a/backend/onyx/connectors/highspot/client.py
+++ b/backend/onyx/connectors/highspot/client.py
@@ -141,7 +141,7 @@ class HighspotClient:
request_headers.update(headers)
try:
- logger.debug(f"Making {method} request to {url}")
+ logger.debug("Making %s request to %s", method, url)
response = self.session.request(
method=method,
url=url,
@@ -200,13 +200,15 @@ class HighspotClient:
params = {"right": "view", "start": current_offset, "limit": PAGE_SIZE}
response = self._make_request("GET", "spots", params=params)
found_spots = response.get("collection", [])
- logger.info(f"Received {len(found_spots)} spots at offset {current_offset}")
+ logger.info(
+ "Received %s spots at offset %s", len(found_spots), current_offset
+ )
all_spots.extend(found_spots)
if len(found_spots) < PAGE_SIZE:
has_more = False
else:
current_offset += PAGE_SIZE
- logger.info(f"Total spots retrieved: {len(all_spots)}")
+ logger.info("Total spots retrieved: %s", len(all_spots))
return all_spots
def get_spot(self, spot_id: str) -> Dict[str, Any]:
diff --git a/backend/onyx/connectors/highspot/connector.py b/backend/onyx/connectors/highspot/connector.py
index a5edd503d6..dd3ff84eee 100644
--- a/backend/onyx/connectors/highspot/connector.py
+++ b/backend/onyx/connectors/highspot/connector.py
@@ -152,14 +152,16 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
while has_more:
logger.info(
- f"Retrieving items from spot {spot.name}, offset {offset}"
+ "Retrieving items from spot %s, offset %s",
+ spot.name,
+ offset,
)
response = self.client.get_spot_items(
spot_id=spot.id, offset=offset, page_size=self.batch_size
)
items = response.get("collection", [])
logger.info(
- f"Received {len(items)} items from spot {spot.name}"
+ "Received %s items from spot %s", len(items), spot.name
)
if not items:
has_more = False
@@ -175,7 +177,7 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
item_details = self.client.get_item(item_id)
if not item_details:
logger.warning(
- f"Item {item_id} details not found, skipping"
+ "Item %s details not found, skipping", item_id
)
continue
# Apply time filter if specified
@@ -197,7 +199,9 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
except (ValueError, TypeError):
# Skip if date cannot be parsed
logger.warning(
- f"Invalid date format for item {item_id}: {updated_at}"
+ "Invalid date format for item %s: %s",
+ item_id,
+ updated_at,
)
continue
@@ -250,7 +254,7 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
else item_id # ty: ignore[possibly-unresolved-reference]
)
logger.error(
- f"Error retrieving item {item_id}: {str(e)}"
+ "Error retrieving item %s: %s", item_id, str(e)
)
except Exception as e:
item_id = (
@@ -259,23 +263,23 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
else item_id # ty: ignore[possibly-unresolved-reference]
)
logger.error(
- f"Unexpected error for item {item_id}: {str(e)}"
+ "Unexpected error for item %s: %s", item_id, str(e)
)
has_more = len(items) >= self.batch_size
offset += self.batch_size
except (HighspotClientError, ValueError) as e:
- logger.error(f"Error processing spot {spot.name}: {str(e)}")
+ logger.error("Error processing spot %s: %s", spot.name, str(e))
raise
except Exception as e:
logger.error(
- f"Unexpected error processing spot {spot.name}: {str(e)}"
+ "Unexpected error processing spot %s: %s", spot.name, str(e)
)
raise
except Exception as e:
- logger.error(f"Error in Highspot connector: {str(e)}")
+ logger.error("Error in Highspot connector: %s", str(e))
raise
if doc_batch:
@@ -303,7 +307,10 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
title, description = self._extract_title_and_description(item_details)
default_content = f"{title}\n{description}"
logger.info(
- f"Processing item {item_id} with extension {file_extension} and file name {content_name}"
+ "Processing item %s with extension %s and file name %s",
+ item_id,
+ file_extension,
+ content_name,
)
try:
@@ -330,23 +337,25 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
else:
logger.warning(
- f"Item {item_id} has unsupported format: {file_extension}"
+ "Item %s has unsupported format: %s", item_id, file_extension
)
return default_content
except HighspotClientError as e:
error_context = f"item {item_id}" if item_id else "(item id not found)"
- logger.warning(f"Could not retrieve content for {error_context}: {str(e)}")
+ logger.warning(
+ "Could not retrieve content for %s: %s", error_context, str(e)
+ )
return default_content
except ValueError as e:
error_context = f"item {item_id}" if item_id else "(item id not found)"
- logger.error(f"Value error for {error_context}: {str(e)}")
+ logger.error("Value error for %s: %s", error_context, str(e))
return default_content
except Exception as e:
error_context = f"item {item_id}" if item_id else "(item id not found)"
logger.error(
- f"Unexpected error retrieving content for {error_context}: {str(e)}"
+ "Unexpected error retrieving content for %s: %s", error_context, str(e)
)
return default_content
@@ -395,7 +404,9 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
while has_more:
logger.info(
- f"Retrieving slim documents from spot {spot.name}, offset {offset}"
+ "Retrieving slim documents from spot %s, offset %s",
+ spot.name,
+ offset,
)
response = self.client.get_spot_items(
spot_id=spot.id, offset=offset, page_size=self.batch_size
@@ -425,7 +436,7 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
except (HighspotClientError, ValueError):
logger.exception(
- f"Error retrieving slim documents from spot {spot.name}"
+ "Error retrieving slim documents from spot %s", spot.name
)
raise
@@ -445,7 +456,7 @@ class HighspotConnector(LoadConnector, PollConnector, SlimConnectorWithPermSync)
try:
return self.client.health_check()
except Exception as e:
- logger.error(f"Failed to validate credentials: {str(e)}")
+ logger.error("Failed to validate credentials: %s", str(e))
return False
diff --git a/backend/onyx/connectors/highspot/utils.py b/backend/onyx/connectors/highspot/utils.py
index efc00dac16..d365dda875 100644
--- a/backend/onyx/connectors/highspot/utils.py
+++ b/backend/onyx/connectors/highspot/utils.py
@@ -38,11 +38,11 @@ def scrape_url_content(
context = browser.new_context()
page = context.new_page()
- logger.info(f"Navigating to URL: {url}")
+ logger.info("Navigating to URL: %s", url)
try:
page.goto(url, timeout=timeout_ms)
except Exception as e:
- logger.error(f"Failed to navigate to {url}: {str(e)}")
+ logger.error("Failed to navigate to %s: %s", url, str(e))
return None
if scroll_before_scraping:
@@ -54,7 +54,7 @@ def scrape_url_content(
try:
page.wait_for_load_state("networkidle", timeout=timeout_ms)
except Exception as e:
- logger.warning(f"Network idle wait timed out: {str(e)}")
+ logger.warning("Network idle wait timed out: %s", str(e))
break
new_height = page.evaluate("document.body.scrollHeight")
@@ -83,12 +83,12 @@ def scrape_url_content(
else:
parsed_html.cleaned_text += "\n" + iframe_content
except Exception as e:
- logger.warning(f"Error processing iframes: {str(e)}")
+ logger.warning("Error processing iframes: %s", str(e))
return parsed_html.cleaned_text
except Exception as e:
- logger.error(f"Error scraping URL {url}: {str(e)}")
+ logger.error("Error scraping URL %s: %s", url, str(e))
return None
finally:
@@ -96,12 +96,12 @@ def scrape_url_content(
try:
browser.close()
except Exception as e:
- logger.debug(f"Error closing browser: {str(e)}")
+ logger.debug("Error closing browser: %s", str(e))
if playwright:
try:
playwright.stop()
except Exception as e:
- logger.debug(f"Error stopping playwright: {str(e)}")
+ logger.debug("Error stopping playwright: %s", str(e))
def validate_url(url: str) -> None:
diff --git a/backend/onyx/connectors/hubspot/connector.py b/backend/onyx/connectors/hubspot/connector.py
index 1b4aa74123..f3f0443607 100644
--- a/backend/onyx/connectors/hubspot/connector.py
+++ b/backend/onyx/connectors/hubspot/connector.py
@@ -153,11 +153,18 @@ class HubSpotConnector(LoadConnector, PollConnector):
last_exc = e
if attempt == 0:
logger.warning(
- f"Batch fetch of {len(chunk)} {object_type} failed, retrying: {e}"
+ "Batch fetch of %s %s failed, retrying: %s",
+ len(chunk),
+ object_type,
+ e,
)
time.sleep(1)
logger.warning(
- f"Failed to batch-fetch {len(chunk)} {object_type} {chunk} after retry: {last_exc}"
+ "Failed to batch-fetch %s %s %s after retry: %s",
+ len(chunk),
+ object_type,
+ chunk,
+ last_exc,
)
return []
@@ -299,9 +306,8 @@ class HubSpotConnector(LoadConnector, PollConnector):
)
except (ValueError, TypeError):
logger.error(
- f"HubSpot search limit reached but last modified timestamp "
- f"has unrecognized format ({last_ts_ms!r}); records after "
- "the 10,000th may be missing."
+ "HubSpot search limit reached but last modified timestamp has unrecognized format (%r); records after the 10,000th may be missing.",
+ last_ts_ms,
)
return
if next_start <= start:
@@ -490,7 +496,10 @@ class HubSpotConnector(LoadConnector, PollConnector):
except Exception as e:
logger.warning(
- f"Failed to get associations from {from_object_type} to {to_object_type}: {e}"
+ "Failed to get associations from %s to %s: %s",
+ from_object_type,
+ to_object_type,
+ e,
)
return []
@@ -529,7 +538,9 @@ class HubSpotConnector(LoadConnector, PollConnector):
return associated_notes
except Exception as e:
- logger.warning(f"Failed to get notes for {object_type} {object_id}: {e}")
+ logger.warning(
+ "Failed to get notes for %s %s: %s", object_type, object_id, e
+ )
return []
def _create_object_section(
diff --git a/backend/onyx/connectors/imap/connector.py b/backend/onyx/connectors/imap/connector.py
index 64b9927310..0e93abc12d 100644
--- a/backend/onyx/connectors/imap/connector.py
+++ b/backend/onyx/connectors/imap/connector.py
@@ -188,7 +188,9 @@ class ImapConnector(
for email_id in current_todos:
email_msg = _fetch_email(mail_client=mail_client, email_id=email_id)
if not email_msg:
- logger.warning(f"Failed to fetch message {email_id=}; skipping")
+ logger.warning(
+ "Failed to fetch message email_id=%r; skipping", email_id
+ )
continue
email_headers = EmailHeaders.from_email_msg(email_msg=email_msg)
@@ -261,7 +263,9 @@ def _fetch_all_mailboxes_for_email_account(mail_client: imaplib.IMAP4_SSL) -> li
mailboxes_str = mailboxes_raw
else:
logger.warning(
- f"Expected the mailbox data to be of type str, instead got {type(mailboxes_raw)=} {mailboxes_raw}; skipping"
+ "Expected the mailbox data to be of type str, instead got type(mailboxes_raw)=%r %s; skipping",
+ type(mailboxes_raw),
+ mailboxes_raw,
)
continue
@@ -275,7 +279,8 @@ def _fetch_all_mailboxes_for_email_account(mail_client: imaplib.IMAP4_SSL) -> li
match = re.match(r'\([^)]*\)\s+"([^"]+)"\s+"?(.+?)"?$', mailboxes_str)
if not match:
logger.warning(
- f"Invalid mailbox-data formatting structure: {mailboxes_str=}; skipping"
+ "Invalid mailbox-data formatting structure: mailboxes_str=%r; skipping",
+ mailboxes_str,
)
continue
@@ -392,8 +397,9 @@ def _parse_email_body(
raw_payload = part.get_payload(decode=True)
if not isinstance(raw_payload, bytes):
logger.warning(
- "Payload section from email was expected to be an array of bytes, instead got "
- f"{type(raw_payload)=}, {raw_payload=}"
+ "Payload section from email was expected to be an array of bytes, instead got type(raw_payload)=%r, raw_payload=%r",
+ type(raw_payload),
+ raw_payload,
)
continue
body = raw_payload.decode(charset)
@@ -404,7 +410,8 @@ def _parse_email_body(
if not body:
logger.warning(
- f"Email with {email_headers.id=} has an empty body; returning an empty string"
+ "Email with email_headers.id=%r has an empty body; returning an empty string",
+ email_headers.id,
)
return ""
diff --git a/backend/onyx/connectors/jira/connector.py b/backend/onyx/connectors/jira/connector.py
index 4a5c2e5c03..268ce65049 100644
--- a/backend/onyx/connectors/jira/connector.py
+++ b/backend/onyx/connectors/jira/connector.py
@@ -270,15 +270,17 @@ def _bulk_fetch_batch(
except requests.exceptions.JSONDecodeError:
if len(issue_ids) <= 1:
logger.exception(
- f"Jira bulk-fetch response for issue(s) {issue_ids} could not "
- f"be decoded as JSON (response too large or truncated)."
+ "Jira bulk-fetch response for issue(s) %s could not be decoded as JSON (response too large or truncated).",
+ issue_ids,
)
raise
mid = len(issue_ids) // 2
logger.warning(
- f"Jira bulk-fetch JSON decode failed for batch of {len(issue_ids)} issues. "
- f"Splitting into sub-batches of {mid} and {len(issue_ids) - mid}."
+ "Jira bulk-fetch JSON decode failed for batch of %s issues. Splitting into sub-batches of %s and %s.",
+ len(issue_ids),
+ mid,
+ len(issue_ids) - mid,
)
left = _bulk_fetch_batch(jira_client, issue_ids[:mid], fields)
right = _bulk_fetch_batch(jira_client, issue_ids[mid:], fields)
@@ -297,7 +299,7 @@ def bulk_fetch_issues(
try:
raw_issues.extend(_bulk_fetch_batch(jira_client, list(batch), fields))
except Exception as e:
- logger.error(f"Error fetching issues: {e}")
+ logger.error("Error fetching issues: %s", e)
raise
return [
@@ -358,7 +360,10 @@ def _perform_jql_search_v2(
Unfortunately, jira server/data center will forever use the v2 APIs that are now deprecated.
"""
logger.debug(
- f"Fetching Jira issues with JQL: {jql}, starting at {start}, max results: {max_results}"
+ "Fetching Jira issues with JQL: %s, starting at %s, max results: %s",
+ jql,
+ start,
+ max_results,
)
try:
issues = jira_client.search_issues(
@@ -388,8 +393,10 @@ def process_jira_issue(
if labels_to_skip:
if any(label in issue.fields.labels for label in labels_to_skip):
logger.info(
- f"Skipping {issue.key} because it has a label to skip. Found "
- f"labels: {issue.fields.labels}. Labels to skip: {labels_to_skip}."
+ "Skipping %s because it has a label to skip. Found labels: %s. Labels to skip: %s.",
+ issue.key,
+ issue.fields.labels,
+ labels_to_skip,
)
return None
@@ -409,7 +416,9 @@ def process_jira_issue(
# Check ticket size
if len(ticket_content.encode("utf-8")) > JIRA_CONNECTOR_MAX_TICKET_SIZE:
logger.info(
- f"Skipping {issue.key} because it exceeds the maximum size of {JIRA_CONNECTOR_MAX_TICKET_SIZE} bytes."
+ "Skipping %s because it exceeds the maximum size of %s bytes.",
+ issue.key,
+ JIRA_CONNECTOR_MAX_TICKET_SIZE,
)
return None
@@ -475,7 +484,7 @@ def process_jira_issue(
metadata_dict[_FIELD_PROJECT_NAME] = project.name
metadata_dict[_FIELD_PROJECT] = project.key
else:
- logger.error(f"Project should exist but does not for {issue.key}")
+ logger.error("Project should exist but does not for %s", issue.key)
return Document(
id=page_url,
@@ -1025,7 +1034,7 @@ class JiraConnector(
ConnectorValidationError: For other HTTP errors with extracted error messages
"""
status_code = getattr(e, "status_code", None)
- logger.error(f"Jira API error during validation: {e}")
+ logger.error("Jira API error during validation: %s", e)
# Handle specific status codes with appropriate exceptions
if status_code == 401:
diff --git a/backend/onyx/connectors/jira/utils.py b/backend/onyx/connectors/jira/utils.py
index 9c83b6983f..16e2ffb231 100644
--- a/backend/onyx/connectors/jira/utils.py
+++ b/backend/onyx/connectors/jira/utils.py
@@ -145,7 +145,7 @@ def get_comment_strs(
comment_strs.append(body_text)
except Exception as e:
- logger.error(f"Failed to process comment due to an error: {e}")
+ logger.error("Failed to process comment due to an error: %s", e)
continue
return comment_strs
@@ -182,7 +182,7 @@ class CustomFieldExtractor:
else:
return str(value)
except Exception as e:
- logger.error(f"Error processing custom field value {value}: {e}")
+ logger.error("Error processing custom field value %s: %s", value, e)
return ""
@staticmethod
diff --git a/backend/onyx/connectors/linear/connector.py b/backend/onyx/connectors/linear/connector.py
index cd4830c981..cd99dc337d 100644
--- a/backend/onyx/connectors/linear/connector.py
+++ b/backend/onyx/connectors/linear/connector.py
@@ -67,7 +67,7 @@ def _make_query(request_body: dict[str, Any], api_key: str) -> requests.Response
if i == _NUM_RETRIES - 1:
raise e
- logger.warning(f"A Linear GraphQL error occurred: {e}. Retrying...")
+ logger.warning("A Linear GraphQL error occurred: %s. Retrying...", e)
raise RuntimeError(
"Unexpected execution when querying Linear. This should never happen."
@@ -306,11 +306,11 @@ class LinearConnector(LoadConnector, PollConnector, OAuthConnector):
"after": endCursor,
},
}
- logger.debug(f"Requesting issues from Linear with query: {graphql_query}")
+ logger.debug("Requesting issues from Linear with query: %s", graphql_query)
response = _make_query(graphql_query, self.linear_api_key)
response_json = response.json()
- logger.debug(f"Raw response from Linear: {response_json}")
+ logger.debug("Raw response from Linear: %s", response_json)
edges = response_json["data"]["issues"]["edges"]
documents: list[Document | HierarchyNode] = []
diff --git a/backend/onyx/connectors/loopio/connector.py b/backend/onyx/connectors/loopio/connector.py
index 560fe00252..7ee4960836 100644
--- a/backend/onyx/connectors/loopio/connector.py
+++ b/backend/onyx/connectors/loopio/connector.py
@@ -65,7 +65,9 @@ class LoopioConnector(LoadConnector, PollConnector):
)
if response.status_code == 400:
logger.error(
- f"Loopio API returned 400 for {resource} with params {params}",
+ "Loopio API returned 400 for %s with params %s",
+ resource,
+ params,
)
logger.error(response.text)
response.raise_for_status()
@@ -123,14 +125,15 @@ class LoopioConnector(LoadConnector, PollConnector):
answer_text = entry.get("answer", {}).get("text", "")
if not answer_text:
logger.warning(
- f"The Library entry {entry['id']} has no answer text. Skipping."
+ "The Library entry %s has no answer text. Skipping.",
+ entry["id"],
)
continue
try:
answer = parse_html_page_basic(answer_text)
except Exception as e:
- logger.error(f"Error parsing HTML for entry {entry['id']}: {e}")
+ logger.error("Error parsing HTML for entry %s: %s", entry["id"], e)
continue
questions = [
diff --git a/backend/onyx/connectors/mediawiki/wiki.py b/backend/onyx/connectors/mediawiki/wiki.py
index 647ce8bf2b..68aac5db09 100644
--- a/backend/onyx/connectors/mediawiki/wiki.py
+++ b/backend/onyx/connectors/mediawiki/wiki.py
@@ -200,7 +200,7 @@ class MediaWikiConnector(LoadConnector, PollConnector):
)
for page in all_pages:
logger.info(
- f"MediaWikiConnector: title='{page.title()}' url={page.full_url()}"
+ "MediaWikiConnector: title='%s' url=%s", page.title(), page.full_url()
)
doc_batch.append(
get_doc_from_page(page, self.site, self.document_source_type)
diff --git a/backend/onyx/connectors/notion/connector.py b/backend/onyx/connectors/notion/connector.py
index f0d608eeca..44b7d1f4bb 100644
--- a/backend/onyx/connectors/notion/connector.py
+++ b/backend/onyx/connectors/notion/connector.py
@@ -186,7 +186,7 @@ class NotionConnector(LoadConnector, PollConnector):
self, block_id: str, cursor: str | None = None
) -> dict[str, Any] | None:
"""Fetch all child blocks via the Notion API."""
- logger.debug(f"Fetching children of block with ID '{block_id}'")
+ logger.debug("Fetching children of block with ID '%s'", block_id)
block_url = f"https://api.notion.com/v1/blocks/{block_id}/children"
query_params = None if not cursor else {"start_cursor": cursor}
res = rl_requests.get(
@@ -202,13 +202,17 @@ class NotionConnector(LoadConnector, PollConnector):
# this happens when a page is not shared with the integration
# in this case, we should just ignore the page
logger.error(
- f"Unable to access block with ID '{block_id}'. "
- f"This is likely due to the block not being shared "
- f"with the Onyx integration. Exact exception:\n\n{e}"
+ "Unable to access block with ID '%s'. "
+ "This is likely due to the block not being shared "
+ "with the Onyx integration. Exact exception:\n\n%s",
+ block_id,
+ e,
)
else:
logger.exception(
- f"Error fetching blocks with status code {res.status_code}: {res.json()}"
+ "Error fetching blocks with status code %s: %s",
+ res.status_code,
+ res.json(),
)
# This can occasionally happen, the reason is unknown and cannot be reproduced on our internal Notion
@@ -219,7 +223,7 @@ class NotionConnector(LoadConnector, PollConnector):
@retry(tries=3, delay=1, backoff=2)
def _fetch_page(self, page_id: str) -> NotionPage:
"""Fetch a page from its ID via the Notion API, retry with database if page fetch fails."""
- logger.debug(f"Fetching page for ID '{page_id}'")
+ logger.debug("Fetching page for ID '%s'", page_id)
page_url = f"https://api.notion.com/v1/pages/{page_id}"
res = rl_requests.get(
page_url,
@@ -230,7 +234,9 @@ class NotionConnector(LoadConnector, PollConnector):
res.raise_for_status()
except Exception as e:
logger.warning(
- f"Failed to fetch page, trying database for ID '{page_id}'. Exception: {e}"
+ "Failed to fetch page, trying database for ID '%s'. Exception: %s",
+ page_id,
+ e,
)
# Try fetching as a database if page fetch fails, this happens if the page is set to a wiki
# it becomes a database from the notion perspective
@@ -244,7 +250,7 @@ class NotionConnector(LoadConnector, PollConnector):
Note: As of API 2025-09-03, database objects no longer include
`properties` (schema moved to individual data sources).
"""
- logger.debug(f"Fetching database for ID '{database_id}' as a page")
+ logger.debug("Fetching database for ID '%s' as a page", database_id)
database_url = f"https://api.notion.com/v1/databases/{database_id}"
res = rl_requests.get(
database_url,
@@ -254,7 +260,7 @@ class NotionConnector(LoadConnector, PollConnector):
try:
res.raise_for_status()
except Exception as e:
- logger.exception(f"Error fetching database as page - {res.json()}")
+ logger.exception("Error fetching database as page - %s", res.json())
raise e
db_data = res.json()
database_name = db_data.get("title")
@@ -271,7 +277,7 @@ class NotionConnector(LoadConnector, PollConnector):
self, database_id: str
) -> list[NotionDataSource]:
"""Fetch the list of data sources for a database."""
- logger.debug(f"Fetching data sources for database '{database_id}'")
+ logger.debug("Fetching data sources for database '%s'", database_id)
res = rl_requests.get(
f"https://api.notion.com/v1/databases/{database_id}",
headers=self.headers,
@@ -282,12 +288,14 @@ class NotionConnector(LoadConnector, PollConnector):
except Exception as e:
if res.status_code in (403, 404):
logger.error(
- f"Unable to access database with ID '{database_id}'. "
- f"This is likely due to the database not being shared "
- f"with the Onyx integration. Exact exception:\n{e}"
+ "Unable to access database with ID '%s'. "
+ "This is likely due to the database not being shared "
+ "with the Onyx integration. Exact exception:\n%s",
+ database_id,
+ e,
)
return []
- logger.exception(f"Error fetching database - {res.json()}")
+ logger.exception("Error fetching database - %s", res.json())
raise e
db_data = res.json()
@@ -303,7 +311,7 @@ class NotionConnector(LoadConnector, PollConnector):
self, data_source_id: str, cursor: str | None = None
) -> dict[str, Any]:
"""Query a data source via POST /v1/data_sources/{id}/query."""
- logger.debug(f"Querying data source '{data_source_id}'")
+ logger.debug("Querying data source '%s'", data_source_id)
url = f"https://api.notion.com/v1/data_sources/{data_source_id}/query"
body = None if not cursor else {"start_cursor": cursor}
res = rl_requests.post(
@@ -317,12 +325,14 @@ class NotionConnector(LoadConnector, PollConnector):
except Exception as e:
if res.status_code in (403, 404):
logger.error(
- f"Unable to access data source with ID '{data_source_id}'. "
- f"This is likely due to it not being shared "
- f"with the Onyx integration. Exact exception:\n{e}"
+ "Unable to access data source with ID '%s'. "
+ "This is likely due to it not being shared "
+ "with the Onyx integration. Exact exception:\n%s",
+ data_source_id,
+ e,
)
return {"results": [], "next_cursor": None}
- logger.exception(f"Error querying data source - {res.json()}")
+ logger.exception("Error querying data source - %s", res.json())
raise e
return res.json()
@@ -499,7 +509,7 @@ class NotionConnector(LoadConnector, PollConnector):
logger.debug("Skipping Notion object id field property")
return None
- logger.debug(f"Unreadable property from innermost prop: {sub_inner_dict}")
+ logger.debug("Unreadable property from innermost prop: %s", sub_inner_dict)
return None
result = ""
@@ -512,7 +522,7 @@ class NotionConnector(LoadConnector, PollConnector):
except Exception as e:
# This is not a critical failure, these properties are not the actual contents of the page
# more similar to metadata
- logger.warning(f"Error recursing properties for {prop_name}: {e}")
+ logger.warning("Error recursing properties for %s: %s", prop_name, e)
continue
# Not a perfect way to format Notion database tables but there's no perfect representation
# since this must be represented as plaintext
@@ -555,8 +565,9 @@ class NotionConnector(LoadConnector, PollConnector):
data_sources = self._fetch_data_sources_for_database(database_id)
if not data_sources:
logger.warning(
- f"Database '{database_id}' returned zero data sources — "
- f"no pages will be indexed from this database."
+ "Database '%s' returned zero data sources — "
+ "no pages will be indexed from this database.",
+ database_id,
)
for ds in data_sources:
self._data_source_to_database_map[ds.id] = database_id
@@ -578,12 +589,16 @@ class NotionConnector(LoadConnector, PollConnector):
if obj_type == "page":
logger.debug(
- f"Found page with ID '{obj_id}' in database '{database_id}'"
+ "Found page with ID '%s' in database '%s'",
+ obj_id,
+ database_id,
)
result_pages.append(result["id"])
elif obj_type == "database":
logger.debug(
- f"Found database with ID '{obj_id}' in database '{database_id}'"
+ "Found database with ID '%s' in database '%s'",
+ obj_id,
+ database_id,
)
nested_db_title = result.get("title", [])
nested_db_name = None
@@ -640,7 +655,9 @@ class NotionConnector(LoadConnector, PollConnector):
for result in data["results"]:
logger.debug(
- f"Found child block for block with ID '{base_block_id}': {result}"
+ "Found child block for block with ID '%s': %s",
+ base_block_id,
+ result,
)
result_block_id = result["id"]
result_type = result["type"]
@@ -648,25 +665,32 @@ class NotionConnector(LoadConnector, PollConnector):
if result_type == "ai_block":
logger.warning(
- f"Skipping 'ai_block' ('{result_block_id}') for base block '{base_block_id}': "
- f"Notion API does not currently support reading AI blocks (as of 24/02/09) "
- f"(discussion: https://github.com/onyx-dot-app/onyx/issues/1053)"
+ "Skipping 'ai_block' ('%s') for base block '%s': "
+ "Notion API does not currently support reading AI blocks (as of 24/02/09) "
+ "(discussion: https://github.com/onyx-dot-app/onyx/issues/1053)",
+ result_block_id,
+ base_block_id,
)
continue
if result_type == "unsupported":
logger.warning(
- f"Skipping unsupported block type '{result_type}' "
- f"('{result_block_id}') for base block '{base_block_id}': "
- f"(discussion: https://github.com/onyx-dot-app/onyx/issues/1230)"
+ "Skipping unsupported block type '%s' "
+ "('%s') for base block '%s': "
+ "(discussion: https://github.com/onyx-dot-app/onyx/issues/1230)",
+ result_type,
+ result_block_id,
+ base_block_id,
)
continue
if result_type == "external_object_instance_page":
logger.warning(
- f"Skipping 'external_object_instance_page' ('{result_block_id}') for base block '{base_block_id}': "
- f"Notion API does not currently support reading external blocks (as of 24/07/03) "
- f"(discussion: https://github.com/onyx-dot-app/onyx/issues/1761)"
+ "Skipping 'external_object_instance_page' ('%s') for base block '%s': "
+ "Notion API does not currently support reading external blocks (as of 24/07/03) "
+ "(discussion: https://github.com/onyx-dot-app/onyx/issues/1761)",
+ result_block_id,
+ base_block_id,
)
continue
@@ -700,9 +724,9 @@ class NotionConnector(LoadConnector, PollConnector):
child_pages.append(result_block_id)
self._child_page_parent_map[result_block_id] = page_id
else:
- logger.debug(f"Entering sub-block: {result_block_id}")
+ logger.debug("Entering sub-block: %s", result_block_id)
sub_output = self._read_blocks(result_block_id, page_id)
- logger.debug(f"Finished sub-block: {result_block_id}")
+ logger.debug("Finished sub-block: %s", result_block_id)
result_blocks.extend(sub_output.blocks)
child_pages.extend(sub_output.child_page_ids)
hierarchy_nodes.extend(sub_output.hierarchy_nodes)
@@ -772,10 +796,10 @@ class NotionConnector(LoadConnector, PollConnector):
all_child_page_ids: list[str] = []
for page in pages:
if page.id in self.indexed_pages:
- logger.debug(f"Already indexed page with ID '{page.id}'. Skipping.")
+ logger.debug("Already indexed page with ID '%s'. Skipping.", page.id)
continue
- logger.info(f"Reading page with ID '{page.id}', with url {page.url}")
+ logger.info("Reading page with ID '%s', with url %s", page.id, page.url)
block_output = self._read_blocks(page.id)
all_child_page_ids.extend(block_output.child_page_ids)
@@ -807,11 +831,12 @@ class NotionConnector(LoadConnector, PollConnector):
if not block_output.blocks:
if not raw_page_title:
logger.warning(
- f"No blocks OR title found for page with ID '{page.id}'. Skipping."
+ "No blocks OR title found for page with ID '%s'. Skipping.",
+ page.id,
)
continue
- logger.debug(f"No blocks found for page with ID '{page.id}'")
+ logger.debug("No blocks found for page with ID '%s'", page.id)
"""
Something like:
@@ -872,7 +897,7 @@ class NotionConnector(LoadConnector, PollConnector):
def _search_notion(self, query_dict: dict[str, Any]) -> NotionSearchResponse:
"""Search for pages from a Notion database. Includes some small number of
retries to handle misc, flakey failures."""
- logger.debug(f"Searching for pages in Notion with query_dict: {query_dict}")
+ logger.debug("Searching for pages in Notion with query_dict: %s", query_dict)
res = rl_requests.post(
"https://api.notion.com/v1/search",
headers=self.headers,
@@ -926,8 +951,10 @@ class NotionConnector(LoadConnector, PollConnector):
)
except requests.exceptions.RequestException as e:
logger.warning(
- f"Could not fetch database '{db_id}', "
- f"defaulting to workspace root. Error: {e}"
+ "Could not fetch database '%s', "
+ "defaulting to workspace root. Error: %s",
+ db_id,
+ e,
)
db_name = f"Database {db_id}"
parent_raw_id = self.workspace_id
@@ -988,7 +1015,8 @@ class NotionConnector(LoadConnector, PollConnector):
yield [workspace_node]
logger.info(
- f"Recursively loading pages from Notion based on root page with ID: {self.root_page_id}"
+ "Recursively loading pages from Notion based on root page with ID: %s",
+ self.root_page_id,
)
pages = [self._fetch_page(page_id=self.root_page_id)]
yield from batch_generator(self._read_pages(pages), self.batch_size)
diff --git a/backend/onyx/connectors/productboard/connector.py b/backend/onyx/connectors/productboard/connector.py
index 6110d1753b..3b83499216 100644
--- a/backend/onyx/connectors/productboard/connector.py
+++ b/backend/onyx/connectors/productboard/connector.py
@@ -218,7 +218,7 @@ class ProductboardConnector(PollConnector):
):
return True
else:
- logger.debug(f"Unable to find updated_at for document '{document.id}'")
+ logger.debug("Unable to find updated_at for document '%s'", document.id)
return False
diff --git a/backend/onyx/connectors/salesforce/connector.py b/backend/onyx/connectors/salesforce/connector.py
index 10a8a1f71c..5cf94777d4 100644
--- a/backend/onyx/connectors/salesforce/connector.py
+++ b/backend/onyx/connectors/salesforce/connector.py
@@ -306,11 +306,14 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
num_csvs += 1
num_bytes += file_size
logger.info(
- f"CSV download: object_type={object_type} path={csv_path} bytes={file_size}"
+ "CSV download: object_type=%s path=%s bytes=%s",
+ object_type,
+ csv_path,
+ file_size,
)
logger.info(
- f"CSV download total: total_csvs={num_csvs} total_bytes={num_bytes}"
+ "CSV download total: total_csvs=%s total_bytes=%s", num_csvs, num_bytes
)
@staticmethod
@@ -339,12 +342,14 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
# This takes 10-70 minutes first time (idk why the range is so big)
total_types = len(object_type_to_csv_path)
- logger.info(f"Starting to process {total_types} object types")
+ logger.info("Starting to process %s object types", total_types)
for i, (object_type, csv_paths) in enumerate(
object_type_to_csv_path.items(), 1
):
- logger.info(f"Processing object type {object_type} ({i}/{total_types})")
+ logger.info(
+ "Processing object type %s (%s/%s)", object_type, i, total_types
+ )
# If path is None, it means it failed to fetch the csv
if csv_paths is None:
continue
@@ -354,10 +359,11 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
num_records = 0
logger.debug(
- f"Processing CSV: object_type={object_type} "
- f"csv={csv_path} "
- f"len={Path(csv_path).stat().st_size} "
- f"records={num_records}"
+ "Processing CSV: object_type=%s csv=%s len=%s records=%s",
+ object_type,
+ csv_path,
+ Path(csv_path).stat().st_size,
+ num_records,
)
with open(csv_path, "r", newline="", encoding="utf-8") as f:
@@ -376,15 +382,16 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
sf_db.flush()
logger.debug(
- f"Added {len(new_ids)} new/updated records for {object_type}"
+ "Added %s new/updated records for %s", len(new_ids), object_type
)
logger.info(
- f"Processed CSV: object_type={object_type} "
- f"csv={csv_path} "
- f"len={Path(csv_path).stat().st_size} "
- f"records={num_records} "
- f"db_len={sf_db.file_size}"
+ "Processed CSV: object_type=%s csv=%s len=%s records=%s db_len=%s",
+ object_type,
+ csv_path,
+ Path(csv_path).stat().st_size,
+ num_records,
+ sf_db.file_size,
)
os.remove(csv_path)
@@ -469,10 +476,11 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
processed = examined_ids - 1
if now - last_log_time > SalesforceConnector.LOG_INTERVAL:
logger.info(
- f"Processing stats: {type_to_processed} "
- f"file_size={sf_db.file_size} "
- f"processed={processed} "
- f"remaining={len(changed_ids_to_type) - processed}"
+ "Processing stats: %s file_size=%s processed=%s remaining=%s",
+ type_to_processed,
+ sf_db.file_size,
+ processed,
+ len(changed_ids_to_type) - processed,
)
last_log_time = now
@@ -481,7 +489,7 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
parent_object = sf_db.get_record(parent_id, parent_type)
if not parent_object:
logger.warning(
- f"Failed to get parent object {parent_id} for {parent_type}"
+ "Failed to get parent object %s for %s", parent_id, parent_type
)
continue
@@ -556,12 +564,14 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
)
total_types = len(object_type_to_csv_paths)
- logger.info(f"Starting to process {total_types} object types")
+ logger.info("Starting to process %s object types", total_types)
for i, (object_type, csv_paths) in enumerate(
object_type_to_csv_paths.items(), 1
):
- logger.info(f"Processing object type {object_type} ({i}/{total_types})")
+ logger.info(
+ "Processing object type %s (%s/%s)", object_type, i, total_types
+ )
# If path is None, it means it failed to fetch the csv
if csv_paths is None:
continue
@@ -575,10 +585,11 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
num_records += 1
logger.debug(
- f"Processing CSV: object_type={object_type} "
- f"csv={csv_path} "
- f"len={Path(csv_path).stat().st_size} "
- f"records={num_records}"
+ "Processing CSV: object_type=%s csv=%s len=%s records=%s",
+ object_type,
+ csv_path,
+ Path(csv_path).stat().st_size,
+ num_records,
)
new_ids = sf_db.update_from_csv(
@@ -591,15 +602,16 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
sf_db.flush()
logger.debug(
- f"Added {len(new_ids)} new/updated records for {object_type}"
+ "Added %s new/updated records for %s", len(new_ids), object_type
)
logger.info(
- f"Processed CSV: object_type={object_type} "
- f"csv={csv_path} "
- f"len={Path(csv_path).stat().st_size} "
- f"records={num_records} "
- f"db_len={sf_db.file_size}"
+ "Processed CSV: object_type=%s csv=%s len=%s records=%s db_len=%s",
+ object_type,
+ csv_path,
+ Path(csv_path).stat().st_size,
+ num_records,
+ sf_db.file_size,
)
os.remove(csv_path)
@@ -607,9 +619,9 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
gc.collect()
- logger.info(f"Found {len(changed_ids_to_type)} total updated records")
+ logger.info("Found %s total updated records", len(changed_ids_to_type))
logger.info(
- f"Starting to process parent objects of types: {ctx.parent_types}"
+ "Starting to process parent objects of types: %s", ctx.parent_types
)
# Step 3 - extract and index docs
@@ -629,13 +641,13 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
raise
finally:
logger.info(
- f"Final processing stats: "
- f"examined={examined_ids} "
- f"parents_changed={parents_changed} "
- f"remaining={len(changed_ids_to_type) - examined_ids}"
+ "Final processing stats: examined=%s parents_changed=%s remaining=%s",
+ examined_ids,
+ parents_changed,
+ len(changed_ids_to_type) - examined_ids,
)
- logger.info(f"Top level object types processed: {type_to_processed}")
+ logger.info("Top level object types processed: %s", type_to_processed)
sf_db.close()
@@ -673,9 +685,9 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
)
gc.collect()
- logger.info(f"Found {len(changed_ids_to_type)} total updated records")
+ logger.info("Found %s total updated records", len(changed_ids_to_type))
logger.info(
- f"Starting to process parent objects of types: {ctx.parent_types}"
+ "Starting to process parent objects of types: %s", ctx.parent_types
)
# Step 3 - extract and index docs
@@ -850,9 +862,10 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
processed = num_examined
if now - last_log_time > SalesforceConnector.LOG_INTERVAL:
logger.info(
- f"Processing stats: {type_to_processed} "
- f"processed={processed} "
- f"remaining={len(changed_ids_to_type) - processed}"
+ "Processing stats: %s processed=%s remaining=%s",
+ type_to_processed,
+ processed,
+ len(changed_ids_to_type) - processed,
)
last_log_time = now
@@ -862,13 +875,13 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
raise
finally:
logger.info(
- f"Final processing stats: "
- f"processed={processed} "
- f"remaining={len(changed_ids_to_type) - processed} "
- f"parents_changed={parents_changed}"
+ "Final processing stats: processed=%s remaining=%s parents_changed=%s",
+ processed,
+ len(changed_ids_to_type) - processed,
+ parents_changed,
)
- logger.info(f"Top level object types processed: {type_to_processed}")
+ logger.info("Top level object types processed: %s", type_to_processed)
sf_db.close()
@@ -927,9 +940,11 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
# 'is_custom': sobject['custom']
# }
- logger.info(f"Describe: num_prefixes={len(prefix_to_type)}")
+ logger.info("Describe: num_prefixes=%s", len(prefix_to_type))
- logger.info(f"Parent object types: num={len(parent_types)} list={parent_types}")
+ logger.info(
+ "Parent object types: num=%s list=%s", len(parent_types), parent_types
+ )
for parent_type in parent_types:
# parent_onyx_sf_type = OnyxSalesforceType(parent_type, sf_client)
@@ -954,17 +969,19 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
# Use only the specified fields
type_to_queryable_fields[parent_type] = field_set
- logger.info(f"Using custom fields for {parent_type}: {field_set}")
+ logger.info("Using custom fields for %s: %s", parent_type, field_set)
else:
# Use all queryable fields
type_to_queryable_fields[parent_type] = (
sf_client.get_queryable_fields_by_type(parent_type)
)
- logger.info(f"Using all fields for {parent_type}")
+ logger.info("Using all fields for %s", parent_type)
child_types_all = sf_client.get_children_of_sf_type(parent_type)
- logger.debug(f"Found {len(child_types_all)} child types for {parent_type}")
- logger.debug(f"child types: {child_types_all}")
+ logger.debug(
+ "Found %s child types for %s", len(child_types_all), parent_type
+ )
+ logger.debug("child types: %s", child_types_all)
child_types_working = child_types_all.copy()
if associations_config is not None:
@@ -975,7 +992,7 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
for k in associations_config:
if k not in child_types_working:
any_not_found = True
- logger.warning(f"Association {k} not found in {parent_type}")
+ logger.warning("Association %s not found in %s", k, parent_type)
if any_not_found:
queryable_fields = sf_client.get_queryable_fields_by_type(
parent_type
@@ -1035,11 +1052,14 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
child_types.update(child_types_working.keys())
logger.info(
- f"Child object types: parent={parent_type} num={len(child_types_working)} list={child_types_working.keys()}"
+ "Child object types: parent=%s num=%s list=%s",
+ parent_type,
+ len(child_types_working),
+ child_types_working.keys(),
)
logger.info(
- f"Final child object types: num={len(child_types)} list={child_types}"
+ "Final child object types: num=%s list=%s", len(child_types), child_types
)
all_types: set[str] = set(parent_types)
@@ -1049,7 +1069,7 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnectorWithPermSyn
all_types.add(USER_OBJECT_TYPE) # Always add User for permissioning purposes
all_types.add(ACCOUNT_OBJECT_TYPE) # Always add Account for reference purposes
- logger.info(f"All object types: num={len(all_types)} list={all_types}")
+ logger.info("All object types: num=%s list=%s", len(all_types), all_types)
# Ensure User and Account have queryable fields if they weren't already processed
essential_types = [USER_OBJECT_TYPE, ACCOUNT_OBJECT_TYPE]
diff --git a/backend/onyx/connectors/salesforce/doc_conversion.py b/backend/onyx/connectors/salesforce/doc_conversion.py
index 2fe3317dfb..86543cff5c 100644
--- a/backend/onyx/connectors/salesforce/doc_conversion.py
+++ b/backend/onyx/connectors/salesforce/doc_conversion.py
@@ -132,10 +132,10 @@ def _extract_primary_owner(
) -> BasicExpertInfo | None:
object_dict = sf_object.data
if not (last_modified_by_id := object_dict.get("LastModifiedById")):
- logger.warning(f"No LastModifiedById found for {sf_object.id}")
+ logger.warning("No LastModifiedById found for %s", sf_object.id)
return None
if not (last_modified_by := sf_db.get_record(last_modified_by_id)):
- logger.warning(f"No LastModifiedBy found for {last_modified_by_id}")
+ logger.warning("No LastModifiedBy found for %s", last_modified_by_id)
return None
user_data = last_modified_by.data
@@ -153,7 +153,7 @@ def _extract_primary_owner(
and expert_info.email is None
and expert_info.display_name is None
):
- logger.warning(f"No identifying information found for user {user_data}")
+ logger.warning("No identifying information found for user %s", user_data)
return None
return expert_info
diff --git a/backend/onyx/connectors/salesforce/onyx_salesforce.py b/backend/onyx/connectors/salesforce/onyx_salesforce.py
index e1d0c2c959..209967ee4e 100644
--- a/backend/onyx/connectors/salesforce/onyx_salesforce.py
+++ b/backend/onyx/connectors/salesforce/onyx_salesforce.py
@@ -78,7 +78,7 @@ class OnyxSalesforce(Salesforce):
except SalesforceRefusedRequest as e:
if is_salesforce_rate_limit_error(e):
logger.warning(
- f"Salesforce rate limit exceeded for query: {query[:100]}..."
+ "Salesforce rate limit exceeded for query: %s...", query[:100]
)
# Add additional delay for rate limit errors
time.sleep(5)
@@ -99,7 +99,7 @@ class OnyxSalesforce(Salesforce):
except SalesforceRefusedRequest as e:
if is_salesforce_rate_limit_error(e):
logger.warning(
- f"Salesforce rate limit exceeded for query_all: {query[:100]}..."
+ "Salesforce rate limit exceeded for query_all: %s...", query[:100]
)
# Add additional delay for rate limit errors
time.sleep(5)
@@ -206,7 +206,7 @@ class OnyxSalesforce(Salesforce):
try:
result = self.safe_query(query)
except Exception:
- logger.exception(f"Query failed: {query=}")
+ logger.exception("Query failed: query=%r", query)
else:
for child_record_key, child_result in result["records"][0].items():
if child_record_key == "attributes":
@@ -256,7 +256,7 @@ class OnyxSalesforce(Salesforce):
except SalesforceRefusedRequest as e:
if is_salesforce_rate_limit_error(e):
logger.warning(
- f"Salesforce rate limit exceeded for describe_type: {name}"
+ "Salesforce rate limit exceeded for describe_type: %s", name
)
# Add additional delay for rate limit errors
time.sleep(3)
@@ -303,14 +303,23 @@ class OnyxSalesforce(Salesforce):
valid, reason = self._is_valid_child_object(child_relationship)
if not valid:
logger.debug(
- f"{index}/{len_relationships} - Invalid child object: "
- f"parent={sf_type} child={child_name} child_field_backreference={child_relationship['field']} {reason=}"
+ "%s/%s - Invalid child object: parent=%s child=%s child_field_backreference=%s reason=%r",
+ index,
+ len_relationships,
+ sf_type,
+ child_name,
+ child_relationship["field"],
+ reason,
)
continue
logger.debug(
- f"{index}/{len_relationships} - Found valid child object: "
- f"parent={sf_type} child={child_name} child_field_backreference={child_relationship['field']}"
+ "%s/%s - Found valid child object: parent=%s child=%s child_field_backreference=%s",
+ index,
+ len_relationships,
+ sf_type,
+ child_name,
+ child_relationship["field"],
)
name = child_name
diff --git a/backend/onyx/connectors/salesforce/salesforce_calls.py b/backend/onyx/connectors/salesforce/salesforce_calls.py
index b4e5e3d497..27bb20df29 100644
--- a/backend/onyx/connectors/salesforce/salesforce_calls.py
+++ b/backend/onyx/connectors/salesforce/salesforce_calls.py
@@ -99,7 +99,7 @@ def _object_type_has_api_data(
except SalesforceRefusedRequest as e:
if is_salesforce_rate_limit_error(e):
logger.warning(
- f"Salesforce rate limit exceeded for object type check: {sf_type}"
+ "Salesforce rate limit exceeded for object type check: %s", sf_type
)
# Add additional delay for rate limit errors
time.sleep(3)
@@ -107,7 +107,7 @@ def _object_type_has_api_data(
except Exception as e:
if "OPERATION_TOO_LARGE" not in str(e):
- logger.warning(f"Object type {sf_type} doesn't support query: {e}")
+ logger.warning("Object type %s doesn't support query: %s", sf_type, e)
return False
return True
@@ -147,9 +147,9 @@ def _bulk_retrieve_from_salesforce(
if not bulk_2_type:
return sf_type, None
- logger.info(f"Downloading {sf_type}")
+ logger.info("Downloading %s", sf_type)
- logger.debug(f"Query: {query}")
+ logger.debug("Query: %s", query)
try:
# This downloads the file to a file in the target path with a random name
@@ -170,16 +170,16 @@ def _bulk_retrieve_from_salesforce(
all_download_paths.append(new_file_path)
except Exception as e:
logger.error(
- f"Failed to download salesforce csv for object type {sf_type}: {e}"
+ "Failed to download salesforce csv for object type %s: %s", sf_type, e
)
- logger.warning(f"Exceptioning query for object type {sf_type}: {query}")
+ logger.warning("Exceptioning query for object type %s: %s", sf_type, query)
return sf_type, None
finally:
bulk_2_handler = None
bulk_2_type = None
gc.collect()
- logger.info(f"Downloaded {sf_type} to {all_download_paths}")
+ logger.info("Downloaded %s to %s", sf_type, all_download_paths)
return sf_type, all_download_paths
@@ -215,26 +215,32 @@ def fetch_all_csvs_in_parallel(
)
if time_filter_temp is None:
logger.warning(
- f"Object type not filterable: type={sf_type} fields={queryable_fields}"
+ "Object type not filterable: type=%s fields=%s",
+ sf_type,
+ queryable_fields,
)
time_filter = ""
else:
logger.info(
- f"Object type filterable: type={sf_type} filter={time_filter_temp}"
+ "Object type filterable: type=%s filter=%s",
+ sf_type,
+ time_filter_temp,
)
time_filter = time_filter_temp
break
if not _object_type_has_api_data(sf_client, sf_type, time_filter):
- logger.warning(f"Object type skipped (no data available): type={sf_type}")
+ logger.warning("Object type skipped (no data available): type=%s", sf_type)
continue
query = _make_time_filtered_query(queryable_fields, sf_type, time_filter)
type_to_query[sf_type] = query
logger.info(
- f"Object types to query: initial={len(all_types_to_filter)} queryable={len(type_to_query)}"
+ "Object types to query: initial=%s queryable=%s",
+ len(all_types_to_filter),
+ len(type_to_query),
)
# Run the bulk retrieve in parallel
diff --git a/backend/onyx/connectors/salesforce/shelve_stuff/shelve_functions.py b/backend/onyx/connectors/salesforce/shelve_stuff/shelve_functions.py
index c57000b405..02062d07e4 100644
--- a/backend/onyx/connectors/salesforce/shelve_stuff/shelve_functions.py
+++ b/backend/onyx/connectors/salesforce/shelve_stuff/shelve_functions.py
@@ -70,8 +70,8 @@ def _update_relationship_shelves(
parent_to_child_db.sync()
except Exception as e:
- logger.error(f"Error updating relationship shelves: {e}")
- logger.error(f"Child ID: {child_id}, Parent IDs: {parent_ids}")
+ logger.error("Error updating relationship shelves: %s", e)
+ logger.error("Child ID: %s, Parent IDs: %s", child_id, parent_ids)
raise
@@ -134,7 +134,7 @@ def get_type_from_id(object_id: str) -> str | None:
# Look up the object type from the ID-to-type mapping
with shelve.open(get_id_type_shelf_path()) as id_type_db:
if object_id not in id_type_db:
- logger.warning(f"Object ID {object_id} not found in ID-to-type mapping")
+ logger.warning("Object ID %s not found in ID-to-type mapping", object_id)
return None
return id_type_db[object_id]
@@ -153,7 +153,7 @@ def get_record(
shelf_path = get_object_shelf_path(object_type)
with shelve.open(shelf_path) as db:
if object_id not in db:
- logger.warning(f"Object ID {object_id} not found in {shelf_path}")
+ logger.warning("Object ID %s not found in %s", object_id, shelf_path)
return None
data = db[object_id]
return SalesforceObject(
diff --git a/backend/onyx/connectors/salesforce/sqlite_functions.py b/backend/onyx/connectors/salesforce/sqlite_functions.py
index 370a1527b1..7c46263def 100644
--- a/backend/onyx/connectors/salesforce/sqlite_functions.py
+++ b/backend/onyx/connectors/salesforce/sqlite_functions.py
@@ -114,13 +114,13 @@ class OnyxSalesforceSQLite:
if SQLITE_DISK_IO_ERROR not in str(e):
raise
- logger.warning(f"SQLite disk I/O error detected, attempting recovery: {e}")
+ logger.warning("SQLite disk I/O error detected, attempting recovery: %s", e)
self._recover_from_corruption()
self._apply_schema_impl()
def _recover_from_corruption(self) -> None:
"""Recover from SQLite corruption by removing all database files and reconnecting."""
- logger.info(f"Removing corrupted SQLite files: {self.filename}")
+ logger.info("Removing corrupted SQLite files: %s", self.filename)
# Close existing connection
self.close()
@@ -146,7 +146,7 @@ class OnyxSalesforceSQLite:
if self._existing_db:
file_path = Path(self.filename)
file_size = file_path.stat().st_size
- logger.info(f"init_db - found existing sqlite db: len={file_size}")
+ logger.info("init_db - found existing sqlite db: len=%s", file_size)
else:
# NOTE(rkuo): why is this only if the db doesn't exist?
@@ -248,7 +248,10 @@ class OnyxSalesforceSQLite:
)
elapsed = time.monotonic() - start
- logger.info(f"init_db - create tables and indices: elapsed={elapsed:.2f}")
+ logger.info(
+ "init_db - create tables and indices: elapsed=%s",
+ format(elapsed, ".2f"),
+ )
# Analyze tables to help query planner
# NOTE(rkuo): skip ANALYZE - it takes too long and we likely don't have
@@ -265,13 +268,17 @@ class OnyxSalesforceSQLite:
start = time.monotonic()
cursor.execute("SELECT COUNT(*) FROM user_email_map")
elapsed = time.monotonic() - start
- logger.info(f"init_db - count user_email_map: elapsed={elapsed:.2f}")
+ logger.info(
+ "init_db - count user_email_map: elapsed=%s", format(elapsed, ".2f")
+ )
start = time.monotonic()
if cursor.fetchone()[0] == 0:
OnyxSalesforceSQLite._update_user_email_map(cursor)
elapsed = time.monotonic() - start
- logger.info(f"init_db - update_user_email_map: elapsed={elapsed:.2f}")
+ logger.info(
+ "init_db - update_user_email_map: elapsed=%s", format(elapsed, ".2f")
+ )
def get_user_id_by_email(self, email: str) -> str | None:
"""Get the Salesforce User ID for a given email address.
@@ -322,10 +329,11 @@ class OnyxSalesforceSQLite:
else:
cache_bytes = abs(cache_pages * 1024)
logger.info(
- f"SQLite stats: sqlite_version={sqlite3.sqlite_version} "
- f"cache_pages={cache_pages} "
- f"page_size={page_size} "
- f"cache_bytes={cache_bytes}"
+ "SQLite stats: sqlite_version=%s cache_pages=%s page_size=%s cache_bytes=%s",
+ sqlite3.sqlite_version,
+ cache_pages,
+ page_size,
+ cache_bytes,
)
# get_changed_parent_ids_by_type_2 replaces this
@@ -464,7 +472,11 @@ class OnyxSalesforceSQLite:
]
for field_name, _ in parent_relationship_fields.items():
if field_name not in sf_object.data:
- logger.warning(f"{field_name=} not in data for {changed_type=}!")
+ logger.warning(
+ "field_name=%r not in data for changed_type=%r!",
+ field_name,
+ changed_type,
+ )
continue
parent_id = cast(str, sf_object.data[field_name])
@@ -472,7 +484,8 @@ class OnyxSalesforceSQLite:
if parent_id_prefix not in prefix_to_type:
logger.warning(
- f"Could not lookup type for prefix: {parent_id_prefix=}"
+ "Could not lookup type for prefix: parent_id_prefix=%r",
+ parent_id_prefix,
)
continue
@@ -573,7 +586,10 @@ class OnyxSalesforceSQLite:
for row in reader:
if ID_FIELD not in row:
logger.warning(
- f"Row {row} does not have an {ID_FIELD} field in {csv_download_path}"
+ "Row %s does not have an %s field in %s",
+ row,
+ ID_FIELD,
+ csv_download_path,
)
continue
@@ -640,7 +656,7 @@ class OnyxSalesforceSQLite:
)
result = cursor.fetchone()
if not result:
- logger.warning(f"Object ID {object_id} not found")
+ logger.warning("Object ID %s not found", object_id)
return None
return result[0]
@@ -673,7 +689,7 @@ class OnyxSalesforceSQLite:
)
result = cursor.fetchall()
if not result:
- logger.warning(f"Object ID {object_id} not found")
+ logger.warning("Object ID %s not found", object_id)
return None
data = json.loads(result[0][0])
@@ -772,7 +788,9 @@ class OnyxSalesforceSQLite:
except Exception:
logger.exception(
- f"Error updating relationship tables: child_id={child_id} parent_ids={parent_ids}"
+ "Error updating relationship tables: child_id=%s parent_ids=%s",
+ child_id,
+ parent_ids,
)
raise
@@ -800,10 +818,10 @@ class OnyxSalesforceSQLite:
of the user if possible."""
object_dict: dict[str, Any] = sf_object.data
if not (last_modified_by_id := object_dict.get("LastModifiedById")):
- logger.warning(f"No LastModifiedById found for {sf_object.id}")
+ logger.warning("No LastModifiedById found for %s", sf_object.id)
return None
if not (last_modified_by := self.get_record(last_modified_by_id)):
- logger.warning(f"No LastModifiedBy found for {last_modified_by_id}")
+ logger.warning("No LastModifiedBy found for %s", last_modified_by_id)
return None
try:
diff --git a/backend/onyx/connectors/sharepoint/connector.py b/backend/onyx/connectors/sharepoint/connector.py
index d2b30c4b6d..cd4fc2a318 100644
--- a/backend/onyx/connectors/sharepoint/connector.py
+++ b/backend/onyx/connectors/sharepoint/connector.py
@@ -269,7 +269,10 @@ def sleep_and_retry(
# 429 / 503 — rate limit or transient error. Back off and retry.
if status in (429, 503) and attempt < max_retries:
logger.warning(
- f"Rate limit exceeded on {method_name}, attempt {attempt + 1}/{max_retries + 1}, sleeping and retrying"
+ "Rate limit exceeded on %s, attempt %s/%s, sleeping and retrying",
+ method_name,
+ attempt + 1,
+ max_retries + 1,
)
retry_after = (
e.response.headers.get( # ty: ignore[unresolved-attribute]
@@ -282,7 +285,7 @@ def sleep_and_retry(
# Exponential backoff: 2^attempt * 5 seconds
sleep_time = min(30, (2**attempt) * 5)
- logger.info(f"Sleeping for {sleep_time} seconds before retry")
+ logger.info("Sleeping for %s seconds before retry", sleep_time)
time.sleep(sleep_time)
continue
@@ -294,7 +297,7 @@ def sleep_and_retry(
# caller intentionally handles.
if e.response is not None:
logger.warning(
- f"SharePoint request failed for {method_name}: status={status}, "
+ "SharePoint request failed for %s: status=%s, ", method_name, status
)
raise e
@@ -338,7 +341,7 @@ def _log_and_raise_for_status(response: requests.Response) -> None:
try:
response.raise_for_status()
except Exception:
- logger.error(f"HTTP request failed: {response.text}")
+ logger.error("HTTP request failed: %s", response.text)
raise
@@ -383,7 +386,7 @@ def load_certificate_from_pfx(pfx_data: bytes, password: str) -> CertificateData
thumbprint=certificate.fingerprint(hashes.SHA1()).hex(),
)
except Exception as e:
- logger.error(f"Error loading certificate: {e}")
+ logger.error("Error loading certificate: %s", e)
return None
@@ -483,7 +486,9 @@ def _download_with_cap(url: str, timeout: int, cap: int) -> bytes:
content_len = int(cl_header)
if content_len > cap:
logger.warning(
- f"Content-Length {content_len} exceeds cap {cap}; skipping download."
+ "Content-Length %s exceeds cap %s; skipping download.",
+ content_len,
+ cap,
)
raise SizeCapExceeded("pre_download")
@@ -496,7 +501,7 @@ def _download_with_cap(url: str, timeout: int, cap: int) -> bytes:
if buf.tell() > cap:
# Avoid keeping a large partial buffer; close and signal caller to skip.
logger.warning(
- f"Streaming download exceeded cap {cap} bytes; aborting early."
+ "Streaming download exceeded cap %s bytes; aborting early.", cap
)
raise SizeCapExceeded("during_download")
@@ -552,7 +557,9 @@ def _convert_driveitem_to_document_with_permissions(
mime_type = driveitem.mime_type
if not mime_type or mime_type in OnyxMimeTypes.EXCLUDED_IMAGE_TYPES:
logger.debug(
- f"Skipping malformed or excluded mime type {mime_type} for {driveitem.name}"
+ "Skipping malformed or excluded mime type %s for %s",
+ mime_type,
+ driveitem.name,
)
return None
@@ -564,7 +571,10 @@ def _convert_driveitem_to_document_with_permissions(
if file_size is not None and file_size > SHAREPOINT_CONNECTOR_SIZE_THRESHOLD:
logger.warning(
- f"Skipping '{driveitem.name}' over size threshold ({file_size} > {SHAREPOINT_CONNECTOR_SIZE_THRESHOLD} bytes)."
+ "Skipping '%s' over size threshold (%s > %s bytes).",
+ driveitem.name,
+ file_size,
+ SHAREPOINT_CONNECTOR_SIZE_THRESHOLD,
)
return None
@@ -578,12 +588,16 @@ def _convert_driveitem_to_document_with_permissions(
SHAREPOINT_CONNECTOR_SIZE_THRESHOLD,
)
except SizeCapExceeded as e:
- logger.warning(f"Skipping '{driveitem.name}' exceeded size cap: {str(e)}")
+ logger.warning(
+ "Skipping '%s' exceeded size cap: %s", driveitem.name, str(e)
+ )
return None
except requests.RequestException as e:
status = e.response.status_code if e.response is not None else -1
logger.warning(
- f"Failed to download via downloadUrl for '{driveitem.name}' (status={status}); falling back to Graph API."
+ "Failed to download via downloadUrl for '%s' (status=%s); falling back to Graph API.",
+ driveitem.name,
+ status,
)
# Fallback: download via Graph API /content endpoint
@@ -598,12 +612,13 @@ def _convert_driveitem_to_document_with_permissions(
)
except SizeCapExceeded:
logger.warning(
- f"Skipping '{driveitem.name}' exceeded size cap during Graph API download."
+ "Skipping '%s' exceeded size cap during Graph API download.",
+ driveitem.name,
)
return None
except Exception as e:
logger.warning(
- f"Failed to download via Graph API for '{driveitem.name}': {e}"
+ "Failed to download via Graph API for '%s': %s", driveitem.name, e
)
return _create_document_failure(
driveitem, f"Failed to download via graph api: {e}", e
@@ -616,7 +631,8 @@ def _convert_driveitem_to_document_with_permissions(
if not content_bytes:
logger.warning(
- f"Zero-length content for '{driveitem.name}'. Skipping text/image extraction."
+ "Zero-length content for '%s'. Skipping text/image extraction.",
+ driveitem.name,
)
elif file_ext in OnyxFileExtensions.IMAGE_EXTENSIONS:
image_section, _ = store_image_and_create_section(
@@ -649,7 +665,7 @@ def _convert_driveitem_to_document_with_permissions(
)
except Exception as e:
logger.warning(
- f"Failed to extract tabular sections for '{driveitem.name}': {e}"
+ "Failed to extract tabular sections for '%s': %s", driveitem.name, e
)
else:
extraction_result = extract_text_and_images(
@@ -665,7 +681,7 @@ def _convert_driveitem_to_document_with_permissions(
)
if include_permissions and ctx is not None:
- logger.info(f"Getting external access for {driveitem.name}")
+ logger.info("Getting external access for %s", driveitem.name)
sdk_item = driveitem.to_sdk_driveitem(graph_client)
external_access = get_sharepoint_external_access(
ctx=ctx,
@@ -961,10 +977,11 @@ class SharepointConnector(
self.sharepoint_domain_suffix = resolved_env.sharepoint_domain_suffix
if sharepoint_domain_suffix != resolved_env.sharepoint_domain_suffix:
logger.warning(
- f"Configured sharepoint_domain_suffix '{sharepoint_domain_suffix}' "
- f"differs from the expected suffix '{resolved_env.sharepoint_domain_suffix}' "
- f"for the {resolved_env.environment} environment. "
- f"Using '{resolved_env.sharepoint_domain_suffix}'."
+ "Configured sharepoint_domain_suffix '%s' differs from the expected suffix '%s' for the %s environment. Using '%s'.",
+ sharepoint_domain_suffix,
+ resolved_env.sharepoint_domain_suffix,
+ resolved_env.environment,
+ resolved_env.sharepoint_domain_suffix,
)
def validate_connector_settings(self) -> None:
@@ -1017,7 +1034,7 @@ class SharepointConnector(
raise
except Exception as e:
logger.warning(
- f"RoleAssignments permission probe failed (non-blocking): {e}"
+ "RoleAssignments permission probe failed (non-blocking): %s", e
)
def _extract_tenant_domain_from_sites(self) -> str | None:
@@ -1036,7 +1053,7 @@ class SharepointConnector(
tenant = hostname.split(".")[0]
if tenant:
return tenant
- logger.warning(f"No tenant domain found from {len(self.sites)} sites")
+ logger.warning("No tenant domain found from %s sites", len(self.sites))
return None
def _resolve_tenant_domain_from_root_site(self) -> str:
@@ -1130,12 +1147,13 @@ class SharepointConnector(
try:
parsed = urlsplit(url)
except ValueError:
- logger.warning(f"Sharepoint URL '{url}' could not be parsed")
+ logger.warning("Sharepoint URL '%s' could not be parsed", url)
return None, []
if not parsed.scheme or not parsed.netloc:
logger.warning(
- f"Sharepoint URL '{url}' is not a valid absolute URL (missing scheme or host)"
+ "Sharepoint URL '%s' is not a valid absolute URL (missing scheme or host)",
+ url,
)
return None, []
@@ -1159,7 +1177,8 @@ class SharepointConnector(
if site_type_index is None or len(parts) <= site_type_index + 1:
logger.warning(
- f"Site URL '{url}' is not a valid Sharepoint URL (must contain /sites/ or /teams/)"
+ "Site URL '%s' is not a valid Sharepoint URL (must contain /sites/ or /teams/)",
+ url,
)
continue
@@ -1200,7 +1219,7 @@ class SharepointConnector(
"""
site = self.graph_client.sites.get_by_url(site_descriptor.url)
drives = site.drives.get().execute_query()
- logger.info(f"Found drives: {[d.name for d in drives]}")
+ logger.info("Found drives: %s", [d.name for d in drives])
matched = [
d
@@ -1212,12 +1231,12 @@ class SharepointConnector(
)
]
if not matched:
- logger.warning(f"Drive '{drive_name}' not found")
+ logger.warning("Drive '%s' not found", drive_name)
return None
drive = matched[0]
drive_web_url: str | None = drive.web_url
- logger.info(f"Found drive: {drive.name} (web_url: {drive_web_url})")
+ logger.info("Found drive: %s (web_url: %s)", drive.name, drive_web_url)
return cast(str, drive.id), drive_web_url
def _get_drive_items_for_drive_id(
@@ -1263,7 +1282,9 @@ class SharepointConnector(
):
raise e
- logger.warning(f"Failed to process site: {site_descriptor.url} - {err_str}")
+ logger.warning(
+ "Failed to process site: %s - %s", site_descriptor.url, err_str
+ )
def _fetch_driveitems(
self,
@@ -1279,7 +1300,7 @@ class SharepointConnector(
try:
site = self.graph_client.sites.get_by_url(site_descriptor.url)
drives = site.drives.get().execute_query()
- logger.debug(f"Found drives: {[d.name for d in drives]}")
+ logger.debug("Found drives: %s", [d.name for d in drives])
if site_descriptor.drive_name:
drives = [
@@ -1293,7 +1314,7 @@ class SharepointConnector(
)
]
if not drives:
- logger.warning(f"Drive '{site_descriptor.drive_name}' not found")
+ logger.warning("Drive '%s' not found", site_descriptor.drive_name)
return
for drive in drives:
@@ -1323,7 +1344,9 @@ class SharepointConnector(
yield item, drive_name or "", drive_web_url
except Exception as e:
- logger.warning(f"Failed to process drive '{drive.name}': {str(e)}")
+ logger.warning(
+ "Failed to process drive '%s': %s", drive.name, str(e)
+ )
except Exception as e:
err_str = str(e)
@@ -1334,7 +1357,7 @@ class SharepointConnector(
):
raise e
- logger.warning(f"Failed to process site: {err_str}")
+ logger.warning("Failed to process site: %s", err_str)
def _handle_paginated_sites(
self, sites: SitesWithRoot
@@ -1364,7 +1387,7 @@ class SharepointConnector(
result = []
for sd in site_descriptors:
if _is_site_excluded(sd.url, self.excluded_sites):
- logger.info(f"Excluding site by denylist: {sd.url}")
+ logger.info("Excluding site by denylist: %s", sd.url)
continue
result.append(sd)
return result
@@ -1416,7 +1439,7 @@ class SharepointConnector(
data = self._graph_api_get_json(page_url, params)
except HTTPError as e:
if e.response is not None and e.response.status_code == 404:
- logger.warning(f"Site page not found: {page_url}")
+ logger.warning("Site page not found: %s", page_url)
break
if (
e.response is not None
@@ -1424,9 +1447,8 @@ class SharepointConnector(
and _is_graph_invalid_request(e.response)
):
logger.warning(
- f"$expand=canvasLayout on the LIST endpoint returned 400 "
- f"for site {site_descriptor.url}. Falling back to "
- f"per-page expansion."
+ "$expand=canvasLayout on the LIST endpoint returned 400 for site %s. Falling back to per-page expansion.",
+ site_descriptor.url,
)
yield from self._fetch_site_pages_individually(
site_pages_base, start, end, skip_ids=yielded_ids
@@ -1447,7 +1469,7 @@ class SharepointConnector(
page_url = data.get("@odata.nextLink")
- logger.debug(f"Yielded {total_yielded} site pages for {site_descriptor.url}")
+ logger.debug("Yielded %s site pages for %s", total_yielded, site_descriptor.url)
def _fetch_site_pages_individually(
self,
@@ -1502,7 +1524,7 @@ class SharepointConnector(
page_url = data.get("@odata.nextLink")
logger.debug(
- f"Yielded {total_yielded} site pages (per-page expansion fallback)"
+ "Yielded %s site pages (per-page expansion fallback)", total_yielded
)
def _try_expand_single_page(
@@ -1526,7 +1548,9 @@ class SharepointConnector(
):
page_name = fallback_page.get("name", page_id)
logger.warning(
- f"$expand=canvasLayout failed for page '{page_name}' ({page_id}). Indexing metadata only."
+ "$expand=canvasLayout failed for page '%s' (%s). Indexing metadata only.",
+ page_name,
+ page_id,
)
return fallback_page
raise
@@ -1574,7 +1598,11 @@ class SharepointConnector(
)
wait = min(retry_after, 60)
logger.warning(
- f"Graph API {response.status_code} on attempt {attempt + 1}, retrying in {wait}s: {url}"
+ "Graph API %s on attempt %s, retrying in %ss: %s",
+ response.status_code,
+ attempt + 1,
+ wait,
+ url,
)
time.sleep(wait)
# Re-acquire token in case it expired during a long traversal
@@ -1587,7 +1615,10 @@ class SharepointConnector(
if attempt < GRAPH_API_MAX_RETRIES:
wait = min(2**attempt, 60)
logger.warning(
- f"Graph API connection error on attempt {attempt + 1}, retrying in {wait}s: {url}"
+ "Graph API connection error on attempt %s, retrying in %ss: %s",
+ attempt + 1,
+ wait,
+ url,
)
time.sleep(wait)
continue
@@ -1856,7 +1887,9 @@ class SharepointConnector(
end=end,
):
if self._is_driveitem_excluded(driveitem):
- logger.debug(f"Excluding by path denylist: {driveitem.web_url}")
+ logger.debug(
+ "Excluding by path denylist: %s", driveitem.web_url
+ )
continue
if drive_web_url:
@@ -1887,7 +1920,7 @@ class SharepointConnector(
)
try:
- logger.debug(f"Processing: {driveitem.web_url}")
+ logger.debug("Processing: %s", driveitem.web_url)
if include_permissions:
ctx = self._create_rest_client_context(site_descriptor.url)
doc_batch.append(
@@ -1911,7 +1944,7 @@ class SharepointConnector(
)
)
except Exception as e:
- logger.warning(f"Failed to process driveitem: {str(e)}")
+ logger.warning("Failed to process driveitem: %s", str(e))
if len(doc_batch) >= SLIM_BATCH_SIZE:
yield doc_batch
@@ -1924,7 +1957,8 @@ class SharepointConnector(
)
for site_page in site_pages:
logger.debug(
- f"Processing site page: {site_page.get('webUrl', site_page.get('name', 'Unknown'))}"
+ "Processing site page: %s",
+ site_page.get("webUrl", site_page.get("name", "Unknown")),
)
try:
if include_permissions:
@@ -1951,8 +1985,9 @@ class SharepointConnector(
)
except Exception as e:
logger.warning(
- f"Failed to process site page "
- f"{site_page.get('webUrl', site_page.get('name', 'Unknown'))}: {e}"
+ "Failed to process site page %s: %s",
+ site_page.get("webUrl", site_page.get("name", "Unknown")),
+ e,
)
if len(doc_batch) >= SLIM_BATCH_SIZE:
yield doc_batch
@@ -1991,7 +2026,7 @@ class SharepointConnector(
if certificate_data is None:
raise RuntimeError("Failed to load certificate")
- logger.info(f"Creating MSAL app with authority url {authority_url}")
+ logger.info("Creating MSAL app with authority url %s", authority_url)
self.msal_app = msal.ConfidentialClientApplication(
authority=authority_url,
client_id=sp_client_id,
@@ -2042,7 +2077,7 @@ class SharepointConnector(
return drive_names
except Exception as e:
- logger.warning(f"Failed to fetch drives for site '{site_url}': {e}")
+ logger.warning("Failed to fetch drives for site '%s': %s", site_url, e)
return []
def _build_folder_url(
@@ -2237,7 +2272,7 @@ class SharepointConnector(
return checkpoint
logger.info(
- f"Found {len(checkpoint.cached_site_descriptors)} sites to process"
+ "Found %s sites to process", len(checkpoint.cached_site_descriptors)
)
# Set first site and return to allow checkpoint persistence
if checkpoint.cached_site_descriptors:
@@ -2245,7 +2280,7 @@ class SharepointConnector(
checkpoint.cached_site_descriptors.popleft()
)
logger.info(
- f"Starting with site: {checkpoint.current_site_descriptor.url}"
+ "Starting with site: %s", checkpoint.current_site_descriptor.url
)
# Yield site hierarchy node for the first site
yield from self._yield_site_hierarchy_node(
@@ -2262,14 +2297,16 @@ class SharepointConnector(
return checkpoint
logger.info(
- f"Initializing drives for site: {checkpoint.current_site_descriptor.url}"
+ "Initializing drives for site: %s",
+ checkpoint.current_site_descriptor.url,
)
try:
# If the user explicitly specified drive(s) for this site, honour that
if checkpoint.current_site_descriptor.drive_name:
logger.info(
- f"Using explicitly specified drive: {checkpoint.current_site_descriptor.drive_name}"
+ "Using explicitly specified drive: %s",
+ checkpoint.current_site_descriptor.drive_name,
)
checkpoint.cached_drive_names = deque(
[checkpoint.current_site_descriptor.drive_name]
@@ -2282,16 +2319,21 @@ class SharepointConnector(
if not checkpoint.cached_drive_names:
logger.warning(
- f"No accessible drives found for site: {checkpoint.current_site_descriptor.url}"
+ "No accessible drives found for site: %s",
+ checkpoint.current_site_descriptor.url,
)
else:
logger.info(
- f"Found {len(checkpoint.cached_drive_names)} drives: {list(checkpoint.cached_drive_names)}"
+ "Found %s drives: %s",
+ len(checkpoint.cached_drive_names),
+ list(checkpoint.cached_drive_names),
)
except Exception as e:
logger.error(
- f"Failed to initialize drives for site: {checkpoint.current_site_descriptor.url}: {e}"
+ "Failed to initialize drives for site: %s: %s",
+ checkpoint.current_site_descriptor.url,
+ e,
)
# Yield a ConnectorFailure for site-level access failures
start_dt = datetime.fromtimestamp(start, tz=timezone.utc)
@@ -2334,9 +2376,11 @@ class SharepointConnector(
site_descriptor = checkpoint.current_site_descriptor
logger.info(
- f"Processing drive '{checkpoint.current_drive_name}' in site: {site_descriptor.url}"
+ "Processing drive '%s' in site: %s",
+ checkpoint.current_drive_name,
+ site_descriptor.url,
)
- logger.debug(f"Time range: {start_dt} to {end_dt}")
+ logger.debug("Time range: %s to %s", start_dt, end_dt)
current_drive_name = checkpoint.current_drive_name
if current_drive_name is None:
@@ -2345,11 +2389,11 @@ class SharepointConnector(
try:
logger.info(
- f"Fetching drive items for drive name: {current_drive_name}"
+ "Fetching drive items for drive name: %s", current_drive_name
)
result = self._resolve_drive(site_descriptor, current_drive_name)
if result is None:
- logger.warning(f"Drive '{current_drive_name}' not found, skipping")
+ logger.warning("Drive '%s' not found, skipping", current_drive_name)
self._clear_drive_checkpoint_state(checkpoint)
return checkpoint
@@ -2358,7 +2402,10 @@ class SharepointConnector(
checkpoint.current_drive_web_url = drive_web_url
except Exception as e:
logger.error(
- f"Failed to retrieve items from drive '{current_drive_name}' in site: {site_descriptor.url}: {e}"
+ "Failed to retrieve items from drive '%s' in site: %s: %s",
+ current_drive_name,
+ site_descriptor.url,
+ e,
)
yield _create_entity_failure(
f"{site_descriptor.url}|{current_drive_name}",
@@ -2419,7 +2466,9 @@ class SharepointConnector(
)
except Exception as e:
logger.error(
- f"Failed to fetch delta page for drive '{current_drive_name}': {e}"
+ "Failed to fetch delta page for drive '%s': %s",
+ current_drive_name,
+ e,
)
yield _create_entity_failure(
f"{site_descriptor.url}|{current_drive_name}",
@@ -2448,19 +2497,22 @@ class SharepointConnector(
item_count += 1
if self._is_driveitem_excluded(driveitem):
- logger.debug(f"Excluding by path denylist: {driveitem.web_url}")
+ logger.debug("Excluding by path denylist: %s", driveitem.web_url)
continue
if driveitem.id and driveitem.id in checkpoint.seen_document_ids:
logger.debug(
- f"Skipping duplicate document {driveitem.id} ({driveitem.name})"
+ "Skipping duplicate document %s (%s)",
+ driveitem.id,
+ driveitem.name,
)
continue
driveitem_extension = get_file_ext(driveitem.name)
if driveitem_extension not in OnyxFileExtensions.ALL_ALLOWED_EXTENSIONS:
logger.warning(
- f"Skipping {driveitem.web_url} as it is not a supported file type"
+ "Skipping %s as it is not a supported file type",
+ driveitem.web_url,
)
continue
@@ -2521,19 +2573,22 @@ class SharepointConnector(
yield doc_or_failure
else:
logger.warning(
- f"Skipping {driveitem.web_url} as it is empty and not a PDF or image"
+ "Skipping %s as it is empty and not a PDF or image",
+ driveitem.web_url,
)
elif isinstance(doc_or_failure, ConnectorFailure):
yield doc_or_failure
except Exception as e:
logger.warning(
- f"Failed to process driveitem {driveitem.web_url}: {e}"
+ "Failed to process driveitem %s: %s", driveitem.web_url, e
)
yield _create_document_failure(
driveitem, f"Failed to process: {str(e)}", e
)
- logger.info(f"Processed {item_count} items in drive '{current_drive_name}'")
+ logger.info(
+ "Processed %s items in drive '%s'", item_count, current_drive_name
+ )
if has_more_delta_pages:
return checkpoint
@@ -2544,7 +2599,8 @@ class SharepointConnector(
# If we have more drives in current site, continue with current site
if checkpoint.cached_drive_names and len(checkpoint.cached_drive_names) > 0:
logger.debug(
- f"Continuing with {len(checkpoint.cached_drive_names)} remaining drives in current site"
+ "Continuing with %s remaining drives in current site",
+ len(checkpoint.cached_drive_names),
)
return checkpoint
@@ -2554,7 +2610,8 @@ class SharepointConnector(
and checkpoint.current_site_descriptor is not None
):
logger.info(
- f"Processing site pages for site: {checkpoint.current_site_descriptor.url}"
+ "Processing site pages for site: %s",
+ checkpoint.current_site_descriptor.url,
)
checkpoint.process_site_pages = True
return checkpoint
@@ -2573,7 +2630,8 @@ class SharepointConnector(
)
for site_page in site_pages:
logger.debug(
- f"Processing site page: {site_page.get('webUrl', site_page.get('name', 'Unknown'))}"
+ "Processing site page: %s",
+ site_page.get("webUrl", site_page.get("name", "Unknown")),
)
client_ctx: ClientContext | None = None
if include_permissions:
@@ -2591,7 +2649,7 @@ class SharepointConnector(
)
)
logger.info(
- f"Finished processing site pages for site: {site_descriptor.url}"
+ "Finished processing site pages for site: %s", site_descriptor.url
)
# If no more drives, move to next site if available
@@ -2610,10 +2668,13 @@ class SharepointConnector(
checkpoint.cached_drive_names = None # Reset for new site
checkpoint.process_site_pages = False
logger.info(
- f"Finished site '{current_site}', moving to next site: {checkpoint.current_site_descriptor.url}"
+ "Finished site '%s', moving to next site: %s",
+ current_site,
+ checkpoint.current_site_descriptor.url,
)
logger.info(
- f"Remaining sites to process: {len(checkpoint.cached_site_descriptors) + 1}"
+ "Remaining sites to process: %s",
+ len(checkpoint.cached_site_descriptors) + 1,
)
# Yield site hierarchy node for the new site
yield from self._yield_site_hierarchy_node(
@@ -2628,7 +2689,7 @@ class SharepointConnector(
else "unknown"
)
logger.info(
- f"SharePoint processing complete. Finished last site: {current_site}"
+ "SharePoint processing complete. Finished last site: %s", current_site
)
checkpoint.has_more = False
return checkpoint
diff --git a/backend/onyx/connectors/slack/connector.py b/backend/onyx/connectors/slack/connector.py
index dc5eeba233..5b98f96052 100644
--- a/backend/onyx/connectors/slack/connector.py
+++ b/backend/onyx/connectors/slack/connector.py
@@ -157,7 +157,7 @@ def get_channel_messages(
channel=channel["id"],
is_private=channel["is_private"],
)
- logger.info(f"Successfully joined '{channel['name']}'")
+ logger.info("Successfully joined '%s'", channel["name"])
for result in make_paginated_slack_api_call(
client.conversations_history,
@@ -419,12 +419,12 @@ def _get_messages(
)
except SlackApiError as e:
if e.response["error"] == "is_archived":
- logger.warning(f"Channel {channel['name']} is archived. Skipping.")
+ logger.warning("Channel %s is archived. Skipping.", channel["name"])
return [], False
- logger.exception(f"Error joining channel {channel['name']}")
+ logger.exception("Error joining channel %s", channel["name"])
raise
- logger.info(f"Successfully joined '{channel['name']}'")
+ logger.info("Successfully joined '%s'", channel["name"])
response = client.conversations_history(
channel=channel["id"],
@@ -624,7 +624,7 @@ def _process_message(
failure=None,
)
except Exception as e:
- logger.exception(f"Error processing message {message['ts']}")
+ logger.exception("Error processing message %s", message["ts"])
return ProcessedSlackMessage(
doc=None,
thread_or_message_ts=thread_or_message_ts,
@@ -844,7 +844,7 @@ class SlackConnector(
auth_response = self.client.auth_test()
self._workspace_url = auth_response.get("url")
except Exception as e:
- logger.warning(f"Failed to get workspace URL from auth_test: {e}")
+ logger.warning("Failed to get workspace URL from auth_test: %s", e)
self._workspace_url = None
def retrieve_all_slim_docs_perm_sync(
@@ -901,7 +901,9 @@ class SlackConnector(
raw_channels, self.channels, self.channel_regex_enabled
)
logger.info(
- f"Channels - initial checkpoint: all={len(raw_channels)} post_filtering={len(filtered_channels)}"
+ "Channels - initial checkpoint: all=%s post_filtering=%s",
+ len(raw_channels),
+ len(filtered_channels),
)
checkpoint.channel_ids = [c["id"] for c in filtered_channels]
@@ -928,10 +930,10 @@ class SlackConnector(
num_channels_remaining += 1
logger.info(
- f"Channels - current status: "
- f"processed={len(final_channel_ids) - num_channels_remaining} "
- f"remaining={num_channels_remaining} "
- f"total={len(final_channel_ids)}"
+ "Channels - current status: processed=%s remaining=%s total=%s",
+ len(final_channel_ids) - num_channels_remaining,
+ num_channels_remaining,
+ len(final_channel_ids),
)
channel = checkpoint.current_channel
@@ -966,7 +968,10 @@ class SlackConnector(
)
logger.debug(
- f"Getting messages for channel {channel} within range {oldest} - {latest}"
+ "Getting messages for channel %s within range %s - %s",
+ channel,
+ oldest,
+ latest,
)
message_batch, has_more_in_channel = _get_messages(
@@ -974,7 +979,11 @@ class SlackConnector(
)
logger.info(
- f"Retrieved messages: {len(message_batch)=} {channel=} {oldest=} {latest=}"
+ "Retrieved messages: len(message_batch)=%r channel=%r oldest=%r latest=%r",
+ len(message_batch),
+ channel,
+ oldest,
+ latest,
)
# message_batch[0] is the newest message (Slack returns newest to oldest)
@@ -1061,7 +1070,10 @@ class SlackConnector(
)
logger.info(
- f"Current channel processing stats: {range_start=} range_end={end} percent_complete={range_percent_complete=:.2f}"
+ "Current channel processing stats: range_start=%r range_end=%s percent_complete=range_percent_complete=%s",
+ range_start,
+ end,
+ format(range_percent_complete, ".2f"),
)
checkpoint.seen_thread_ts = list(seen_thread_ts)
@@ -1117,14 +1129,14 @@ class SlackConnector(
channels_processed / len(final_channel_ids) * 100.0
)
logger.info(
- f"All channels processing stats: "
- f"processed={len(final_channel_ids) - num_channels_remaining} "
- f"remaining={num_channels_remaining} "
- f"total={len(final_channel_ids)} "
- f"percent_complete={channels_percent_complete:.2f}"
+ "All channels processing stats: processed=%s remaining=%s total=%s percent_complete=%s",
+ len(final_channel_ids) - num_channels_remaining,
+ num_channels_remaining,
+ len(final_channel_ids),
+ format(channels_percent_complete, ".2f"),
)
except Exception as e:
- logger.exception(f"Error processing channel {channel['name']}")
+ logger.exception("Error processing channel %s", channel["name"])
yield ConnectorFailure(
failed_entity=EntityFailure(
entity_id=channel["id"],
@@ -1225,8 +1237,8 @@ class SlackConnector(
# Handle rate limiting specifically
retry_after = int(e.response.headers.get("Retry-After", 1))
logger.warning(
- f"Slack API rate limited during validation. Retry suggested after {retry_after} seconds. "
- "Proceeding with validation, but be aware that connector operations might be throttled."
+ "Slack API rate limited during validation. Retry suggested after %s seconds. Proceeding with validation, but be aware that connector operations might be throttled.",
+ retry_after,
)
# Continue validation without failing - the connector is likely valid but just rate limited
return
diff --git a/backend/onyx/connectors/slack/onyx_retry_handler.py b/backend/onyx/connectors/slack/onyx_retry_handler.py
index ee70252a53..3b05b5c5ab 100644
--- a/backend/onyx/connectors/slack/onyx_retry_handler.py
+++ b/backend/onyx/connectors/slack/onyx_retry_handler.py
@@ -132,10 +132,10 @@ class OnyxRedisSlackRetryHandler(RetryHandler):
self._redis.set(self._delay_key, "1", px=ttl_ms_new)
logger.warning(
- f"OnyxRedisSlackRetryHandler.prepare_for_next_attempt setting delay: "
- f"current_attempt={state.current_attempt} "
- f"retry-after={retry_after_value} "
- f"{ttl_ms_new=}"
+ "OnyxRedisSlackRetryHandler.prepare_for_next_attempt setting delay: current_attempt=%s retry-after=%s ttl_ms_new=%r",
+ state.current_attempt,
+ retry_after_value,
+ ttl_ms_new,
)
state.increment_current_attempt()
diff --git a/backend/onyx/connectors/slack/onyx_slack_web_client.py b/backend/onyx/connectors/slack/onyx_slack_web_client.py
index b6c4b940b2..2b28a7c180 100644
--- a/backend/onyx/connectors/slack/onyx_slack_web_client.py
+++ b/backend/onyx/connectors/slack/onyx_slack_web_client.py
@@ -100,7 +100,9 @@ class OnyxSlackWebClient(WebClient):
if delay_ms > 0:
logger.warning(
- f"OnyxSlackWebClient._perform_urllib_http_request_internal delay: {delay_ms=} {self.num_requests=}"
+ "OnyxSlackWebClient._perform_urllib_http_request_internal delay: delay_ms=%r self.num_requests=%r",
+ delay_ms,
+ self.num_requests,
)
time.sleep(delay_ms / 1000.0)
diff --git a/backend/onyx/connectors/slack/utils.py b/backend/onyx/connectors/slack/utils.py
index 4c9a0fe758..4e606d2292 100644
--- a/backend/onyx/connectors/slack/utils.py
+++ b/backend/onyx/connectors/slack/utils.py
@@ -206,7 +206,7 @@ class SlackTextCleaner:
# message indexing path continues with the id in place of
# the display name (ONYX-BACKEND-H6FN).
logger.warning(
- f"Error fetching data for user {user_id}: {e.response['error']}"
+ "Error fetching data for user %s: %s", user_id, e.response["error"]
)
self._id_to_name_map[user_id] = user_id
@@ -231,7 +231,9 @@ class SlackTextCleaner:
# only fires on unexpected errors (e.g. malformed response);
# still defensive, but not actionable per-message — warn.
logger.warning(
- f"Unable to replace user ID with username for user_id '{user_id}': {e}"
+ "Unable to replace user ID with username for user_id '%s': %s",
+ user_id,
+ e,
)
return message
diff --git a/backend/onyx/connectors/teams/connector.py b/backend/onyx/connectors/teams/connector.py
index 87739e6944..822a5107c3 100644
--- a/backend/onyx/connectors/teams/connector.py
+++ b/backend/onyx/connectors/teams/connector.py
@@ -132,8 +132,9 @@ class TeamsConnector(
try:
# For validation, do a lightweight check instead of full team search
logger.info(
- f"Requested team count: {len(self.requested_team_list) if self.requested_team_list else 0}, "
- f"Has special chars: {has_special_chars}"
+ "Requested team count: %s, Has special chars: %s",
+ len(self.requested_team_list) if self.requested_team_list else 0,
+ has_special_chars,
)
validation_query = self.graph_client.teams.get().top(1)
@@ -252,7 +253,9 @@ class TeamsConnector(
yield channel_doc
logger.info(
- f"Processed team with id {todo_team_id}; {len(todos)} team(s) left to process"
+ "Processed team with id %s; %s team(s) left to process",
+ todo_team_id,
+ len(todos),
)
return TeamsCheckpoint(
@@ -288,7 +291,7 @@ class TeamsConnector(
for team in teams:
if not team.id:
logger.warning(
- f"Expected a team with an id, instead got no id: {team=}"
+ "Expected a team with an id, instead got no id: team=%r", team
)
continue
@@ -299,7 +302,8 @@ class TeamsConnector(
for channel in channels:
if not channel.id:
logger.warning(
- f"Expected a channel with an id, instead got no id: {channel=}"
+ "Expected a channel with an id, instead got no id: channel=%r",
+ channel,
)
continue
@@ -414,7 +418,7 @@ def _construct_semantic_identifier(channel: Channel, top_message: Message) -> st
user_display_name if user_display_name else "Unknown User"
)
else:
- logger.warning(f"Message {top_message=} has no `from.user` field")
+ logger.warning("Message top_message=%r has no `from.user` field", top_message)
top_message_user_name = "Unknown User"
top_message_content = top_message.body.content or ""
@@ -427,7 +431,9 @@ def _construct_semantic_identifier(channel: Channel, top_message: Message) -> st
except Exception:
logger.exception(
- f"Error parsing snippet for message {top_message.id} with url {top_message.web_url}"
+ "Error parsing snippet for message %s with url %s",
+ top_message.id,
+ top_message.web_url,
)
snippet = ""
@@ -533,9 +539,8 @@ def _collect_all_teams(
if problematic_names and not safe_names:
# ALL requested teams have special characters - cannot use OData filtering
logger.info(
- f"All requested team names contain special characters (&, (, )) which require "
- f"client-side filtering. Using basic /teams endpoint with pagination. "
- f"Teams: {problematic_names}"
+ "All requested team names contain special characters (&, (, )) which require client-side filtering. Using basic /teams endpoint with pagination. Teams: %s",
+ problematic_names,
)
# Use unfiltered query with pagination limit to avoid fetching too many teams
use_client_side_filtering = True
@@ -543,14 +548,15 @@ def _collect_all_teams(
elif problematic_names and safe_names:
# Mixed scenario - need to fetch more teams to find the problematic ones
logger.info(
- f"Mixed team types: will use client-side filtering for all. "
- f"Safe names: {safe_names}, Special char names: {problematic_names}"
+ "Mixed team types: will use client-side filtering for all. Safe names: %s, Special char names: %s",
+ safe_names,
+ problematic_names,
)
use_client_side_filtering = True
odata_filter = None
elif safe_names:
# All names are safe - use OData filtering
- logger.info(f"Using OData filtering for all requested teams: {safe_names}")
+ logger.info("Using OData filtering for all requested teams: %s", safe_names)
use_client_side_filtering = False
odata_filter = _build_simple_odata_filter(safe_names)
else:
@@ -584,7 +590,7 @@ def _collect_all_teams(
# If OData filter fails, fall back to client-side filtering
if not use_client_side_filtering and odata_filter:
logger.warning(
- f"OData filter failed: {e}. Falling back to client-side filtering."
+ "OData filter failed: %s. Falling back to client-side filtering.", e
)
use_client_side_filtering = True
odata_filter = None
@@ -593,7 +599,7 @@ def _collect_all_teams(
page_count = 0
continue
# If client-side approach also fails, re-raise
- logger.error(f"Teams query failed: {e}")
+ logger.error("Teams query failed: %s", e)
raise
filtered_teams = (
@@ -614,18 +620,21 @@ def _collect_all_teams(
# Log progress every 10 pages to avoid excessive logging
if page_count % 10 == 0:
logger.info(
- f"Searched {page_count} pages, found {len(found_team_names)} matching teams so far"
+ "Searched %s pages, found %s matching teams so far",
+ page_count,
+ len(found_team_names),
)
# Stop if we found all requested teams or hit the page limit
if requested_set.issubset(found_team_names):
- logger.info(f"Found all requested teams after {page_count} pages")
+ logger.info("Found all requested teams after %s pages", page_count)
break
elif page_count >= max_pages:
logger.warning(
- f"Reached maximum page limit ({max_pages}) while searching for teams. "
- f"Found: {found_team_names & requested_set}, "
- f"Missing: {requested_set - found_team_names}"
+ "Reached maximum page limit (%s) while searching for teams. Found: %s, Missing: %s",
+ max_pages,
+ found_team_names & requested_set,
+ requested_set - found_team_names,
)
break
diff --git a/backend/onyx/connectors/teams/utils.py b/backend/onyx/connectors/teams/utils.py
index ec6d91eeaa..0f1edea649 100644
--- a/backend/onyx/connectors/teams/utils.py
+++ b/backend/onyx/connectors/teams/utils.py
@@ -94,14 +94,14 @@ def _get_or_fetch_email(
user_id = member.properties.get("userId")
if not user_id:
- logger.warning(f"No user-id found for this member; {member=}")
+ logger.warning("No user-id found for this member; member=%r", member)
return None
json_data = _retry(graph_client=graph_client, request_url=f"users/{user_id}")
email = json_data.get("userPrincipalName")
if not isinstance(email, str):
- logger.warning(f"Expected email to be of type str, instead got {email=}")
+ logger.warning("Expected email to be of type str, instead got email=%r", email)
return None
return email
@@ -172,12 +172,14 @@ def fetch_expert_infos(
expert_infos = []
for member in members:
if not member.display_name:
- logger.warning(f"Failed to grab the display-name of {member=}; skipping")
+ logger.warning(
+ "Failed to grab the display-name of member=%r; skipping", member
+ )
continue
email = _get_or_fetch_email(graph_client=graph_client, member=member)
if not email:
- logger.warning(f"Failed to grab the email of {member=}; skipping")
+ logger.warning("Failed to grab the email of member=%r; skipping", member)
continue
expert_infos.append(
diff --git a/backend/onyx/connectors/testrail/connector.py b/backend/onyx/connectors/testrail/connector.py
index 55fb3ab27c..6abcb58eb1 100644
--- a/backend/onyx/connectors/testrail/connector.py
+++ b/backend/onyx/connectors/testrail/connector.py
@@ -205,7 +205,7 @@ class TestRailConnector(LoadConnector, PollConnector):
fields = self._api_get("get_case_fields")
return fields if isinstance(fields, list) else []
except Exception as e:
- logger.warning(f"Failed to fetch case fields from TestRail: {e}")
+ logger.warning("Failed to fetch case fields from TestRail: %s", e)
return []
def _parse_items_string(self, items_str: str) -> dict[str, str]:
@@ -263,7 +263,7 @@ class TestRailConnector(LoadConnector, PollConnector):
)
except Exception as e:
- logger.warning(f"Failed to build field maps from TestRail: {e}")
+ logger.warning("Failed to build field maps from TestRail: %s", e)
return field_labels, value_maps
@@ -454,7 +454,9 @@ class TestRailConnector(LoadConnector, PollConnector):
full_text = "\n".join(text_lines)
if len(full_text) > self.skip_doc_absolute_chars:
logger.warning(
- f"Skipping TestRail case {case_id} due to excessive size: {len(full_text)} chars"
+ "Skipping TestRail case %s due to excessive size: %s chars",
+ case_id,
+ len(full_text),
)
return None
diff --git a/backend/onyx/connectors/web/connector.py b/backend/onyx/connectors/web/connector.py
index 302a25a3aa..fef47aa5b7 100644
--- a/backend/onyx/connectors/web/connector.py
+++ b/backend/onyx/connectors/web/connector.py
@@ -184,7 +184,7 @@ def check_internet_connection(url: str) -> None:
# around this.
if status_code == 403:
logger.warning(
- f"Received 403 Forbidden for {url}, will retry with browser automation"
+ "Received 403 Forbidden for %s, will retry with browser automation", url
)
return
@@ -438,10 +438,12 @@ def _handle_cookies(context: BrowserContext, url: str) -> None:
try:
context.add_cookies([cookie]) # ty: ignore[invalid-argument-type]
except Exception as e:
- logger.debug(f"Failed to add cookie {cookie['name']} for {domain}: {e}")
+ logger.debug(
+ "Failed to add cookie %s for %s: %s", cookie["name"], domain, e
+ )
except Exception:
logger.exception(
- f"Unexpected error while handling cookies for Web Connector with URL {url}"
+ "Unexpected error while handling cookies for Web Connector with URL %s", url
)
@@ -600,12 +602,15 @@ class WebConnector(LoadConnector, SlimConnector):
initial_url = final_url
if initial_url in session_ctx.visited_links:
logger.info(
- f"{index}: {initial_url} redirected to {final_url} - already indexed"
+ "%s: %s redirected to %s - already indexed",
+ index,
+ initial_url,
+ final_url,
)
page.close()
return result
- logger.info(f"{index}: {initial_url} redirected to {final_url}")
+ logger.info("%s: %s redirected to %s", index, initial_url, final_url)
session_ctx.visited_links.add(initial_url)
# If we got here, the request was successful
@@ -640,7 +645,10 @@ class WebConnector(LoadConnector, SlimConnector):
scroll_attempts += 1
except Exception as scroll_err:
logger.warning(
- f"{index}: auto-scroll skipped for {initial_url}: {scroll_err}"
+ "%s: auto-scroll skipped for %s: %s",
+ index,
+ initial_url,
+ scroll_err,
)
content = page.content()
@@ -677,7 +685,7 @@ class WebConnector(LoadConnector, SlimConnector):
the code below can extract text from within these iframes.
"""
logger.debug(
- f"{index}: Length of cleaned text {len(parsed_html.cleaned_text)}"
+ "%s: Length of cleaned text %s", index, len(parsed_html.cleaned_text)
)
if JAVASCRIPT_DISABLED_MESSAGE in parsed_html.cleaned_text:
iframe_count = page.frame_locator("iframe").locator("html").count()
@@ -698,7 +706,7 @@ class WebConnector(LoadConnector, SlimConnector):
hashed_text = hash((parsed_html.title, parsed_html.cleaned_text))
if hashed_text in session_ctx.content_hashes:
logger.info(
- f"{index}: Skipping duplicate title + content for {initial_url}"
+ "%s: Skipping duplicate title + content for %s", index, initial_url
)
return result
@@ -755,7 +763,7 @@ class WebConnector(LoadConnector, SlimConnector):
index = len(session_ctx.visited_links)
logger.info(
- f"{index}: {'Slim-visiting' if slim else 'Visiting'} {initial_url}"
+ "%s: %s %s", index, "Slim-visiting" if slim else "Visiting", initial_url
)
# Add retry mechanism with exponential backoff
@@ -766,7 +774,11 @@ class WebConnector(LoadConnector, SlimConnector):
# Add a random delay between retries (exponential backoff)
delay = min(2**retry_count + random.uniform(0, 1), 10)
logger.info(
- f"Retry {retry_count}/{self.MAX_RETRIES} for {initial_url} after {delay:.2f}s delay"
+ "Retry %s/%s for %s after %ss delay",
+ retry_count,
+ self.MAX_RETRIES,
+ initial_url,
+ format(delay, ".2f"),
)
time.sleep(delay)
diff --git a/backend/onyx/connectors/xenforo/connector.py b/backend/onyx/connectors/xenforo/connector.py
index 09c9e01ac2..159d0d110f 100644
--- a/backend/onyx/connectors/xenforo/connector.py
+++ b/backend/onyx/connectors/xenforo/connector.py
@@ -172,7 +172,9 @@ class XenforoConnector(LoadConnector):
# Get all pages on thread_list_page
for pre_count, thread_list_page in enumerate(pages, start=1):
logger.info(
- f"Getting pages from thread_list_page.. Current: {pre_count}/{len(pages)}\r"
+ "Getting pages from thread_list_page.. Current: %s/%s\r",
+ pre_count,
+ len(pages),
)
all_threads += self.get_threads(thread_list_page)
# If the URL contains "threads/", add the thread to the list.
@@ -183,13 +185,17 @@ class XenforoConnector(LoadConnector):
for thread_count, thread_url in enumerate(all_threads, start=1):
soup = self.requestsite(thread_url)
if soup is None:
- logger.error(f"Failed to load page: {self.base_url}")
+ logger.error("Failed to load page: %s", self.base_url)
continue
pages = get_pages(soup, thread_url)
# Getting all pages for all threads
for page_index, page in enumerate(pages, start=1):
logger.info(
- f"Progress: Page {page_index}/{len(pages)} - Thread {thread_count}/{len(all_threads)}\r"
+ "Progress: Page %s/%s - Thread %s/%s\r",
+ page_index,
+ len(pages),
+ thread_count,
+ len(all_threads),
)
soup_page = self.requestsite(page)
doc_batch.extend(
@@ -225,13 +231,16 @@ class XenforoConnector(LoadConnector):
)
if response.status_code != 200:
logger.error(
- f"<{url}> Request Error: {response.status_code} - {response.reason}"
+ "<%s> Request Error: %s - %s",
+ url,
+ response.status_code,
+ response.reason,
)
return BeautifulSoup(response.text, "html.parser")
except TimeoutError:
logger.error("Timed out Error.")
except Exception as e:
- logger.error(f"Error on {url}")
+ logger.error("Error on %s", url)
logger.exception(e)
return BeautifulSoup("", "html.parser")
diff --git a/backend/onyx/connectors/zulip/connector.py b/backend/onyx/connectors/zulip/connector.py
index 9eee0b6b1b..2c66dacb68 100644
--- a/backend/onyx/connectors/zulip/connector.py
+++ b/backend/onyx/connectors/zulip/connector.py
@@ -97,7 +97,7 @@ class ZulipConnector(LoadConnector, PollConnector):
narrow_link = f"{self.base_url}#narrow/stream/{stream_operand}/topic/{topic_operand}/near/{m.id}"
return narrow_link
except Exception as e:
- logger.error(f"Error generating Zulip message link: {e}")
+ logger.error("Error generating Zulip message link: %s", e)
# Fallback to a basic link that at least includes the base URL
return f"{self.base_url}#narrow/id/{m.id}"
@@ -105,7 +105,7 @@ class ZulipConnector(LoadConnector, PollConnector):
if self.client is None:
raise ConnectorMissingCredentialError("Zulip")
- logger.info(f"Fetching messages starting with anchor={anchor}")
+ logger.info("Fetching messages starting with anchor=%s", anchor)
request = build_search_narrow(
limit=INDEX_BATCH_SIZE, anchor=anchor, apply_md=False
)
@@ -135,7 +135,9 @@ class ZulipConnector(LoadConnector, PollConnector):
doc_time = edit_time if edit_time is not None else post_time
except (ValueError, TypeError) as e:
- logger.warning(f"Failed to parse timestamp for message {message.id}: {e}")
+ logger.warning(
+ "Failed to parse timestamp for message %s: %s", message.id, e
+ )
post_time = None
edit_time = None
doc_time = None
diff --git a/backend/onyx/connectors/zulip/utils.py b/backend/onyx/connectors/zulip/utils.py
index e189ed3154..76252d267c 100644
--- a/backend/onyx/connectors/zulip/utils.py
+++ b/backend/onyx/connectors/zulip/utils.py
@@ -37,7 +37,7 @@ def __call_with_retry(fun: Callable, *args: Any, **kwargs: Any) -> Dict[str, Any
if result.get("result") == "error":
if result.get("code") == "RATE_LIMIT_HIT":
retry_after = float(result["retry-after"]) + 1
- logger.warning(f"Rate limit hit, retrying after {retry_after} seconds")
+ logger.warning("Rate limit hit, retrying after %s seconds", retry_after)
time.sleep(retry_after)
return __call_with_retry(fun, *args)
return result
diff --git a/backend/onyx/context/search/federated/slack_search.py b/backend/onyx/context/search/federated/slack_search.py
index 3c0c3ba7e7..3dea4d7bb4 100644
--- a/backend/onyx/context/search/federated/slack_search.py
+++ b/backend/onyx/context/search/federated/slack_search.py
@@ -80,26 +80,26 @@ def fetch_and_cache_channel_metadata(
try:
cached = redis_client.get(cache_key)
if cached:
- logger.debug(f"Channel metadata cache HIT for team {team_id}")
+ logger.debug("Channel metadata cache HIT for team %s", team_id)
cached_str: str = (
cached.decode("utf-8") if isinstance(cached, bytes) else str(cached)
)
cached_data = cast(dict[str, ChannelMetadata], json.loads(cached_str))
- logger.debug(f"Loaded {len(cached_data)} channels from cache")
+ logger.debug("Loaded %s channels from cache", len(cached_data))
if not include_private:
filtered: dict[str, ChannelMetadata] = {
k: v
for k, v in cached_data.items()
if v.get("type") != ChannelType.PRIVATE_CHANNEL.value
}
- logger.debug(f"Filtered to {len(filtered)} channels (exclude private)")
+ logger.debug("Filtered to %s channels (exclude private)", len(filtered))
return filtered
return cached_data
except Exception as e:
- logger.warning(f"Error reading from channel metadata cache: {e}")
+ logger.warning("Error reading from channel metadata cache: %s", e)
# Cache miss - fetch from Slack API with retry logic
- logger.debug(f"Channel metadata cache MISS for team {team_id} - fetching from API")
+ logger.debug("Channel metadata cache MISS for team %s - fetching from API", team_id)
slack_client = WebClient(token=access_token)
channel_metadata: dict[str, ChannelMetadata] = {}
@@ -149,7 +149,7 @@ def fetch_and_cache_channel_metadata(
if not cursor:
break
- logger.info(f"Fetched {channel_count} channels for team {team_id}")
+ logger.info("Fetched %s channels for team %s", channel_count, team_id)
# Cache the results
try:
@@ -159,10 +159,14 @@ def fetch_and_cache_channel_metadata(
ex=CHANNEL_METADATA_CACHE_TTL,
)
logger.info(
- f"Cached {channel_count} channels for team {team_id} (TTL: {CHANNEL_METADATA_CACHE_TTL}s, key: {cache_key})"
+ "Cached %s channels for team %s (TTL: %ss, key: %s)",
+ channel_count,
+ team_id,
+ CHANNEL_METADATA_CACHE_TTL,
+ cache_key,
)
except Exception as e:
- logger.warning(f"Error caching channel metadata: {e}")
+ logger.warning("Error caching channel metadata: %s", e)
return channel_metadata
@@ -189,8 +193,10 @@ def fetch_and_cache_channel_metadata(
# Remove the problematic channel type and retry
available_channel_types.remove(missing_channel_type)
logger.warning(
- f"Missing scope '{needed_scope}' for channel type '{missing_channel_type}'. "
- f"Continuing with reduced channel types: {available_channel_types}"
+ "Missing scope '%s' for channel type '%s'. Continuing with reduced channel types: %s",
+ needed_scope,
+ missing_channel_type,
+ available_channel_types,
)
# Don't count this as a retry attempt, just try again with fewer types
if available_channel_types: # Only continue if we have types left
@@ -198,27 +204,35 @@ def fetch_and_cache_channel_metadata(
# Otherwise fall through to retry logic
else:
logger.error(
- f"Missing scope '{needed_scope}' but could not map to channel type or already removed. "
- f"Response: {e.response}"
+ "Missing scope '%s' but could not map to channel type or already removed. Response: %s",
+ needed_scope,
+ e.response,
)
# For other errors, use retry logic
if attempt < CHANNEL_METADATA_MAX_RETRIES - 1:
retry_delay = CHANNEL_METADATA_RETRY_DELAY * (2**attempt)
logger.warning(
- f"Failed to fetch channel metadata (attempt {attempt + 1}/{CHANNEL_METADATA_MAX_RETRIES}): {e}. "
- f"Retrying in {retry_delay}s..."
+ "Failed to fetch channel metadata (attempt %s/%s): %s. Retrying in %ss...",
+ attempt + 1,
+ CHANNEL_METADATA_MAX_RETRIES,
+ e,
+ retry_delay,
)
time.sleep(retry_delay)
else:
logger.error(
- f"Failed to fetch channel metadata after {CHANNEL_METADATA_MAX_RETRIES} attempts: {e}"
+ "Failed to fetch channel metadata after %s attempts: %s",
+ CHANNEL_METADATA_MAX_RETRIES,
+ e,
)
# If we have some channel metadata despite errors, return it with a warning
if channel_metadata:
logger.warning(
- f"Returning partial channel metadata ({len(channel_metadata)} channels) despite errors. Last error: {last_exception}"
+ "Returning partial channel metadata (%s channels) despite errors. Last error: %s",
+ len(channel_metadata),
+ last_exception,
)
return channel_metadata
@@ -262,7 +276,7 @@ def get_cached_user_profile(
# Empty string means user was not found previously
return cached_str if cached_str else None
except Exception as e:
- logger.debug(f"Error reading user profile cache: {e}")
+ logger.debug("Error reading user profile cache: %s", e)
# Cache miss - fetch from Slack API
slack_client = WebClient(token=access_token)
@@ -280,7 +294,7 @@ def get_cached_user_profile(
ex=USER_PROFILE_CACHE_TTL,
)
except Exception as e:
- logger.debug(f"Error caching user profile: {e}")
+ logger.debug("Error caching user profile: %s", e)
return name
@@ -288,14 +302,15 @@ def get_cached_user_profile(
error_str = str(e)
if "user_not_found" in error_str:
logger.debug(
- f"User {user_id} not found in Slack workspace (likely deleted/deactivated)"
+ "User %s not found in Slack workspace (likely deleted/deactivated)",
+ user_id,
)
elif "ratelimited" in error_str:
# Don't cache rate limit errors - we'll retry later
- logger.debug(f"Rate limited fetching user {user_id}, will retry later")
+ logger.debug("Rate limited fetching user %s, will retry later", user_id)
return None
else:
- logger.warning(f"Could not fetch profile for user {user_id}: {e}")
+ logger.warning("Could not fetch profile for user %s: %s", user_id, e)
# Cache negative result to avoid repeated lookups for missing users
try:
@@ -405,7 +420,9 @@ def _should_skip_channel(
return True
except Exception as e:
logger.warning(
- f"Could not determine channel type for {channel_id}, filtering out: {e}"
+ "Could not determine channel type for %s, filtering out: %s",
+ channel_id,
+ e,
)
return True
return False
@@ -439,13 +456,18 @@ def _fetch_thread_from_url(
messages: list[dict[str, Any]] = response.get("messages", [])
except SlackApiError as e:
logger.warning(
- f"Failed to fetch thread from URL (channel={channel_id}, ts={thread_ts}): {e}"
+ "Failed to fetch thread from URL (channel=%s, ts=%s): %s",
+ channel_id,
+ thread_ts,
+ e,
)
return SlackQueryResult(messages=[], filtered_channels=[])
if not messages:
logger.warning(
- f"No messages found for URL override (channel={channel_id}, ts={thread_ts})"
+ "No messages found for URL override (channel=%s, ts=%s)",
+ channel_id,
+ thread_ts,
)
return SlackQueryResult(messages=[], filtered_channels=[])
@@ -502,7 +524,10 @@ def _fetch_thread_from_url(
)
logger.info(
- f"URL override: fetched thread from channel={channel_id}, ts={thread_ts}, {len(messages)} messages"
+ "URL override: fetched thread from channel=%s, ts=%s, %s messages",
+ channel_id,
+ thread_ts,
+ len(messages),
)
return SlackQueryResult(messages=[slack_message], filtered_channels=[])
@@ -536,7 +561,7 @@ def query_slack(
# Add channel filter to query
final_query = f"{query_string} {channel_filter}"
- logger.info(f"Final query to slack: {final_query}")
+ logger.info("Final query to slack: %s", final_query)
# Detect if query asks for most recent results
sort_by_time = is_recency_query(query_string)
@@ -560,16 +585,18 @@ def query_slack(
messages: dict[str, Any] = response.get("messages", {})
matches: list[dict[str, Any]] = messages.get("matches", [])
- logger.info(f"Slack search found {len(matches)} messages")
+ logger.info("Slack search found %s messages", len(matches))
except SlackApiError as slack_error:
- logger.error(f"Slack API error in search_messages: {slack_error}")
+ logger.error("Slack API error in search_messages: %s", slack_error)
logger.error(
- f"Slack API error details: status={slack_error.response.status_code}, error={slack_error.response.get('error')}"
+ "Slack API error details: status=%s, error=%s",
+ slack_error.response.status_code,
+ slack_error.response.get("error"),
)
if "not_allowed_token_type" in str(slack_error):
# Log token type prefix
token_prefix = access_token[:4] if len(access_token) >= 4 else "unknown"
- logger.error(f"TOKEN TYPE ERROR: access_token type: {token_prefix}...")
+ logger.error("TOKEN TYPE ERROR: access_token type: %s...", token_prefix)
return SlackQueryResult(messages=[], filtered_channels=[])
# convert matches to slack messages
@@ -765,15 +792,17 @@ def _fetch_thread_context(
# Check for rate limit error specifically
if e.response and e.response.status_code == 429:
logger.warning(
- f"Slack rate limit hit while fetching thread context for {channel_id}/{thread_id}"
+ "Slack rate limit hit while fetching thread context for %s/%s",
+ channel_id,
+ thread_id,
)
return ThreadContextResult.rate_limited(message.text)
# For other Slack errors, log and return original text
- logger.error(f"Slack API error in thread context fetch: {e}")
+ logger.error("Slack API error in thread context fetch: %s", e)
return ThreadContextResult.error(message.text)
except Exception as e:
# Network errors, timeouts, etc - treat as recoverable error
- logger.error(f"Unexpected error in thread context fetch: {e}")
+ logger.error("Unexpected error in thread context fetch: %s", e)
return ThreadContextResult.error(message.text)
# If empty response or single message (not a thread), return original text
@@ -804,7 +833,7 @@ def _build_thread_text(
if not replies:
return thread_text
- logger.debug(f"Thread {messages[0].get('ts')}: {len(replies)} replies included")
+ logger.debug("Thread %s: %s replies included", messages[0].get("ts"), len(replies))
thread_text += "\n\nReplies:"
for msg in replies:
@@ -829,10 +858,10 @@ def _build_thread_text(
except SlackApiError as e:
if "user_not_found" in str(e):
logger.debug(
- f"User {userid} not found (likely deleted/deactivated)"
+ "User %s not found (likely deleted/deactivated)", userid
)
else:
- logger.warning(f"Could not fetch profile for user {userid}: {e}")
+ logger.warning("Could not fetch profile for user %s: %s", userid, e)
continue
if not user_name:
continue
@@ -878,8 +907,11 @@ def fetch_thread_contexts_with_rate_limit_handling(
messages_without_context = []
logger.info(
- f"Fetching thread context for {len(messages_for_context)} of {len(slack_messages)} messages "
- f"(batch_size={batch_size}, max={max_messages or 'unlimited'})"
+ "Fetching thread context for %s of %s messages (batch_size=%s, max=%s)",
+ len(messages_for_context),
+ len(slack_messages),
+ batch_size,
+ max_messages or "unlimited",
)
results: list[str] = []
@@ -896,9 +928,11 @@ def fetch_thread_contexts_with_rate_limit_handling(
remaining = messages_for_context[i:]
skipped_batches = total_batches - rate_limit_batch
logger.warning(
- f"Slack rate limit: skipping {len(remaining)} remaining messages "
- f"({skipped_batches} of {total_batches} batches). "
- f"Successfully enriched {len(results)} messages before rate limit."
+ "Slack rate limit: skipping %s remaining messages (%s of %s batches). Successfully enriched %s messages before rate limit.",
+ len(remaining),
+ skipped_batches,
+ total_batches,
+ len(results),
)
results.extend([msg.text for msg in remaining])
break
@@ -925,7 +959,7 @@ def fetch_thread_contexts_with_rate_limit_handling(
for j, result in enumerate(batch_results):
if result is None:
# Unexpected exception (shouldn't happen) - use original text, stop
- logger.error(f"Unexpected None result for message {j} in batch")
+ logger.error("Unexpected None result for message %s in batch", j)
results.append(batch[j].text)
rate_limited = True
rate_limit_batch = current_batch
@@ -940,8 +974,9 @@ def fetch_thread_contexts_with_rate_limit_handling(
if rate_limited:
logger.warning(
- f"Slack rate limit (429) hit at batch {current_batch}/{total_batches} "
- f"while fetching thread context. Stopping further API calls."
+ "Slack rate limit (429) hit at batch %s/%s while fetching thread context. Stopping further API calls.",
+ current_batch,
+ total_batches,
)
# Add original text for messages we didn't fetch context for
@@ -1002,7 +1037,7 @@ def slack_retrieval(
if not entities:
logger.debug("No entity configuration found, using defaults")
else:
- logger.debug(f"Using entity configuration: {entities}")
+ logger.debug("Using entity configuration: %s", entities)
# Extract limit from entity config if not explicitly provided
query_limit = limit
@@ -1011,9 +1046,11 @@ def slack_retrieval(
parsed_entities = SlackEntities(**entities)
if limit is None:
query_limit = parsed_entities.max_messages_per_query
- logger.debug(f"Using max_messages_per_query from config: {query_limit}")
+ logger.debug(
+ "Using max_messages_per_query from config: %s", query_limit
+ )
except Exception as e:
- logger.warning(f"Error parsing entities for limit: {e}")
+ logger.warning("Error parsing entities for limit: %s", e)
if limit is None:
query_limit = 100 # Fallback default
elif limit is None:
@@ -1059,7 +1096,8 @@ def slack_retrieval(
if channel_type == ChannelType.PRIVATE_CHANNEL:
allowed_private_channel = slack_event_context.channel_id
logger.debug(
- f"Private channel context: will only allow messages from {allowed_private_channel} + public channels"
+ "Private channel context: will only allow messages from %s + public channels",
+ allowed_private_channel,
)
# Build search tasks — direct thread fetches + keyword searches
diff --git a/backend/onyx/context/search/federated/slack_search_utils.py b/backend/onyx/context/search/federated/slack_search_utils.py
index 66c7e543cb..a81bf51ac1 100644
--- a/backend/onyx/context/search/federated/slack_search_utils.py
+++ b/backend/onyx/context/search/federated/slack_search_utils.py
@@ -214,37 +214,44 @@ def extract_date_range_from_query(
data = json.loads(response_clean)
if not isinstance(data, dict):
logger.debug(
- f"LLM date extraction returned non-dict response for query: "
- f"'{query}', using default: {default_search_days} days"
+ "LLM date extraction returned non-dict response for query: '%s', using default: %s days",
+ query,
+ default_search_days,
)
return default_search_days
days_back = data.get("days_back")
if days_back is None:
logger.debug(
- f"LLM date extraction returned null for query: '{query}', using default: {default_search_days} days"
+ "LLM date extraction returned null for query: '%s', using default: %s days",
+ query,
+ default_search_days,
)
return default_search_days
if not isinstance(days_back, (int, float)):
logger.debug(
- f"LLM date extraction returned non-numeric days_back for "
- f"query: '{query}', using default: {default_search_days} days"
+ "LLM date extraction returned non-numeric days_back for query: '%s', using default: %s days",
+ query,
+ default_search_days,
)
return default_search_days
except json.JSONDecodeError:
logger.debug(
- f"Failed to parse LLM date extraction response for query: '{query}' "
- f"(response: '{response_clean}'), "
- f"using default: {default_search_days} days"
+ "Failed to parse LLM date extraction response for query: '%s' (response: '%s'), using default: %s days",
+ query,
+ response_clean,
+ default_search_days,
)
return default_search_days
return min(int(days_back), default_search_days)
except Exception as e:
- logger.warning(f"Error extracting date range with LLM for query '{query}': {e}")
+ logger.warning(
+ "Error extracting date range with LLM for query '%s': %s", query, e
+ )
return default_search_days
@@ -625,7 +632,7 @@ def expand_query_with_llm(query_text: str, llm: LLM) -> list[str]:
# Log if we filtered out garbage
if len(raw_queries) != len(rephrased_queries):
filtered_out = set(raw_queries) - set(rephrased_queries)
- logger.warning(f"Filtered out non-keyword LLM responses: {filtered_out}")
+ logger.warning("Filtered out non-keyword LLM responses: %s", filtered_out)
# If no queries generated, use empty query
if not rephrased_queries:
@@ -633,12 +640,14 @@ def expand_query_with_llm(query_text: str, llm: LLM) -> list[str]:
return [""]
logger.debug(
- f"Expanded query into {len(rephrased_queries)} queries: {rephrased_queries}"
+ "Expanded query into %s queries: %s",
+ len(rephrased_queries),
+ rephrased_queries,
)
return rephrased_queries[:MAX_SLACK_QUERY_EXPANSIONS]
except Exception as e:
- logger.error(f"Error expanding query: {e}")
+ logger.error("Error expanding query: %s", e)
return [query_text]
@@ -681,7 +690,7 @@ def build_slack_queries(
parsed_entities = SlackEntities(**entities)
default_search_days = parsed_entities.default_search_days
except ValidationError as e:
- logger.warning(f"Invalid entities in build_slack_queries: {e}")
+ logger.warning("Invalid entities in build_slack_queries: %s", e)
days_back = extract_date_range_from_query(
query=query.query,
@@ -705,7 +714,7 @@ def build_slack_queries(
url_fetches.append(
DirectThreadFetch(channel_id=channel_id, thread_ts=thread_ts)
)
- logger.info(f"Detected Slack URL: channel={channel_id}, ts={thread_ts}")
+ logger.info("Detected Slack URL: channel=%s, ts=%s", channel_id, thread_ts)
# ALWAYS extract channel references from the query (not just for recency queries)
channel_references = extract_channel_references_from_query(query.query)
@@ -718,7 +727,7 @@ def build_slack_queries(
channel_references, entities, available_channels
)
logger.info(
- f"Detected and validated channel references: {channel_references}"
+ "Detected and validated channel references: %s", channel_references
)
# If valid channels detected, use ONLY those channels with NO keywords
@@ -728,7 +737,7 @@ def build_slack_queries(
]
except ValueError as e:
# If validation fails, log the error and continue with normal flow
- logger.warning(f"Channel reference validation failed: {e}")
+ logger.warning("Channel reference validation failed: %s", e)
channel_references = set()
# use llm to generate slack queries (use original query to use same keywords as the user)
diff --git a/backend/onyx/context/search/retrieval/search_runner.py b/backend/onyx/context/search/retrieval/search_runner.py
index 555824bf1b..6ca527e938 100644
--- a/backend/onyx/context/search/retrieval/search_runner.py
+++ b/backend/onyx/context/search/retrieval/search_runner.py
@@ -173,7 +173,9 @@ def search_chunks(
if not top_chunks:
logger.debug(
- f"Search returned no results for query: {query_request.query} with filters: {query_request.filters}."
+ "Search returned no results for query: %s with filters: %s.",
+ query_request.query,
+ query_request.filters,
)
return top_chunks
diff --git a/backend/onyx/db/chat.py b/backend/onyx/db/chat.py
index 5aa2fc24c7..1c76c0deb6 100644
--- a/backend/onyx/db/chat.py
+++ b/backend/onyx/db/chat.py
@@ -416,7 +416,8 @@ def get_chat_message(
if expected_user_id != user_id:
logger.error(
- f"User {user_id} tried to fetch a chat message that does not belong to them"
+ "User %s tried to fetch a chat message that does not belong to them",
+ user_id,
)
raise ValueError("Chat message does not belong to user")
diff --git a/backend/onyx/db/connector.py b/backend/onyx/db/connector.py
index f5d4a524cf..e8ce0d7130 100644
--- a/backend/onyx/db/connector.py
+++ b/backend/onyx/db/connector.py
@@ -400,5 +400,5 @@ def get_kg_enabled_connectors(db_session: Session) -> list[KGConnectorData]:
return connector_results
except Exception as e:
- logger.error(f"Error fetching unprocessed connector IDs: {str(e)}")
+ logger.error("Error fetching unprocessed connector IDs: %s", str(e))
raise e
diff --git a/backend/onyx/db/connector_credential_pair.py b/backend/onyx/db/connector_credential_pair.py
index 13bf5dccf2..e602da9aca 100644
--- a/backend/onyx/db/connector_credential_pair.py
+++ b/backend/onyx/db/connector_credential_pair.py
@@ -397,7 +397,8 @@ def update_connector_credential_pair_from_id(
)
if not cc_pair:
logger.warning(
- f"Attempted to update pair for Connector Credential Pair '{cc_pair_id}' but it does not exist"
+ "Attempted to update pair for Connector Credential Pair '%s' but it does not exist",
+ cc_pair_id,
)
return
@@ -425,7 +426,9 @@ def update_connector_credential_pair(
)
if not cc_pair:
logger.warning(
- f"Attempted to update pair for connector id {connector_id} and credential id {credential_id}"
+ "Attempted to update pair for connector id %s and credential id %s",
+ connector_id,
+ credential_id,
)
return
diff --git a/backend/onyx/db/credentials.py b/backend/onyx/db/credentials.py
index 86392f9789..4ac361566f 100644
--- a/backend/onyx/db/credentials.py
+++ b/backend/onyx/db/credentials.py
@@ -386,7 +386,7 @@ def _delete_credential_internal(
if associated_connectors or associated_doc_cc_pairs:
if force:
logger.warning(
- f"Force deleting credential {credential_id} and its associated records"
+ "Force deleting credential %s and its associated records", credential_id
)
# Delete DocumentByConnectorCredentialPair records first
@@ -406,9 +406,9 @@ def _delete_credential_internal(
)
if force:
- logger.warning(f"Force deleting credential {credential_id}")
+ logger.warning("Force deleting credential %s", credential_id)
else:
- logger.notice(f"Deleting credential {credential_id}")
+ logger.notice("Deleting credential %s", credential_id)
_cleanup_credential__user_group_relationships__no_commit(db_session, credential_id)
db_session.delete(credential)
diff --git a/backend/onyx/db/discord_bot.py b/backend/onyx/db/discord_bot.py
index b65f7c9909..6c20efb737 100644
--- a/backend/onyx/db/discord_bot.py
+++ b/backend/onyx/db/discord_bot.py
@@ -100,7 +100,8 @@ def get_or_create_discord_service_api_key(
# Database only stores the hash, so we must regenerate to get the raw key.
# This is safe since the Discord bot is the only consumer of this key.
logger.debug(
- f"Found existing Discord service API key for tenant {tenant_id} that isn't in cache, regenerating to update cache"
+ "Found existing Discord service API key for tenant %s that isn't in cache, regenerating to update cache",
+ tenant_id,
)
new_api_key = generate_api_key(tenant_id)
existing.hashed_api_key = hash_api_key(new_api_key)
@@ -109,7 +110,7 @@ def get_or_create_discord_service_api_key(
return new_api_key
# Create new API key
- logger.info(f"Creating Discord service API key for tenant {tenant_id}")
+ logger.info("Creating Discord service API key for tenant %s", tenant_id)
api_key_args = APIKeyArgs(
name=DISCORD_SERVICE_API_KEY_NAME,
role=UserRole.LIMITED, # Limited role is sufficient for chat requests
diff --git a/backend/onyx/db/document.py b/backend/onyx/db/document.py
index 346159bb9d..e7e5692869 100644
--- a/backend/onyx/db/document.py
+++ b/backend/onyx/db/document.py
@@ -1120,7 +1120,9 @@ def prepare_to_modify_documents(
break
except OperationalError as e:
logger.warning(
- f"Failed to acquire locks for documents on attempt {i}, retrying. Error: {e}"
+ "Failed to acquire locks for documents on attempt %s, retrying. Error: %s",
+ i,
+ e,
)
time.sleep(retry_delay)
diff --git a/backend/onyx/db/document_set.py b/backend/onyx/db/document_set.py
index 4629c3ee23..fcea055e6c 100644
--- a/backend/onyx/db/document_set.py
+++ b/backend/onyx/db/document_set.py
@@ -307,7 +307,7 @@ def insert_document_set(
db_session.commit()
except Exception as e:
db_session.rollback()
- logger.error(f"Error creating document set: {e}")
+ logger.error("Error creating document set: %s", e)
raise
return new_document_set_row, ds_cc_pairs
diff --git a/backend/onyx/db/engine/sql_engine.py b/backend/onyx/db/engine/sql_engine.py
index 0bf18a1285..11ab5f946d 100644
--- a/backend/onyx/db/engine/sql_engine.py
+++ b/backend/onyx/db/engine/sql_engine.py
@@ -108,7 +108,9 @@ if LOG_POSTGRES_LATENCY:
total_time = time.time() - conn.info["query_start_time"]
if total_time > 0.1:
logger.debug(
- f"Query Complete: {statement}\n\nTotal Time: {total_time:.4f} seconds"
+ "Query Complete: %s\n\nTotal Time: %s seconds",
+ statement,
+ format(total_time, ".4f"),
)
@@ -128,17 +130,21 @@ if LOG_POSTGRES_CONN_COUNTS:
pool_size = connection_proxy._pool.size()
logger.debug(
"Connection Checkout\n"
- f"Active Connections: {active_connections};\n"
- f"Idle: {idle_connections};\n"
- f"Pool Size: {pool_size};\n"
- f"Total connection checkouts: {checkout_count}"
+ "Active Connections: %s;\n"
+ "Idle: %s;\n"
+ "Pool Size: %s;\n"
+ "Total connection checkouts: %s",
+ active_connections,
+ idle_connections,
+ pool_size,
+ checkout_count,
)
@event.listens_for(Engine, "checkin")
def log_checkin(dbapi_connection, connection_record): # noqa: ARG001
global checkin_count
checkin_count += 1
- logger.debug(f"Total connection checkins: {checkin_count}")
+ logger.debug("Total connection checkins: %s", checkin_count)
class SqlEngine:
@@ -201,7 +207,7 @@ class SqlEngine:
# any passed in kwargs override the defaults
final_engine_kwargs.update(extra_engine_kwargs)
- logger.info(f"Creating engine with kwargs: {final_engine_kwargs}")
+ logger.info("Creating engine with kwargs: %s", final_engine_kwargs)
# echo=True here for inspecting all emitted db queries
engine = create_engine(connection_string, **final_engine_kwargs)
@@ -261,7 +267,7 @@ class SqlEngine:
# any passed in kwargs override the defaults
final_engine_kwargs.update(extra_engine_kwargs)
- logger.info(f"Creating engine with kwargs: {final_engine_kwargs}")
+ logger.info("Creating engine with kwargs: %s", final_engine_kwargs)
# echo=True here for inspecting all emitted db queries
engine = create_engine(connection_string, **final_engine_kwargs)
diff --git a/backend/onyx/db/federated.py b/backend/onyx/db/federated.py
index 08f5628ecf..6f12545e27 100644
--- a/backend/onyx/db/federated.py
+++ b/backend/onyx/db/federated.py
@@ -56,7 +56,7 @@ def validate_federated_connector_credentials(
get_federated_connector(source, credentials)
return True
except Exception as e:
- logger.error(f"Error validating credentials for source {source}: {e}")
+ logger.error("Error validating credentials for source %s: %s", source, e)
return False
diff --git a/backend/onyx/db/hierarchy.py b/backend/onyx/db/hierarchy.py
index 0f0f05cc62..560f572e06 100644
--- a/backend/onyx/db/hierarchy.py
+++ b/backend/onyx/db/hierarchy.py
@@ -126,7 +126,10 @@ def ensure_source_node_exists(
db_session.commit()
logger.info(
- f"Created SOURCE hierarchy node for {source.value}: id={source_node.id}, display_name={display_name}"
+ "Created SOURCE hierarchy node for %s: id=%s, display_name=%s",
+ source.value,
+ source_node.id,
+ display_name,
)
return source_node
@@ -154,7 +157,9 @@ def resolve_parent_hierarchy_node_id(
# Parent not found - fall back to SOURCE node
logger.warning(
- f"Parent hierarchy node not found: raw_id={raw_parent_id}, source={source}. Falling back to SOURCE node."
+ "Parent hierarchy node not found: raw_id=%s, source=%s. Falling back to SOURCE node.",
+ raw_parent_id,
+ source,
)
source_node = get_source_hierarchy_node(db_session, source)
return source_node.id if source_node else None
@@ -392,7 +397,9 @@ def link_hierarchy_nodes_to_documents(
if nodes_to_update:
logger.debug(
- f"Linked {len(nodes_to_update)} hierarchy nodes to documents for source {source.value}"
+ "Linked %s hierarchy nodes to documents for source %s",
+ len(nodes_to_update),
+ source.value,
)
return len(nodes_to_update)
@@ -606,7 +613,9 @@ def update_hierarchy_node_permissions(
if not existing_node:
logger.warning(
- f"Hierarchy node not found for permission update: raw_node_id={raw_node_id}, source={source}"
+ "Hierarchy node not found for permission update: raw_node_id=%s, source=%s",
+ raw_node_id,
+ source,
)
return False
diff --git a/backend/onyx/db/image_generation.py b/backend/onyx/db/image_generation.py
index 5cd50a2b6f..748b717262 100644
--- a/backend/onyx/db/image_generation.py
+++ b/backend/onyx/db/image_generation.py
@@ -233,13 +233,13 @@ def create_default_image_gen_config_from_api_key(
db_session.commit()
- logger.info(f"Created default image generation config: {image_provider_id}")
+ logger.info("Created default image generation config: %s", image_provider_id)
return config
except Exception:
db_session.rollback()
logger.exception(
- f"Failed to create default image generation config {image_provider_id}"
+ "Failed to create default image generation config %s", image_provider_id
)
return None
diff --git a/backend/onyx/db/index_attempt_metrics.py b/backend/onyx/db/index_attempt_metrics.py
index b82309e9b9..38a1c98984 100644
--- a/backend/onyx/db/index_attempt_metrics.py
+++ b/backend/onyx/db/index_attempt_metrics.py
@@ -190,8 +190,9 @@ def safe_record_single_event(
)
except Exception:
logger.exception(
- f"Failed to record stage event {stage.value} "
- f"for attempt {index_attempt_id}"
+ "Failed to record stage event %s for attempt %s",
+ stage.value,
+ index_attempt_id,
)
@@ -260,8 +261,9 @@ def time_stage(
)
except Exception:
logger.exception(
- f"Failed to record stage event {stage.value} "
- f"for attempt {index_attempt_id}"
+ "Failed to record stage event %s for attempt %s",
+ stage.value,
+ index_attempt_id,
)
@@ -353,8 +355,9 @@ class StageEventBuffer:
)
except Exception:
logger.exception(
- f"Failed to flush StageEventBuffer for "
- f"{self.stage.value} / attempt {self.index_attempt_id}"
+ "Failed to flush StageEventBuffer for %s / attempt %s",
+ self.stage.value,
+ self.index_attempt_id,
)
def _reset(self) -> None:
diff --git a/backend/onyx/db/indexing_coordination.py b/backend/onyx/db/indexing_coordination.py
index 6579eae84b..6010a96ee1 100644
--- a/backend/onyx/db/indexing_coordination.py
+++ b/backend/onyx/db/indexing_coordination.py
@@ -65,10 +65,10 @@ class IndexingCoordination:
if existing_attempt:
logger.info(
- f"Indexing already in progress: "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id} "
- f"existing_attempt={existing_attempt[0].id}"
+ "Indexing already in progress: cc_pair=%s search_settings=%s existing_attempt=%s",
+ cc_pair_id,
+ search_settings_id,
+ existing_attempt[0].id,
)
return None
@@ -82,21 +82,21 @@ class IndexingCoordination:
)
logger.info(
- f"Created Index Attempt: "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id} "
- f"attempt_id={attempt_id} "
- f"celery_task_id={celery_task_id}"
+ "Created Index Attempt: cc_pair=%s search_settings=%s attempt_id=%s celery_task_id=%s",
+ cc_pair_id,
+ search_settings_id,
+ attempt_id,
+ celery_task_id,
)
return attempt_id
except SQLAlchemyError as e:
logger.info(
- f"Failed to create index attempt (likely race condition): "
- f"cc_pair={cc_pair_id} "
- f"search_settings={search_settings_id} "
- f"error={str(e)}"
+ "Failed to create index attempt (likely race condition): cc_pair=%s search_settings=%s error=%s",
+ cc_pair_id,
+ search_settings_id,
+ str(e),
)
db_session.rollback()
return None
@@ -127,7 +127,7 @@ class IndexingCoordination:
attempt.cancellation_requested = True
db_session.commit()
- logger.info(f"Requested cancellation for attempt {index_attempt_id}")
+ logger.info("Requested cancellation for attempt %s", index_attempt_id)
@staticmethod
def set_total_batches(
@@ -145,7 +145,9 @@ class IndexingCoordination:
db_session.commit()
logger.info(
- f"Set total batches: attempt={index_attempt_id} total={total_batches}"
+ "Set total batches: attempt=%s total=%s",
+ index_attempt_id,
+ total_batches,
)
@staticmethod
@@ -183,11 +185,11 @@ class IndexingCoordination:
db_session.commit()
logger.info(
- f"Updated batch completion: "
- f"attempt={index_attempt_id} "
- f"completed={attempt.completed_batches} "
- f"total={attempt.total_batches} "
- f"docs={total_docs_indexed} "
+ "Updated batch completion: attempt=%s completed=%s total=%s docs=%s ",
+ index_attempt_id,
+ attempt.completed_batches,
+ attempt.total_batches,
+ total_docs_indexed,
)
return attempt.completed_batches, attempt.total_batches
@@ -195,7 +197,7 @@ class IndexingCoordination:
except Exception:
db_session.rollback()
logger.exception(
- f"Failed to update batch completion for attempt {index_attempt_id}"
+ "Failed to update batch completion for attempt %s", index_attempt_id
)
raise
@@ -276,7 +278,7 @@ class IndexingCoordination:
attempt = get_index_attempt(db_session, index_attempt_id)
if not attempt:
- logger.error(f"Index attempt {index_attempt_id} not found in database")
+ logger.error("Index attempt %s not found in database", index_attempt_id)
return False
current_time = get_db_current_time(db_session)
diff --git a/backend/onyx/db/kg_config.py b/backend/onyx/db/kg_config.py
index e01c5199ac..2d5266f034 100644
--- a/backend/onyx/db/kg_config.py
+++ b/backend/onyx/db/kg_config.py
@@ -21,10 +21,10 @@ def get_kg_config_settings() -> KGConfigSettings:
return KGConfigSettings.model_validate(stored_config or {})
except KvKeyNotFoundError:
# Default to empty kg config if no config have been set yet
- logger.debug(f"No kg config found in KV store for key: {KV_KG_CONFIG_KEY}")
+ logger.debug("No kg config found in KV store for key: %s", KV_KG_CONFIG_KEY)
return KGConfigSettings()
except Exception as e:
- logger.error(f"Error loading kg config from KV store: {str(e)}")
+ logger.error("Error loading kg config from KV store: %s", str(e))
return KGConfigSettings()
diff --git a/backend/onyx/db/mcp.py b/backend/onyx/db/mcp.py
index 46b495f5dd..571ea8535b 100644
--- a/backend/onyx/db/mcp.py
+++ b/backend/onyx/db/mcp.py
@@ -167,12 +167,14 @@ def delete_mcp_server(server_id: int, db_session: Session) -> None:
# Count tools that will be deleted
tools_count = db_session.query(Tool).filter(Tool.mcp_server_id == server_id).count()
- logger.info(f"Deleting MCP server {server_id} with {tools_count} associated tools")
+ logger.info(
+ "Deleting MCP server %s with %s associated tools", server_id, tools_count
+ )
db_session.delete(server)
db_session.commit()
- logger.info(f"Successfully deleted MCP server {server_id} and its tools")
+ logger.info("Successfully deleted MCP server %s and its tools", server_id)
def get_all_mcp_tools_for_server(server_id: int, db_session: Session) -> list[Tool]:
diff --git a/backend/onyx/db/models.py b/backend/onyx/db/models.py
index 6b8b679eb9..73764a2b27 100644
--- a/backend/onyx/db/models.py
+++ b/backend/onyx/db/models.py
@@ -273,7 +273,7 @@ class NullFilteredString(TypeDecorator):
dialect: Dialect, # noqa: ARG002
) -> str | None:
if value is not None and "\x00" in value:
- logger.warning(f"NUL characters found in value: {value}")
+ logger.warning("NUL characters found in value: %s", value)
return value.replace("\x00", "")
return value
diff --git a/backend/onyx/db/pat.py b/backend/onyx/db/pat.py
index 855086b9bf..c7abd53a73 100644
--- a/backend/onyx/db/pat.py
+++ b/backend/onyx/db/pat.py
@@ -79,7 +79,7 @@ def _schedule_pat_last_used_update(hashed_token: str, now: datetime) -> None:
)
await session.commit()
except Exception as e:
- logger.warning(f"Failed to update last_used_at for PAT: {e}")
+ logger.warning("Failed to update last_used_at for PAT: %s", e)
asyncio.create_task(_update())
diff --git a/backend/onyx/db/projects.py b/backend/onyx/db/projects.py
index fe6ed96f42..7ace2c7fcc 100644
--- a/backend/onyx/db/projects.py
+++ b/backend/onyx/db/projects.py
@@ -143,7 +143,7 @@ def upload_files_to_user_files_with_indexing(
tenant_id = get_current_tenant_id()
for rejected_file in rejected_files:
logger.warning(
- f"File {rejected_file.filename} rejected for {rejected_file.reason}"
+ "File %s rejected for %s", rejected_file.filename, rejected_file.reason
)
if DISABLE_VECTOR_DB and background_tasks is not None:
@@ -151,7 +151,9 @@ def upload_files_to_user_files_with_indexing(
background_tasks.add_task(drain_processing_loop, tenant_id)
for user_file in indexable_files:
- logger.info(f"Queued in-process processing for user_file_id={user_file.id}")
+ logger.info(
+ "Queued in-process processing for user_file_id=%s", user_file.id
+ )
else:
from onyx.background.celery.versioned_apps.client import app as client_app
@@ -164,7 +166,9 @@ def upload_files_to_user_files_with_indexing(
expires=CELERY_USER_FILE_PROCESSING_TASK_EXPIRES,
)
logger.info(
- f"Triggered indexing for user_file_id={user_file.id} with task_id={task.id}"
+ "Triggered indexing for user_file_id=%s with task_id=%s",
+ user_file.id,
+ task.id,
)
return CategorizedFilesResult(
diff --git a/backend/onyx/db/release_notes.py b/backend/onyx/db/release_notes.py
index 36e03e334e..79c56f891c 100644
--- a/backend/onyx/db/release_notes.py
+++ b/backend/onyx/db/release_notes.py
@@ -91,7 +91,10 @@ def create_release_notifications_for_versions(
total_created += created_count
logger.debug(
- f"Created {created_count} release notes notifications (version {entry.version}, {len(user_ids)} eligible users)"
+ "Created %s release notes notifications (version %s, %s eligible users)",
+ created_count,
+ entry.version,
+ len(user_ids),
)
return total_created
diff --git a/backend/onyx/db/rotate_encryption_key.py b/backend/onyx/db/rotate_encryption_key.py
index 37a79cc079..8a50a66e80 100644
--- a/backend/onyx/db/rotate_encryption_key.py
+++ b/backend/onyx/db/rotate_encryption_key.py
@@ -128,7 +128,11 @@ def rotate_encryption_key(
except (ValueError, UnicodeDecodeError) as e:
pk_vals = [row[i] for i in range(len(pk_names))]
logger.warning(
- f"Could not decrypt/parse {table_name}.{col_name} row {pk_vals} — skipping: {e}"
+ "Could not decrypt/parse %s.%s row %s — skipping: %s",
+ table_name,
+ col_name,
+ pk_vals,
+ e,
)
continue
@@ -152,7 +156,11 @@ def rotate_encryption_key(
if reencrypted > 0:
totals[f"{table_name}.{col_name}"] = reencrypted
logger.info(
- f"{'[DRY RUN] Would re-encrypt' if dry_run else 'Re-encrypted'} {reencrypted} value(s) in {table_name}.{col_name}"
+ "%s %s value(s) in %s.%s",
+ "[DRY RUN] Would re-encrypt" if dry_run else "Re-encrypted",
+ reencrypted,
+ table_name,
+ col_name,
)
return totals
diff --git a/backend/onyx/db/seeding/chat_history_seeding.py b/backend/onyx/db/seeding/chat_history_seeding.py
index a53285633a..6f081897cc 100644
--- a/backend/onyx/db/seeding/chat_history_seeding.py
+++ b/backend/onyx/db/seeding/chat_history_seeding.py
@@ -32,16 +32,16 @@ def seed_chat_history(
persona_id: optional persona/assistant to associate with sessions
"""
with get_session_with_current_tenant() as db_session:
- logger.info(f"Seeding {num_sessions} sessions.")
+ logger.info("Seeding %s sessions.", num_sessions)
for y in range(0, num_sessions):
create_chat_session(db_session, f"pytest_session_{y}", user_id, persona_id)
# randomize all session times
- logger.info(f"Seeding {num_messages} messages per session.")
+ logger.info("Seeding %s messages per session.", num_messages)
rows = db_session.query(ChatSession).all()
for x in range(0, len(rows)):
if x % 1024 == 0:
- logger.info(f"Seeded messages for {x} sessions so far.")
+ logger.info("Seeded messages for %s sessions so far.", x)
row = rows[x]
row.time_created = datetime.now(tz=timezone.utc) - timedelta(
@@ -89,4 +89,4 @@ def seed_chat_history(
db_session.commit()
- logger.info(f"Seeded messages for {len(rows)} sessions. Finished.")
+ logger.info("Seeded messages for %s sessions. Finished.", len(rows))
diff --git a/backend/onyx/db/swap_index.py b/backend/onyx/db/swap_index.py
index 8b692b5559..4f11ab51d5 100644
--- a/backend/onyx/db/swap_index.py
+++ b/backend/onyx/db/swap_index.py
@@ -91,7 +91,7 @@ def _perform_index_swap(
contextual_rag_llm_name=new_search_settings.contextual_rag_llm_name,
)
except ValueError as e:
- logger.error(f"Model not found, defaulting to no contextual model: {e}")
+ logger.error("Model not found, defaulting to no contextual model: %s", e)
update_no_default_contextual_rag_provider(
db_session=db_session,
)
@@ -111,7 +111,10 @@ def _perform_index_swap(
for x in range(VESPA_NUM_ATTEMPTS_ON_STARTUP):
try:
logger.notice(
- f"Document index {document_index.__class__.__name__} swap (attempt {x + 1}/{VESPA_NUM_ATTEMPTS_ON_STARTUP})..."
+ "Document index %s swap (attempt %s/%s)...",
+ document_index.__class__.__name__,
+ x + 1,
+ VESPA_NUM_ATTEMPTS_ON_STARTUP,
)
document_index.ensure_indices_exist(
primary_embedding_dim=new_search_settings.final_embedding_dim,
@@ -126,15 +129,17 @@ def _perform_index_swap(
break
except Exception:
logger.exception(
- f"Document index swap for {document_index.__class__.__name__} did not succeed. "
- f"The document index services may not be ready yet. Retrying in {WAIT_SECONDS} seconds."
+ "Document index swap for %s did not succeed. The document index services may not be ready yet. Retrying in %s seconds.",
+ document_index.__class__.__name__,
+ WAIT_SECONDS,
)
time.sleep(WAIT_SECONDS)
if not success:
logger.error(
- f"Document index swap for {document_index.__class__.__name__} did not succeed. "
- f"Attempt limit reached. ({VESPA_NUM_ATTEMPTS_ON_STARTUP})"
+ "Document index swap for %s did not succeed. Attempt limit reached. (%s)",
+ document_index.__class__.__name__,
+ VESPA_NUM_ATTEMPTS_ON_STARTUP,
)
return None
@@ -230,5 +235,5 @@ def check_and_perform_index_swap(db_session: Session) -> SearchSettings | None:
return None
# Should not reach here, but handle gracefully
- logger.error(f"Unknown switchover_type: {switchover_type}")
+ logger.error("Unknown switchover_type: %s", switchover_type)
return None
diff --git a/backend/onyx/db/sync_record.py b/backend/onyx/db/sync_record.py
index 5a56c407da..f60ed7d19f 100644
--- a/backend/onyx/db/sync_record.py
+++ b/backend/onyx/db/sync_record.py
@@ -32,8 +32,10 @@ def insert_sync_record(
if existing_in_progress_sync_record is not None:
logger.info(
- f"Cancelling existing in-progress sync record {existing_in_progress_sync_record.id} "
- f"for entity_id={entity_id} sync_type={sync_type}"
+ "Cancelling existing in-progress sync record %s for entity_id=%s sync_type=%s",
+ existing_in_progress_sync_record.id,
+ entity_id,
+ sync_type,
)
mark_sync_records_as_cancelled(db_session, entity_id, sync_type)
@@ -130,10 +132,9 @@ def update_sync_record_status(
sync_record = fetch_latest_sync_record(db_session, entity_id, sync_type)
if sync_record is None:
logger.warning(
- f"No sync record found for entity_id={entity_id} "
- f"sync_type={sync_type} — skipping status update. "
- f"This typically means the record was never created "
- f"(insert_sync_record failed silently) or was cleaned up."
+ "No sync record found for entity_id=%s sync_type=%s — skipping status update. This typically means the record was never created (insert_sync_record failed silently) or was cleaned up.",
+ entity_id,
+ sync_type,
)
return
diff --git a/backend/onyx/db/tag.py b/backend/onyx/db/tag.py
index 46070dd8d6..1155791e3f 100644
--- a/backend/onyx/db/tag.py
+++ b/backend/onyx/db/tag.py
@@ -23,7 +23,9 @@ def check_tag_validity(tag_key: str, tag_value: str) -> bool:
Additionally, extremely long tags are not really usable / useful."""
if len(tag_key) + len(tag_value) > 255:
logger.error(
- f"Tag with key '{tag_key}' and value '{tag_value}' is too long, cannot be used"
+ "Tag with key '%s' and value '%s' is too long, cannot be used",
+ tag_key,
+ tag_value,
)
return False
diff --git a/backend/onyx/db/user_preferences.py b/backend/onyx/db/user_preferences.py
index 8487074c2a..c8847ddda5 100644
--- a/backend/onyx/db/user_preferences.py
+++ b/backend/onyx/db/user_preferences.py
@@ -126,7 +126,7 @@ def get_latest_access_token_for_user(
)
return result.scalar_one_or_none()
except Exception as e:
- logger.error(f"Error fetching AccessToken: {e}")
+ logger.error("Error fetching AccessToken: %s", e)
return None
diff --git a/backend/onyx/db/users.py b/backend/onyx/db/users.py
index 9a5f66da63..623265c55c 100644
--- a/backend/onyx/db/users.py
+++ b/backend/onyx/db/users.py
@@ -487,7 +487,9 @@ def assign_user_to_default_groups__no_commit(
recompute_user_permissions__no_commit(user.id, db_session)
- logger.info(f"Assigned user {user.email} to default group '{default_group.name}'")
+ logger.info(
+ "Assigned user %s to default group '%s'", user.email, default_group.name
+ )
def delete_user_from_db(
diff --git a/backend/onyx/deep_research/dr_loop.py b/backend/onyx/deep_research/dr_loop.py
index 322858e675..4716639fdb 100644
--- a/backend/onyx/deep_research/dr_loop.py
+++ b/backend/onyx/deep_research/dr_loop.py
@@ -439,8 +439,9 @@ def run_deep_research_llm_loop(
if timed_out or is_last_cycle:
if timed_out:
logger.info(
- f"Deep research exceeded {DEEP_RESEARCH_FORCE_REPORT_SECONDS}s "
- f"(elapsed: {elapsed_seconds:.1f}s), forcing final report generation"
+ "Deep research exceeded %ss (elapsed: %ss), forcing final report generation",
+ DEEP_RESEARCH_FORCE_REPORT_SECONDS,
+ format(elapsed_seconds, ".1f"),
)
report_turn_index = (
orchestrator_start_turn_index + cycle + reasoning_cycles
@@ -632,7 +633,7 @@ def run_deep_research_llm_loop(
for tool_call in tool_calls:
if tool_call.tool_name != RESEARCH_AGENT_TOOL_NAME:
logger.warning(
- f"Unexpected tool call: {tool_call.tool_name}"
+ "Unexpected tool call: %s", tool_call.tool_name
)
continue
@@ -735,7 +736,8 @@ def run_deep_research_llm_loop(
# synthetic failure response so the invariant holds and the LLM
# knows the call failed.
logger.error(
- f"Research agent call at tab_index {tab_index} failed; emitting synthetic failure response"
+ "Research agent call at tab_index %s failed; emitting synthetic failure response",
+ tab_index,
)
failed_tool_call = research_agent_calls[tab_index]
failure_message = "Research agent call failed. Try a different approach or continue without this result."
diff --git a/backend/onyx/document_index/opensearch/client.py b/backend/onyx/document_index/opensearch/client.py
index bc2ebe45a4..8e1ee0ac8d 100644
--- a/backend/onyx/document_index/opensearch/client.py
+++ b/backend/onyx/document_index/opensearch/client.py
@@ -139,7 +139,10 @@ class OpenSearchClient(AbstractContextManager):
timeout: int = DEFAULT_OPENSEARCH_CLIENT_TIMEOUT_S,
):
logger.debug(
- f"Creating OpenSearch client with host {host}, port {port} and timeout {timeout} seconds."
+ "Creating OpenSearch client with host %s, port %s and timeout %s seconds.",
+ host,
+ port,
+ timeout,
)
self._client = OpenSearch(
hosts=[{"host": host, "port": port}],
@@ -220,7 +223,7 @@ class OpenSearchClient(AbstractContextManager):
logger.info("Successfully put cluster settings.")
return True
else:
- logger.error(f"Failed to put cluster settings: {response}.")
+ logger.error("Failed to put cluster settings: %s.", response)
return False
@log_function_time(print_only=True, debug_only=True)
@@ -321,7 +324,8 @@ class OpenSearchIndexClient(OpenSearchClient):
self._index_name = index_name
self._emit_metrics = emit_metrics
logger.debug(
- f"OpenSearch client created successfully for index {self._index_name}."
+ "OpenSearch client created successfully for index %s.",
+ self._index_name,
)
@log_function_time(print_only=True, debug_only=True, include_args=True)
@@ -342,7 +346,7 @@ class OpenSearchIndexClient(OpenSearchClient):
"mappings": mappings,
"settings": settings,
}
- logger.debug(f"Creating index {self._index_name}.")
+ logger.debug("Creating index %s.", self._index_name)
response = self._client.indices.create(index=self._index_name, body=body)
if not response.get("acknowledged", False):
raise RuntimeError(f"Failed to create index {self._index_name}.")
@@ -351,7 +355,7 @@ class OpenSearchIndexClient(OpenSearchClient):
raise RuntimeError(
f"OpenSearch responded with index name {response_index} when creating index {self._index_name}."
)
- logger.debug(f"Index {self._index_name} created successfully.")
+ logger.debug("Index %s created successfully.", self._index_name)
@log_function_time(print_only=True, debug_only=True)
def delete_index(self) -> bool:
@@ -365,15 +369,16 @@ class OpenSearchIndexClient(OpenSearchClient):
"""
if not self._client.indices.exists(index=self._index_name):
logger.warning(
- f"Tried to delete index {self._index_name} but it does not exist."
+ "Tried to delete index %s but it does not exist.",
+ self._index_name,
)
return False
- logger.info(f"Deleting index {self._index_name}.")
+ logger.info("Deleting index %s.", self._index_name)
response = self._client.indices.delete(index=self._index_name)
if not response.get("acknowledged", False):
raise RuntimeError(f"Failed to delete index {self._index_name}.")
- logger.info(f"Index {self._index_name} deleted successfully.")
+ logger.info("Index %s deleted successfully.", self._index_name)
return True
@log_function_time(print_only=True, debug_only=True)
@@ -408,7 +413,7 @@ class OpenSearchIndexClient(OpenSearchClient):
Exception: There was an error updating the mappings, such as
attempting to change the type of an existing field.
"""
- logger.debug(f"Putting mappings for index {self._index_name}.")
+ logger.debug("Putting mappings for index %s.", self._index_name)
response = self._client.indices.put_mapping(
index=self._index_name, body=mappings
)
@@ -416,7 +421,7 @@ class OpenSearchIndexClient(OpenSearchClient):
raise RuntimeError(
f"Failed to put the mapping update for index {self._index_name}."
)
- logger.debug(f"Successfully put mappings for index {self._index_name}.")
+ logger.debug("Successfully put mappings for index %s.", self._index_name)
@log_function_time(print_only=True, debug_only=True, include_args=True)
def validate_index(self, expected_mappings: dict[str, Any]) -> bool:
@@ -444,10 +449,11 @@ class OpenSearchIndexClient(OpenSearchClient):
exists_response = self.index_exists()
if not exists_response:
logger.warning(
- f"Tried to validate index {self._index_name} but it does not exist."
+ "Tried to validate index %s but it does not exist.",
+ self._index_name,
)
return False
- logger.debug(f"Validating index {self._index_name}.")
+ logger.debug("Validating index %s.", self._index_name)
get_result = self._client.indices.get(index=self._index_name)
index_info: dict[str, Any] = get_result.get(self._index_name, {})
@@ -469,7 +475,9 @@ class OpenSearchIndexClient(OpenSearchClient):
for property in expected_mapping_properties:
if property not in index_mapping_properties:
logger.warning(
- f'The field "{property}" was not found in the index {self._index_name}.'
+ 'The field "%s" was not found in the index %s.',
+ property,
+ self._index_name,
)
return False
@@ -483,12 +491,16 @@ class OpenSearchIndexClient(OpenSearchClient):
index_property_type = index_mapping_properties[property].get("type", "")
if expected_property_type != index_property_type:
logger.warning(
- f'The field "{property}" in the index {self._index_name} has type {index_property_type} '
- f"but the expected type is {expected_property_type}."
+ 'The field "%s" in the index %s has type %s '
+ "but the expected type is %s.",
+ property,
+ self._index_name,
+ index_property_type,
+ expected_property_type,
)
return False
- logger.debug(f"Index {self._index_name} validated successfully.")
+ logger.debug("Index %s validated successfully.", self._index_name)
return True
@log_function_time(print_only=True, debug_only=True, include_args=True)
@@ -509,7 +521,7 @@ class OpenSearchIndexClient(OpenSearchClient):
Raises:
Exception: There was an error updating the settings of the index.
"""
- logger.debug(f"Updating settings of index {self._index_name}.")
+ logger.debug("Updating settings of index %s.", self._index_name)
params = {
"timeout": timeout,
}
@@ -520,7 +532,7 @@ class OpenSearchIndexClient(OpenSearchClient):
raise RuntimeError(
f"Failed to update settings of index {self._index_name}."
)
- logger.debug(f"Settings of index {self._index_name} updated successfully.")
+ logger.debug("Settings of index %s updated successfully.", self._index_name)
@log_function_time(print_only=True, debug_only=True)
def get_settings(
@@ -550,7 +562,7 @@ class OpenSearchIndexClient(OpenSearchClient):
Raises:
Exception: There was an error getting the settings of the index.
"""
- logger.debug(f"Getting settings of index {self._index_name}.")
+ logger.debug("Getting settings of index %s.", self._index_name)
params = {
"include_defaults": str(include_defaults).lower(),
"flat_settings": str(flat_settings).lower(),
@@ -572,14 +584,14 @@ class OpenSearchIndexClient(OpenSearchClient):
Raises:
Exception: There was an error opening the index.
"""
- logger.debug(f"Opening index {self._index_name}.")
+ logger.debug("Opening index %s.", self._index_name)
params = {
"timeout": timeout,
}
response = self._client.indices.open(index=self._index_name, params=params)
if not response.get("acknowledged", False):
raise RuntimeError(f"Failed to open index {self._index_name}.")
- logger.debug(f"Index {self._index_name} opened successfully.")
+ logger.debug("Index %s opened successfully.", self._index_name)
@log_function_time(print_only=True, debug_only=True)
def close_index(self, timeout: float = DEFAULT_INDEX_SETTINGS_TIMEOUT_S) -> None:
@@ -588,14 +600,14 @@ class OpenSearchIndexClient(OpenSearchClient):
Raises:
Exception: There was an error closing the index.
"""
- logger.debug(f"Closing index {self._index_name}.")
+ logger.debug("Closing index %s.", self._index_name)
params = {
"timeout": timeout,
}
response = self._client.indices.close(index=self._index_name, params=params)
if not response.get("acknowledged", False):
raise RuntimeError(f"Failed to close index {self._index_name}.")
- logger.debug(f"Index {self._index_name} closed successfully.")
+ logger.debug("Index %s closed successfully.", self._index_name)
@log_function_time(
print_only=True,
@@ -629,8 +641,10 @@ class OpenSearchIndexClient(OpenSearchClient):
update_if_exists is False.
"""
logger.debug(
- f"Trying to index document ID {document.document_id} for tenant {tenant_state.tenant_id}. "
- f"update_if_exists={update_if_exists}."
+ "Trying to index document ID %s for tenant %s. " "update_if_exists=%s.",
+ document.document_id,
+ tenant_state.tenant_id,
+ update_if_exists,
)
document_chunk_id: str = get_opensearch_doc_chunk_id(
tenant_state=tenant_state,
@@ -671,7 +685,7 @@ class OpenSearchIndexClient(OpenSearchClient):
raise RuntimeError(
f'Unknown OpenSearch indexing result: "{result_string}".'
)
- logger.debug(f"Successfully indexed {document_chunk_id}.")
+ logger.debug("Successfully indexed %s.", document_chunk_id)
@log_function_time(
print_only=True,
@@ -716,7 +730,10 @@ class OpenSearchIndexClient(OpenSearchClient):
if not documents:
return
logger.debug(
- f"Bulk indexing {len(documents)} documents for tenant {tenant_state.tenant_id}. update_if_exists={update_if_exists}."
+ "Bulk indexing %s documents for tenant %s. update_if_exists=%s.",
+ len(documents),
+ tenant_state.tenant_id,
+ update_if_exists,
)
data = []
for document in documents:
@@ -745,7 +762,7 @@ class OpenSearchIndexClient(OpenSearchClient):
f"OpenSearch reported no errors during bulk index but the number of successful operations "
f"({success}) does not match the number of documents ({len(documents)})."
)
- logger.debug(f"Successfully bulk indexed {len(documents)} documents.")
+ logger.debug("Successfully bulk indexed %s documents.", len(documents))
@log_function_time(print_only=True, debug_only=True, include_args=True)
def delete_document(self, document_chunk_id: str) -> bool:
@@ -763,13 +780,17 @@ class OpenSearchIndexClient(OpenSearchClient):
"""
try:
logger.debug(
- f"Trying to delete document chunk {document_chunk_id} from index {self._index_name}."
+ "Trying to delete document chunk %s from index %s.",
+ document_chunk_id,
+ self._index_name,
)
result = self._client.delete(index=self._index_name, id=document_chunk_id)
except TransportError as e:
if e.status_code == 404:
logger.debug(
- f"Document chunk {document_chunk_id} not found in index {self._index_name}."
+ "Document chunk %s not found in index %s.",
+ document_chunk_id,
+ self._index_name,
)
return False
else:
@@ -779,12 +800,16 @@ class OpenSearchIndexClient(OpenSearchClient):
match result_string:
case "deleted":
logger.debug(
- f"Successfully deleted document chunk {document_chunk_id} from index {self._index_name}."
+ "Successfully deleted document chunk %s from index %s.",
+ document_chunk_id,
+ self._index_name,
)
return True
case "not_found":
logger.debug(
- f"Document chunk {document_chunk_id} not found in index {self._index_name}."
+ "Document chunk %s not found in index %s.",
+ document_chunk_id,
+ self._index_name,
)
return False
case _:
@@ -806,7 +831,8 @@ class OpenSearchIndexClient(OpenSearchClient):
The number of documents deleted.
"""
logger.debug(
- f"Trying to delete documents by query for index {self._index_name}."
+ "Trying to delete documents by query for index %s.",
+ self._index_name,
)
result = self._client.delete_by_query(index=self._index_name, body=query_body)
if result.get("timed_out", False):
@@ -827,7 +853,9 @@ class OpenSearchIndexClient(OpenSearchClient):
)
logger.debug(
- f"Successfully deleted {num_deleted} documents by query for index {self._index_name}."
+ "Successfully deleted %s documents by query for index %s.",
+ num_deleted,
+ self._index_name,
)
return num_deleted
@@ -854,7 +882,9 @@ class OpenSearchIndexClient(OpenSearchClient):
Exception: There was an error updating the document.
"""
logger.debug(
- f"Trying to update document chunk {document_chunk_id} for index {self._index_name}."
+ "Trying to update document chunk %s for index %s.",
+ document_chunk_id,
+ self._index_name,
)
update_body: dict[str, Any] = {"doc": properties_to_update}
result = self._client.update(
@@ -875,12 +905,15 @@ class OpenSearchIndexClient(OpenSearchClient):
# Sanity check.
case "updated":
logger.debug(
- f"Successfully updated document chunk {document_chunk_id} for index {self._index_name}."
+ "Successfully updated document chunk %s for index %s.",
+ document_chunk_id,
+ self._index_name,
)
return
case "noop":
logger.warning(
- f'OpenSearch reported a no-op when trying to update document with ID "{document_chunk_id}".'
+ 'OpenSearch reported a no-op when trying to update document with ID "%s".',
+ document_chunk_id,
)
return
case _:
@@ -906,7 +939,9 @@ class OpenSearchIndexClient(OpenSearchClient):
The document chunk.
"""
logger.debug(
- f"Trying to get document chunk {document_chunk_id} from index {self._index_name}."
+ "Trying to get document chunk %s from index %s.",
+ document_chunk_id,
+ self._index_name,
)
result = self._client.get(index=self._index_name, id=document_chunk_id)
found_result: bool = result.get("found", False)
@@ -922,7 +957,9 @@ class OpenSearchIndexClient(OpenSearchClient):
)
logger.debug(
- f"Successfully got document chunk {document_chunk_id} from index {self._index_name}."
+ "Successfully got document chunk %s from index %s.",
+ document_chunk_id,
+ self._index_name,
)
return DocumentChunk.model_validate(document_chunk_source)
@@ -959,7 +996,9 @@ class OpenSearchIndexClient(OpenSearchClient):
List of search hits that match the search request.
"""
logger.debug(
- f"Trying to search index {self._index_name} with search pipeline {search_pipeline_id}."
+ "Trying to search index %s with search pipeline %s.",
+ self._index_name,
+ search_pipeline_id,
)
result: dict[str, Any]
params = {"phase_took": "true"}
@@ -1014,7 +1053,9 @@ class OpenSearchIndexClient(OpenSearchClient):
)
search_hits.append(search_hit)
logger.debug(
- f"Successfully searched index {self._index_name} and got {len(search_hits)} hits."
+ "Successfully searched index %s and got %s hits.",
+ self._index_name,
+ len(search_hits),
)
return search_hits
@@ -1050,7 +1091,8 @@ class OpenSearchIndexClient(OpenSearchClient):
List of document chunk IDs that match the search request.
"""
logger.debug(
- f"Trying to search for document chunk IDs in index {self._index_name}."
+ "Trying to search for document chunk IDs in index %s.",
+ self._index_name,
)
if "_source" not in body or body["_source"] is not False:
logger.warning(
@@ -1099,7 +1141,9 @@ class OpenSearchIndexClient(OpenSearchClient):
)
document_chunk_ids.append(document_chunk_id)
logger.debug(
- f"Successfully searched for document chunk IDs in index {self._index_name} and got {len(document_chunk_ids)} hits."
+ "Successfully searched for document chunk IDs in index %s and got %s hits.",
+ self._index_name,
+ len(document_chunk_ids),
)
return document_chunk_ids
@@ -1176,11 +1220,17 @@ class OpenSearchIndexClient(OpenSearchClient):
"""
if time_took and time_took > CLIENT_THRESHOLD_TO_LOG_SLOW_SEARCH_MS:
logger.warning(
- f"OpenSearch client warning: Search for index {self._index_name} took {time_took} milliseconds.\n"
- f"Body: {get_new_body_without_vectors(body)}\n"
- f"Search pipeline ID: {search_pipeline_id}\n"
- f"Phase took: {phase_took}\n"
- f"Profile: {json.dumps(profile, indent=2)}\n"
+ "OpenSearch client warning: Search for index %s took %s milliseconds.\n"
+ "Body: %s\n"
+ "Search pipeline ID: %s\n"
+ "Phase took: %s\n"
+ "Profile: %s\n",
+ self._index_name,
+ time_took,
+ get_new_body_without_vectors(body),
+ search_pipeline_id,
+ phase_took,
+ json.dumps(profile, indent=2),
)
if timed_out:
error_str = f"OpenSearch client error: Search timed out for index {self._index_name}."
@@ -1234,10 +1284,13 @@ def wait_for_opensearch_with_timeout(
time_elapsed = time.monotonic() - time_start
if time_elapsed > wait_limit_s:
logger.info(
- f"[OpenSearch] Readiness probe did not succeed within the timeout ({wait_limit_s} seconds)."
+ "[OpenSearch] Readiness probe did not succeed within the timeout (%s seconds).",
+ wait_limit_s,
)
return False
logger.info(
- f"[OpenSearch] Readiness probe ongoing. elapsed={time_elapsed:.1f} timeout={wait_limit_s:.1f}"
+ "[OpenSearch] Readiness probe ongoing. elapsed=%s timeout=%s",
+ format(time_elapsed, ".1f"),
+ format(wait_limit_s, ".1f"),
)
time.sleep(wait_interval_s)
diff --git a/backend/onyx/document_index/opensearch/opensearch_document_index.py b/backend/onyx/document_index/opensearch/opensearch_document_index.py
index 2e529428c5..90b17b9df8 100644
--- a/backend/onyx/document_index/opensearch/opensearch_document_index.py
+++ b/backend/onyx/document_index/opensearch/opensearch_document_index.py
@@ -442,7 +442,8 @@ class OpenSearchOldDocumentIndex(OldDocumentIndex):
"""
if fields is None and user_fields is None:
logger.warning(
- f"Tried to update document {doc_id} with no updated fields or user fields."
+ "Tried to update document %s with no updated fields or user fields.",
+ doc_id,
)
return
@@ -481,20 +482,19 @@ class OpenSearchOldDocumentIndex(OldDocumentIndex):
self._secondary_real_index.update([update_request])
except NotFoundError:
logger.exception(
- f"Tried to update document {doc_id} but at least one of its chunks was not found in OpenSearch. "
- "This is likely due to it not having been indexed yet. Skipping update for now..."
+ "Tried to update document %s but at least one of its chunks was not found in OpenSearch. This is likely due to it not having been indexed yet. Skipping update for now...",
+ doc_id,
)
return
except ChunkCountNotFoundError:
logger.warning(
- f"Tried to update document {doc_id} but its chunk count is not known. We tolerate this for now "
- "but this will not be an acceptable state once OpenSearch is the primary document index and the "
- "indexing/updating race condition is fixed."
+ "Tried to update document %s but its chunk count is not known. We tolerate this for now but this will not be an acceptable state once OpenSearch is the primary document index and the indexing/updating race condition is fixed.",
+ doc_id,
)
return
except ChunkCountZeroError:
logger.warning(
- f"Tried to update document {doc_id} but its chunk count was 0."
+ "Tried to update document %s but its chunk count was 0.", doc_id
)
return
@@ -647,8 +647,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
search pipelines.
"""
logger.debug(
- f"[OpenSearchDocumentIndex] Verifying and creating index {self._index_name} if "
- f"necessary, with embedding dimension {embedding_dim}."
+ "[OpenSearchDocumentIndex] Verifying and creating index %s if necessary, with embedding dimension %s.",
+ self._index_name,
+ embedding_dim,
)
with redis_shared_lock(
@@ -678,8 +679,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
self._client.put_mapping(expected_mappings)
except Exception as e:
logger.error(
- f"Failed to update mappings for index {self._index_name}. This likely means a "
- f"field type was changed which requires reindexing. Error: {e}"
+ "Failed to update mappings for index %s. This likely means a field type was changed which requires reindexing. Error: %s",
+ self._index_name,
+ e,
)
raise
@@ -716,8 +718,10 @@ class OpenSearchDocumentIndex(DocumentIndex):
for cc in indexing_metadata.doc_id_to_chunk_cnt_diff.values()
)
logger.debug(
- f"[OpenSearchDocumentIndex] Indexing {total_chunks} chunks from {len(indexing_metadata.doc_id_to_chunk_cnt_diff)} "
- f"documents for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Indexing %s chunks from %s documents for index %s.",
+ total_chunks,
+ len(indexing_metadata.doc_id_to_chunk_cnt_diff),
+ self._index_name,
)
document_indexing_results: list[DocumentInsertionRecord] = []
@@ -778,7 +782,8 @@ class OpenSearchDocumentIndex(DocumentIndex):
# Refresh the index and try one more time. We do not refresh
# after every delete because this may become expensive.
logger.warning(
- f"Failed to bulk index documents: {e}. Refreshing index and trying again."
+ "Failed to bulk index documents: %s. Refreshing index and trying again.",
+ e,
)
self._client.refresh_index()
self._client.bulk_index_documents(
@@ -834,7 +839,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
The number of chunks successfully deleted.
"""
logger.debug(
- f"[OpenSearchDocumentIndex] Deleting document {document_id} from index {self._index_name}."
+ "[OpenSearchDocumentIndex] Deleting document %s from index %s.",
+ document_id,
+ self._index_name,
)
query_body = DocumentQuery.delete_from_document_id_query(
document_id=document_id,
@@ -870,7 +877,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
specified documents.
"""
logger.debug(
- f"[OpenSearchDocumentIndex] Updating {len(update_requests)} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Updating %s chunks for index %s.",
+ len(update_requests),
+ self._index_name,
)
for update_request in update_requests:
properties_to_update: dict[str, Any] = dict()
@@ -908,8 +917,8 @@ class OpenSearchDocumentIndex(DocumentIndex):
else:
update_string = f"document {update_request.document_ids[0]}"
logger.warning(
- f"[OpenSearchDocumentIndex] Tried to update {update_string} "
- "with no specified update fields. This will be a no-op."
+ "[OpenSearchDocumentIndex] Tried to update %s with no specified update fields. This will be a no-op.",
+ update_string,
)
continue
@@ -962,7 +971,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
chunk IDs vs querying for matching document chunks.
"""
logger.debug(
- f"[OpenSearchDocumentIndex] Retrieving {len(chunk_requests)} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Retrieving %s chunks for index %s.",
+ len(chunk_requests),
+ self._index_name,
)
results: list[InferenceChunk] = []
for chunk_request in chunk_requests:
@@ -1012,7 +1023,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
# TODO(andrei): There is some duplicated logic in this function with
# others in this file.
logger.debug(
- f"[OpenSearchDocumentIndex] Hybrid retrieving {num_to_retrieve} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Hybrid retrieving %s chunks for index %s.",
+ num_to_retrieve,
+ self._index_name,
)
# TODO(andrei): This could be better, the caller should just make this
# decision when passing in the query param. See the above comment in the
@@ -1062,7 +1075,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
# TODO(andrei): There is some duplicated logic in this function with
# others in this file.
logger.debug(
- f"[OpenSearchDocumentIndex] Keyword retrieving {num_to_retrieve} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Keyword retrieving %s chunks for index %s.",
+ num_to_retrieve,
+ self._index_name,
)
query_body = DocumentQuery.get_keyword_search_query(
query_text=query,
@@ -1104,7 +1119,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
# TODO(andrei): There is some duplicated logic in this function with
# others in this file.
logger.debug(
- f"[OpenSearchDocumentIndex] Semantic retrieving {num_to_retrieve} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Semantic retrieving %s chunks for index %s.",
+ num_to_retrieve,
+ self._index_name,
)
query_body = DocumentQuery.get_semantic_search_query(
query_embedding=query_embedding,
@@ -1144,7 +1161,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
dirty: bool | None = None, # noqa: ARG002
) -> list[InferenceChunk]:
logger.debug(
- f"[OpenSearchDocumentIndex] Randomly retrieving {num_to_retrieve} chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Randomly retrieving %s chunks for index %s.",
+ num_to_retrieve,
+ self._index_name,
)
query_body = DocumentQuery.get_random_search_query(
tenant_state=self._tenant_state,
@@ -1175,7 +1194,9 @@ class OpenSearchDocumentIndex(DocumentIndex):
complete.
"""
logger.debug(
- f"[OpenSearchDocumentIndex] Indexing {len(chunks)} raw chunks for index {self._index_name}."
+ "[OpenSearchDocumentIndex] Indexing %s raw chunks for index %s.",
+ len(chunks),
+ self._index_name,
)
# Do not raise if the document already exists, just update. This is
# because the document may already have been indexed during the
diff --git a/backend/onyx/document_index/vespa/chunk_retrieval.py b/backend/onyx/document_index/vespa/chunk_retrieval.py
index b496fb1716..cc8bba0f39 100644
--- a/backend/onyx/document_index/vespa/chunk_retrieval.py
+++ b/backend/onyx/document_index/vespa/chunk_retrieval.py
@@ -125,7 +125,8 @@ def _vespa_hit_to_inference_chunk(
semantic_identifier = fields.get(SEMANTIC_IDENTIFIER, "")
if not semantic_identifier:
logger.error(
- f"Chunk with blurb: {fields.get(BLURB, 'Unknown')[:50]}... has no Semantic Identifier"
+ "Chunk with blurb: %s... has no Semantic Identifier",
+ fields.get(BLURB, "Unknown")[:50],
)
source_links = fields.get(SOURCE_LINKS, {})
@@ -239,11 +240,16 @@ def get_chunks_via_visit_api(
except httpx.HTTPError as e:
error_base = "Failed to query Vespa"
logger.error(
- f"{error_base}:\n"
- f"Request URL: {e.request.url}\n"
- f"Request Headers: {e.request.headers}\n"
- f"Request Payload: {params}\n"
- f"Exception: {str(e)}"
+ "%s:\n"
+ "Request URL: %s\n"
+ "Request Headers: %s\n"
+ "Request Payload: %s\n"
+ "Exception: %s",
+ error_base,
+ e.request.url,
+ e.request.headers,
+ params,
+ str(e),
)
raise httpx.HTTPError(error_base) from e
@@ -266,9 +272,11 @@ def get_chunks_via_visit_api(
document_tenant_id = document["fields"].get(TENANT_ID)
if document_tenant_id != filters.tenant_id:
logger.error(
- f"Skipping document {document['document_id']} because "
- f"it does not belong to tenant {filters.tenant_id}. "
- "This should never happen."
+ "Skipping document %s because "
+ "it does not belong to tenant %s. "
+ "This should never happen.",
+ document["document_id"],
+ filters.tenant_id,
)
continue
@@ -317,7 +325,9 @@ def get_all_chunks_paginated(
) -> tuple[list[dict], str | None]:
if continuation_token == FINISHED_VISITING_SLICE_CONTINUATION_TOKEN:
logger.debug(
- f"Slice {slice_id} has finished visiting. Returning empty list and {FINISHED_VISITING_SLICE_CONTINUATION_TOKEN}."
+ "Slice %s has finished visiting. Returning empty list and %s.",
+ slice_id,
+ FINISHED_VISITING_SLICE_CONTINUATION_TOKEN,
)
return [], FINISHED_VISITING_SLICE_CONTINUATION_TOKEN
@@ -362,7 +372,10 @@ def get_all_chunks_paginated(
f"{continuation_token} in {time.monotonic() - start_time:.3f} seconds."
)
logger.exception(
- f"Request URL: {e.request.url}\nRequest Headers: {e.request.headers}\nRequest Payload: {params}\n"
+ "Request URL: %s\nRequest Headers: %s\nRequest Payload: %s",
+ e.request.url,
+ e.request.headers,
+ params,
)
error_message = (
response.json().get("message") if response else "No response"
@@ -382,7 +395,10 @@ def get_all_chunks_paginated(
chunks = [chunk["fields"] for chunk in response_data.get("documents", [])]
if next_continuation_token == FINISHED_VISITING_SLICE_CONTINUATION_TOKEN:
logger.debug(
- f"Slice {slice_id} has finished visiting. Returning {len(chunks)} chunks and {next_continuation_token}."
+ "Slice %s has finished visiting. Returning %s chunks and %s.",
+ slice_id,
+ len(chunks),
+ next_continuation_token,
)
return chunks, next_continuation_token
@@ -423,8 +439,10 @@ def get_all_chunks_paginated(
raise RuntimeError(f"Slice {i} is not in the continuation token map.")
if parallel_result is None:
logger.error(
- f"Failed to get chunks for slice {i} of {total_slices}. "
- "The continuation token for this slice will not be updated."
+ "Failed to get chunks for slice %s of %s. "
+ "The continuation token for this slice will not be updated.",
+ i,
+ total_slices,
)
continue
chunks.extend(parallel_result[0])
@@ -522,14 +540,14 @@ def query_vespa(
# Log each detail on its own line so log collectors capture them
# as separate entries rather than truncating a single multiline msg
logger.error(
- f"Failed to query Vespa | "
- f"status={status_code} | "
- f"yql_length={yql_length} | "
- f"exception={str(e)}"
+ "Failed to query Vespa | " "status=%s | " "yql_length=%s | " "exception=%s",
+ status_code,
+ yql_length,
+ str(e),
)
if response_text:
- logger.error(f"Vespa error response: {response_text[:1000]}")
- logger.error(f"Vespa request URL: {e.request.url}")
+ logger.error("Vespa error response: %s", response_text[:1000])
+ logger.error("Vespa request URL: %s", e.request.url)
# Re-raise with diagnostics so callers see what actually went wrong
raise httpx.HTTPError(
@@ -544,17 +562,19 @@ def query_vespa(
if not hits:
logger.warning(
- f"No hits found for YQL Query: {query_params.get('yql', 'No YQL Query')}"
+ "No hits found for YQL Query: %s",
+ query_params.get("yql", "No YQL Query"),
)
- logger.debug(f"Vespa Response: {response.text}")
+ logger.debug("Vespa Response: %s", response.text)
for hit in hits:
if hit["fields"].get(CONTENT) is None:
identifier = hit["fields"].get("documentid") or hit["id"]
logger.error(
- f"Vespa Index with Vespa ID {identifier} has no contents. "
- f"This is invalid because the vector is not meaningful and keywordsearch cannot "
- f"fetch this document"
+ "Vespa Index with Vespa ID %s has no contents. "
+ "This is invalid because the vector is not meaningful and keywordsearch cannot "
+ "fetch this document",
+ identifier,
)
filtered_hits = [hit for hit in hits if hit["fields"].get(CONTENT) is not None]
@@ -567,11 +587,13 @@ def query_vespa(
set([chunk.document_id for chunk in inference_chunks])
)
logger.info(
- f"Retrieved {num_retrieved_inference_chunks} inference chunks for {num_retrieved_document_ids} documents"
+ "Retrieved %s inference chunks for %s documents",
+ num_retrieved_inference_chunks,
+ num_retrieved_document_ids,
)
except Exception as e:
# Debug logging only, should not fail the retrieval
- logger.error(f"Error logging retrieval statistics: {e}")
+ logger.error("Error logging retrieval statistics: %s", e)
# Good Debugging Spot
return inference_chunks
@@ -657,7 +679,7 @@ def batch_search_api_retrieval(
)
if uncapped_requests:
- logger.debug(f"Retrieving {len(uncapped_requests)} uncapped requests")
+ logger.debug("Retrieving %s uncapped requests", len(uncapped_requests))
retrieved_chunks.extend(
parallel_visit_api_retrieval(
index_name, uncapped_requests, filters, get_large_chunks
diff --git a/backend/onyx/document_index/vespa/deletion.py b/backend/onyx/document_index/vespa/deletion.py
index 4d1682fca7..34647e425f 100644
--- a/backend/onyx/document_index/vespa/deletion.py
+++ b/backend/onyx/document_index/vespa/deletion.py
@@ -29,7 +29,7 @@ def _delete_vespa_chunk(
f"{DOCUMENT_ID_ENDPOINT.format(index_name=index_name)}/{doc_chunk_id}",
)
except httpx.HTTPStatusError as e:
- logger.error(f"Failed to delete chunk, details: {e.response.text}")
+ logger.error("Failed to delete chunk, details: %s", e.response.text)
raise
diff --git a/backend/onyx/document_index/vespa/index.py b/backend/onyx/document_index/vespa/index.py
index d213aa55e9..a4dd506dd3 100644
--- a/backend/onyx/document_index/vespa/index.py
+++ b/backend/onyx/document_index/vespa/index.py
@@ -274,7 +274,7 @@ class VespaIndex(DocumentIndex):
jinja_env = jinja2.Environment()
deploy_url = f"{VESPA_APPLICATION_ENDPOINT}/tenant/default/prepareandactivate"
- logger.notice(f"Deploying Vespa application package to {deploy_url}")
+ logger.notice("Deploying Vespa application package to %s", deploy_url)
vespa_schema_path = os.path.join(
os.getcwd(), "onyx", "document_index", "vespa", "app_config"
@@ -359,7 +359,7 @@ class VespaIndex(DocumentIndex):
response = requests.post(deploy_url, headers=headers, data=zip_file)
if response.status_code != 200:
logger.error(
- f"Failed to prepare Vespa Onyx Index. Response: {response.text}"
+ "Failed to prepare Vespa Onyx Index. Response: %s", response.text
)
raise RuntimeError(
f"Failed to prepare Vespa Onyx Index. Response: {response.text}"
@@ -375,7 +375,7 @@ class VespaIndex(DocumentIndex):
raise ValueError("Multi-tenant is not enabled")
deploy_url = f"{VESPA_APPLICATION_ENDPOINT}/tenant/default/prepareandactivate"
- logger.info(f"Deploying Vespa application package to {deploy_url}")
+ logger.info("Deploying Vespa application package to %s", deploy_url)
vespa_schema_path = os.path.join(
os.getcwd(), "onyx", "document_index", "vespa", "app_config"
@@ -437,7 +437,9 @@ class VespaIndex(DocumentIndex):
embedding_dim = embedding_dims[i]
embedding_precision = embedding_precisions[i]
logger.info(
- f"Creating index: {index_name} with embedding dimension: {embedding_dim}"
+ "Creating index: %s with embedding dimension: %s",
+ index_name,
+ embedding_dim,
)
schema = schema_template.render(
@@ -535,7 +537,9 @@ class VespaIndex(DocumentIndex):
update: _VespaUpdateRequest, http_client: httpx.Client
) -> httpx.Response:
logger.debug(
- f"Updating with request to {update.url} with body {update.update_request}"
+ "Updating with request to %s with body %s",
+ update.url,
+ update.update_request,
)
return http_client.put(
update.url,
@@ -669,7 +673,8 @@ class VespaIndex(DocumentIndex):
"""
if fields is None and user_fields is None:
logger.warning(
- f"Tried to update document {doc_id} with no updated fields or user fields."
+ "Tried to update document %s with no updated fields or user fields.",
+ doc_id,
)
return
@@ -930,7 +935,7 @@ class VespaIndex(DocumentIndex):
int: The number of documents deleted.
"""
logger.info(
- f"Deleting entries with tenant_id: {tenant_id} from index: {index_name}"
+ "Deleting entries with tenant_id: %s from index: %s", tenant_id, index_name
)
# Step 1: Retrieve all document IDs with the given tenant_id
@@ -938,7 +943,9 @@ class VespaIndex(DocumentIndex):
if not document_ids:
logger.info(
- f"No documents found with tenant_id: {tenant_id} in index: {index_name}"
+ "No documents found with tenant_id: %s in index: %s",
+ tenant_id,
+ index_name,
)
return 0
@@ -972,7 +979,9 @@ class VespaIndex(DocumentIndex):
document_ids = []
logger.debug(
- f"Starting document ID retrieval for tenant_id: {tenant_id} in index: {index_name}"
+ "Starting document ID retrieval for tenant_id: %s in index: %s",
+ tenant_id,
+ index_name,
)
while True:
@@ -989,7 +998,9 @@ class VespaIndex(DocumentIndex):
url = f"{VESPA_APPLICATION_ENDPOINT}/search/"
logger.debug(
- f"Querying for document IDs with tenant_id: {tenant_id}, offset: {offset}"
+ "Querying for document IDs with tenant_id: %s, offset: %s",
+ tenant_id,
+ offset,
)
with get_vespa_http_client() as http_client:
@@ -1010,7 +1021,7 @@ class VespaIndex(DocumentIndex):
offset += limit # Move to the next page
logger.debug(
- f"Retrieved {len(document_ids)} document IDs for tenant_id: {tenant_id}"
+ "Retrieved %s document IDs for tenant_id: %s", len(document_ids), tenant_id
)
return document_ids
@@ -1036,7 +1047,7 @@ class VespaIndex(DocumentIndex):
def _delete_document(
delete_request: "_VespaDeleteRequest", http_client: httpx.Client
) -> None:
- logger.debug(f"Deleting document with ID {delete_request.document_id}")
+ logger.debug("Deleting document with ID %s", delete_request.document_id)
response = http_client.delete(
delete_request.url,
headers={"Content-Type": "application/json"},
@@ -1044,7 +1055,7 @@ class VespaIndex(DocumentIndex):
)
response.raise_for_status()
- logger.debug(f"Starting batch deletion for {len(delete_requests)} documents")
+ logger.debug("Starting batch deletion for %s documents", len(delete_requests))
with concurrent.futures.ThreadPoolExecutor(max_workers=NUM_THREADS) as executor:
with get_vespa_http_client() as http_client:
@@ -1066,9 +1077,9 @@ class VespaIndex(DocumentIndex):
doc_id = future_to_document_id[future]
try:
future.result()
- logger.debug(f"Successfully deleted document: {doc_id}")
+ logger.debug("Successfully deleted document: %s", doc_id)
except httpx.HTTPError as e:
- logger.error(f"Failed to delete document {doc_id}: {e}")
+ logger.error("Failed to delete document %s: %s", doc_id, e)
# Optionally, implement retry logic or error handling here
logger.info("Batch deletion completed")
diff --git a/backend/onyx/document_index/vespa/indexing_utils.py b/backend/onyx/document_index/vespa/indexing_utils.py
index cad9a717ef..6ea46f8e7c 100644
--- a/backend/onyx/document_index/vespa/indexing_utils.py
+++ b/backend/onyx/document_index/vespa/indexing_utils.py
@@ -80,7 +80,7 @@ def _does_doc_chunk_exist(
return False
if doc_fetch_response.status_code != 200:
- logger.debug(f"Failed to check for document with URL {doc_url}")
+ logger.debug("Failed to check for document with URL %s", doc_url)
raise RuntimeError(
f"Unexpected fetch document by ID value from Vespa: "
f"error={doc_fetch_response.status_code} "
@@ -227,7 +227,7 @@ def _index_vespa_chunk(
if chunk.tenant_id:
vespa_document_fields[TENANT_ID] = chunk.tenant_id
vespa_url = f"{DOCUMENT_ID_ENDPOINT.format(index_name=index_name)}/{vespa_chunk_id}"
- logger.debug(f'Indexing to URL "{vespa_url}"')
+ logger.debug('Indexing to URL "%s"', vespa_url)
# Retry logic with exponential backoff for rate limiting
for attempt in range(INDEXING_MAX_RETRIES):
@@ -246,10 +246,12 @@ def _index_vespa_chunk(
INDEXING_BASE_DELAY * (2**attempt), INDEXING_MAX_DELAY
) * random.uniform(0.5, 1.0)
logger.warning(
- f"Rate limited while indexing document '{document.id}' "
- f"(attempt {attempt + 1}/{INDEXING_MAX_RETRIES}). "
- f"Vespa response: '{e.response.text}'. "
- f"Backing off for {delay:.2f} seconds."
+ "Rate limited while indexing document '%s' (attempt %s/%s). Vespa response: '%s'. Backing off for %s seconds.",
+ document.id,
+ attempt + 1,
+ INDEXING_MAX_RETRIES,
+ e.response.text,
+ format(delay, ".2f"),
)
time.sleep(delay)
continue
@@ -259,7 +261,9 @@ def _index_vespa_chunk(
) from e
elif e.response.status_code == HTTPStatus.INSUFFICIENT_STORAGE:
logger.error(
- f"Failed to index document: '{document.id}'. Got response: '{e.response.text}'"
+ "Failed to index document: '%s'. Got response: '%s'",
+ document.id,
+ e.response.text,
)
logger.error(
"NOTE: HTTP Status 507 Insufficient Storage usually means "
@@ -277,21 +281,29 @@ def _index_vespa_chunk(
):
# Non-retryable errors - fail immediately
logger.error(
- f"Non-retryable HTTP {e.response.status_code} error for document '{document.id}'"
+ "Non-retryable HTTP %s error for document '%s'",
+ e.response.status_code,
+ document.id,
)
raise
# Retry other errors with shorter backoff
if attempt < INDEXING_MAX_RETRIES - 1:
delay = INDEXING_BASE_DELAY * (1.5**attempt)
logger.warning(
- f"HTTP error {e.response.status_code} while indexing document '{document.id}' "
- f"(attempt {attempt + 1}/{INDEXING_MAX_RETRIES}). Retrying in {delay:.2f} seconds."
+ "HTTP error %s while indexing document '%s' (attempt %s/%s). Retrying in %s seconds.",
+ e.response.status_code,
+ document.id,
+ attempt + 1,
+ INDEXING_MAX_RETRIES,
+ format(delay, ".2f"),
)
time.sleep(delay)
continue
else:
logger.exception(
- f"Failed to index document: '{document.id}'. Got response: '{e.response.text}'"
+ "Failed to index document: '%s'. Got response: '%s'",
+ document.id,
+ e.response.text,
)
raise
except Exception as e:
@@ -299,14 +311,17 @@ def _index_vespa_chunk(
if attempt < INDEXING_MAX_RETRIES - 1:
delay = INDEXING_BASE_DELAY * (1.5**attempt)
logger.warning(
- f"Error while indexing document '{document.id}' "
- f"(attempt {attempt + 1}/{INDEXING_MAX_RETRIES}): {str(e)}. "
- f"Retrying in {delay:.2f} seconds."
+ "Error while indexing document '%s' (attempt %s/%s): %s. Retrying in %s seconds.",
+ document.id,
+ attempt + 1,
+ INDEXING_MAX_RETRIES,
+ str(e),
+ format(delay, ".2f"),
)
time.sleep(delay)
continue
else:
- logger.exception(f"Failed to index document: '{document.id}'")
+ logger.exception("Failed to index document: '%s'", document.id)
raise
diff --git a/backend/onyx/document_index/vespa/shared_utils/utils.py b/backend/onyx/document_index/vespa/shared_utils/utils.py
index 370c3bd297..38399eea62 100644
--- a/backend/onyx/document_index/vespa/shared_utils/utils.py
+++ b/backend/onyx/document_index/vespa/shared_utils/utils.py
@@ -90,18 +90,23 @@ def wait_for_vespa_with_timeout(wait_interval: int = 5, wait_limit: int = 60) ->
return True
except Exception as e:
logger.warning(
- f"Vespa: Readiness probe failed trying to connect to {url}. Exception: {e}"
+ "Vespa: Readiness probe failed trying to connect to %s. Exception: %s",
+ url,
+ e,
)
time_elapsed = time.monotonic() - time_start
if time_elapsed > wait_limit:
logger.info(
- f"Vespa: Readiness probe did not succeed within the timeout ({wait_limit} seconds)."
+ "Vespa: Readiness probe did not succeed within the timeout (%s seconds).",
+ wait_limit,
)
return False
logger.info(
- f"Vespa: Readiness probe ongoing. elapsed={time_elapsed:.1f} timeout={wait_limit:.1f}"
+ "Vespa: Readiness probe ongoing. elapsed=%s timeout=%s",
+ format(time_elapsed, ".1f"),
+ format(wait_limit, ".1f"),
)
time.sleep(wait_interval)
diff --git a/backend/onyx/document_index/vespa/shared_utils/vespa_request_builders.py b/backend/onyx/document_index/vespa/shared_utils/vespa_request_builders.py
index 9f44e87ad5..ea7f369871 100644
--- a/backend/onyx/document_index/vespa/shared_utils/vespa_request_builders.py
+++ b/backend/onyx/document_index/vespa/shared_utils/vespa_request_builders.py
@@ -155,7 +155,7 @@ def build_vespa_filters(
try:
pid = int(persona_id)
except Exception:
- logger.warning(f"Invalid persona ID: {persona_id}")
+ logger.warning("Invalid persona ID: %s", persona_id)
return ""
return f'({PERSONAS} contains "{pid}")'
diff --git a/backend/onyx/document_index/vespa/vespa_document_index.py b/backend/onyx/document_index/vespa/vespa_document_index.py
index 3162085eef..cfcf2f7366 100644
--- a/backend/onyx/document_index/vespa/vespa_document_index.py
+++ b/backend/onyx/document_index/vespa/vespa_document_index.py
@@ -264,8 +264,11 @@ def _update_single_chunk(
resp.raise_for_status()
except httpx.HTTPStatusError as e:
logger.error(
- f"Failed to update doc chunk {doc_chunk_id} (doc_id={doc_id}). "
- f"Code: {e.response.status_code}. Details: {e.response.text}"
+ "Failed to update doc chunk %s (doc_id=%s). Code: %s. Details: %s",
+ doc_chunk_id,
+ doc_id,
+ e.response.status_code,
+ e.response.text,
)
# Re-raise so the @retry decorator will catch and retry, unless the
# status code is < 5xx, in which case wrap the exception in something
@@ -523,7 +526,7 @@ class VespaDocumentIndex(DocumentIndex):
)
logger.info(
- f"Updated {len(doc_chunk_ids)} chunks for document {doc_id}."
+ "Updated %s chunks for document %s.", len(doc_chunk_ids), doc_id
)
def id_based_retrieval(
@@ -594,9 +597,9 @@ class VespaDocumentIndex(DocumentIndex):
f"hybrid_search_{query_type.value}_base_{len(query_embedding)}"
)
- logger.info(f"Selected ranking profile: {ranking_profile}")
+ logger.info("Selected ranking profile: %s", ranking_profile)
- logger.debug(f"Query YQL: {yql}")
+ logger.debug("Query YQL: %s", yql)
# In this interface we do not pass in hybrid alpha. Tracing the codepath
# of the legacy Vespa interface, it so happens that KEYWORD always
diff --git a/backend/onyx/error_handling/exceptions.py b/backend/onyx/error_handling/exceptions.py
index 357c82c26b..3fab19f8fb 100644
--- a/backend/onyx/error_handling/exceptions.py
+++ b/backend/onyx/error_handling/exceptions.py
@@ -63,9 +63,9 @@ def log_onyx_error(exc: OnyxError) -> None:
detail = exc.detail
status_code = exc.status_code
if status_code >= 500:
- logger.error(f"OnyxError {exc.error_code.code}: {detail}")
+ logger.error("OnyxError %s: %s", exc.error_code.code, detail)
elif status_code >= 400:
- logger.warning(f"OnyxError {exc.error_code.code}: {detail}")
+ logger.warning("OnyxError %s: %s", exc.error_code.code, detail)
def onyx_error_to_json_response(exc: OnyxError) -> JSONResponse:
diff --git a/backend/onyx/evals/eval.py b/backend/onyx/evals/eval.py
index b5223bc122..497a6115a8 100644
--- a/backend/onyx/evals/eval.py
+++ b/backend/onyx/evals/eval.py
@@ -249,8 +249,11 @@ def _get_answer_with_tools(
)
logger.info(
- f"Eval completed. Tools called: {result.tools_called}.\n"
- f"Assertion passed: {assertion_passed}. Details: {assertion_details}\n"
+ "Eval completed. Tools called: %s.\n"
+ "Assertion passed: %s. Details: %s",
+ result.tools_called,
+ assertion_passed,
+ assertion_details,
)
return EvalToolResult(
@@ -333,7 +336,10 @@ def _get_multi_turn_answer_with_tools(
# Process each turn sequentially
for turn_idx, msg in enumerate(messages):
logger.info(
- f"Processing turn {turn_idx + 1}/{len(messages)}: {msg.message[:50]}..."
+ "Processing turn %s/%s: %s...",
+ turn_idx + 1,
+ len(messages),
+ msg.message[:50],
)
# Handle per-turn tool forcing
@@ -403,8 +409,12 @@ def _get_multi_turn_answer_with_tools(
)
logger.info(
- f"Turn {turn_idx + 1} completed. Tools called: {result.tools_called}.\n"
- f"Assertion passed: {assertion_passed}. Details: {assertion_details}\n"
+ "Turn %s completed. Tools called: %s.\n"
+ "Assertion passed: %s. Details: %s",
+ turn_idx + 1,
+ result.tools_called,
+ assertion_passed,
+ assertion_details,
)
turn_results.append(
diff --git a/backend/onyx/evals/providers/local.py b/backend/onyx/evals/providers/local.py
index b3bb9f55b7..0b9a5170fb 100644
--- a/backend/onyx/evals/providers/local.py
+++ b/backend/onyx/evals/providers/local.py
@@ -172,7 +172,7 @@ class LocalEvalProvider(EvalProvider):
except Exception as e:
print(f" {RED}ERROR:{RESET} {e}")
failed[0] += 1
- logger.exception(f"Error running eval for input: {message}")
+ logger.exception("Error running eval for input: %s", message)
def _run_multi_turn_eval(
self,
@@ -232,4 +232,4 @@ class LocalEvalProvider(EvalProvider):
except Exception as e:
print(f" {RED}ERROR:{RESET} {e}")
failed[0] += 1
- logger.exception(f"Error running multi-turn eval: {first_msg}")
+ logger.exception("Error running multi-turn eval: %s", first_msg)
diff --git a/backend/onyx/federated_connectors/federated_retrieval.py b/backend/onyx/federated_connectors/federated_retrieval.py
index e109833900..82141368c3 100644
--- a/backend/onyx/federated_connectors/federated_retrieval.py
+++ b/backend/onyx/federated_connectors/federated_retrieval.py
@@ -71,28 +71,29 @@ def get_federated_retrieval_functions(
mapping.federated_connector.config or {}
)
logger.debug(
- f"Found Slack federated connector config: {slack_federated_connector_config}"
+ "Found Slack federated connector config: %s",
+ slack_federated_connector_config,
)
break
if slack_federated_connector_config is None:
logger.debug(
- f"Skipping Slack federated search: document sets {document_set_names} "
- "are not associated with any Slack federated connector"
+ "Skipping Slack federated search: document sets %s are not associated with any Slack federated connector",
+ document_set_names,
)
# Return empty list - no Slack federated search for this context
return []
try:
slack_bots = fetch_slack_bots(db_session)
- logger.debug(f"Found {len(slack_bots)} Slack bots")
+ logger.debug("Found %s Slack bots", len(slack_bots))
# First try to find a bot with user token
tenant_slack_bot = next(
(bot for bot in slack_bots if bot.enabled and bot.user_token), None
)
if tenant_slack_bot:
- logger.debug(f"Selected bot with user_token: {tenant_slack_bot.name}")
+ logger.debug("Selected bot with user_token: %s", tenant_slack_bot.name)
else:
# Fall back to any enabled bot without user token
tenant_slack_bot = next(
@@ -100,7 +101,8 @@ def get_federated_retrieval_functions(
)
if tenant_slack_bot:
logger.debug(
- f"Selected bot without user_token: {tenant_slack_bot.name} (limited functionality)"
+ "Selected bot without user_token: %s (limited functionality)",
+ tenant_slack_bot.name,
)
else:
logger.warning("No enabled Slack bots found")
@@ -121,7 +123,8 @@ def get_federated_retrieval_functions(
)
if not tenant_slack_bot.user_token:
logger.warning(
- f"Using bot_token for Slack search (limited functionality): {tenant_slack_bot.name}"
+ "Using bot_token for Slack search (limited functionality): %s",
+ tenant_slack_bot.name,
)
# For bot context, we don't need real OAuth credentials
@@ -147,7 +150,8 @@ def get_federated_retrieval_functions(
# Use connector config for channel filtering (guaranteed to exist at this point)
connector_entities = slack_federated_connector_config
logger.debug(
- f"Using Slack federated connector entities for bot context: {connector_entities}"
+ "Using Slack federated connector entities for bot context: %s",
+ connector_entities,
)
def create_slack_retrieval_function(
@@ -182,12 +186,13 @@ def get_federated_retrieval_functions(
)
)
logger.debug(
- f"Added Slack federated search for bot, returning {len(federated_retrieval_infos_slack)} retrieval functions"
+ "Added Slack federated search for bot, returning %s retrieval functions",
+ len(federated_retrieval_infos_slack),
)
return federated_retrieval_infos_slack
except Exception as e:
- logger.warning(f"Could not setup Slack bot federated search: {e}")
+ logger.warning("Could not setup Slack bot federated search: %s", e)
# Fall through to regular federated connector logic
if user_id is None:
diff --git a/backend/onyx/federated_connectors/oauth_utils.py b/backend/onyx/federated_connectors/oauth_utils.py
index d5117ed519..6eddc19f71 100644
--- a/backend/onyx/federated_connectors/oauth_utils.py
+++ b/backend/onyx/federated_connectors/oauth_utils.py
@@ -84,7 +84,10 @@ def generate_oauth_state(
cache.set(cache_key, json.dumps(session.to_dict()), ex=ttl)
logger.info(
- f"Generated OAuth state for federated_connector_id={federated_connector_id}, user_id={user_id}, state={state_b64}"
+ "Generated OAuth state for federated_connector_id=%s, user_id=%s, state=%s",
+ federated_connector_id,
+ user_id,
+ state_b64,
)
return state_b64
diff --git a/backend/onyx/federated_connectors/slack/federated_connector.py b/backend/onyx/federated_connectors/slack/federated_connector.py
index d185ce54a4..6d18020577 100644
--- a/backend/onyx/federated_connectors/slack/federated_connector.py
+++ b/backend/onyx/federated_connectors/slack/federated_connector.py
@@ -57,10 +57,10 @@ class SlackFederatedConnector(FederatedConnector):
SlackEntities(**entities)
return True
except ValidationError as e:
- logger.warning(f"Validation error for Slack entities: {e}")
+ logger.warning("Validation error for Slack entities: %s", e)
return False
except Exception as e:
- logger.error(f"Error validating Slack entities: {e}")
+ logger.error("Error validating Slack entities: %s", e)
return False
@classmethod
@@ -290,7 +290,7 @@ class SlackFederatedConnector(FederatedConnector):
Returns:
Search results in SlackSearchResponse format
"""
- logger.debug(f"Slack federated search called with entities: {entities}")
+ logger.debug("Slack federated search called with entities: %s", entities)
# Get team_id from Slack API for caching and filtering
team_id = None
@@ -304,9 +304,9 @@ class SlackFederatedConnector(FederatedConnector):
auth_response.data
)
team_id = auth_data.get("team_id")
- logger.debug(f"Slack team_id: {team_id}")
+ logger.debug("Slack team_id: %s", team_id)
except Exception as e:
- logger.warning(f"Could not fetch team_id from Slack API: {e}")
+ logger.warning("Could not fetch team_id from Slack API: %s", e)
with get_session_with_current_tenant() as db_session:
return slack_retrieval(
diff --git a/backend/onyx/file_processing/extract_file_text.py b/backend/onyx/file_processing/extract_file_text.py
index 6d793a47a5..ce2f4da62c 100644
--- a/backend/onyx/file_processing/extract_file_text.py
+++ b/backend/onyx/file_processing/extract_file_text.py
@@ -446,7 +446,9 @@ def read_docx_file(
UnsupportedFormatException,
) as e:
logger.warning(
- f"Failed to extract docx {file_name or 'docx file'}: {e}. Attempting to read as text file."
+ "Failed to extract docx %s: %s. Attempting to read as text file.",
+ file_name or "docx file",
+ e,
)
# May be an invalid docx, but still a valid text file
@@ -631,7 +633,9 @@ def xlsx_sheet_extraction(file: IO[Any], file_name: str = "") -> list[tuple[str,
except Exception as e:
if any(s in str(e) for s in KNOWN_OPENPYXL_BUGS):
logger.warning(
- f"Failed to extract text from {file_name or 'xlsx file'}. This happens due to a bug in openpyxl. {e}"
+ "Failed to extract text from %s. This happens due to a bug in openpyxl. %s",
+ file_name or "xlsx file",
+ e,
)
return []
raise
@@ -669,7 +673,8 @@ def eml_to_text(file: IO[Any]) -> str:
raw_file = text_file.detach()
except Exception as detach_error:
logger.warning(
- f"Failed to detach TextIOWrapper for EML upload, using original file: {detach_error}"
+ "Failed to detach TextIOWrapper for EML upload, using original file: %s",
+ detach_error,
)
raw_file = file
try:
@@ -686,7 +691,7 @@ def eml_to_text(file: IO[Any]) -> str:
elif isinstance(payload, list):
text_content.extend(item for item in payload if isinstance(item, str))
else:
- logger.warning(f"Unexpected payload type: {type(payload)}")
+ logger.warning("Unexpected payload type: %s", type(payload))
return TEXT_SECTION_SEPARATOR.join(text_content)
@@ -735,7 +740,8 @@ def extract_file_text(
return unstructured_to_text(file, file_name)
except Exception as unstructured_error:
logger.error(
- f"Failed to process with Unstructured: {str(unstructured_error)}. Falling back to normal processing."
+ "Failed to process with Unstructured: %s. Falling back to normal processing.",
+ str(unstructured_error),
)
if extension is None:
extension = get_file_ext(file_name)
@@ -757,7 +763,7 @@ def extract_file_text(
raise RuntimeError(
f"Failed to process file {file_name or 'Unknown'}: {str(e)}"
) from e
- logger.warning(f"Failed to process file {file_name or 'Unknown'}: {str(e)}")
+ logger.warning("Failed to process file %s: %s", file_name or "Unknown", str(e))
return ""
@@ -814,7 +820,7 @@ def extract_text_and_images(
)
# Clean up any temporary objects and force garbage collection
unreachable = gc.collect()
- logger.info(f"Unreachable objects: {unreachable}")
+ logger.info("Unreachable objects: %s", unreachable)
return res
@@ -836,7 +842,8 @@ def _extract_text_and_images(
)
except Exception as e:
logger.error(
- f"Failed to process with Unstructured: {str(e)}. Falling back to normal processing."
+ "Failed to process with Unstructured: %s. Falling back to normal processing.",
+ str(e),
)
file.seek(0) # Reset file pointer just in case
@@ -913,7 +920,7 @@ def _extract_text_and_images(
return ExtractionResult(text_content="", embedded_images=[], metadata={})
except Exception as e:
- logger.exception(f"Failed to extract text/images from {file_name}: {e}")
+ logger.exception("Failed to extract text/images from %s: %s", file_name, e)
return ExtractionResult(text_content="", embedded_images=[], metadata={})
diff --git a/backend/onyx/file_processing/html_utils.py b/backend/onyx/file_processing/html_utils.py
index f9376a2802..0371df4c24 100644
--- a/backend/onyx/file_processing/html_utils.py
+++ b/backend/onyx/file_processing/html_utils.py
@@ -212,7 +212,7 @@ def web_html_cleanup(
if not page_text:
raise ValueError("Empty content returned by trafilatura.")
except Exception as e:
- logger.info(f"Trafilatura parsing failed: {e}. Falling back on bs4.")
+ logger.info("Trafilatura parsing failed: %s. Falling back on bs4.", e)
page_text = format_document_soup(soup)
else:
page_text = format_document_soup(soup)
diff --git a/backend/onyx/file_processing/image_utils.py b/backend/onyx/file_processing/image_utils.py
index 4e90c8490b..c31331b737 100644
--- a/backend/onyx/file_processing/image_utils.py
+++ b/backend/onyx/file_processing/image_utils.py
@@ -90,7 +90,7 @@ def store_image_and_create_section(
file_id=file_id,
)
except Exception as e:
- logger.error(f"Failed to store image: {e}")
+ logger.error("Failed to store image: %s", e)
raise e
# Create an ImageSection with empty text (will be filled by LLM later in the pipeline)
diff --git a/backend/onyx/file_processing/password_validation.py b/backend/onyx/file_processing/password_validation.py
index 53a66db84c..cea56afff3 100644
--- a/backend/onyx/file_processing/password_validation.py
+++ b/backend/onyx/file_processing/password_validation.py
@@ -90,7 +90,7 @@ def is_file_password_protected(
if extension not in extension_to_function:
logger.warning(
- f"Extension={extension} can be password protected, but no function found"
+ "Extension=%s can be password protected, but no function found", extension
)
return False
diff --git a/backend/onyx/file_processing/unstructured.py b/backend/onyx/file_processing/unstructured.py
index 411b746445..84f7db3e16 100644
--- a/backend/onyx/file_processing/unstructured.py
+++ b/backend/onyx/file_processing/unstructured.py
@@ -49,7 +49,9 @@ def _sdk_partition_request(
)
return request
except Exception as e:
- logger.error(f"Error creating partition request for file {file_name}: {str(e)}")
+ logger.error(
+ "Error creating partition request for file %s: %s", file_name, str(e)
+ )
raise
@@ -57,7 +59,7 @@ def unstructured_to_text(file: IO[Any], file_name: str) -> str:
from unstructured.staging.base import dict_to_elements
from unstructured_client import UnstructuredClient
- logger.debug(f"Starting to read file: {file_name}")
+ logger.debug("Starting to read file: %s", file_name)
req = _sdk_partition_request(file, file_name, strategy="fast")
unstructured_client = UnstructuredClient(api_key_auth=get_unstructured_api_key())
diff --git a/backend/onyx/file_store/document_batch_storage.py b/backend/onyx/file_store/document_batch_storage.py
index 1d873c600b..9d3702a157 100644
--- a/backend/onyx/file_store/document_batch_storage.py
+++ b/backend/onyx/file_store/document_batch_storage.py
@@ -125,7 +125,7 @@ class DocumentBatchStorage(ABC):
if converted_keys:
doc_id = doc_dict.get("id", "unknown")
logger.warning(
- f"Normalized legacy metadata for document {doc_id}: {converted_keys}"
+ "Normalized legacy metadata for document %s: %s", doc_id, converted_keys
)
doc_dict["metadata"] = normalized_metadata
@@ -167,10 +167,13 @@ class FileStoreDocumentBatchStorage(DocumentBatchStorage):
)
logger.debug(
- f"Stored batch {batch_num} with {len(documents)} documents to FileStore as {file_name}"
+ "Stored batch %s with %s documents to FileStore as %s",
+ batch_num,
+ len(documents),
+ file_name,
)
except Exception as e:
- logger.error(f"Failed to store batch {batch_num}: {e}")
+ logger.error("Failed to store batch %s: %s", batch_num, e)
raise
def get_batch(self, batch_num: int) -> list[Document] | None:
@@ -184,7 +187,7 @@ class FileStoreDocumentBatchStorage(DocumentBatchStorage):
file_type="application/json",
):
logger.warning(
- f"Batch {batch_num} not found in FileStore with name {file_name}"
+ "Batch %s not found in FileStore with name %s", batch_num, file_name
)
return None
@@ -193,23 +196,27 @@ class FileStoreDocumentBatchStorage(DocumentBatchStorage):
documents = self._deserialize_documents(data)
logger.debug(
- f"Retrieved batch {batch_num} with {len(documents)} documents from FileStore"
+ "Retrieved batch %s with %s documents from FileStore",
+ batch_num,
+ len(documents),
)
return documents
except Exception as e:
- logger.error(f"Failed to retrieve batch {batch_num}: {e}")
+ logger.error("Failed to retrieve batch %s: %s", batch_num, e)
raise
def delete_batch_by_name(self, batch_file_name: str) -> None:
"""Delete a specific batch from FileStore."""
self.file_store.delete_file(batch_file_name)
- logger.debug(f"Deleted batch {batch_file_name} from FileStore")
+ logger.debug("Deleted batch %s from FileStore", batch_file_name)
def delete_batch_by_num(self, batch_num: int) -> None:
"""Delete a specific batch from FileStore."""
batch_file_name = self._get_batch_file_name(batch_num)
self.delete_batch_by_name(batch_file_name)
- logger.debug(f"Deleted batch num {batch_num} {batch_file_name} from FileStore")
+ logger.debug(
+ "Deleted batch num %s %s from FileStore", batch_num, batch_file_name
+ )
def cleanup_all_batches(self) -> None:
"""Clean up all batches for this index attempt."""
@@ -235,7 +242,7 @@ class FileStoreDocumentBatchStorage(DocumentBatchStorage):
path_info = self.extract_path_info(batch_file_name)
if path_info is None:
logger.warning(
- f"Could not extract path info from batch file: {batch_file_name}"
+ "Could not extract path info from batch file: %s", batch_file_name
)
continue
new_batch_file_name = self._get_batch_file_name(path_info.batch_num)
@@ -255,7 +262,7 @@ class FileStoreDocumentBatchStorage(DocumentBatchStorage):
batch_num=int(batch_num.split(".")[0]), # remove .json
)
except Exception as e:
- logger.error(f"Failed to extract path info from {path}: {e}")
+ logger.error("Failed to extract path info from %s: %s", path, e)
return None
diff --git a/backend/onyx/file_store/file_store.py b/backend/onyx/file_store/file_store.py
index f485396317..439da5d29f 100644
--- a/backend/onyx/file_store/file_store.py
+++ b/backend/onyx/file_store/file_store.py
@@ -231,7 +231,7 @@ class S3BackedFileStore(FileStore):
self._s3_client = boto3.client(**client_kwargs)
except Exception as e:
- logger.error(f"Failed to initialize S3 client: {e}")
+ logger.error("Failed to initialize S3 client: %s", e)
raise RuntimeError(f"Failed to initialize S3 client: {e}")
return self._s3_client
@@ -255,7 +255,7 @@ class S3BackedFileStore(FileStore):
# Log if truncation occurred (when the key is exactly at the limit)
if len(s3_key) == 1024:
- logger.info(f"File name was too long and was truncated: {file_name}")
+ logger.info("File name was too long and was truncated: %s", file_name)
return s3_key
@@ -267,12 +267,12 @@ class S3BackedFileStore(FileStore):
# Check if bucket exists
try:
s3_client.head_bucket(Bucket=bucket_name)
- logger.info(f"S3 bucket '{bucket_name}' already exists")
+ logger.info("S3 bucket '%s' already exists", bucket_name)
except ClientError as e:
error_code = e.response["Error"]["Code"]
if error_code == "404":
# Bucket doesn't exist, create it
- logger.info(f"Creating S3 bucket '{bucket_name}'")
+ logger.info("Creating S3 bucket '%s'", bucket_name)
# For AWS S3, we need to handle region-specific bucket creation
region = (
@@ -291,18 +291,18 @@ class S3BackedFileStore(FileStore):
# For us-east-1 or MinIO/other S3-compatible services
s3_client.create_bucket(Bucket=bucket_name)
- logger.info(f"Successfully created S3 bucket '{bucket_name}'")
+ logger.info("Successfully created S3 bucket '%s'", bucket_name)
elif error_code == "403":
# Bucket exists but we don't have permission to access it
logger.warning(
- f"S3 bucket '{bucket_name}' exists but access is forbidden"
+ "S3 bucket '%s' exists but access is forbidden", bucket_name
)
raise RuntimeError(
f"Access denied to S3 bucket '{bucket_name}'. Check credentials and permissions."
)
else:
# Some other error occurred
- logger.error(f"Failed to check S3 bucket '{bucket_name}': {e}")
+ logger.error("Failed to check S3 bucket '%s': %s", bucket_name, e)
raise RuntimeError(f"Failed to check S3 bucket '{bucket_name}': {e}")
def has_file(
@@ -405,7 +405,7 @@ class S3BackedFileStore(FileStore):
Bucket=file_record.bucket_name, Key=file_record.object_key
)
except ClientError:
- logger.error(f"Failed to read file {file_id} from S3")
+ logger.error("Failed to read file %s from S3", file_id)
raise
# FIX: Stream file content instead of loading entire file into memory
@@ -451,7 +451,7 @@ class S3BackedFileStore(FileStore):
)
return response.get("ContentLength")
except Exception as e:
- logger.warning(f"Error getting file size for {file_id}: {e}")
+ logger.warning("Error getting file size for %s: %s", file_id, e)
return None
def delete_file(
@@ -473,8 +473,9 @@ class S3BackedFileStore(FileStore):
return
if not file_record.bucket_name:
logger.error(
- f"File record {file_id} with key {file_record.object_key} "
- "has no bucket name, cannot delete from filestore"
+ "File record %s with key %s has no bucket name, cannot delete from filestore",
+ file_id,
+ file_record.object_key,
)
delete_filerecord_by_file_id(file_id=file_id, db_session=db_session)
db_session.commit()
@@ -491,8 +492,9 @@ class S3BackedFileStore(FileStore):
# since the end goal (object not existing) is achieved
if e.response.get("Error", {}).get("Code") == "NoSuchKey":
logger.warning(
- f"delete_file: File {file_id} not found in file store (key: {file_record.object_key}), "
- "cleaning up database record."
+ "delete_file: File %s not found in file store (key: %s), cleaning up database record.",
+ file_id,
+ file_record.object_key,
)
else:
raise
@@ -564,7 +566,10 @@ class S3BackedFileStore(FileStore):
except Exception as e:
db_session.rollback()
logger.exception(
- f"Failed to change file ID from {old_file_id} to {new_file_id}: {e}"
+ "Failed to change file ID from %s to %s: %s",
+ old_file_id,
+ new_file_id,
+ e,
)
raise
diff --git a/backend/onyx/file_store/postgres_file_store.py b/backend/onyx/file_store/postgres_file_store.py
index 3114736d96..0bef3debdd 100644
--- a/backend/onyx/file_store/postgres_file_store.py
+++ b/backend/onyx/file_store/postgres_file_store.py
@@ -167,7 +167,9 @@ class PostgresBackedFileStore(FileStore):
_delete_large_object(raw_conn, old_oid)
except Exception:
logger.warning(
- f"Failed to unlink old large object {old_oid} for file {file_id}"
+ "Failed to unlink old large object %s for file %s",
+ old_oid,
+ file_id,
)
session.commit()
@@ -178,7 +180,7 @@ class PostgresBackedFileStore(FileStore):
_delete_large_object(raw_conn, oid)
except Exception:
logger.exception(
- f"Failed to delete large object {oid} for file {file_id}"
+ "Failed to delete large object %s for file %s", oid, file_id
)
raise e
@@ -219,7 +221,7 @@ class PostgresBackedFileStore(FileStore):
)
return record.file_size
except Exception as e:
- logger.warning(f"Error getting file size for {file_id}: {e}")
+ logger.warning("Error getting file size for %s: %s", file_id, e)
return None
def delete_file(
@@ -245,7 +247,9 @@ class PostgresBackedFileStore(FileStore):
_delete_large_object(raw_conn, file_content.lobj_oid)
except Exception:
logger.warning(
- f"Large object {file_content.lobj_oid} for file {file_id} not found, cleaning up records only."
+ "Large object %s for file %s not found, cleaning up records only.",
+ file_content.lobj_oid,
+ file_id,
)
delete_file_content_by_file_id(file_id=file_id, db_session=session)
@@ -309,7 +313,10 @@ class PostgresBackedFileStore(FileStore):
except Exception as e:
session.rollback()
logger.exception(
- f"Failed to change file ID from {old_file_id} to {new_file_id}: {e}"
+ "Failed to change file ID from %s to %s: %s",
+ old_file_id,
+ new_file_id,
+ e,
)
raise
diff --git a/backend/onyx/file_store/staging.py b/backend/onyx/file_store/staging.py
index 631d5c77ee..b1141a2cea 100644
--- a/backend/onyx/file_store/staging.py
+++ b/backend/onyx/file_store/staging.py
@@ -85,11 +85,12 @@ def delete_files_best_effort(
deleted += 1
except Exception:
logger.exception(
- f"[{context}] Failed to delete file_id={file_id}; will be "
- "retried on next sweep."
+ "[%s] Failed to delete file_id=%s; will be retried on next sweep.",
+ context,
+ file_id,
)
if deleted:
- logger.info(f"[{context}] reaped {deleted} file(s)")
+ logger.info("[%s] reaped %s file(s)", context, deleted)
return deleted
diff --git a/backend/onyx/file_store/utils.py b/backend/onyx/file_store/utils.py
index f411e0d854..6d5c715eb8 100644
--- a/backend/onyx/file_store/utils.py
+++ b/backend/onyx/file_store/utils.py
@@ -55,7 +55,7 @@ def store_plaintext(file_id: str, plaintext_content: str) -> bool:
)
return True
except Exception as e:
- logger.warning(f"Failed to store plaintext for {file_id}: {e}")
+ logger.warning("Failed to store plaintext for %s: %s", file_id, e)
return False
@@ -134,7 +134,7 @@ def load_user_file(file_id: UUID, db_session: Session) -> InMemoryChatFile:
status = "plaintext"
return chat_file
except Exception as e:
- logger.warning(f"Failed to load plaintext for user file {user_file.id}: {e}")
+ logger.warning("Failed to load plaintext for user file %s: %s", user_file.id, e)
# Fall back to original file if plaintext not available
file_io = file_store.read_file(user_file.file_id, mode="b")
@@ -148,7 +148,10 @@ def load_user_file(file_id: UUID, db_session: Session) -> InMemoryChatFile:
return chat_file
finally:
logger.debug(
- f"load_user_file finished: file_id={user_file.file_id} chat_file_type={chat_file_type} status={status}"
+ "load_user_file finished: file_id=%s chat_file_type=%s status=%s",
+ user_file.file_id,
+ chat_file_type,
+ status,
)
@@ -333,7 +336,8 @@ def verify_user_files(
user_file_ids.append(UUID(file_descriptor["user_file_id"]))
except (ValueError, TypeError):
logger.warning(
- f"Invalid user_file_id in file descriptor: {file_descriptor['user_file_id']}"
+ "Invalid user_file_id in file descriptor: %s",
+ file_descriptor["user_file_id"],
)
continue
else:
diff --git a/backend/onyx/indexing/adapters/user_file_indexing_adapter.py b/backend/onyx/indexing/adapters/user_file_indexing_adapter.py
index 5736310354..cc49aeb9c5 100644
--- a/backend/onyx/indexing/adapters/user_file_indexing_adapter.py
+++ b/backend/onyx/indexing/adapters/user_file_indexing_adapter.py
@@ -96,7 +96,9 @@ class UserFileIndexingAdapter:
break
except OperationalError as e:
logger.warning(
- f"Failed to acquire locks for user files on attempt {i}, retrying. Error: {e}"
+ "Failed to acquire locks for user files on attempt %s, retrying. Error: %s",
+ i,
+ e,
)
time.sleep(retry_delay)
@@ -157,7 +159,7 @@ class UserFileIndexingAdapter:
provider_type=llm.config.model_provider,
)
except Exception as e:
- logger.error(f"Error getting tokenizer: {e}")
+ logger.error("Error getting tokenizer: %s", e)
llm_tokenizer = None
user_file_id_to_raw_text: dict[str, str] = {}
diff --git a/backend/onyx/indexing/chunker.py b/backend/onyx/indexing/chunker.py
index 2b926a1b60..02455a8521 100644
--- a/backend/onyx/indexing/chunker.py
+++ b/backend/onyx/indexing/chunker.py
@@ -191,7 +191,7 @@ class Chunker:
) -> list[DocAwareChunk]:
# Specifically for reproducing an issue with gmail
if document.source == DocumentSource.GMAIL:
- logger.debug(f"Chunking {document.semantic_identifier}")
+ logger.debug("Chunking %s", document.semantic_identifier)
# Title prep
title = extract_blurb(
diff --git a/backend/onyx/indexing/chunking/document_chunker.py b/backend/onyx/indexing/chunking/document_chunker.py
index efe545de0b..4861f57aba 100644
--- a/backend/onyx/indexing/chunking/document_chunker.py
+++ b/backend/onyx/indexing/chunking/document_chunker.py
@@ -87,8 +87,9 @@ class DocumentChunker:
if not section_text and (not document.title or section_idx > 0):
logger.warning(
- f"Skipping empty or irrelevant section in doc "
- f"{document.semantic_identifier}, link={section.link}"
+ "Skipping empty or irrelevant section in doc %s, link=%s",
+ document.semantic_identifier,
+ section.link,
)
continue
diff --git a/backend/onyx/indexing/chunking/tabular_section_chunker/tabular_section_chunker.py b/backend/onyx/indexing/chunking/tabular_section_chunker/tabular_section_chunker.py
index 1695558ad7..a5fb4f9125 100644
--- a/backend/onyx/indexing/chunking/tabular_section_chunker/tabular_section_chunker.py
+++ b/backend/onyx/indexing/chunking/tabular_section_chunker/tabular_section_chunker.py
@@ -274,7 +274,7 @@ class TabularChunker(SectionChunker):
if not chunk_texts:
logger.warning(
- f"TabularChunker: skipping unparseable section (link={section.link})"
+ "TabularChunker: skipping unparseable section (link=%s)", section.link
)
return SectionChunkerOutput(
payloads=payloads, accumulator=AccumulatorState()
diff --git a/backend/onyx/indexing/embedder.py b/backend/onyx/indexing/embedder.py
index 08f2ec5e3b..4a8c967aab 100644
--- a/backend/onyx/indexing/embedder.py
+++ b/backend/onyx/indexing/embedder.py
@@ -299,7 +299,7 @@ def embed_chunks_with_failure_handling(
scope.set_tag("tenant_id", tenant_id)
scope.fingerprint = ["embedding-failure", type(e).__name__]
sentry_sdk.capture_exception(e)
- logger.exception(f"Failed to embed chunks for document '{doc_id}'")
+ logger.exception("Failed to embed chunks for document '%s'", doc_id)
failures.append(
ConnectorFailure(
failed_document=DocumentFailure(
diff --git a/backend/onyx/indexing/indexing_pipeline.py b/backend/onyx/indexing/indexing_pipeline.py
index 898d358ce7..48287bb0c5 100644
--- a/backend/onyx/indexing/indexing_pipeline.py
+++ b/backend/onyx/indexing/indexing_pipeline.py
@@ -224,7 +224,7 @@ def _embed_chunks_to_store(
if not chunk_batch:
continue
- logger.debug(f"Embedding batch {batch_idx}: {len(chunk_batch)} chunks")
+ logger.debug("Embedding batch %s: %s chunks", batch_idx, len(chunk_batch))
chunks_with_embeddings, embedding_failures = embed_chunks_with_failure_handling(
chunks=chunk_batch,
@@ -372,7 +372,7 @@ def index_doc_batch_with_handler(
scope.set_extra("document_ids", document_ids)
scope.fingerprint = ["indexing-pipeline-failure", type(e).__name__]
sentry_sdk.capture_exception(e)
- logger.exception(f"Failed to index document batch: {document_ids}")
+ logger.exception("Failed to index document batch: %s", document_ids)
index_pipeline_result = IndexingPipelineResult(
new_docs=0,
@@ -432,7 +432,7 @@ def _delete_replaced_files(
try:
file_store.delete_file(old_file_id, error_on_missing=False)
except Exception:
- logger.exception(f"Failed to delete replaced file_id={old_file_id}.")
+ logger.exception("Failed to delete replaced file_id=%s.", old_file_id)
def index_doc_batch_prepare(
@@ -469,7 +469,9 @@ def index_doc_batch_prepare(
doc.id for doc in documents if doc.id not in updatable_doc_ids
]
logger.info(
- f"Skipping {len(skipped_doc_ids)} documents because they are up to date. Skipped doc IDs: {skipped_doc_ids}"
+ "Skipping %s documents because they are up to date. Skipped doc IDs: %s",
+ len(skipped_doc_ids),
+ skipped_doc_ids,
)
# for all updatable docs, upsert into the DB
@@ -495,7 +497,9 @@ def index_doc_batch_prepare(
)
logger.info(
- f"Upserted {len(updatable_docs)} changed docs out of {len(documents)} total docs into the DB"
+ "Upserted %s changed docs out of %s total docs into the DB",
+ len(updatable_docs),
+ len(documents),
)
# for all docs, upsert the document to cc pair relationship
@@ -549,7 +553,8 @@ def filter_documents(document_batch: list[Document]) -> list[Document]:
# This is again verified later in the pipeline after chunking but at that point there should
# already be no documents that are empty.
logger.warning(
- f"Skipping document with ID {document.id} as it has neither title nor content."
+ "Skipping document with ID %s as it has neither title nor content.",
+ document.id,
)
continue
@@ -557,7 +562,7 @@ def filter_documents(document_batch: list[Document]) -> list[Document]:
# The title is explicitly empty ("" and not None) and the document is empty
# so when building the chunk text representation, it will be empty and unuseable
logger.warning(
- f"Skipping document with ID {document.id} as the chunks will be empty."
+ "Skipping document with ID %s as the chunks will be empty.", document.id
)
continue
@@ -580,8 +585,10 @@ def filter_documents(document_batch: list[Document]) -> list[Document]:
# Assumption here is that files that are that long, are generated files and not the type users
# generally care for.
logger.warning(
- f"Skipping document with ID {document.id} as it is too long "
- f"({doc_total_chars:,} chars, max={MAX_DOCUMENT_CHARS:,})"
+ "Skipping document with ID %s as it is too long (%s chars, max=%s)",
+ document.id,
+ format(doc_total_chars, ","),
+ format(MAX_DOCUMENT_CHARS, ","),
)
skipped_too_long.append((document.id, doc_total_chars))
continue
@@ -595,12 +602,16 @@ def filter_documents(document_batch: list[Document]) -> list[Document]:
# Get the source from the first document (all in batch should be same source)
source = documents[0].source.value if documents[0].source else "unknown"
logger.debug(
- f"Document batch filter [{source}]: {len(documents)} docs kept, {len(skipped_too_long)} skipped (too long). "
- f"Total chars: {total_chars_in_batch:,}, Avg: {avg_chars:,.0f} chars/doc"
+ "Document batch filter [%s]: %s docs kept, %s skipped (too long). Total chars: %s, Avg: %s chars/doc",
+ source,
+ len(documents),
+ len(skipped_too_long),
+ format(total_chars_in_batch, ","),
+ format(avg_chars, ",.0f"),
)
if skipped_too_long:
logger.warning(
- f"Skipped oversized documents [{source}]: {skipped_too_long[:5]}"
+ "Skipped oversized documents [%s]: %s", source, skipped_too_long[:5]
) # Log first 5
return documents
@@ -695,7 +706,7 @@ def process_image_sections(documents: list[Document]) -> list[IndexingDocument]:
file_record = file_store.read_file_record(file_id=section.image_file_id)
if not file_record:
logger.warning(
- f"Image file {section.image_file_id} not found in FileStore"
+ "Image file %s not found in FileStore", section.image_file_id
)
processed_section.text = "[Image could not be processed]"
continue
@@ -709,7 +720,7 @@ def process_image_sections(documents: list[Document]) -> list[IndexingDocument]:
)
)
except Exception as e:
- logger.error(f"Error reading image section: {e}")
+ logger.error("Error reading image section: %s", e)
processed_section.text = "[Error processing image]"
indexed_documents.append(
@@ -854,10 +865,10 @@ def add_chunk_summaries(
except LLMRateLimitError as e:
# Erroring during chunker is undesirable, so we log the error and continue
# TODO: for v2, add robust retry logic
- logger.exception(f"Rate limit adding chunk summary: {e}", exc_info=e)
+ logger.exception("Rate limit adding chunk summary: %s", e, exc_info=e)
chunk.chunk_context = ""
except Exception as e:
- logger.exception(f"Error adding chunk summary: {e}", exc_info=e)
+ logger.exception("Error adding chunk summary: %s", e, exc_info=e)
chunk.chunk_context = ""
run_functions_tuples_in_parallel(
@@ -998,7 +1009,7 @@ def _apply_document_ingestion_hook(
if not hook_result.sections:
reason = hook_result.rejection_reason or "Document rejected by hook"
logger.info(
- f"Document ingestion hook dropped document doc_id={doc.id!r}: {reason}"
+ "Document ingestion hook dropped document doc_id=%r: %s", doc.id, reason
)
return None
new_sections: list[TextSection | ImageSection] = []
@@ -1011,12 +1022,13 @@ def _apply_document_ingestion_hook(
new_sections.append(TextSection(text=s.text, link=s.link))
else:
logger.warning(
- f"Document ingestion hook returned a section with neither text nor "
- f"image_file_id for doc_id={doc.id!r} — skipping section."
+ "Document ingestion hook returned a section with neither text nor image_file_id for doc_id=%r — skipping section.",
+ doc.id,
)
if not new_sections:
logger.info(
- f"Document ingestion hook produced no valid sections for doc_id={doc.id!r} — dropping document."
+ "Document ingestion hook produced no valid sections for doc_id=%r — dropping document.",
+ doc.id,
)
return None
return doc.model_copy(update={"sections": new_sections})
@@ -1085,9 +1097,11 @@ def index_doc_batch(
connector_id = getattr(adapter, "connector_id", None)
credential_id = getattr(adapter, "credential_id", None)
logger.debug(
- f"Starting index_doc_batch: connector_id={connector_id}, "
- f"credential_id={credential_id}, tenant_id={tenant_id}, "
- f"num_docs={len(document_batch)}"
+ "Starting index_doc_batch: connector_id=%s, credential_id=%s, tenant_id=%s, num_docs=%s",
+ connector_id,
+ credential_id,
+ tenant_id,
+ len(document_batch),
)
# Pull the attempt id off the adapter (when present) so per-stage metrics
@@ -1128,7 +1142,7 @@ def index_doc_batch(
}
for doc in context.indexable_docs
]
- logger.debug(f"Starting indexing process for documents: {doc_descriptors}")
+ logger.debug("Starting indexing process for documents: %s", doc_descriptors)
logger.debug("Starting chunking")
# NOTE: no special handling for failures here, since the chunker is not
diff --git a/backend/onyx/indexing/vector_db_insertion.py b/backend/onyx/indexing/vector_db_insertion.py
index 652bfe4ba2..a78d345f3e 100644
--- a/backend/onyx/indexing/vector_db_insertion.py
+++ b/backend/onyx/indexing/vector_db_insertion.py
@@ -64,8 +64,9 @@ def write_chunks_to_vector_db_with_backoff(
# where the 60s read timeout fires when the server is slow to
# finish the bulk index.)
logger.warning(
- f"Failed to write chunk batch to vector db. Trying individual docs. "
- f"Batch error: {type(e).__name__}: {e}"
+ "Failed to write chunk batch to vector db. Trying individual docs. Batch error: %s: %s",
+ type(e).__name__,
+ e,
)
# give some specific logging on this common failure case.
@@ -106,7 +107,7 @@ def write_chunks_to_vector_db_with_backoff(
scope.fingerprint = ["vector-db-write-failure", type(e).__name__]
sentry_sdk.capture_exception(e)
logger.exception(
- f"Failed to write document chunks for '{doc_id}' to vector db"
+ "Failed to write document chunks for '%s' to vector db", doc_id
)
# give some specific logging on this common failure case.
diff --git a/backend/onyx/key_value_store/store.py b/backend/onyx/key_value_store/store.py
index aca9e5a772..f22e92ec24 100644
--- a/backend/onyx/key_value_store/store.py
+++ b/backend/onyx/key_value_store/store.py
@@ -36,7 +36,7 @@ class PgRedisKVStore(KeyValueStore):
except Exception as e:
# Fallback gracefully to Postgres if Cache backend fails
logger.error(
- f"Failed to set value in Cache backend for key '{key}': {str(e)}"
+ "Failed to set value in Cache backend for key '%s': %s", key, str(e)
)
encrypted_val = val if encrypt else None
@@ -60,7 +60,7 @@ class PgRedisKVStore(KeyValueStore):
return json.loads(cached.decode("utf-8"))
except Exception as e:
logger.error(
- f"Failed to get value from cache for key '{key}': {str(e)}"
+ "Failed to get value from cache for key '%s': %s", key, str(e)
)
with get_session_with_current_tenant() as db_session:
@@ -83,7 +83,9 @@ class PgRedisKVStore(KeyValueStore):
ex=KV_REDIS_KEY_EXPIRATION,
)
except Exception as e:
- logger.error(f"Failed to set value in cache for key '{key}': {str(e)}")
+ logger.error(
+ "Failed to set value in cache for key '%s': %s", key, str(e)
+ )
return cast(JSON_ro, value)
@@ -91,7 +93,9 @@ class PgRedisKVStore(KeyValueStore):
try:
self._get_cache().delete(REDIS_KEY_PREFIX + key)
except Exception as e:
- logger.error(f"Failed to delete value from cache for key '{key}': {str(e)}")
+ logger.error(
+ "Failed to delete value from cache for key '%s': %s", key, str(e)
+ )
with get_session_with_current_tenant() as db_session:
result = db_session.query(KVStore).filter_by(key=key).delete()
diff --git a/backend/onyx/kg/clustering/clustering.py b/backend/onyx/kg/clustering/clustering.py
index a712bc824b..87efa0fd1c 100644
--- a/backend/onyx/kg/clustering/clustering.py
+++ b/backend/onyx/kg/clustering/clustering.py
@@ -202,7 +202,7 @@ def _cluster_one_grounded_entity(
# if there is a match, update the entity, otherwise create a new one
with get_session_with_current_tenant() as db_session:
if best_entity:
- logger.debug(f"Merged {entity.name} with {best_entity.name}")
+ logger.debug("Merged %s with %s", entity.name, best_entity.name)
update_vespa = (
best_entity.document_id is None and entity.document_id is not None
)
@@ -281,7 +281,8 @@ def _transfer_one_relationship(
}
if len(entity_translations) != len(staging_entity_id_names):
logger.error(
- f"Missing entity translations for {staging_entity_id_names - entity_translations.keys()}"
+ "Missing entity translations for %s",
+ staging_entity_id_names - entity_translations.keys(),
)
return
@@ -312,7 +313,7 @@ def kg_clustering(
This will change with deep extraction, where grounded-sourceless entities
can be extracted and then need to be clustered.
"""
- logger.info(f"Starting kg clustering for tenant {tenant_id}")
+ logger.info("Starting kg clustering for tenant %s", tenant_id)
kg_config_settings = get_kg_config_settings()
validate_kg_settings(kg_config_settings)
@@ -336,7 +337,9 @@ def kg_clustering(
# NOTE: we assume every entity is transferred, as we currently only have grounded entities
time_delta = time.monotonic() - start_time
logger.info(
- f"Finished transferring {i_batch + 1} entity batches in {time_delta:.2f}s"
+ "Finished transferring %s entity batches in %ss",
+ i_batch + 1,
+ format(time_delta, ".2f"),
)
# Create parent-child relationships in parallel
@@ -373,7 +376,9 @@ def kg_clustering(
# logger.debug(f"Transferred relationship types batch {i}")
time_delta = time.monotonic() - start_time
logger.info(
- f"Finished transferring {i_batch + 1} relationship type batches in {time_delta:.2f}s"
+ "Finished transferring %s relationship type batches in %ss",
+ i_batch + 1,
+ format(time_delta, ".2f"),
)
# Transfer the relationships in parallel
@@ -394,7 +399,9 @@ def kg_clustering(
# logger.debug(f"Transferred relationships batch {i}")
time_delta = time.monotonic() - start_time
logger.info(
- f"Finished transferring {i_batch + 1} relationship batches in {time_delta:.2f}s"
+ "Finished transferring %s relationship batches in %ss",
+ i_batch + 1,
+ format(time_delta, ".2f"),
)
# Update vespa for each document
@@ -413,14 +420,16 @@ def kg_clustering(
try:
update_kg_chunks_vespa_info(update_requests, index_name, tenant_id)
except Exception as e:
- logger.error(f"Error updating vespa for document {document.id}: {e}")
+ logger.error("Error updating vespa for document %s: %s", document.id, e)
last_lock_time = extend_lock(
lock, CELERY_GENERIC_BEAT_LOCK_TIMEOUT, last_lock_time
)
# logger.debug(f"Updated vespa for documents batch {i}")
time_delta = time.monotonic() - start_time
logger.info(
- f"Finished updating {i_batch + 1} document batches in {time_delta:.2f}s"
+ "Finished updating %s document batches in %ss",
+ i_batch + 1,
+ format(time_delta, ".2f"),
)
# Delete the transferred objects from the staging tables
@@ -431,7 +440,7 @@ def kg_clustering(
).delete(synchronize_session=False)
db_session.commit()
except Exception as e:
- logger.error(f"Error deleting relationships: {e}")
+ logger.error("Error deleting relationships: %s", e)
try:
with get_session_with_current_tenant() as db_session:
@@ -440,7 +449,7 @@ def kg_clustering(
).delete(synchronize_session=False)
db_session.commit()
except Exception as e:
- logger.error(f"Error deleting relationship types: {e}")
+ logger.error("Error deleting relationship types: %s", e)
try:
with get_session_with_current_tenant() as db_session:
@@ -449,5 +458,5 @@ def kg_clustering(
).delete(synchronize_session=False)
db_session.commit()
except Exception as e:
- logger.error(f"Error deleting entities: {e}")
+ logger.error("Error deleting entities: %s", e)
logger.info("Finished deleting all transferred staging entries")
diff --git a/backend/onyx/kg/clustering/normalizations.py b/backend/onyx/kg/clustering/normalizations.py
index d9590a0aac..a429bd207d 100644
--- a/backend/onyx/kg/clustering/normalizations.py
+++ b/backend/onyx/kg/clustering/normalizations.py
@@ -267,7 +267,7 @@ def normalize_entities(
)
normalized_map[entity] = format_entity_id_for_models(normalized_entity)
else:
- logger.warning(f"No normalized entity found for {entity}")
+ logger.warning("No normalized entity found for %s", entity)
normalized_map[entity] = format_entity_id_for_models(entity)
return NormalizedEntities(
@@ -308,7 +308,7 @@ def normalize_relationships(
norm_target = entity_normalization_map.get(target)
if norm_source is None or norm_target is None:
- logger.warning(f"No normalized entities found for {raw_rel}")
+ logger.warning("No normalized entities found for %s", raw_rel)
continue
# 2. Find candidate normalized relationships
@@ -325,7 +325,7 @@ def normalize_relationships(
]
if not candidate_rels:
- logger.warning(f"No candidate relationships found for {raw_rel}")
+ logger.warning("No candidate relationships found for %s", raw_rel)
continue
# 3. Encode and find best match
diff --git a/backend/onyx/kg/extractions/extraction_processing.py b/backend/onyx/kg/extractions/extraction_processing.py
index 921d31d6ab..9f91e302b4 100644
--- a/backend/onyx/kg/extractions/extraction_processing.py
+++ b/backend/onyx/kg/extractions/extraction_processing.py
@@ -217,7 +217,7 @@ def kg_extraction(
- Update document table to set kg_extracted = True
"""
- logger.info(f"Starting kg extraction for tenant {tenant_id}")
+ logger.info("Starting kg extraction for tenant %s", tenant_id)
kg_config_settings = get_kg_config_settings()
validate_kg_settings(kg_config_settings)
@@ -275,7 +275,9 @@ def kg_extraction(
if len(unprocessed_document_batch) == 0:
logger.info(
- f"No unprocessed documents found for connector {connector_id}. Processed {document_batch_counter} batches."
+ "No unprocessed documents found for connector %s. Processed %s batches.",
+ connector_id,
+ document_batch_counter,
)
break
@@ -283,7 +285,7 @@ def kg_extraction(
last_lock_time = extend_lock(
lock, CELERY_GENERIC_BEAT_LOCK_TIMEOUT, last_lock_time
)
- logger.info(f"Processing document batch {document_batch_counter}")
+ logger.info("Processing document batch %s", document_batch_counter)
# Get the document attributes and entity types
batch_metadata = _get_batch_documents_enhanced_metadata(
@@ -300,7 +302,7 @@ def kg_extraction(
# info for after the connector has been processed
kg_stage = KGStage.SKIPPED
logger.debug(
- f"Document {unprocessed_document.id} is not of any entity type"
+ "Document %s is not of any entity type", unprocessed_document.id
)
elif batch_metadata[unprocessed_document.id].skip:
# info for after the connector has been processed. But no message as there may be many
@@ -445,7 +447,8 @@ def kg_extraction(
parts = split_entity_id(entity)
if len(parts) != 2:
logger.error(
- f"Invalid entity {entity} in aggregated_kg_extractions.entities"
+ "Invalid entity %s in aggregated_kg_extractions.entities",
+ entity,
)
continue
@@ -506,14 +509,15 @@ def kg_extraction(
db_session.commit()
except Exception as e:
- logger.error(f"Error adding entity {entity}. Error message: {e}")
+ logger.error("Error adding entity %s. Error message: %s", entity, e)
for document_id, relationship in batch_relationships:
relationship_split = split_relationship_id(relationship)
if len(relationship_split) != 3:
logger.error(
- f"Invalid relationship {relationship} in aggregated_kg_extractions.relationships"
+ "Invalid relationship %s in aggregated_kg_extractions.relationships",
+ relationship,
)
continue
@@ -543,7 +547,9 @@ def kg_extraction(
db_session.commit()
except Exception as e:
logger.error(
- f"Error adding relationship type {relationship_type_id_name} to the database: {e}"
+ "Error adding relationship type %s to the database: %s",
+ relationship_type_id_name,
+ e,
)
with get_session_with_current_tenant() as db_session:
@@ -557,7 +563,9 @@ def kg_extraction(
db_session.commit()
except Exception as e:
logger.error(
- f"Error adding relationship {relationship} to the database: {e}"
+ "Error adding relationship %s to the database: %s",
+ relationship,
+ e,
)
# Populate the Documents table with the kg information for the documents
diff --git a/backend/onyx/kg/resets/reset_vespa.py b/backend/onyx/kg/resets/reset_vespa.py
index 8d312bb523..25af389a03 100644
--- a/backend/onyx/kg/resets/reset_vespa.py
+++ b/backend/onyx/kg/resets/reset_vespa.py
@@ -71,7 +71,10 @@ def reset_vespa_kg_index(
or all documents from kg grounded sources if source_name is None.
"""
logger.info(
- f"Resetting kg vespa index {index_name} for tenant {tenant_id}, source: {source_name if source_name else 'all'}"
+ "Resetting kg vespa index %s for tenant %s, source: %s",
+ index_name,
+ tenant_id,
+ source_name if source_name else "all",
)
last_lock_time = time.monotonic()
@@ -121,5 +124,8 @@ def reset_vespa_kg_index(
)
logger.info(
- f"Finished resetting kg vespa index {index_name} for tenant {tenant_id}, source: {source_name if source_name else 'all'}"
+ "Finished resetting kg vespa index %s for tenant %s, source: %s",
+ index_name,
+ tenant_id,
+ source_name if source_name else "all",
)
diff --git a/backend/onyx/kg/utils/extraction_utils.py b/backend/onyx/kg/utils/extraction_utils.py
index 3fc5d56564..a33cd5cd81 100644
--- a/backend/onyx/kg/utils/extraction_utils.py
+++ b/backend/onyx/kg/utils/extraction_utils.py
@@ -297,7 +297,7 @@ def kg_implied_extraction(
if process_results is None:
continue
- (implied_entity, implied_relationship, _, _) = process_results
+ implied_entity, implied_relationship, _, _ = process_results
implied_entities.add(implied_entity)
implied_relationships.add(implied_relationship)
else:
@@ -446,7 +446,9 @@ def kg_classify_document(
classification_class=classification_class,
)
except Exception as e:
- logger.error(f"Failed to classify document {document_entity}. Error: {str(e)}")
+ logger.error(
+ "Failed to classify document %s. Error: %s", document_entity, str(e)
+ )
return None
@@ -523,7 +525,10 @@ def kg_deep_extract_chunks(
except Exception as e:
failed_chunks = [chunk.chunk_id for chunk in chunk_batch]
logger.error(
- f"Failed to process chunks {failed_chunks} from document {document_entity}. Error: {str(e)}"
+ "Failed to process chunks %s from document %s. Error: %s",
+ failed_chunks,
+ document_entity,
+ str(e),
)
return None
diff --git a/backend/onyx/llm/cost.py b/backend/onyx/llm/cost.py
index 33ecf7cc27..f94eec60e4 100644
--- a/backend/onyx/llm/cost.py
+++ b/backend/onyx/llm/cost.py
@@ -33,6 +33,8 @@ def calculate_llm_cost_cents(
except Exception as e:
# Log but don't fail - unknown models or errors shouldn't block usage
logger.debug(
- f"Could not calculate cost for model {model_name}: {e}. Assuming cost is 0."
+ "Could not calculate cost for model %s: %s. Assuming cost is 0.",
+ model_name,
+ e,
)
return 0.0
diff --git a/backend/onyx/llm/litellm_singleton/config.py b/backend/onyx/llm/litellm_singleton/config.py
index ebb79bae5a..0c6fc48f42 100644
--- a/backend/onyx/llm/litellm_singleton/config.py
+++ b/backend/onyx/llm/litellm_singleton/config.py
@@ -124,7 +124,9 @@ def load_model_metadata_enrichments() -> None:
enrichments_path = Path(__file__).parent.parent / "model_metadata_enrichments.json"
if not enrichments_path.exists():
- logger.warning(f"Model metadata enrichments file not found: {enrichments_path}")
+ logger.warning(
+ "Model metadata enrichments file not found: %s", enrichments_path
+ )
return
try:
@@ -140,7 +142,7 @@ def load_model_metadata_enrichments() -> None:
# Model not in litellm.model_cost - add it with just our metadata
litellm.model_cost[model_key] = metadata
- logger.info(f"Loaded model metadata enrichments for {len(enrichments)} models")
+ logger.info("Loaded model metadata enrichments for %s models", len(enrichments))
# Clear the model name parser cache since enrichments are now loaded
# This ensures any parsing done before enrichments were loaded gets refreshed
@@ -151,7 +153,7 @@ def load_model_metadata_enrichments() -> None:
except ImportError:
pass # Parser not yet imported, no cache to clear
except Exception as e:
- logger.error(f"Failed to load model metadata enrichments: {e}")
+ logger.error("Failed to load model metadata enrichments: %s", e)
def initialize_litellm() -> None:
diff --git a/backend/onyx/llm/multi_llm.py b/backend/onyx/llm/multi_llm.py
index 537c12dad7..3b68050c34 100644
--- a/backend/onyx/llm/multi_llm.py
+++ b/backend/onyx/llm/multi_llm.py
@@ -421,7 +421,7 @@ class LitellmLLM(LLM):
db_session.commit()
except Exception as e:
# Log but don't fail the LLM call if tracking fails
- logger.warning(f"Failed to track LLM cost: {e}")
+ logger.warning("Failed to track LLM cost: %s", e)
def _completion(
self,
diff --git a/backend/onyx/llm/prompt_cache/cache_manager.py b/backend/onyx/llm/prompt_cache/cache_manager.py
index 56b40024e4..fc1af6ec36 100644
--- a/backend/onyx/llm/prompt_cache/cache_manager.py
+++ b/backend/onyx/llm/prompt_cache/cache_manager.py
@@ -85,13 +85,15 @@ class CacheManager:
self._kv_store.store(cache_key, metadata_dict, encrypt=False)
logger.debug(
- f"Stored cache metadata: provider={metadata.provider}, "
- f"model={metadata.model_name}, cache_key={metadata.cache_key[:16]}..., "
- f"tenant_id={metadata.tenant_id}"
+ "Stored cache metadata: provider=%s, model=%s, cache_key=%s..., tenant_id=%s",
+ metadata.provider,
+ metadata.model_name,
+ metadata.cache_key[:16],
+ metadata.tenant_id,
)
except Exception as e:
# Best-effort: log and continue
- logger.warning(f"Failed to store cache metadata: {str(e)}")
+ logger.warning("Failed to store cache metadata: %s", str(e))
def retrieve_cache_metadata(
self,
@@ -125,14 +127,16 @@ class CacheManager:
self.store_cache_metadata(metadata)
logger.debug(
- f"Retrieved cache metadata: provider={provider}, "
- f"model={model_name}, cache_key={cache_key_hash[:16]}..., "
- f"tenant_id={tenant_id}"
+ "Retrieved cache metadata: provider=%s, model=%s, cache_key=%s..., tenant_id=%s",
+ provider,
+ model_name,
+ cache_key_hash[:16],
+ tenant_id,
)
return metadata
except Exception as e:
# Best-effort: log and continue
- logger.debug(f"Cache metadata not found or error retrieving: {str(e)}")
+ logger.debug("Cache metadata not found or error retrieving: %s", str(e))
return None
def delete_cache_metadata(
@@ -156,11 +160,14 @@ class CacheManager:
)
self._kv_store.delete(cache_key)
logger.debug(
- f"Deleted cache metadata for provider={provider}, model={model_name}, cache_key={cache_key_hash[:16]}..."
+ "Deleted cache metadata for provider=%s, model=%s, cache_key=%s...",
+ provider,
+ model_name,
+ cache_key_hash[:16],
)
except Exception as e:
# Best-effort: log and continue
- logger.warning(f"Failed to delete cache metadata: {str(e)}")
+ logger.warning("Failed to delete cache metadata: %s", str(e))
def _make_json_serializable(obj: object) -> object:
diff --git a/backend/onyx/llm/prompt_cache/processor.py b/backend/onyx/llm/prompt_cache/processor.py
index c1885bc62d..b848e6789c 100644
--- a/backend/onyx/llm/prompt_cache/processor.py
+++ b/backend/onyx/llm/prompt_cache/processor.py
@@ -68,7 +68,8 @@ def process_with_prompt_cache(
# If provider doesn't support caching, combine and return unchanged
if not provider_adapter.supports_caching():
logger.debug(
- f"Provider {llm_config.model_provider} does not support caching, combining messages without caching"
+ "Provider %s does not support caching, combining messages without caching",
+ llm_config.model_provider,
)
# Use no-op adapter to combine messages
from onyx.llm.prompt_cache.providers.noop import NoOpPromptCacheProvider
@@ -105,9 +106,11 @@ def process_with_prompt_cache(
)
logger.debug(
- f"Processed prompt with caching: provider={llm_config.model_provider}, "
- f"model={llm_config.model_name}, cache_key={cache_key_hash[:16]}..., "
- f"continuation={continuation}"
+ "Processed prompt with caching: provider=%s, model=%s, cache_key=%s..., continuation=%s",
+ llm_config.model_provider,
+ llm_config.model_name,
+ cache_key_hash[:16],
+ continuation,
)
# Create cache metadata for tracking (even for implicit caching)
@@ -126,8 +129,9 @@ def process_with_prompt_cache(
except Exception as e:
# Best-effort: log error and fall back to no-op behavior
logger.warning(
- f"Error processing prompt with caching for provider={llm_config.model_provider}: {str(e)}. "
- "Falling back to non-cached behavior."
+ "Error processing prompt with caching for provider=%s: %s. Falling back to non-cached behavior.",
+ llm_config.model_provider,
+ str(e),
)
# Fall back to no-op adapter
from onyx.llm.prompt_cache.providers.noop import NoOpPromptCacheProvider
diff --git a/backend/onyx/llm/utils.py b/backend/onyx/llm/utils.py
index 51d1b50355..0342d3ae21 100644
--- a/backend/onyx/llm/utils.py
+++ b/backend/onyx/llm/utils.py
@@ -421,7 +421,7 @@ def test_llm(llm: LLM) -> str | None:
llm.invoke(UserMessage(content="Do not respond"), max_tokens=50)
return None
except Exception as e:
- logger.warning(f"Failed to call LLM with the following error: {e!s}")
+ logger.warning("Failed to call LLM with the following error: %s", e)
safe_msg, _, _ = litellm_exception_to_error_msg(
e, llm, fallback_to_error_msg=False
)
@@ -588,9 +588,8 @@ def get_llm_contextual_cost(
)
except Exception:
logger.exception(
- "An unexpected error occurred while calculating cost for model "
- f"{llm.config.model_name} (potentially due to malformed name). "
- "Assuming cost is 0."
+ "An unexpected error occurred while calculating cost for model %s (potentially due to malformed name). Assuming cost is 0.",
+ llm.config.model_name,
)
return 0
@@ -606,7 +605,7 @@ def llm_max_input_tokens(
"""Best effort attempt to get the max input tokens for the LLM."""
if GEN_AI_MAX_TOKENS:
# This is an override, so always return this
- logger.info(f"Using override GEN_AI_MAX_TOKENS: {GEN_AI_MAX_TOKENS}")
+ logger.info("Using override GEN_AI_MAX_TOKENS: %s", GEN_AI_MAX_TOKENS)
return GEN_AI_MAX_TOKENS
model_obj = find_model_obj(
@@ -616,7 +615,9 @@ def llm_max_input_tokens(
)
if not model_obj:
logger.warning(
- f"Model '{model_name}' not found in LiteLLM. Falling back to {GEN_AI_MODEL_FALLBACK_MAX_TOKENS} tokens."
+ "Model '%s' not found in LiteLLM. Falling back to %s tokens.",
+ model_name,
+ GEN_AI_MODEL_FALLBACK_MAX_TOKENS,
)
return GEN_AI_MODEL_FALLBACK_MAX_TOKENS
@@ -629,7 +630,9 @@ def llm_max_input_tokens(
return max_tokens
logger.warning(
- f"No max tokens found for '{model_name}'. Falling back to {GEN_AI_MODEL_FALLBACK_MAX_TOKENS} tokens."
+ "No max tokens found for '%s'. Falling back to %s tokens.",
+ model_name,
+ GEN_AI_MODEL_FALLBACK_MAX_TOKENS,
)
return GEN_AI_MODEL_FALLBACK_MAX_TOKENS
@@ -648,7 +651,9 @@ def get_llm_max_output_tokens(
if not model_obj:
logger.warning(
- f"Model '{model_name}' not found in LiteLLM. Falling back to {default_output_tokens} output tokens."
+ "Model '%s' not found in LiteLLM. Falling back to %s output tokens.",
+ model_name,
+ default_output_tokens,
)
return default_output_tokens
@@ -662,7 +667,9 @@ def get_llm_max_output_tokens(
return int(max_tokens * 0.1)
logger.warning(
- f"No max output tokens found for '{model_name}'. Falling back to {default_output_tokens} output tokens."
+ "No max output tokens found for '%s'. Falling back to %s output tokens.",
+ model_name,
+ default_output_tokens,
)
return default_output_tokens
@@ -798,7 +805,10 @@ def model_supports_image_input(model_name: str, model_provider: str) -> bool:
return True
except Exception as e:
logger.warning(
- f"Failed to query database for {model_provider} model {model_name} image support: {e}"
+ "Failed to query database for %s model %s image support: %s",
+ model_provider,
+ model_name,
+ e,
)
# Fallback to looking up the model in the litellm model_cost dict
@@ -815,14 +825,16 @@ def litellm_thinks_model_supports_image_input(
model_obj = find_model_obj(get_model_map(), model_provider, model_name)
if not model_obj:
logger.warning(
- f"No litellm entry found for {model_provider}/{model_name}, this model may or may not support image input."
+ "No litellm entry found for %s/%s, this model may or may not support image input.",
+ model_provider,
+ model_name,
)
return False
# The or False here is because sometimes the dict contains the key but the value is None
return model_obj.get("supports_vision", False) or False
except Exception:
logger.exception(
- f"Failed to get model object for {model_provider}/{model_name}"
+ "Failed to get model object for %s/%s", model_provider, model_name
)
return False
@@ -842,7 +854,9 @@ def model_is_reasoning_model(model_name: str, model_provider: str) -> bool:
if reasoning is not None:
return reasoning
logger.error(
- f"Cannot find reasoning for name={model_name} and provider={model_provider}"
+ "Cannot find reasoning for name=%s and provider=%s",
+ model_name,
+ model_provider,
)
# Fallback: try using litellm.supports_reasoning() for newer models
@@ -856,13 +870,15 @@ def model_is_reasoning_model(model_name: str, model_provider: str) -> bool:
return litellm.supports_reasoning(model=full_model_name)
except Exception:
logger.exception(
- f"Failed to check if {model_provider}/{model_name} supports reasoning"
+ "Failed to check if %s/%s supports reasoning",
+ model_provider,
+ model_name,
)
return False
except Exception:
logger.exception(
- f"Failed to get model object for {model_provider}/{model_name}"
+ "Failed to get model object for %s/%s", model_provider, model_name
)
return False
@@ -910,7 +926,9 @@ def is_true_openai_model(model_provider: str, model_name: str) -> bool:
except Exception:
logger.exception(
- f"Failed to determine if {model_provider}/{model_name} is a true OpenAI model"
+ "Failed to determine if %s/%s is a true OpenAI model",
+ model_provider,
+ model_name,
)
return False
diff --git a/backend/onyx/llm/well_known_providers/auto_update_service.py b/backend/onyx/llm/well_known_providers/auto_update_service.py
index 92a6bd8304..7b00892de6 100644
--- a/backend/onyx/llm/well_known_providers/auto_update_service.py
+++ b/backend/onyx/llm/well_known_providers/auto_update_service.py
@@ -32,7 +32,7 @@ def _get_cached_last_updated_at() -> datetime | None:
if value is not None:
return datetime.fromisoformat(value.decode("utf-8"))
except Exception as e:
- logger.warning(f"Failed to get cached last_updated_at: {e}")
+ logger.warning("Failed to get cached last_updated_at: %s", e)
return None
@@ -44,7 +44,7 @@ def _set_cached_last_updated_at(updated_at: datetime) -> None:
ex=_CACHE_TTL_SECONDS,
)
except Exception as e:
- logger.warning(f"Failed to set cached last_updated_at: {e}")
+ logger.warning("Failed to set cached last_updated_at: %s", e)
def fetch_llm_recommendations_from_github(
@@ -67,10 +67,10 @@ def fetch_llm_recommendations_from_github(
data = response.json()
return LLMRecommendations.model_validate(data)
except httpx.HTTPError as e:
- logger.error(f"Failed to fetch LLM config from GitHub: {e}")
+ logger.error("Failed to fetch LLM config from GitHub: %s", e)
return None
except Exception as e:
- logger.error(f"Error parsing LLM config: {e}")
+ logger.error("Error parsing LLM config: %s", e)
return None
@@ -120,7 +120,7 @@ def sync_llm_models_from_github(
if provider_type not in config.providers:
logger.debug(
- f"No config for provider type '{provider_type}' in GitHub config"
+ "No config for provider type '%s' in GitHub config", provider_type
)
continue
@@ -134,7 +134,7 @@ def sync_llm_models_from_github(
if changes > 0:
results[provider.name] = changes
logger.info(
- f"Applied {changes} model changes to provider '{provider.name}'"
+ "Applied %s model changes to provider '%s'", changes, provider.name
)
_set_cached_last_updated_at(config.updated_at)
@@ -146,4 +146,4 @@ def reset_cache() -> None:
try:
get_cache_backend().delete(_CACHE_KEY_LAST_UPDATED_AT)
except Exception as e:
- logger.warning(f"Failed to reset cache: {e}")
+ logger.warning("Failed to reset cache: %s", e)
diff --git a/backend/onyx/main.py b/backend/onyx/main.py
index 05ba767898..ce8da2124e 100644
--- a/backend/onyx/main.py
+++ b/backend/onyx/main.py
@@ -186,19 +186,19 @@ setup_uvicorn_logger(shared_file_handlers=file_handlers)
def validation_exception_handler(request: Request, exc: Exception) -> JSONResponse:
if not isinstance(exc, RequestValidationError):
logger.error(
- f"Unexpected exception type in validation_exception_handler - {type(exc)}"
+ "Unexpected exception type in validation_exception_handler - %s", type(exc)
)
raise exc
exc_str = f"{exc}".replace("\n", " ").replace(" ", " ")
- logger.exception(f"{request}: {exc_str}")
+ logger.exception("%s: %s", request, exc_str)
content = {"status_code": 422, "message": exc_str, "data": None}
return JSONResponse(content=content, status_code=422)
def value_error_handler(_: Request, exc: Exception) -> JSONResponse:
if not isinstance(exc, ValueError):
- logger.error(f"Unexpected exception type in value_error_handler - {type(exc)}")
+ logger.error("Unexpected exception type in value_error_handler - %s", type(exc))
raise exc
try:
@@ -313,7 +313,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # noqa: ARG001
# Set recursion limit
if SYSTEM_RECURSION_LIMIT is not None:
sys.setrecursionlimit(SYSTEM_RECURSION_LIMIT)
- logger.notice(f"System recursion limit set to {SYSTEM_RECURSION_LIMIT}")
+ logger.notice("System recursion limit set to %s", SYSTEM_RECURSION_LIMIT)
SqlEngine.set_app_name(POSTGRES_WEB_APP_NAME)
@@ -404,11 +404,11 @@ def log_http_error(request: Request, exc: Exception) -> JSONResponse:
if isinstance(exc, BasicAuthenticationError):
# For BasicAuthenticationError, just log a brief message without stack trace
# (almost always spammy)
- logger.debug(f"Authentication failed: {str(exc)}")
+ logger.debug("Authentication failed: %s", str(exc))
elif status_code == 404 and request.url.path == "/metrics":
# Log 404 errors for the /metrics endpoint with debug level
- logger.debug(f"404 error for /metrics endpoint: {str(exc)}")
+ logger.debug("404 error for /metrics endpoint: %s", str(exc))
elif status_code >= 400:
error_msg = f"{str(exc)}\n"
@@ -595,7 +595,7 @@ def get_application(lifespan_override: Lifespan | None = None) -> FastAPI:
if "offline_access" not in oidc_scopes:
oidc_scopes.append("offline_access")
except Exception as e:
- logger.warning(f"Error configuring OIDC scopes: {e}")
+ logger.warning("Error configuring OIDC scopes: %s", e)
# Fall back to default scopes if there's an error
oidc_scopes = BASE_SCOPES
@@ -700,7 +700,10 @@ app = fetch_versioned_implementation(module="onyx.main", attribute="get_applicat
if __name__ == "__main__":
logger.notice(
- f"Starting Onyx Backend version {__version__} on http://{APP_HOST}:{str(APP_PORT)}/"
+ "Starting Onyx Backend version %s on http://%s:%s/",
+ __version__,
+ APP_HOST,
+ str(APP_PORT),
)
if global_version.is_ee_version():
diff --git a/backend/onyx/mcp_server/api.py b/backend/onyx/mcp_server/api.py
index 3b1681cd20..604b1d0091 100644
--- a/backend/onyx/mcp_server/api.py
+++ b/backend/onyx/mcp_server/api.py
@@ -97,7 +97,7 @@ def create_mcp_fastapi_app() -> FastAPI:
# Authentication is handled by FastMCP's OnyxTokenVerifier (see auth.py)
if MCP_SERVER_CORS_ORIGINS:
- logger.info(f"CORS origins: {MCP_SERVER_CORS_ORIGINS}")
+ logger.info("CORS origins: %s", MCP_SERVER_CORS_ORIGINS)
app.add_middleware(
CORSMiddleware,
allow_origins=MCP_SERVER_CORS_ORIGINS,
diff --git a/backend/onyx/mcp_server/tools/search.py b/backend/onyx/mcp_server/tools/search.py
index 791fdbbdac..4e20d44c8e 100644
--- a/backend/onyx/mcp_server/tools/search.py
+++ b/backend/onyx/mcp_server/tools/search.py
@@ -120,8 +120,11 @@ async def search_indexed_documents(
```
"""
logger.info(
- f"Onyx MCP Server: document search: query='{query}', sources={source_types}, "
- f"document_sets={document_set_names}, limit={limit}"
+ "Onyx MCP Server: document search: query='%s', sources=%s, document_sets=%s, limit=%s",
+ query,
+ source_types,
+ document_set_names,
+ limit,
)
# Normalize empty list inputs to None so downstream filter construction is
@@ -137,7 +140,9 @@ async def search_indexed_documents(
time_cutoff_dt = datetime.fromisoformat(time_cutoff.replace("Z", "+00:00"))
except ValueError as e:
logger.warning(
- f"Onyx MCP Server: Invalid time_cutoff format '{time_cutoff}': {e}. Continuing without time filter."
+ "Onyx MCP Server: Invalid time_cutoff format '%s': %s. Continuing without time filter.",
+ time_cutoff,
+ e,
)
# Continue with no time_cutoff instead of returning an error
time_cutoff_dt = None
@@ -183,7 +188,8 @@ async def search_indexed_documents(
source_type_enums.append(DocumentSource(src.lower()))
except ValueError:
logger.warning(
- f"Onyx MCP Server: Invalid source type '{src}' - will be ignored by server"
+ "Onyx MCP Server: Invalid source type '%s' - will be ignored by server",
+ src,
)
filters: BaseFilters | None = None
@@ -270,7 +276,7 @@ async def search_indexed_documents(
documents = documents[:limit]
logger.info(
- f"Onyx MCP Server: Internal search returned {len(documents)} results"
+ "Onyx MCP Server: Internal search returned %s results", len(documents)
)
return {
"documents": documents,
@@ -278,7 +284,7 @@ async def search_indexed_documents(
"query": query,
}
except Exception as e:
- logger.error(f"Onyx MCP Server: Document search error: {e}", exc_info=True)
+ logger.error("Onyx MCP Server: Document search error: %s", e, exc_info=True)
return {
"error": f"Document search failed: {str(e)}",
"documents": [],
@@ -306,7 +312,7 @@ async def search_web(
}
```
"""
- logger.info(f"Onyx MCP Server: Web search: query='{query}', limit={limit}")
+ logger.info("Onyx MCP Server: Web search: query='%s', limit=%s", query, limit)
access_token = require_access_token()
@@ -328,7 +334,7 @@ async def search_web(
"query": query,
}
except Exception as e:
- logger.error(f"Onyx MCP Server: Web search error: {e}", exc_info=True)
+ logger.error("Onyx MCP Server: Web search error: %s", e, exc_info=True)
return {
"error": f"Web search failed: {str(e)}",
"results": [],
@@ -356,7 +362,7 @@ async def open_urls(
}
```
"""
- logger.info(f"Onyx MCP Server: Open URL: fetching {len(urls)} URLs")
+ logger.info("Onyx MCP Server: Open URL: fetching %s URLs", len(urls))
access_token = require_access_token()
@@ -376,7 +382,7 @@ async def open_urls(
"results": [result.model_dump(mode="json") for result in payload.results],
}
except Exception as e:
- logger.error(f"Onyx MCP Server: URL fetch error: {e}", exc_info=True)
+ logger.error("Onyx MCP Server: URL fetch error: %s", e, exc_info=True)
return {
"error": f"URL fetch failed: {str(e)}",
"results": [],
diff --git a/backend/onyx/mcp_server_main.py b/backend/onyx/mcp_server_main.py
index 0b8c806520..fc7b726b97 100644
--- a/backend/onyx/mcp_server_main.py
+++ b/backend/onyx/mcp_server_main.py
@@ -20,7 +20,7 @@ def main() -> None:
set_is_ee_based_on_env_variable()
setup_tracing()
- logger.info(f"Starting MCP server on {MCP_SERVER_HOST}:{MCP_SERVER_PORT}")
+ logger.info("Starting MCP server on %s:%s", MCP_SERVER_HOST, MCP_SERVER_PORT)
from onyx.mcp_server.api import mcp_app
diff --git a/backend/onyx/natural_language_processing/search_nlp_models.py b/backend/onyx/natural_language_processing/search_nlp_models.py
index b7ed1beace..825ae0fd02 100644
--- a/backend/onyx/natural_language_processing/search_nlp_models.py
+++ b/backend/onyx/natural_language_processing/search_nlp_models.py
@@ -134,7 +134,9 @@ def cleanup_embedding_thread_locals() -> None:
pending = asyncio.all_tasks(loop)
if pending:
logger.debug(
- f"Cleaning up event loop with {len(pending)} pending tasks in thread {threading.current_thread().name}"
+ "Cleaning up event loop with %s pending tasks in thread %s",
+ len(pending),
+ threading.current_thread().name,
)
for task in pending:
task.cancel()
@@ -144,12 +146,12 @@ def cleanup_embedding_thread_locals() -> None:
)
except Exception as e:
# If gathering tasks fails, just close the loop
- logger.debug(f"Error gathering tasks during cleanup: {e}")
+ logger.debug("Error gathering tasks during cleanup: %s", e)
# Close the event loop
loop.close()
logger.debug(
- f"Closed event loop in thread {threading.current_thread().name}"
+ "Closed event loop in thread %s", threading.current_thread().name
)
# Clear the thread-local reference
@@ -420,8 +422,10 @@ class CloudEmbedding:
all_embeddings: list[Embedding] = []
logger.debug(
- f"VertexAI embedding: processing {len(texts)} texts in {len(batches)} batches "
- f"(batch_size={VERTEXAI_EMBEDDING_LOCAL_BATCH_SIZE})"
+ "VertexAI embedding: processing %s texts in %s batches (batch_size=%s)",
+ len(texts),
+ len(batches),
+ VERTEXAI_EMBEDDING_LOCAL_BATCH_SIZE,
)
try:
@@ -432,11 +436,15 @@ class CloudEmbedding:
# Log progress for large batches to track memory usage patterns
if batch_idx % 10 == 0 and batch_idx > 0:
logger.debug(
- f"VertexAI embedding progress: batch {batch_idx}/{len(batches)}, total_embeddings={len(all_embeddings)}"
+ "VertexAI embedding progress: batch %s/%s, total_embeddings=%s",
+ batch_idx,
+ len(batches),
+ len(all_embeddings),
)
logger.debug(
- f"VertexAI embedding completed: {len(all_embeddings)} embeddings generated"
+ "VertexAI embedding completed: %s embeddings generated",
+ len(all_embeddings),
)
return all_embeddings
finally:
@@ -446,7 +454,7 @@ class CloudEmbedding:
except asyncio.TimeoutError:
logger.warning("Google GenAI client aclose() timed out after 5s")
except Exception as e:
- logger.warning(f"Error closing Google GenAI client: {e}")
+ logger.warning("Error closing Google GenAI client: %s", e)
async def _embed_litellm_proxy(
self, texts: list[str], model_name: str | None
@@ -524,7 +532,7 @@ class CloudEmbedding:
# transient provider outages). The final failure surfaces via
# the RuntimeError below and is logged by the caller.
logger.warning(error_string)
- logger.debug(f"Exception texts: {texts}")
+ logger.debug("Exception texts: %s", texts)
raise RuntimeError(error_string)
except Exception as e:
@@ -539,7 +547,7 @@ class CloudEmbedding:
sanitized_api_key=self.sanitized_api_key,
)
logger.warning(error_string)
- logger.debug(f"Exception texts: {texts}")
+ logger.debug("Exception texts: %s", texts)
raise RuntimeError(error_string)
@@ -550,7 +558,7 @@ class CloudEmbedding:
api_url: str | None = None,
api_version: str | None = None,
) -> "CloudEmbedding":
- logger.debug(f"Creating Embedding instance for provider: {provider}")
+ logger.debug("Creating Embedding instance for provider: %s", provider)
return CloudEmbedding(api_key, provider, api_url, api_version)
async def aclose(self) -> None:
@@ -737,7 +745,10 @@ class EmbeddingModel:
total_chars = sum(len(text) for text in embed_request.texts)
logger.info(
- f"Embedding {len(embed_request.texts)} texts with {total_chars} total characters with provider: {self.provider_type}"
+ "Embedding %s texts with %s total characters with provider: %s",
+ len(embed_request.texts),
+ total_chars,
+ self.provider_type,
)
async with CloudEmbedding(
@@ -763,11 +774,11 @@ class EmbeddingModel:
elapsed = time.monotonic() - start_time
logger.info(
- f"event=embedding_provider "
- f"texts={len(embed_request.texts)} "
- f"chars={total_chars} "
- f"provider={self.provider_type} "
- f"elapsed={elapsed:.2f}"
+ "event=embedding_provider texts=%s chars=%s provider=%s elapsed=%s",
+ len(embed_request.texts),
+ total_chars,
+ self.provider_type,
+ format(elapsed, ".2f"),
)
return EmbedResponse(embeddings=embeddings)
@@ -849,7 +860,7 @@ class EmbeddingModel:
text_batches = batch_list(texts, batch_size)
num_of_batches = len(text_batches)
- logger.debug(f"Encoding {len(texts)} texts in {num_of_batches} batches.")
+ logger.debug("Encoding %s texts in %s batches.", len(texts), num_of_batches)
embeddings: list[Embedding] = []
@@ -958,7 +969,10 @@ class EmbeddingModel:
)
logger.debug(
- f"process_batch: Batch idx {batch_idx}, total num {num_of_batches}, processing time: {processing_time:.2f}s."
+ "process_batch: Batch idx %s, total num %s, processing time: %ss.",
+ batch_idx,
+ num_of_batches,
+ format(processing_time, ".2f"),
)
return batch_idx, response.embeddings
@@ -1255,7 +1269,10 @@ def warm_up_retry(
except Exception as e:
exceptions.append(e)
logger.info(
- f"Attempt {attempt + 1}/{tries} failed; retrying in {delay} seconds..."
+ "Attempt %s/%s failed; retrying in %s seconds...",
+ attempt + 1,
+ tries,
+ delay,
)
time.sleep(delay)
raise Exception(f"All retries failed: {exceptions}")
@@ -1272,7 +1289,7 @@ def warm_up_bi_encoder(
warm_up_str = " ".join(WARM_UP_STRINGS)
- logger.debug(f"Warming up encoder model: {embedding_model.model_name}")
+ logger.debug("Warming up encoder model: %s", embedding_model.model_name)
get_tokenizer(
model_name=embedding_model.model_name,
provider_type=embedding_model.provider_type,
@@ -1282,17 +1299,20 @@ def warm_up_bi_encoder(
try:
embedding_model.encode(texts=[warm_up_str], text_type=EmbedTextType.QUERY)
logger.debug(
- f"Warm-up complete for encoder model: {embedding_model.model_name}"
+ "Warm-up complete for encoder model: %s", embedding_model.model_name
)
except Exception as e:
logger.warning(
- f"Warm-up request failed for encoder model {embedding_model.model_name}: {e}"
+ "Warm-up request failed for encoder model %s: %s",
+ embedding_model.model_name,
+ e,
)
if non_blocking:
threading.Thread(target=_warm_up, daemon=True).start()
logger.debug(
- f"Started non-blocking warm-up for encoder model: {embedding_model.model_name}"
+ "Started non-blocking warm-up for encoder model: %s",
+ embedding_model.model_name,
)
else:
retry_encode = warm_up_retry(embedding_model.encode)
@@ -1307,7 +1327,7 @@ def warm_up_cross_encoder(
if SKIP_WARM_UP:
return
- logger.debug(f"Warming up reranking model: {rerank_model_name}")
+ logger.debug("Warming up reranking model: %s", rerank_model_name)
reranking_model = RerankingModel(
model_name=rerank_model_name,
@@ -1319,16 +1339,18 @@ def warm_up_cross_encoder(
def _warm_up() -> None:
try:
reranking_model.predict(WARM_UP_STRINGS[0], WARM_UP_STRINGS[1:])
- logger.debug(f"Warm-up complete for reranking model: {rerank_model_name}")
+ logger.debug("Warm-up complete for reranking model: %s", rerank_model_name)
except Exception as e:
logger.warning(
- f"Warm-up request failed for reranking model {rerank_model_name}: {e}"
+ "Warm-up request failed for reranking model %s: %s",
+ rerank_model_name,
+ e,
)
if non_blocking:
threading.Thread(target=_warm_up, daemon=True).start()
logger.debug(
- f"Started non-blocking warm-up for reranking model: {rerank_model_name}"
+ "Started non-blocking warm-up for reranking model: %s", rerank_model_name
)
else:
retry_rerank = warm_up_retry(reranking_model.predict)
diff --git a/backend/onyx/natural_language_processing/utils.py b/backend/onyx/natural_language_processing/utils.py
index 5834341a11..c3d275b52f 100644
--- a/backend/onyx/natural_language_processing/utils.py
+++ b/backend/onyx/natural_language_processing/utils.py
@@ -57,7 +57,10 @@ class TiktokenTokenizer(BaseTokenizer):
if len(decoded) != len(encoded):
logger.warning(
- f"OpenAI tokenized length {len(decoded)} does not match encoded length {len(encoded)} for string: {string}"
+ "OpenAI tokenized length %s does not match encoded length %s for string: %s",
+ len(decoded),
+ len(encoded),
+ string,
)
return decoded
@@ -111,7 +114,8 @@ def _check_tokenizer_cache(
if not tokenizer:
logger.info(
- f"Falling back to default embedding model tokenizer: {DOCUMENT_ENCODER_MODEL}"
+ "Falling back to default embedding model tokenizer: %s",
+ DOCUMENT_ENCODER_MODEL,
)
tokenizer = _get_default_tokenizer()
@@ -129,21 +133,25 @@ def _try_initialize_tokenizer(
# Try using TiktokenTokenizer first if model_provider exists
try:
tokenizer = TiktokenTokenizer(model_name)
- logger.info(f"Initialized TiktokenTokenizer for: {model_name}")
+ logger.info("Initialized TiktokenTokenizer for: %s", model_name)
return tokenizer
except Exception as tiktoken_error:
logger.debug(
- f"TiktokenTokenizer not available for model {model_name}: {tiktoken_error}"
+ "TiktokenTokenizer not available for model %s: %s",
+ model_name,
+ tiktoken_error,
)
else:
# If no provider specified, try HuggingFaceTokenizer
try:
tokenizer = HuggingFaceTokenizer(model_name)
- logger.info(f"Initialized HuggingFaceTokenizer for: {model_name}")
+ logger.info("Initialized HuggingFaceTokenizer for: %s", model_name)
return tokenizer
except Exception as hf_error:
logger.warning(
- f"Failed to initialize HuggingFaceTokenizer for {model_name}: {hf_error}"
+ "Failed to initialize HuggingFaceTokenizer for %s: %s",
+ model_name,
+ hf_error,
)
# If both initializations fail, return None
@@ -169,7 +177,8 @@ def get_tokenizer(
provider_type = EmbeddingProvider(provider_type)
except ValueError:
logger.debug(
- f"Invalid provider_type '{provider_type}'. Falling back to default tokenizer."
+ "Invalid provider_type '%s'. Falling back to default tokenizer.",
+ provider_type,
)
return _get_default_tokenizer()
return _check_tokenizer_cache(provider_type, model_name)
diff --git a/backend/onyx/onyxbot/discord/api_client.py b/backend/onyx/onyxbot/discord/api_client.py
index 1689485bd9..a9b4087b03 100644
--- a/backend/onyx/onyxbot/discord/api_client.py
+++ b/backend/onyx/onyxbot/discord/api_client.py
@@ -70,7 +70,7 @@ class OnyxAPIClient:
connect=30, # 30 seconds to establish connection
)
self._session = aiohttp.ClientSession(timeout=timeout)
- logger.info(f"API client initialized with base URL: {self._base_url}")
+ logger.info("API client initialized with base URL: %s", self._base_url)
async def close(self) -> None:
"""Close the aiohttp session.
@@ -174,24 +174,26 @@ class OnyxAPIClient:
response_obj = ChatFullResponse.model_validate(data)
if response_obj.error_msg:
- logger.warning(f"Chat API returned error: {response_obj.error_msg}")
+ logger.warning(
+ "Chat API returned error: %s", response_obj.error_msg
+ )
return response_obj
except aiohttp.ClientConnectorError as e:
- logger.error(f"Failed to connect to API: {e}")
+ logger.error("Failed to connect to API: %s", e)
raise APIConnectionError(
f"Failed to connect to API at {self._base_url}: {e}"
) from e
except TimeoutError as e:
- logger.error(f"API request timed out after {self._timeout}s")
+ logger.error("API request timed out after %ss", self._timeout)
raise APITimeoutError(
f"Request timed out after {self._timeout} seconds"
) from e
except aiohttp.ClientError as e:
- logger.error(f"HTTP client error: {e}")
+ logger.error("HTTP client error: %s", e)
raise APIConnectionError(f"HTTP client error: {e}") from e
async def health_check(self) -> bool:
@@ -211,5 +213,5 @@ class OnyxAPIClient:
) as response:
return response.status == 200
except Exception as e:
- logger.warning(f"API server health check failed: {e}")
+ logger.warning("API server health check failed: %s", e)
return False
diff --git a/backend/onyx/onyxbot/discord/cache.py b/backend/onyx/onyxbot/discord/cache.py
index b7d4402321..5f96c416ea 100644
--- a/backend/onyx/onyxbot/discord/cache.py
+++ b/backend/onyx/onyxbot/discord/cache.py
@@ -54,13 +54,13 @@ class DiscordCacheManager:
try:
guild_ids, api_key = await self._load_tenant_data(tenant_id)
if not guild_ids:
- logger.debug(f"No guilds found for tenant {tenant_id}")
+ logger.debug("No guilds found for tenant %s", tenant_id)
continue
if not api_key:
logger.warning(
- "Discord service API key missing for tenant that has registered guilds. "
- f"{tenant_id} will not be handled in this refresh cycle."
+ "Discord service API key missing for tenant that has registered guilds. %s will not be handled in this refresh cycle.",
+ tenant_id,
)
continue
@@ -69,7 +69,7 @@ class DiscordCacheManager:
new_api_keys[tenant_id] = api_key
except Exception as e:
- logger.warning(f"Failed to refresh tenant {tenant_id}: {e}")
+ logger.warning("Failed to refresh tenant %s: %s", tenant_id, e)
finally:
CURRENT_TENANT_ID_CONTEXTVAR.reset(context_token)
@@ -78,17 +78,21 @@ class DiscordCacheManager:
self._initialized = True
logger.info(
- f"Cache refresh complete: {len(new_guild_tenants)} guilds, {len(new_api_keys)} tenants"
+ "Cache refresh complete: %s guilds, %s tenants",
+ len(new_guild_tenants),
+ len(new_api_keys),
)
except Exception as e:
- logger.error(f"Cache refresh failed: {e}")
+ logger.error("Cache refresh failed: %s", e)
raise CacheError(f"Failed to refresh cache: {e}") from e
async def refresh_guild(self, guild_id: int, tenant_id: str) -> None:
"""Add a single guild to cache after registration."""
async with self._lock:
- logger.info(f"Refreshing cache for guild {guild_id} (tenant: {tenant_id})")
+ logger.info(
+ "Refreshing cache for guild %s (tenant: %s)", guild_id, tenant_id
+ )
guild_ids, api_key = await self._load_tenant_data(tenant_id)
@@ -96,9 +100,9 @@ class DiscordCacheManager:
self._guild_tenants[guild_id] = tenant_id
if api_key:
self._api_keys[tenant_id] = api_key
- logger.info(f"Cache updated for guild {guild_id}")
+ logger.info("Cache updated for guild %s", guild_id)
else:
- logger.warning(f"Guild {guild_id} not found or disabled")
+ logger.warning("Guild %s not found or disabled", guild_id)
async def _load_tenant_data(self, tenant_id: str) -> tuple[list[int], str | None]:
"""Load guild IDs and provision API key if needed.
diff --git a/backend/onyx/onyxbot/discord/client.py b/backend/onyx/onyxbot/discord/client.py
index bb3e6a05f2..84663f70d0 100644
--- a/backend/onyx/onyxbot/discord/client.py
+++ b/backend/onyx/onyxbot/discord/client.py
@@ -69,7 +69,7 @@ class OnyxDiscordClient(commands.Bot):
try:
await self.cache.refresh_all()
except Exception as e:
- logger.error(f"Cache refresh failed: {e}")
+ logger.error("Cache refresh failed: %s", e)
async def on_ready(self) -> None:
"""Bot connected and ready."""
@@ -79,9 +79,11 @@ class OnyxDiscordClient(commands.Bot):
if not self.user:
raise RuntimeError("Critical error: Discord Bot user not found")
- logger.info(f"Discord Bot connected as {self.user} (ID: {self.user.id})")
- logger.info(f"Connected to {len(self.guilds)} guild(s)")
- logger.info(f"Cached {len(self.cache.get_all_guild_ids())} registered guild(s)")
+ logger.info("Discord Bot connected as %s (ID: %s)", self.user, self.user.id)
+ logger.info("Connected to %s guild(s)", len(self.guilds))
+ logger.info(
+ "Cached %s registered guild(s)", len(self.cache.get_all_guild_ids())
+ )
self.ready = True
@@ -158,7 +160,7 @@ class OnyxDiscordClient(commands.Bot):
# Get API key
api_key = self.cache.get_api_key(tenant_id)
if not api_key:
- logger.warning(f"No API key cached for tenant {tenant_id}")
+ logger.warning("No API key cached for tenant %s", tenant_id)
return
# Check if bot should respond
@@ -168,9 +170,11 @@ class OnyxDiscordClient(commands.Bot):
return
logger.debug(
- f"Processing message: '{message.content[:50]}' in "
- f"#{getattr(message.channel, 'name', 'unknown')} ({message.guild.name}), "
- f"persona_id={should_respond_context.persona_id}"
+ "Processing message: '%s' in #%s (%s), persona_id=%s",
+ message.content[:50],
+ getattr(message.channel, "name", "unknown"),
+ message.guild.name,
+ should_respond_context.persona_id,
)
# Process the message
@@ -184,7 +188,7 @@ class OnyxDiscordClient(commands.Bot):
)
except Exception as e:
- logger.exception(f"Error processing message: {e}")
+ logger.exception("Error processing message: %s", e)
# -----------------------------------------------------------------------------
diff --git a/backend/onyx/onyxbot/discord/handle_commands.py b/backend/onyx/onyxbot/discord/handle_commands.py
index 9e7bca9f7b..eee8004cbe 100644
--- a/backend/onyx/onyxbot/discord/handle_commands.py
+++ b/backend/onyx/onyxbot/discord/handle_commands.py
@@ -44,29 +44,29 @@ async def handle_dm(message: discord.Message) -> None:
async def _try_dm_author(message: discord.Message, content: str) -> bool:
"""Attempt to DM the message author. Returns True if successful."""
- logger.debug(f"Responding in Discord DM with {content}")
+ logger.debug("Responding in Discord DM with %s", content)
try:
await message.author.send(content)
return True
except (discord.Forbidden, discord.HTTPException) as e:
# User has DMs disabled or other error
- logger.warning(f"Failed to DM author {message.author.id}: {e}")
+ logger.warning("Failed to DM author %s: %s", message.author.id, e)
except Exception as e:
- logger.exception(f"Unexpected error DMing author {message.author.id}: {e}")
+ logger.exception("Unexpected error DMing author %s: %s", message.author.id, e)
return False
async def _try_delete_message(message: discord.Message) -> bool:
"""Attempt to delete a message. Returns True if successful."""
- logger.debug(f"Deleting potentially sensitive message {message.id}")
+ logger.debug("Deleting potentially sensitive message %s", message.id)
try:
await message.delete()
return True
except (discord.Forbidden, discord.HTTPException) as e:
# Bot lacks permission or other error
- logger.warning(f"Failed to delete message {message.id}: {e}")
+ logger.warning("Failed to delete message %s: %s", message.id, e)
except Exception as e:
- logger.exception(f"Unexpected error deleting message {message.id}: {e}")
+ logger.exception("Unexpected error deleting message %s: %s", message.id, e)
return False
@@ -77,9 +77,9 @@ async def _try_react_x(message: discord.Message) -> bool:
return True
except (discord.Forbidden, discord.HTTPException) as e:
# Bot lacks permission or other error
- logger.warning(f"Failed to react to message {message.id}: {e}")
+ logger.warning("Failed to react to message %s: %s", message.id, e)
except Exception as e:
- logger.exception(f"Unexpected error reacting to message {message.id}: {e}")
+ logger.exception("Unexpected error reacting to message %s: %s", message.id, e)
return False
@@ -107,7 +107,7 @@ async def handle_registration_command(
return True
guild_name = message.guild.name
- logger.info(f"Registration command received: {guild_name}")
+ logger.info("Registration command received: %s", guild_name)
try:
# Parse the registration key
@@ -132,18 +132,18 @@ async def handle_registration_command(
)
await _register_guild(message, registration_key, cache)
- logger.info(f"Registration successful: {guild_name}")
+ logger.info("Registration successful: %s", guild_name)
await message.reply(
":white_check_mark: **Successfully registered!**\n\n"
"This server is now connected to Onyx. "
"I'll respond to messages based on your server and channel settings set in Onyx."
)
except RegistrationError as e:
- logger.debug(f"Registration failed: {guild_name}, error={e}")
+ logger.debug("Registration failed: %s, error=%s", guild_name, e)
await _try_dm_author(message, f":x: **Registration failed.**\n\n{e}")
await _try_delete_message(message)
except Exception:
- logger.exception(f"Registration failed unexpectedly: {guild_name}")
+ logger.exception("Registration failed unexpectedly: %s", guild_name)
await _try_dm_author(
message,
":x: **Registration failed.**\n\nAn unexpected error occurred. Please try again later.",
@@ -163,7 +163,7 @@ async def _register_guild(
# mypy, even though we already know that message.guild is not None
raise RegistrationError("This command can only be used in a server.")
- logger.info(f"Guild '{message.guild.name}' attempting to register Discord bot")
+ logger.info("Guild '%s' attempting to register Discord bot", message.guild.name)
registration_key = registration_key.strip()
# Parse tenant_id from registration key
@@ -175,14 +175,14 @@ async def _register_guild(
tenant_id = parsed
- logger.info(f"Parsed tenant_id {tenant_id} from registration key")
+ logger.info("Parsed tenant_id %s from registration key", tenant_id)
# Check if this guild is already registered to any tenant
guild_id = message.guild.id
existing_tenant = cache.get_tenant(guild_id)
if existing_tenant is not None:
logger.warning(
- f"Guild {guild_id} is already registered to tenant {existing_tenant}"
+ "Guild %s is already registered to tenant %s", guild_id, existing_tenant
)
raise RegistrationError(
"This server is already registered.\n\nOnyxBot can only connect one Discord server to one Onyx workspace."
@@ -195,7 +195,7 @@ async def _register_guild(
# Collect all text channels from the guild
channels = get_text_channels(guild)
- logger.info(f"Found {len(channels)} text channels in guild '{guild_name}'")
+ logger.info("Found %s text channels in guild '%s'", len(channels), guild_name)
# Validate and update in database
def _sync_register() -> int:
@@ -234,7 +234,7 @@ async def _register_guild(
await cache.refresh_guild(guild_id, tenant_id)
logger.info(
- f"Guild '{guild_name}' registered with {len(channels)} channel configs"
+ "Guild '%s' registered with %s channel configs", guild_name, len(channels)
)
finally:
CURRENT_TENANT_ID_CONTEXTVAR.reset(context_token)
@@ -251,7 +251,10 @@ def get_text_channels(guild: discord.Guild) -> list[DiscordChannelView]:
is_private = not everyone_perms.view_channel
logger.debug(
- f"Found channel: #{channel.name}, type={channel.type.name}, is_private={is_private}"
+ "Found channel: #%s, type=%s, is_private=%s",
+ channel.name,
+ channel.type.name,
+ is_private,
)
channels.append(
@@ -263,7 +266,7 @@ def get_text_channels(guild: discord.Guild) -> list[DiscordChannelView]:
)
)
- logger.debug(f"Retrieved {len(channels)} channels from guild '{guild.name}'")
+ logger.debug("Retrieved %s channels from guild '%s'", len(channels), guild.name)
return channels
@@ -292,7 +295,7 @@ async def handle_sync_channels_command(
return True
guild_name = message.guild.name
- logger.info(f"Sync-channels command received: {guild_name}")
+ logger.info("Sync-channels command received: %s", guild_name)
try:
# Must be registered
@@ -335,7 +338,11 @@ async def handle_sync_channels_command(
guild_config_id, tenant_id, bot
)
logger.info(
- f"Sync-channels successful: {guild_name}, added={added}, removed={removed}, updated={updated}"
+ "Sync-channels successful: %s, added=%s, removed=%s, updated=%s",
+ guild_name,
+ added,
+ removed,
+ updated,
)
await message.reply(
f":white_check_mark: **Channel sync complete!**\n\n"
@@ -345,11 +352,11 @@ async def handle_sync_channels_command(
"New channels are disabled by default. Enable them in the Onyx admin panel."
)
except SyncChannelsError as e:
- logger.debug(f"Sync-channels failed: {guild_name}, error={e}")
+ logger.debug("Sync-channels failed: %s, error=%s", guild_name, e)
await _try_dm_author(message, f":x: **Channel sync failed.**\n\n{e}")
await _try_react_x(message)
except Exception:
- logger.exception(f"Sync-channels failed unexpectedly: {guild_name}")
+ logger.exception("Sync-channels failed unexpectedly: %s", guild_name)
await _try_dm_author(
message,
":x: **Channel sync failed.**\n\nAn unexpected error occurred. Please try again later.",
@@ -406,7 +413,7 @@ async def sync_guild_channels(
# Get current channels from Discord
channels = get_text_channels(guild)
- logger.info(f"Syncing {len(channels)} channels for guild '{guild.name}'")
+ logger.info("Syncing %s channels for guild '%s'", len(channels), guild.name)
# Sync with database
def _sync() -> tuple[int, int, int]:
@@ -420,7 +427,11 @@ async def sync_guild_channels(
added, removed, updated = await asyncio.to_thread(_sync)
logger.info(
- f"Channel sync complete for guild '{guild.name}': added={added}, removed={removed}, updated={updated}"
+ "Channel sync complete for guild '%s': added=%s, removed=%s, updated=%s",
+ guild.name,
+ added,
+ removed,
+ updated,
)
return added, removed, updated
diff --git a/backend/onyx/onyxbot/discord/handle_message.py b/backend/onyx/onyxbot/discord/handle_message.py
index 89c5fde780..280bfb9033 100644
--- a/backend/onyx/onyxbot/discord/handle_message.py
+++ b/backend/onyx/onyxbot/discord/handle_message.py
@@ -116,7 +116,7 @@ async def check_implicit_invocation(
)
if referenced_msg.author.id == bot_user.id:
logger.debug(
- f"Implicit invocation via reply: '{message.content[:50]}...'"
+ "Implicit invocation via reply: '%s...'", message.content[:50]
)
return True
except (discord.NotFound, discord.HTTPException):
@@ -129,7 +129,9 @@ async def check_implicit_invocation(
# Bot owns the thread
if thread.owner_id == bot_user.id:
logger.debug(
- f"Implicit invocation via bot-owned thread: '{message.content[:50]}...' in #{thread.name}"
+ "Implicit invocation via bot-owned thread: '%s...' in #%s",
+ message.content[:50],
+ thread.name,
)
return True
@@ -139,7 +141,9 @@ async def check_implicit_invocation(
starter = await thread.parent.fetch_message(thread.id)
if starter.author.id == bot_user.id:
logger.debug(
- f"Implicit invocation via bot-started thread: '{message.content[:50]}...' in #{thread.name}"
+ "Implicit invocation via bot-started thread: '%s...' in #%s",
+ message.content[:50],
+ thread.name,
)
return True
except (discord.NotFound, discord.HTTPException):
@@ -166,7 +170,7 @@ async def process_chat_message(
await message.add_reaction(THINKING_EMOJI)
except discord.DiscordException:
logger.warning(
- f"Failed to add thinking reaction to message: '{message.content[:50]}...'"
+ "Failed to add thinking reaction to message: '%s...'", message.content[:50]
)
try:
@@ -203,10 +207,10 @@ async def process_chat_message(
pass
except APIError as e:
- logger.error(f"API error processing message: {e}")
+ logger.error("API error processing message: %s", e)
await send_error_response(message, bot_user)
except Exception as e:
- logger.exception(f"Error processing chat message: {e}")
+ logger.exception("Error processing chat message: %s", e)
await send_error_response(message, bot_user)
@@ -298,13 +302,15 @@ async def _build_reply_chain_context(
messages.reverse() # Chronological order
logger.debug(
- f"Built reply chain context: {len(messages)} messages in #{getattr(message.channel, 'name', 'unknown')}"
+ "Built reply chain context: %s messages in #%s",
+ len(messages),
+ getattr(message.channel, "name", "unknown"),
)
return _format_messages_as_context(messages, bot_user)
except Exception as e:
- logger.warning(f"Failed to build reply chain context: {e}")
+ logger.warning("Failed to build reply chain context: %s", e)
return None
@@ -358,13 +364,13 @@ async def _build_thread_context(
messages.sort(key=lambda m: m.id) # Chronological order
logger.debug(
- f"Built thread context: {len(messages)} messages in #{thread.name}"
+ "Built thread context: %s messages in #%s", len(messages), thread.name
)
return _format_messages_as_context(messages, bot_user)
except Exception as e:
- logger.warning(f"Failed to build thread context: {e}")
+ logger.warning("Failed to build thread context: %s", e)
return None
diff --git a/backend/onyx/onyxbot/discord/utils.py b/backend/onyx/onyxbot/discord/utils.py
index 79bf916f02..36e70a2cf2 100644
--- a/backend/onyx/onyxbot/discord/utils.py
+++ b/backend/onyx/onyxbot/discord/utils.py
@@ -35,7 +35,7 @@ def get_bot_token() -> str | None:
with get_session_with_tenant(tenant_id=POSTGRES_DEFAULT_SCHEMA) as db:
config = get_discord_bot_config(db)
except Exception as e:
- logger.error(f"Failed to get bot token from database: {e}")
+ logger.error("Failed to get bot token from database: %s", e)
return None
if config and config.bot_token:
if isinstance(config.bot_token, SensitiveValue):
diff --git a/backend/onyx/onyxbot/slack/handlers/handle_buttons.py b/backend/onyx/onyxbot/slack/handlers/handle_buttons.py
index d5dd547ccf..b0990c23ff 100644
--- a/backend/onyx/onyxbot/slack/handlers/handle_buttons.py
+++ b/backend/onyx/onyxbot/slack/handlers/handle_buttons.py
@@ -238,7 +238,7 @@ def handle_publish_ephemeral_message_button(
chat_message_id, None, db_session
) # is this good idea?
except Exception as e:
- logger.error(f"Failed to get chat message: {e}")
+ logger.error("Failed to get chat message: %s", e)
raise e
chat_message_detail = translate_db_message_to_chat_message_detail(chat_message)
@@ -276,7 +276,7 @@ def handle_publish_ephemeral_message_button(
delete_original=True,
)
except Exception as e:
- logger.error(f"Failed to send webhook: {e}")
+ logger.error("Failed to send webhook: %s", e)
# remove handling of empheremal block and add AI feedback.
all_blocks = build_slack_response_blocks(
@@ -302,7 +302,7 @@ def handle_publish_ephemeral_message_button(
send_as_ephemeral=False,
)
except Exception as e:
- logger.error(f"Failed to publish ephemeral message: {e}")
+ logger.error("Failed to publish ephemeral message: %s", e)
raise e
elif action_id == KEEP_TO_YOURSELF_ACTION_ID:
@@ -353,7 +353,7 @@ def handle_publish_ephemeral_message_button(
delete_original=False,
)
except Exception as e:
- logger.error(f"Failed to send webhook: {e}")
+ logger.error("Failed to send webhook: %s", e)
def handle_slack_feedback(
@@ -412,7 +412,7 @@ def handle_slack_feedback(
feedback=feedback,
)
else:
- logger.error(f"Feedback type '{feedback_type}' not supported")
+ logger.error("Feedback type '%s' not supported", feedback_type)
if get_feedback_visibility() == FeedbackVisibility.PRIVATE or feedback_type not in [
LIKE_BLOCK_ACTION_ID,
diff --git a/backend/onyx/onyxbot/slack/handlers/handle_message.py b/backend/onyx/onyxbot/slack/handlers/handle_message.py
index a848d83afe..84de8a3d4c 100644
--- a/backend/onyx/onyxbot/slack/handlers/handle_message.py
+++ b/backend/onyx/onyxbot/slack/handlers/handle_message.py
@@ -62,7 +62,7 @@ def schedule_feedback_reminder(
message_ts=details.msg_to_respond, # ty: ignore[invalid-argument-type]
)
except SlackApiError as e:
- logger.error(f"Unable to generate the feedback reminder permalink: {e}")
+ logger.error("Unable to generate the feedback reminder permalink: %s", e)
return None
now = datetime.datetime.now()
@@ -87,7 +87,7 @@ def schedule_feedback_reminder(
"scheduled_message_id"
]
except SlackApiError as e:
- logger.error(f"Unable to generate the feedback reminder message: {e}")
+ logger.error("Unable to generate the feedback reminder message: %s", e)
return None
@@ -165,9 +165,9 @@ def handle_message(
return False
logger.info(
- "Found slack bot config for channel. Restricting bot to use document "
- f"sets: {document_set_names}, "
- f"validity checks enabled: {channel_conf.get('answer_filters', 'NA')}"
+ "Found slack bot config for channel. Restricting bot to use document sets: %s, validity checks enabled: %s",
+ document_set_names,
+ channel_conf.get("answer_filters", "NA"),
)
respond_tag_only = channel_conf.get("respond_tag_only") or False
@@ -196,7 +196,7 @@ def handle_message(
send_to = list(set(send_to + user_ids)) if send_to else user_ids
if missing_users:
- logger.warning(f"Failed to find these users/groups: {missing_users}")
+ logger.warning("Failed to find these users/groups: %s", missing_users)
# If configured to respond to team members only, then cannot be used with a /OnyxBot command
# which would just respond to the sender
@@ -213,7 +213,7 @@ def handle_message(
try:
send_msg_ack_to_user(message_info, client)
except SlackApiError as e:
- logger.error(f"Was not able to react to user message due to: {e}")
+ logger.error("Was not able to react to user message due to: %s", e)
with get_session_with_current_tenant() as db_session:
if message_info.email:
@@ -229,7 +229,9 @@ def handle_message(
seat_result = check_seat_fn(db_session=db_session)
if seat_result is not None and not seat_result.available:
logger.info(
- f"Blocked new Slack user {message_info.email}: {seat_result.error_message}"
+ "Blocked new Slack user %s: %s",
+ message_info.email,
+ seat_result.error_message,
)
respond_in_thread_or_channel(
client=client,
@@ -257,7 +259,9 @@ def handle_message(
seat_result = check_seat_fn(db_session=db_session)
if seat_result is not None and not seat_result.available:
logger.info(
- f"Blocked inactive Slack user {message_info.email}: {seat_result.error_message}"
+ "Blocked inactive Slack user %s: %s",
+ message_info.email,
+ seat_result.error_message,
)
respond_in_thread_or_channel(
client=client,
@@ -280,7 +284,7 @@ def handle_message(
None,
)
invalidate_license_cache_fn()
- logger.info(f"Reactivated inactive Slack user {message_info.email}")
+ logger.info("Reactivated inactive Slack user %s", message_info.email)
add_slack_user_if_not_exists(db_session, message_info.email)
diff --git a/backend/onyx/onyxbot/slack/handlers/handle_regular_answer.py b/backend/onyx/onyxbot/slack/handlers/handle_regular_answer.py
index b9a5208318..73a9ddb3e4 100644
--- a/backend/onyx/onyxbot/slack/handlers/handle_regular_answer.py
+++ b/backend/onyx/onyxbot/slack/handlers/handle_regular_answer.py
@@ -68,7 +68,7 @@ def resolve_channel_references(
channel_info = get_channel_from_id(client=client, channel_id=channel_id)
channel_name = channel_info.get("name") or None
except Exception:
- logger.warning(f"Failed to resolve channel name for ID: {channel_id}")
+ logger.warning("Failed to resolve channel name for ID: %s", channel_id)
if not channel_name:
continue
@@ -197,7 +197,7 @@ def handle_regular_answer(
document_set.name for document_set in persona.document_sets
]
else:
- logger.info(f"Using persona {persona.name} for channel config")
+ logger.info("Using persona %s for channel config", persona.name)
document_set_names = [
document_set.name for document_set in persona.document_sets
]
@@ -306,7 +306,8 @@ def handle_regular_answer(
except Exception as e:
logger.exception(
- f"Unable to process message - did not successfully answer in {num_retries} attempts"
+ "Unable to process message - did not successfully answer in %s attempts",
+ num_retries,
)
# Optionally, respond in thread with the error message, Used primarily
# for debugging purposes
@@ -359,7 +360,7 @@ def handle_regular_answer(
and not channel_tags
):
logger.error(
- f"Unable to find citations to answer: '{answer.answer}' - not answering!"
+ "Unable to find citations to answer: '%s' - not answering!", answer.answer
)
# Optionally, respond in thread with the error message
# Used primarily for debugging purposes
@@ -434,6 +435,7 @@ def handle_regular_answer(
except Exception:
logger.exception(
- f"Unable to process message - could not respond in slack in {num_retries} attempts"
+ "Unable to process message - could not respond in slack in %s attempts",
+ num_retries,
)
return True
diff --git a/backend/onyx/onyxbot/slack/listener.py b/backend/onyx/onyxbot/slack/listener.py
index 57a038ca17..a897676f2c 100644
--- a/backend/onyx/onyxbot/slack/listener.py
+++ b/backend/onyx/onyxbot/slack/listener.py
@@ -147,7 +147,7 @@ class SlackbotHandler:
self._lock = threading.Lock()
- logger.info(f"Pod ID: {self.pod_id}")
+ logger.info("Pod ID: %s", self.pod_id)
# Set up signal handlers for graceful shutdown
signal.signal(signal.SIGTERM, self.shutdown)
@@ -184,10 +184,10 @@ class SlackbotHandler:
len(self.tenant_ids)
)
logger.debug(
- f"Current active tenants with Slack bots: {len(self.tenant_ids)}"
+ "Current active tenants with Slack bots: %s", len(self.tenant_ids)
)
except Exception as e:
- logger.exception(f"Error in Slack acquisition: {e}")
+ logger.exception("Error in Slack acquisition: %s", e)
self._shutdown_event.wait(timeout=TENANT_ACQUISITION_INTERVAL)
def heartbeat_loop(self) -> None:
@@ -202,9 +202,9 @@ class SlackbotHandler:
tenant_ids = self.tenant_ids.copy()
SlackbotHandler.send_heartbeats(self.pod_id, tenant_ids)
- logger.debug(f"Sent heartbeats for {len(tenant_ids)} active tenants")
+ logger.debug("Sent heartbeats for %s active tenants", len(tenant_ids))
except Exception as e:
- logger.exception(f"Error in heartbeat loop: {e}")
+ logger.exception("Error in heartbeat loop: %s", e)
self._shutdown_event.wait(timeout=TENANT_HEARTBEAT_INTERVAL)
def _manage_clients_per_tenant(
@@ -220,7 +220,7 @@ class SlackbotHandler:
# If the tokens are missing or empty, close the socket client and remove them.
if not bot.bot_token or not bot.app_token:
logger.debug(
- f"No Slack bot tokens found for tenant={tenant_id}, bot {bot.id}"
+ "No Slack bot tokens found for tenant=%s, bot %s", tenant_id, bot.id
)
if tenant_bot_pair in self.socket_clients:
self.socket_clients[tenant_bot_pair].close()
@@ -240,7 +240,9 @@ class SlackbotHandler:
if not tokens_exist or tokens_changed:
if tokens_exist:
logger.info(
- f"Slack Bot tokens changed for tenant={tenant_id}, bot {bot.id}; reconnecting"
+ "Slack Bot tokens changed for tenant=%s, bot %s; reconnecting",
+ tenant_id,
+ bot.id,
)
else:
# Warm up the model if needed
@@ -266,7 +268,10 @@ class SlackbotHandler:
self.socket_clients[tenant_id, bot.id] = socket_client
logger.info(
- f"Started SocketModeClient: {tenant_id=} {socket_client.bot_name=} {bot.id=}"
+ "Started SocketModeClient: tenant_id=%r socket_client.bot_name=%r bot.id=%r",
+ tenant_id,
+ socket_client.bot_name,
+ bot.id,
)
self.tenant_ids.add(tenant_id)
@@ -300,7 +305,7 @@ class SlackbotHandler:
DISALLOWED_SLACK_BOT_TENANT_LIST is not None
and tenant_id in DISALLOWED_SLACK_BOT_TENANT_LIST
):
- logger.debug(f"Tenant {tenant_id} is disallowed; skipping.")
+ logger.debug("Tenant %s is disallowed; skipping.", tenant_id)
continue
# Already acquired in a previous loop iteration?
@@ -310,7 +315,8 @@ class SlackbotHandler:
# Respect max tenant limit per pod
if len(self.tenant_ids) >= MAX_TENANTS_PER_POD:
logger.info(
- f"Max tenants per pod reached, not acquiring more: {MAX_TENANTS_PER_POD=}"
+ "Max tenants per pod reached, not acquiring more: MAX_TENANTS_PER_POD=%r",
+ MAX_TENANTS_PER_POD,
)
break
@@ -327,17 +333,17 @@ class SlackbotHandler:
if not lock_acquired and not DEV_MODE:
logger.debug(
- f"Another pod holds the lock for tenant {tenant_id}, skipping."
+ "Another pod holds the lock for tenant %s, skipping.", tenant_id
)
continue
if lock_acquired:
- logger.debug(f"Acquired lock for tenant {tenant_id}.")
+ logger.debug("Acquired lock for tenant %s.", tenant_id)
self.redis_locks[tenant_id] = rlock
else:
# DEV_MODE will skip the lock acquisition guard
logger.debug(
- f"Running in DEV_MODE. Not enforcing lock for {tenant_id}."
+ "Running in DEV_MODE. Not enforcing lock for %s.", tenant_id
)
# Now check if this tenant actually has Slack bots
@@ -358,16 +364,18 @@ class SlackbotHandler:
# migration has not completed yet.
if isinstance(e.orig, psycopg2.errors.UndefinedTable):
logger.warning(
- f"Tenant {tenant_id} missing slack_bot table "
- "(likely mid-provisioning); will retry next cycle."
+ "Tenant %s missing slack_bot table (likely mid-provisioning); will retry next cycle.",
+ tenant_id,
)
else:
logger.exception(
- f"Error fetching Slack bots for tenant {tenant_id}: {e}"
+ "Error fetching Slack bots for tenant %s: %s",
+ tenant_id,
+ e,
)
except Exception as e:
logger.exception(
- f"Error fetching Slack bots for tenant {tenant_id}: {e}"
+ "Error fetching Slack bots for tenant %s: %s", tenant_id, e
)
if bots:
@@ -385,7 +393,8 @@ class SlackbotHandler:
rlock.release()
del self.redis_locks[tenant_id]
logger.debug(
- f"No Slack bots for tenant {tenant_id}; lock released (if held)."
+ "No Slack bots for tenant %s; lock released (if held).",
+ tenant_id,
)
finally:
CURRENT_TENANT_ID_CONTEXTVAR.reset(token)
@@ -395,7 +404,7 @@ class SlackbotHandler:
for tenant_id in list(self.tenant_ids):
if tenant_id in gated_tenants:
logger.info(
- f"Tenant {tenant_id} is now gated (suspended). Disconnecting."
+ "Tenant %s is now gated (suspended). Disconnecting.", tenant_id
)
self._remove_tenant(tenant_id)
if tenant_id in self.redis_locks and not DEV_MODE:
@@ -406,7 +415,7 @@ class SlackbotHandler:
pass
except Exception as e:
logger.warning(
- f"Error releasing lock for gated tenant {tenant_id}: {e}"
+ "Error releasing lock for gated tenant %s: %s", tenant_id, e
)
finally:
self.redis_locks.pop(tenant_id, None)
@@ -428,19 +437,21 @@ class SlackbotHandler:
except ProgrammingError as e:
if isinstance(e.orig, psycopg2.errors.UndefinedTable):
logger.warning(
- f"Tenant {tenant_id} missing slack_bot table "
- "(likely mid-provisioning); will retry next cycle."
+ "Tenant %s missing slack_bot table (likely mid-provisioning); will retry next cycle.",
+ tenant_id,
)
else:
- logger.exception(f"Error handling tenant {tenant_id}: {e}")
+ logger.exception(
+ "Error handling tenant %s: %s", tenant_id, e
+ )
bots = []
except Exception as e:
- logger.exception(f"Error handling tenant {tenant_id}: {e}")
+ logger.exception("Error handling tenant %s: %s", tenant_id, e)
bots = []
if not bots:
logger.info(
- f"Tenant {tenant_id} no longer has Slack bots. Removing."
+ "Tenant %s no longer has Slack bots. Removing.", tenant_id
)
self._remove_tenant(tenant_id)
@@ -448,13 +459,15 @@ class SlackbotHandler:
if tenant_id in self.redis_locks and not DEV_MODE:
try:
self.redis_locks[tenant_id].release()
- logger.info(f"Released lock for tenant {tenant_id}")
+ logger.info("Released lock for tenant %s", tenant_id)
except LockNotOwnedError:
# Expected: lock expired or was stolen.
pass
except Exception as e:
logger.warning(
- f"Error releasing lock for tenant {tenant_id}: {e}"
+ "Error releasing lock for tenant %s: %s",
+ tenant_id,
+ e,
)
finally:
self.redis_locks.pop(tenant_id, None)
@@ -482,7 +495,9 @@ class SlackbotHandler:
del self.socket_clients[(t_id, slack_bot_id)]
del self.slack_bot_tokens[(t_id, slack_bot_id)]
logger.info(
- f"Stopped SocketModeClient for tenant: {t_id}, app: {slack_bot_id}"
+ "Stopped SocketModeClient for tenant: %s, app: %s",
+ t_id,
+ slack_bot_id,
)
# Remove from active set
@@ -492,7 +507,7 @@ class SlackbotHandler:
@staticmethod
def send_heartbeats(pod_id: str, tenant_ids: set[str]) -> None:
current_time = int(time.time())
- logger.debug(f"Sending heartbeats for {len(tenant_ids)} active tenants")
+ logger.debug("Sending heartbeats for %s active tenants", len(tenant_ids))
for tenant_id in tenant_ids:
redis_client = get_redis_client(tenant_id=tenant_id)
heartbeat_key = f"{OnyxRedisLocks.SLACK_BOT_HEARTBEAT_PREFIX}:{pod_id}"
@@ -537,18 +552,27 @@ class SlackbotHandler:
)
):
logger.warning(
- f"Slack auth failed, skipping bot: {tenant_id=} {slack_bot_id=} error={e}"
+ "Slack auth failed, skipping bot: tenant_id=%r slack_bot_id=%r error=%s",
+ tenant_id,
+ slack_bot_id,
+ e,
)
return None
# Log other Slack API errors but continue
logger.error(
- f"Slack API error fetching bot info: {e} for tenant: {tenant_id}, app: {slack_bot_id}"
+ "Slack API error fetching bot info: %s for tenant: %s, app: %s",
+ e,
+ tenant_id,
+ slack_bot_id,
)
except Exception as e:
# Log other exceptions but continue
logger.error(
- f"Error fetching bot info: {e} for tenant: {tenant_id}, app: {slack_bot_id}"
+ "Error fetching bot info: %s for tenant: %s, app: %s",
+ e,
+ tenant_id,
+ slack_bot_id,
)
# Append the event handler
@@ -567,7 +591,10 @@ class SlackbotHandler:
socket_client.connect()
except SlackApiError as e:
logger.warning(
- f"Failed to open Slack socket connection: {tenant_id=} {slack_bot_id=} error={e}"
+ "Failed to open Slack socket connection: tenant_id=%r slack_bot_id=%r error=%s",
+ tenant_id,
+ slack_bot_id,
+ e,
)
return None
@@ -585,7 +612,12 @@ class SlackbotHandler:
x += 1
client.close()
logger.info(
- f"Stopped SocketModeClient {x}/{length}: {pod_id=} {tenant_id=} {slack_bot_id=}"
+ "Stopped SocketModeClient %s/%s: pod_id=%r tenant_id=%r slack_bot_id=%r",
+ x,
+ length,
+ pod_id,
+ tenant_id,
+ slack_bot_id,
)
def shutdown(
@@ -605,21 +637,23 @@ class SlackbotHandler:
self.heartbeat_thread.join(timeout=60.0)
# Stop all socket clients
- logger.info(f"Stopping {len(self.socket_clients)} socket clients")
+ logger.info("Stopping %s socket clients", len(self.socket_clients))
SlackbotHandler.stop_socket_clients(self.pod_id, self.socket_clients)
# Release locks for all tenants we currently hold
- logger.info(f"Releasing locks for {len(self.tenant_ids)} tenants")
+ logger.info("Releasing locks for %s tenants", len(self.tenant_ids))
for tenant_id in list(self.tenant_ids):
if tenant_id in self.redis_locks:
try:
self.redis_locks[tenant_id].release()
- logger.info(f"Released lock for tenant {tenant_id}")
+ logger.info("Released lock for tenant %s", tenant_id)
except LockNotOwnedError:
# Expected during shutdown: lock expired or was stolen.
pass
except Exception as e:
- logger.warning(f"Error releasing lock for tenant {tenant_id}: {e}")
+ logger.warning(
+ "Error releasing lock for tenant %s: %s", tenant_id, e
+ )
finally:
del self.redis_locks[tenant_id]
@@ -655,7 +689,11 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
bot_token_user_id, bot_token_bot_id = get_onyx_bot_auth_ids(
tenant_id, client.web_client
)
- logger.info(f"prefilter_requests: {bot_token_user_id=} {bot_token_bot_id=}")
+ logger.info(
+ "prefilter_requests: bot_token_user_id=%r bot_token_bot_id=%r",
+ bot_token_user_id,
+ bot_token_bot_id,
+ )
with get_session_with_current_tenant() as db_session:
slack_bot = fetch_slack_bot(
@@ -663,13 +701,15 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
)
if not slack_bot:
logger.error(
- f"Slack bot with ID '{client.slack_bot_id}' not found. Skipping request."
+ "Slack bot with ID '%s' not found. Skipping request.",
+ client.slack_bot_id,
)
return False
if not slack_bot.enabled:
logger.info(
- f"Slack bot with ID '{client.slack_bot_id}' is disabled. Skipping request."
+ "Slack bot with ID '%s' is disabled. Skipping request.",
+ client.slack_bot_id,
)
return False
@@ -707,10 +747,10 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
in _SLACK_GREETINGS_TO_IGNORE
):
channel_specific_logger.error(
- f"Ignoring weird Slack greeting message: '{msg}'"
+ "Ignoring weird Slack greeting message: '%s'", msg
)
channel_specific_logger.error(
- f"Weird Slack greeting message payload: '{req.payload}'"
+ "Weird Slack greeting message payload: '%s'", req.payload
)
return False
@@ -783,7 +823,8 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
message_subtype = event.get("subtype")
if message_subtype not in [None, "file_share", "bot_message"]:
channel_specific_logger.info(
- f"Ignoring message with subtype '{message_subtype}' since it is a special message type"
+ "Ignoring message with subtype '%s' since it is a special message type",
+ message_subtype,
)
return False
@@ -830,7 +871,9 @@ def prefilter_requests(req: SocketModeRequest, client: TenantSocketModeClient) -
# Don't log Slack message content
logger.debug(
- f"Handling Slack request: {client.bot_name=} '{sanitize_slack_payload(req.payload)=}'"
+ "Handling Slack request: client.bot_name=%r 'sanitize_slack_payload(req.payload)=%r'",
+ client.bot_name,
+ sanitize_slack_payload(req.payload),
)
return True
@@ -864,7 +907,7 @@ def process_feedback(req: SocketModeRequest, client: TenantSocketModeClient) ->
)
query_event_id, _, _ = decompose_action_id(feedback_id)
- logger.info(f"Successfully handled QA feedback for event: {query_event_id}")
+ logger.info("Successfully handled QA feedback for event: %s", query_event_id)
def build_request_details(
@@ -890,7 +933,7 @@ def build_request_details(
msg = remove_onyx_bot_tag(tenant_id, msg, client=client.web_client)
- logger.info(f"Received Slack message: {msg}")
+ logger.info("Received Slack message: %s", msg)
event_type = event.get("type")
if event_type == "app_mention":
@@ -915,8 +958,10 @@ def build_request_details(
message_ts=message_ts,
)
logger.info(
- f"build_request_details: Capturing Slack context: "
- f"channel_type={channel_type} channel_id={channel} message_ts={message_ts}"
+ "build_request_details: Capturing Slack context: channel_type=%s channel_id=%s message_ts=%s",
+ channel_type,
+ channel,
+ message_ts,
)
if thread_ts != message_ts and thread_ts is not None:
@@ -977,7 +1022,9 @@ def build_request_details(
message_ts=None, # Slash commands don't have a message timestamp
)
logger.info(
- f"build_request_details: Capturing Slack context for slash command: channel_type={channel_type} channel_id={channel}"
+ "build_request_details: Capturing Slack context for slash command: channel_type=%s channel_id=%s",
+ channel_type,
+ channel,
)
single_msg = ThreadMessage(message=msg, sender=None, role=MessageType.USER)
@@ -1020,17 +1067,27 @@ def process_message(
event = cast(dict[str, Any], req.payload["event"])
event_type = event.get("type")
logger.info(
- f"process_message start: {tenant_id=} {req.type=} {req.envelope_id=} {event_type=}"
+ "process_message start: tenant_id=%r req.type=%r req.envelope_id=%r event_type=%r",
+ tenant_id,
+ req.type,
+ req.envelope_id,
+ event_type,
)
else:
logger.info(
- f"process_message start: {tenant_id=} {req.type=} {req.envelope_id=}"
+ "process_message start: tenant_id=%r req.type=%r req.envelope_id=%r",
+ tenant_id,
+ req.type,
+ req.envelope_id,
)
# Throw out requests that can't or shouldn't be handled
if not prefilter_requests(req, client):
logger.info(
- f"process_message prefiltered: {tenant_id=} {req.type=} {req.envelope_id=}"
+ "process_message prefiltered: tenant_id=%r req.type=%r req.envelope_id=%r",
+ tenant_id,
+ req.type,
+ req.envelope_id,
)
return
@@ -1075,7 +1132,11 @@ def process_message(
apologize_for_fail(details, client)
logger.info(
- f"process_message finished: success={not failed} {tenant_id=} {req.type=} {req.envelope_id=}"
+ "process_message finished: success=%s tenant_id=%r req.type=%r req.envelope_id=%r",
+ not failed,
+ tenant_id,
+ req.type,
+ req.envelope_id,
)
@@ -1185,7 +1246,7 @@ def _check_tenant_gated(client: TenantSocketModeClient, req: SocketModeRequest)
"Your organization's subscription has expired. Please contact your Onyx administrator to restore access."
),
)
- logger.info(f"Blocked Slack request for gated tenant {get_current_tenant_id()}")
+ logger.info("Blocked Slack request for gated tenant %s", get_current_tenant_id())
return True
diff --git a/backend/onyx/onyxbot/slack/utils.py b/backend/onyx/onyxbot/slack/utils.py
index 1a9f50f467..ff94132cc0 100644
--- a/backend/onyx/onyxbot/slack/utils.py
+++ b/backend/onyx/onyxbot/slack/utils.py
@@ -95,15 +95,18 @@ def get_channel_type_from_id(web_client: WebClient, channel_id: str) -> ChannelT
return ChannelType.PUBLIC_CHANNEL # Public channel
else:
logger.warning(
- f"Could not determine channel type for {channel_id}, defaulting to unknown"
+ "Could not determine channel type for %s, defaulting to unknown",
+ channel_id,
)
return ChannelType.UNKNOWN
else:
- logger.warning(f"Invalid channel info response for {channel_id}")
+ logger.warning("Invalid channel info response for %s", channel_id)
return ChannelType.UNKNOWN
except Exception as e:
logger.warning(
- f"Error getting channel info for {channel_id}, defaulting to unknown: {e}"
+ "Error getting channel info for %s, defaulting to unknown: %s",
+ channel_id,
+ e,
)
return ChannelType.UNKNOWN
@@ -124,9 +127,11 @@ def check_message_limit() -> bool:
_ONYX_BOT_COUNT_START_TIME = time.time()
if (_ONYX_BOT_MESSAGE_COUNT + 1) > ONYX_BOT_RESPONSE_LIMIT_PER_TIME_PERIOD:
logger.error(
- f"OnyxBot has reached the message limit {ONYX_BOT_RESPONSE_LIMIT_PER_TIME_PERIOD}"
- f" for the time period {ONYX_BOT_RESPONSE_LIMIT_TIME_PERIOD_SECONDS} seconds."
- " These limits are configurable in backend/onyx/configs/onyxbot_configs.py"
+ "OnyxBot has reached the message limit %s"
+ " for the time period %s seconds."
+ " These limits are configurable in backend/onyx/configs/onyxbot_configs.py",
+ ONYX_BOT_RESPONSE_LIMIT_PER_TIME_PERIOD,
+ ONYX_BOT_RESPONSE_LIMIT_TIME_PERIOD_SECONDS,
)
return False
_ONYX_BOT_MESSAGE_COUNT += 1
@@ -142,7 +147,11 @@ def update_emote_react(
) -> None:
if not message_ts:
action = "remove" if remove else "add"
- logger.error(f"update_emote_react - no message specified: {channel=} {action=}")
+ logger.error(
+ "update_emote_react - no message specified: channel=%s action=%s",
+ channel,
+ action,
+ )
return
if remove:
@@ -153,7 +162,7 @@ def update_emote_react(
timestamp=message_ts,
)
except SlackApiError as e:
- logger.error(f"Failed to remove Reaction due to: {e}")
+ logger.error("Failed to remove Reaction due to: %s", e)
return
@@ -164,7 +173,7 @@ def update_emote_react(
timestamp=message_ts,
)
except SlackApiError as e:
- logger.error(f"Was not able to react to user message due to: {e}")
+ logger.error("Was not able to react to user message due to: %s", e)
return
@@ -242,7 +251,7 @@ def respond_in_thread_or_channel(
)
except Exception as e:
blocks_str = str(blocks)[:1024] # truncate block logging
- logger.warning(f"Failed to post message: {e} \n blocks: {blocks_str}")
+ logger.warning("Failed to post message: %s \n blocks: %s", e, blocks_str)
logger.warning("Trying again without blocks that have urls")
if not blocks:
@@ -280,7 +289,9 @@ def respond_in_thread_or_channel(
)
except Exception as e:
blocks_str = str(blocks)[:1024] # truncate block logging
- logger.warning(f"Failed to post message: {e} \n blocks: {blocks_str}")
+ logger.warning(
+ "Failed to post message: %s \n blocks: %s", e, blocks_str
+ )
logger.warning("Trying again without blocks that have urls")
if not blocks:
@@ -435,7 +446,7 @@ def get_channel_name_from_id(
is_dm = any([channel_info.get("is_im"), channel_info.get("is_mpim")])
return name, is_dm
except SlackApiError as e:
- logger.exception(f"Couldn't fetch channel name from id: {channel_id}")
+ logger.exception("Couldn't fetch channel name from id: %s", channel_id)
raise e
@@ -451,7 +462,7 @@ def fetch_slack_user_ids_from_emails(
user.data["user"]["id"] # ty: ignore[invalid-argument-type]
)
except Exception:
- logger.error(f"Was not able to find slack user by email: {email}")
+ logger.error("Was not able to find slack user by email: %s", email)
failed_to_find.append(email)
return user_ids, failed_to_find
@@ -485,10 +496,10 @@ def fetch_user_ids_from_groups(
else:
failed_to_find.append(given_name)
except Exception as e:
- logger.error(f"Error fetching user group ids: {str(e)}")
+ logger.error("Error fetching user group ids: %s", e)
failed_to_find.append(given_name)
except Exception as e:
- logger.error(f"Error fetching user groups: {str(e)}")
+ logger.error("Error fetching user groups: %s", e)
failed_to_find = given_names
return user_ids, failed_to_find
@@ -520,7 +531,7 @@ def fetch_group_ids_from_names(
failed_to_find.append(given_name)
except Exception as e:
failed_to_find = given_names
- logger.error(f"Error fetching user groups: {str(e)}")
+ logger.error("Error fetching user groups: %s", e)
return group_data, failed_to_find
@@ -584,7 +595,7 @@ def read_slack_thread(
# auto-detected filters
blocks = reply.get("blocks")
if not blocks:
- logger.warning(f"OnyxBot response has no blocks: {reply}")
+ logger.warning("OnyxBot response has no blocks: %s", reply)
continue
message = blocks[0].get("text", {}).get("text")
@@ -593,7 +604,7 @@ def read_slack_thread(
# The first block is the auto-detected filters
if message is not None and message.startswith("_Filters"):
if len(blocks) < 2:
- logger.warning(f"Only filter blocks found: {reply}")
+ logger.warning("Only filter blocks found: %s", reply)
continue
# This is the OnyxBot answer format, if there is a change to how we respond,
# this will need to be updated to get the correct "answer" portion
diff --git a/backend/onyx/prompts/prompt_utils.py b/backend/onyx/prompts/prompt_utils.py
index 891a409252..0cc65f0f23 100644
--- a/backend/onyx/prompts/prompt_utils.py
+++ b/backend/onyx/prompts/prompt_utils.py
@@ -157,7 +157,7 @@ def get_company_context() -> str | None:
)
return prompt_str
except Exception as e:
- logger.error(f"Error handling company awareness: {e}")
+ logger.error("Error handling company awareness: %s", e)
return None
@@ -226,7 +226,9 @@ def find_last_index(lst: list[int], max_prompt_tokens: int) -> int:
if last_ind >= len(lst):
logger.error(
- f"Last message alone is too large! max_prompt_tokens: {max_prompt_tokens}, message_token_counts: {lst}"
+ "Last message alone is too large! max_prompt_tokens: %s, message_token_counts: %s",
+ max_prompt_tokens,
+ lst,
)
raise ValueError("Last message alone is too large!")
diff --git a/backend/onyx/redis/lock_context.py b/backend/onyx/redis/lock_context.py
index 33f1f91141..9da79dde66 100644
--- a/backend/onyx/redis/lock_context.py
+++ b/backend/onyx/redis/lock_context.py
@@ -69,9 +69,13 @@ def redis_shared_lock(
if lock.owned():
lock.release()
logger.debug(
- f"Redis lock {lock_name} released after {time.monotonic() - start_time:.3f} seconds."
+ "Redis lock %s released after %s seconds.",
+ lock_name,
+ format(time.monotonic() - start_time, ".3f"),
)
else:
logger.warning(
- f"Redis lock {lock_name} was not owned on exit. The lock context manager took {time.monotonic() - start_time:.3f} seconds."
+ "Redis lock %s was not owned on exit. The lock context manager took %s seconds.",
+ lock_name,
+ format(time.monotonic() - start_time, ".3f"),
)
diff --git a/backend/onyx/redis/redis_connector_doc_perm_sync.py b/backend/onyx/redis/redis_connector_doc_perm_sync.py
index 9e6c1dd87a..4d5b3052f7 100644
--- a/backend/onyx/redis/redis_connector_doc_perm_sync.py
+++ b/backend/onyx/redis/redis_connector_doc_perm_sync.py
@@ -216,10 +216,14 @@ class RedisConnectorPermissionSync:
else permissions.raw_node_id
)
task_logger.warning(
- f"Permissions length exceeded, skipping...: "
- f"{element_id} "
- f"{num_users=} {num_groups=} "
- f"{permissions.external_access.MAX_NUM_ENTRIES=}"
+ "Permissions length exceeded, skipping...: "
+ "%s "
+ "num_users=%s num_groups=%s "
+ "permissions.external_access.MAX_NUM_ENTRIES=%s",
+ element_id,
+ num_users,
+ num_groups,
+ permissions.external_access.MAX_NUM_ENTRIES,
)
continue
@@ -251,7 +255,7 @@ class RedisConnectorPermissionSync:
else permissions.raw_node_id
)
task_logger.exception(
- f"Failed to update permissions for element {element_id}"
+ "Failed to update permissions for element %s", element_id
)
finally:
cumulative_db_update_time += time.monotonic() - db_start
diff --git a/backend/onyx/redis/redis_hierarchy.py b/backend/onyx/redis/redis_hierarchy.py
index 446d43bfbd..c6708b5765 100644
--- a/backend/onyx/redis/redis_hierarchy.py
+++ b/backend/onyx/redis/redis_hierarchy.py
@@ -328,7 +328,8 @@ def refresh_hierarchy_cache_from_db(
acquired = lock.acquire(blocking=True)
if not acquired:
logger.warning(
- f"Could not acquire lock for hierarchy cache refresh for source {source.value} - another worker may be refreshing"
+ "Could not acquire lock for hierarchy cache refresh for source %s - another worker may be refreshing",
+ source.value,
)
return
@@ -336,13 +337,13 @@ def refresh_hierarchy_cache_from_db(
# Always refresh from DB when called - new nodes may have been added
# since the cache was last populated. The lock ensures only one worker
# does the refresh at a time.
- logger.info(f"Refreshing hierarchy cache for source {source.value} from DB")
+ logger.info("Refreshing hierarchy cache for source %s from DB", source.value)
# Load all nodes for this source from DB
nodes = get_all_hierarchy_nodes_for_source(db_session, source)
if not nodes:
- logger.warning(f"No hierarchy nodes found in DB for source {source.value}")
+ logger.warning("No hierarchy nodes found in DB for source %s", source.value)
return
# Batch insert into cache
@@ -350,14 +351,14 @@ def refresh_hierarchy_cache_from_db(
cache_hierarchy_nodes_batch(redis_client, source, cache_entries)
logger.info(
- f"Refreshed hierarchy cache for {source.value} with {len(nodes)} nodes"
+ "Refreshed hierarchy cache for %s with %s nodes", source.value, len(nodes)
)
finally:
try:
lock.release()
except Exception as e:
- logger.warning(f"Error releasing hierarchy cache lock: {e}")
+ logger.warning("Error releasing hierarchy cache lock: %s", e)
def _walk_ancestor_chain(
@@ -379,7 +380,10 @@ def _walk_ancestor_chain(
while current_id is not None and len(ancestors) < MAX_DEPTH:
if current_id in visited:
logger.error(
- f"Cycle detected in hierarchy for source {source.value} at node {current_id}. Ancestors so far: {ancestors}"
+ "Cycle detected in hierarchy for source %s at node %s. Ancestors so far: %s",
+ source.value,
+ current_id,
+ ancestors,
)
break
@@ -390,7 +394,9 @@ def _walk_ancestor_chain(
if not found:
logger.debug(
- f"Cache miss for hierarchy node {current_id} of source {source.value}, attempting refresh"
+ "Cache miss for hierarchy node %s of source %s, attempting refresh",
+ current_id,
+ source.value,
)
refresh_hierarchy_cache_from_db(redis_client, db_session, source)
parent_id, found = get_parent_id_from_cache(
@@ -399,7 +405,9 @@ def _walk_ancestor_chain(
if not found:
logger.error(
- f"Hierarchy node {current_id} not found in cache for source {source.value} even after refresh."
+ "Hierarchy node %s not found in cache for source %s even after refresh.",
+ current_id,
+ source.value,
)
break
@@ -407,8 +415,9 @@ def _walk_ancestor_chain(
if len(ancestors) >= MAX_DEPTH:
logger.error(
- f"Hit max depth {MAX_DEPTH} traversing hierarchy for source "
- f"{source.value}. Possible infinite loop or very deep hierarchy."
+ "Hit max depth %s traversing hierarchy for source %s. Possible infinite loop or very deep hierarchy.",
+ MAX_DEPTH,
+ source.value,
)
return ancestors
@@ -452,7 +461,9 @@ def get_ancestors_from_raw_id(
if not found:
# Cache miss - try refresh
logger.debug(
- f"Cache miss for raw_node_id '{parent_hierarchy_raw_node_id}' of source {source.value}, attempting refresh"
+ "Cache miss for raw_node_id '%s' of source %s, attempting refresh",
+ parent_hierarchy_raw_node_id,
+ source.value,
)
refresh_hierarchy_cache_from_db(redis_client, db_session, source)
node_id, found = get_node_id_from_raw_id(
@@ -461,8 +472,9 @@ def get_ancestors_from_raw_id(
if not found or node_id is None:
logger.error(
- f"Raw node ID '{parent_hierarchy_raw_node_id}' not found in cache "
- f"for source {source.value}. Falling back to SOURCE node only."
+ "Raw node ID '%s' not found in cache for source %s. Falling back to SOURCE node only.",
+ parent_hierarchy_raw_node_id,
+ source.value,
)
source_node_id = get_source_node_id_from_cache(redis_client, db_session, source)
return [source_node_id] if source_node_id else []
@@ -507,7 +519,7 @@ def get_source_node_id_from_cache(
raise ValueError(f"SOURCE node value is not a string: {value}")
return int(value)
- logger.error(f"SOURCE node not found for source {source.value}")
+ logger.error("SOURCE node not found for source %s", source.value)
return None
@@ -568,7 +580,9 @@ def ensure_source_node_exists(
cache_hierarchy_node(redis_client, source, cache_entry)
logger.info(
- f"Ensured SOURCE node exists and cached for {source.value}: id={source_node.id}"
+ "Ensured SOURCE node exists and cached for %s: id=%s",
+ source.value,
+ source_node.id,
)
return source_node.id
diff --git a/backend/onyx/redis/redis_pool.py b/backend/onyx/redis/redis_pool.py
index 506341dfa2..d174ac2f48 100644
--- a/backend/onyx/redis/redis_pool.py
+++ b/backend/onyx/redis/redis_pool.py
@@ -468,7 +468,7 @@ async def retrieve_auth_token_data(token: str) -> dict | None:
token_data_str = await redis.get(redis_key)
if not token_data_str:
- logger.debug(f"Token key {redis_key} not found or expired in Redis")
+ logger.debug("Token key %s not found or expired in Redis", redis_key)
return None
return json.loads(token_data_str)
@@ -476,7 +476,7 @@ async def retrieve_auth_token_data(token: str) -> dict | None:
logger.error("Error decoding token data from Redis")
return None
except Exception as e:
- logger.error(f"Unexpected error in retrieve_auth_token_data: {str(e)}")
+ logger.error("Unexpected error in retrieve_auth_token_data: %s", str(e))
raise ValueError(f"Unexpected error in retrieve_auth_token_data: {str(e)}")
@@ -526,7 +526,7 @@ async def store_ws_token(token: str, user_id: str) -> None:
if new_count > WS_TOKEN_RATE_LIMIT_MAX:
# Over limit — decrement back since we won't use this slot
await redis.decr(rate_limit_key)
- logger.warning(f"WS token rate limit exceeded for user {user_id}")
+ logger.warning("WS token rate limit exceeded for user %s", user_id)
raise WsTokenRateLimitExceeded(
f"Rate limit exceeded. Maximum {WS_TOKEN_RATE_LIMIT_MAX} tokens per minute."
)
@@ -564,7 +564,7 @@ async def retrieve_ws_token_data(token: str) -> dict | None:
logger.error("Error decoding WS token data from Redis")
return None
except Exception as e:
- logger.error(f"Unexpected error in retrieve_ws_token_data: {str(e)}")
+ logger.error("Unexpected error in retrieve_ws_token_data: %s", str(e))
return None
@@ -584,11 +584,11 @@ def redis_lock_dump(lock: RedisLock, r: Redis) -> None:
remote_token = None
logger.warning(
- f"RedisLock diagnostic: "
- f"name={name} "
- f"locked={locked} "
- f"owned={owned} "
- f"local_token={local_token} "
- f"remote_token={remote_token} "
- f"ttl={ttl}"
+ "RedisLock diagnostic: name=%s locked=%s owned=%s local_token=%s remote_token=%s ttl=%s",
+ name,
+ locked,
+ owned,
+ local_token,
+ remote_token,
+ ttl,
)
diff --git a/backend/onyx/redis/redis_tenant_work_gating.py b/backend/onyx/redis/redis_tenant_work_gating.py
index fdeef945a2..e018f6aeb2 100644
--- a/backend/onyx/redis/redis_tenant_work_gating.py
+++ b/backend/onyx/redis/redis_tenant_work_gating.py
@@ -87,7 +87,7 @@ def mark_tenant_active(tenant_id: str) -> None:
# existing members, which is exactly the refresh semantics we want.
_client().zadd(_SET_KEY, mapping={tenant_id: _now_ms()})
except Exception:
- logger.exception(f"mark_tenant_active failed: tenant_id={tenant_id}")
+ logger.exception("mark_tenant_active failed: tenant_id=%s", tenant_id)
def maybe_mark_tenant_active(tenant_id: str, caller: str = "unknown") -> None:
@@ -109,7 +109,7 @@ def maybe_mark_tenant_active(tenant_id: str, caller: str = "unknown") -> None:
mark_tenant_active(tenant_id)
_marked_total.labels(caller=caller).inc()
except Exception:
- logger.exception(f"maybe_mark_tenant_active failed: tenant_id={tenant_id}")
+ logger.exception("maybe_mark_tenant_active failed: tenant_id=%s", tenant_id)
def observe_active_set_size() -> int | None:
diff --git a/backend/onyx/secondary_llm_flows/document_filter.py b/backend/onyx/secondary_llm_flows/document_filter.py
index d4b3b71d57..1b42787f12 100644
--- a/backend/onyx/secondary_llm_flows/document_filter.py
+++ b/backend/onyx/secondary_llm_flows/document_filter.py
@@ -159,12 +159,13 @@ def classify_section_relevance(
)
else:
logger.warning(
- f"Could not parse situation number from LLM response: {llm_response}"
+ "Could not parse situation number from LLM response: %s",
+ llm_response,
)
classification = default_classification
except Exception as e:
- logger.error(f"Error calling LLM for context selection: {e}")
+ logger.error("Error calling LLM for context selection: %s", e)
classification = default_classification
# To save some effort down the line, if there is nothing surrounding, don't allow a classification of adjacent or whole doc
@@ -354,7 +355,7 @@ def select_sections_for_expansion(
if not section_ids:
logger.warning(
- f"Could not parse section IDs from LLM response: {llm_response}"
+ "Could not parse section IDs from LLM response: %s", llm_response
)
return sections[:max_sections], None
@@ -369,13 +370,17 @@ def select_sections_for_expansion(
try:
section_id_int = int(section_id_str)
except ValueError:
- logger.warning(f"Could not convert section ID to int: {section_id_str}")
+ logger.warning(
+ "Could not convert section ID to int: %s", section_id_str
+ )
continue
# Check if in valid range
if section_id_int < 0 or section_id_int >= num_sections:
logger.warning(
- f"Section ID {section_id_int} is out of range [0, {num_sections - 1}], skipping"
+ "Section ID %s is out of range [0, %s], skipping",
+ section_id_int,
+ num_sections - 1,
)
continue
@@ -407,9 +412,11 @@ def select_sections_for_expansion(
]
logger.debug(
- f"LLM selected {len(selected_sections)} valid sections from {len(sections)} total candidates. "
- f"Selected document IDs: {selected_document_ids}. "
- f"Document IDs with exclamation: {document_ids_with_exclamation if document_ids_with_exclamation else []}"
+ "LLM selected %s valid sections from %s total candidates. Selected document IDs: %s. Document IDs with exclamation: %s",
+ len(selected_sections),
+ len(sections),
+ selected_document_ids,
+ document_ids_with_exclamation if document_ids_with_exclamation else [],
)
# Return document_ids if any sections had exclamation marks, otherwise None
@@ -418,5 +425,5 @@ def select_sections_for_expansion(
)
except Exception as e:
- logger.error(f"Error calling LLM for document selection: {e}")
+ logger.error("Error calling LLM for document selection: %s", e)
return sections[:max_sections], None
diff --git a/backend/onyx/secondary_llm_flows/memory_update.py b/backend/onyx/secondary_llm_flows/memory_update.py
index 6b88ee1fa3..94a67b3f0b 100644
--- a/backend/onyx/secondary_llm_flows/memory_update.py
+++ b/backend/onyx/secondary_llm_flows/memory_update.py
@@ -127,7 +127,7 @@ def process_memory_update(
record_llm_response(span_generation, response)
content = response.choice.message.content
except Exception as e:
- logger.warning(f"LLM invocation failed for memory update: {e}")
+ logger.warning("LLM invocation failed for memory update: %s", e)
return (new_memory, None)
# Handle empty response
@@ -142,7 +142,8 @@ def process_memory_update(
if not parsed_response:
logger.warning(
- f"Failed to parse JSON from LLM response: {content[:200]}..., defaulting to add"
+ "Failed to parse JSON from LLM response: %s..., defaulting to add",
+ content[:200],
)
return (new_memory, None)
@@ -171,7 +172,7 @@ def process_memory_update(
try:
memory_id_int = int(memory_id)
except (ValueError, TypeError):
- logger.warning(f"Invalid memory_id format: {memory_id}")
+ logger.warning("Invalid memory_id format: %s", memory_id)
return (memory_text, None)
# Convert from 1-indexed (LLM response) to 0-indexed (internal)
@@ -180,13 +181,15 @@ def process_memory_update(
# Validate index is in range
if index_to_replace < 0 or index_to_replace >= len(existing_memories):
logger.warning(
- f"memory_id {memory_id_int} out of range (1-{len(existing_memories)}), defaulting to add"
+ "memory_id %s out of range (1-%s), defaulting to add",
+ memory_id_int,
+ len(existing_memories),
)
return (memory_text, None)
- logger.debug(f"Memory update operation: update at index {index_to_replace}")
+ logger.debug("Memory update operation: update at index %s", index_to_replace)
return (memory_text, index_to_replace)
# Unknown operation, default to add
- logger.warning(f"Unknown operation '{operation}', defaulting to add")
+ logger.warning("Unknown operation '%s', defaulting to add", operation)
return (memory_text, None)
diff --git a/backend/onyx/secondary_llm_flows/source_filter.py b/backend/onyx/secondary_llm_flows/source_filter.py
index 5658cb2426..9f338181a3 100644
--- a/backend/onyx/secondary_llm_flows/source_filter.py
+++ b/backend/onyx/secondary_llm_flows/source_filter.py
@@ -13,7 +13,7 @@ def strings_to_document_sources(source_strs: list[str]) -> list[DocumentSource]:
try:
sources.append(DocumentSource(s))
except ValueError:
- logger.warning(f"Failed to translate {s} to a DocumentSource")
+ logger.warning("Failed to translate %s to a DocumentSource", s)
return sources
diff --git a/backend/onyx/server/auth/captcha_api.py b/backend/onyx/server/auth/captcha_api.py
index 57c1185120..12ca2b3897 100644
--- a/backend/onyx/server/auth/captcha_api.py
+++ b/backend/onyx/server/auth/captcha_api.py
@@ -174,7 +174,8 @@ class LoginCaptchaMiddleware(BaseHTTPMiddleware):
):
if _health_check_bypass_ok(request):
logger.info(
- f"Login captcha bypassed via health-check token client={_client_ip_for_log(request)}"
+ "Login captcha bypassed via health-check token client=%s",
+ _client_ip_for_log(request),
)
else:
token = request.headers.get(LOGIN_CAPTCHA_HEADER, "")
diff --git a/backend/onyx/server/documents/cc_pair.py b/backend/onyx/server/documents/cc_pair.py
index 992de00ed1..062e6ffd52 100644
--- a/backend/onyx/server/documents/cc_pair.py
+++ b/backend/onyx/server/documents/cc_pair.py
@@ -350,12 +350,13 @@ def update_cc_pair_status(
if attempt.celery_task_id:
client_app.control.revoke(attempt.celery_task_id)
logger.info(
- f"Requested cancellation for active indexing attempt {attempt.id} "
- f"due to connector pause: cc_pair={cc_pair_id}"
+ "Requested cancellation for active indexing attempt %s due to connector pause: cc_pair=%s",
+ attempt.id,
+ cc_pair_id,
)
except Exception:
logger.exception(
- f"Failed to request cancellation for indexing attempt {attempt.id}"
+ "Failed to request cancellation for indexing attempt %s", attempt.id
)
else:
@@ -502,10 +503,11 @@ def prune_cc_pair(
)
logger.info(
- f"Pruning cc_pair: cc_pair={cc_pair_id} "
- f"connector={cc_pair.connector_id} "
- f"credential={cc_pair.credential_id} "
- f"{cc_pair.connector.name} connector."
+ "Pruning cc_pair: cc_pair=%s connector=%s credential=%s %s connector.",
+ cc_pair_id,
+ cc_pair.connector_id,
+ cc_pair.credential_id,
+ cc_pair.connector.name,
)
payload_id = try_creating_prune_generator_task(
client_app, cc_pair, db_session, r, tenant_id
@@ -516,7 +518,7 @@ def prune_cc_pair(
detail="Pruning task creation failed.",
)
- logger.info(f"Pruning queued: cc_pair={cc_pair.id} id={payload_id}")
+ logger.info("Pruning queued: cc_pair=%s id=%s", cc_pair.id, payload_id)
return StatusResponse(
success=True,
@@ -635,7 +637,8 @@ def associate_credential_to_connector(
)
logger.info(
- f"associate_credential_to_connector - running check_for_indexing: cc_pair={response.data}"
+ "associate_credential_to_connector - running check_for_indexing: cc_pair=%s",
+ response.data,
)
return response
@@ -651,14 +654,14 @@ def associate_credential_to_connector(
status_code=400, detail="Connector validation error: " + str(e)
)
except IntegrityError as e:
- logger.error(f"IntegrityError: {e}")
+ logger.error("IntegrityError: %s", e)
delete_connector(db_session, connector_id)
db_session.commit()
raise HTTPException(status_code=400, detail="Name must be unique")
except Exception as e:
- logger.exception(f"Unexpected error: {e}")
+ logger.exception("Unexpected error: %s", e)
raise HTTPException(status_code=500, detail="Unexpected error")
diff --git a/backend/onyx/server/documents/connector.py b/backend/onyx/server/documents/connector.py
index 241d2e5698..8a614e1329 100644
--- a/backend/onyx/server/documents/connector.py
+++ b/backend/onyx/server/documents/connector.py
@@ -426,7 +426,7 @@ def save_zip_metadata_to_file_store(
try:
json.loads(metadata_bytes)
except json.JSONDecodeError as e:
- logger.warning(f"Unable to load {ONYX_METADATA_FILENAME}: {e}")
+ logger.warning("Unable to load %s: %s", ONYX_METADATA_FILENAME, e)
raise HTTPException(
status_code=400,
detail=f"Unable to load {ONYX_METADATA_FILENAME}: {e}",
@@ -441,7 +441,7 @@ def save_zip_metadata_to_file_store(
)
return file_id
except KeyError:
- logger.info(f"No {ONYX_METADATA_FILENAME} file")
+ logger.info("No %s file", ONYX_METADATA_FILENAME)
return None
@@ -678,7 +678,7 @@ def list_connector_files(
)
)
except Exception as e:
- logger.warning(f"Error reading file record for {file_id}: {e}")
+ logger.warning("Error reading file record for %s: %s", file_id, e)
# Include file with basic info even if record fetch fails
files.append(
ConnectorFileInfo(
@@ -754,7 +754,7 @@ def update_connector_files(
else:
current_zip_metadata = loaded_metadata
except Exception as e:
- logger.warning(f"Failed to load existing metadata file: {e}")
+ logger.warning("Failed to load existing metadata file: %s", e)
raise HTTPException(
status_code=500,
detail="Failed to load existing connector metadata file",
@@ -785,7 +785,7 @@ def update_connector_files(
else:
new_zip_metadata = loaded_metadata
except Exception as e:
- logger.warning(f"Failed to load new metadata file: {e}")
+ logger.warning("Failed to load new metadata file: %s", e)
# Remove specified files
files_to_remove_set = set(file_ids_list)
@@ -878,7 +878,9 @@ def update_connector_files(
priority=OnyxCeleryPriority.HIGH,
)
logger.info(
- f"Marked cc_pair {cc_pair.id} for UPDATE indexing (new files) for connector {connector_id}"
+ "Marked cc_pair %s for UPDATE indexing (new files) for connector %s",
+ cc_pair.id,
+ connector_id,
)
# If files were removed, trigger pruning immediately
@@ -889,15 +891,19 @@ def update_connector_files(
)
if payload_id:
logger.info(
- f"Triggered pruning for cc_pair {cc_pair.id} (removed files) for connector "
- f"{connector_id}, payload_id={payload_id}"
+ "Triggered pruning for cc_pair %s (removed files) for connector %s, payload_id=%s",
+ cc_pair.id,
+ connector_id,
+ payload_id,
)
else:
logger.warning(
- f"Failed to trigger pruning for cc_pair {cc_pair.id} (removed files) for connector {connector_id}"
+ "Failed to trigger pruning for cc_pair %s (removed files) for connector %s",
+ cc_pair.id,
+ connector_id,
)
except Exception as e:
- logger.error(f"Failed to trigger re-indexing after file update: {e}")
+ logger.error("Failed to trigger re-indexing after file update: %s", e)
return FileUploadResponse(
file_paths=final_file_locations,
@@ -1560,7 +1566,7 @@ def create_connector_from_model(
return connector_response
except ValueError as e:
- logger.error(f"Error creating connector: {e}")
+ logger.error("Error creating connector: %s", e)
raise HTTPException(status_code=400, detail=str(e))
@@ -1631,7 +1637,8 @@ def create_connector_with_mock_credential(
)
logger.info(
- f"create_connector_with_mock_credential - running check_for_indexing: cc_pair={response.data}"
+ "create_connector_with_mock_credential - running check_for_indexing: cc_pair=%s",
+ response.data,
)
mt_cloud_telemetry(
@@ -1988,16 +1995,20 @@ Tenant ID: {tenant_id}
text_body=email_body_text,
)
logger.info(
- f"Connector request email sent to hello@onyx.app for connector: {connector_name}"
+ "Connector request email sent to hello@onyx.app for connector: %s",
+ connector_name,
)
except Exception as e:
# Log error but don't fail the request if email fails
logger.error(
- f"Failed to send connector request email for {connector_name}: {e}"
+ "Failed to send connector request email for %s: %s", connector_name, e
)
logger.info(
- f"Connector request submitted: {connector_name} by user {user_email or 'anonymous'} (tenant: {tenant_id})"
+ "Connector request submitted: %s by user %s (tenant: %s)",
+ connector_name,
+ user_email or "anonymous",
+ tenant_id,
)
return StatusResponse(
@@ -2100,16 +2111,16 @@ def trigger_indexing_for_cc_pair(
num_triggers += 1
logger.info(
- f"connector_run_once - marking cc_pair with indexing trigger: "
- f"connector={connector_id} "
- f"cc_pair={cc_pair.id} "
- f"indexing_trigger={indexing_mode}"
+ "connector_run_once - marking cc_pair with indexing trigger: connector=%s cc_pair=%s indexing_trigger=%s",
+ connector_id,
+ cc_pair.id,
+ indexing_mode,
)
priority = OnyxCeleryPriority.HIGH
# run the beat task to pick up the triggers immediately
- logger.info(f"Sending indexing check task with priority {priority}")
+ logger.info("Sending indexing check task with priority %s", priority)
client_app.send_task(
OnyxCeleryTask.CHECK_FOR_INDEXING,
priority=priority,
diff --git a/backend/onyx/server/documents/document_utils.py b/backend/onyx/server/documents/document_utils.py
index 168e87692c..292e945a62 100644
--- a/backend/onyx/server/documents/document_utils.py
+++ b/backend/onyx/server/documents/document_utils.py
@@ -43,12 +43,12 @@ def validate_pkcs12_content(file_bytes: bytes) -> bool:
if _is_password_related_error(e):
# These errors indicate the file format is correct but password is wrong/missing
logger.debug(
- f"PKCS#12 format appears valid, password-related error: {e}"
+ "PKCS#12 format appears valid, password-related error: %s", e
)
return True
else:
# Other ValueError likely indicates format issues
- logger.debug(f"PKCS#12 format validation failed: {e}")
+ logger.debug("PKCS#12 format validation failed: %s", e)
return False
except Exception as e:
# Try with empty password as fallback
@@ -58,18 +58,19 @@ def validate_pkcs12_content(file_bytes: bytes) -> bool:
except ValueError as e2:
if _is_password_related_error(e2):
logger.debug(
- f"PKCS#12 format appears valid with empty password attempt: {e2}"
+ "PKCS#12 format appears valid with empty password attempt: %s",
+ e2,
)
return True
else:
logger.debug(
- f"PKCS#12 validation failed on both attempts: {e}, {e2}"
+ "PKCS#12 validation failed on both attempts: %s, %s", e, e2
)
return False
except Exception:
- logger.debug(f"PKCS#12 validation failed: {e}")
+ logger.debug("PKCS#12 validation failed: %s", e)
return False
except Exception as e:
- logger.debug(f"Unexpected error during PKCS#12 validation: {e}")
+ logger.debug("Unexpected error during PKCS#12 validation: %s", e)
return False
diff --git a/backend/onyx/server/features/build/api/api.py b/backend/onyx/server/features/build/api/api.py
index 1a571aefe5..b845637a2b 100644
--- a/backend/onyx/server/features/build/api/api.py
+++ b/backend/onyx/server/features/build/api/api.py
@@ -391,7 +391,7 @@ def _proxy_request(
if request.query_params:
target_url = f"{target_url}?{request.query_params}"
- logger.debug(f"Proxying request to: {target_url}")
+ logger.debug("Proxying request to: %s", target_url)
try:
# Make the request to the target URL
@@ -437,10 +437,10 @@ def _proxy_request(
)
except httpx.TimeoutException:
- logger.error(f"Timeout while proxying request to {target_url}")
+ logger.error("Timeout while proxying request to %s", target_url)
raise HTTPException(status_code=504, detail="Gateway timeout")
except httpx.RequestError as e:
- logger.error(f"Error proxying request to {target_url}: {e}")
+ logger.error("Error proxying request to %s: %s", target_url, e)
raise HTTPException(status_code=502, detail="Bad gateway")
@@ -546,7 +546,7 @@ def reset_sandbox(
raise
except Exception as e:
db_session.rollback()
- logger.error(f"Failed to reset sandbox for user {user.id}: {e}")
+ logger.error("Failed to reset sandbox for user %s: %s", user.id, e)
raise HTTPException(
status_code=500,
detail=f"Failed to reset sandbox: {e}",
diff --git a/backend/onyx/server/features/build/api/sessions_api.py b/backend/onyx/server/features/build/api/sessions_api.py
index 319f792d9f..440139d18d 100644
--- a/backend/onyx/server/features/build/api/sessions_api.py
+++ b/backend/onyx/server/features/build/api/sessions_api.py
@@ -148,7 +148,7 @@ def create_session(
raise HTTPException(status_code=429, detail=str(e))
except Exception as e:
db_session.rollback()
- logger.error(f"Session creation failed: {e}")
+ logger.error("Session creation failed: %s", e)
raise HTTPException(status_code=500, detail=f"Session creation failed: {e}")
finally:
if lock.owned():
@@ -341,7 +341,7 @@ def delete_session(
except Exception as e:
# Sandbox termination failed - rollback to preserve session
db_session.rollback()
- logger.error(f"Failed to delete session {session_id}: {e}")
+ logger.error("Failed to delete session %s: %s", session_id, e)
raise HTTPException(
status_code=500,
detail=f"Failed to delete session: {e}",
@@ -418,7 +418,8 @@ def restore_session(
if not is_healthy:
logger.warning(
- f"Sandbox {sandbox.id} marked as RUNNING but pod is unhealthy/missing. Entering recovery mode."
+ "Sandbox %s marked as RUNNING but pod is unhealthy/missing. Entering recovery mode.",
+ sandbox.id,
)
# Terminate to clean up any lingering K8s resources
sandbox_manager.terminate(sandbox.id)
@@ -487,7 +488,7 @@ def restore_session(
db_session.commit()
except Exception as e:
logger.error(
- f"Snapshot restore failed for session {session_id}: {e}"
+ "Snapshot restore failed for session %s: %s", session_id, e
)
session.nextjs_port = None
db_session.commit()
@@ -504,11 +505,13 @@ def restore_session(
db_session.commit()
else:
logger.warning(
- f"Sandbox {sandbox.id} status is {sandbox.status} after re-provision, expected RUNNING"
+ "Sandbox %s status is %s after re-provision, expected RUNNING",
+ sandbox.id,
+ sandbox.status,
)
except Exception as e:
- logger.error(f"Failed to restore session {session_id}: {e}", exc_info=True)
+ logger.error("Failed to restore session %s: %s", session_id, e, exc_info=True)
raise HTTPException(
status_code=500,
detail=f"Failed to restore session: {e}",
diff --git a/backend/onyx/server/features/build/api/subscription_check.py b/backend/onyx/server/features/build/api/subscription_check.py
index 0704bdbbad..c4f42550a2 100644
--- a/backend/onyx/server/features/build/api/subscription_check.py
+++ b/backend/onyx/server/features/build/api/subscription_check.py
@@ -45,7 +45,7 @@ def is_user_subscribed(user: User, db_session: Session) -> bool: # noqa: ARG001
# Subscribed = NOT on trial
return not on_trial
except Exception as e:
- logger.warning(f"Subscription check failed for tenant {tenant_id}: {e}")
+ logger.warning("Subscription check failed for tenant %s: %s", tenant_id, e)
# Default to non-subscribed (safer/more restrictive)
return False
diff --git a/backend/onyx/server/features/build/api/user_library.py b/backend/onyx/server/features/build/api/user_library.py
index 852fa9cd7c..f348e900f4 100644
--- a/backend/onyx/server/features/build/api/user_library.py
+++ b/backend/onyx/server/features/build/api/user_library.py
@@ -483,7 +483,10 @@ async def upload_files(
_trigger_sandbox_sync(str(user.id), tenant_id, source=USER_LIBRARY_SOURCE_DIR)
logger.info(
- f"Uploaded {len(uploaded_entries)} files ({total_size} bytes) for user {user.id}"
+ "Uploaded %s files (%s bytes) for user %s",
+ len(uploaded_entries),
+ total_size,
+ user.id,
)
return UploadResponse(
@@ -566,7 +569,9 @@ async def upload_zip(
# Validate individual file size
if file_size > USER_LIBRARY_MAX_FILE_SIZE_BYTES:
- logger.warning(f"Skipping '{zip_info.filename}' - exceeds max size")
+ logger.warning(
+ "Skipping '%s' - exceeds max size", zip_info.filename
+ )
continue
# Skip PDFs that would trip the per-file or per-batch image
@@ -684,7 +689,10 @@ async def upload_zip(
_trigger_sandbox_sync(str(user.id), tenant_id, source=USER_LIBRARY_SOURCE_DIR)
logger.info(
- f"Extracted {len(uploaded_entries)} files ({total_size} bytes) from zip for user {user.id}"
+ "Extracted %s files (%s bytes) from zip for user %s",
+ len(uploaded_entries),
+ total_size,
+ user.id,
)
return UploadResponse(
@@ -826,7 +834,7 @@ def delete_file(
else:
writer.delete_raw_file(file_path)
except Exception as e:
- logger.warning(f"Failed to delete file at path {file_path}: {e}")
+ logger.warning("Failed to delete file at path %s: %s", file_path, e)
else:
# Fallback for documents created before file_path was stored
storage_key = doc_metadata.get("storage_key") or doc_metadata.get("s3_key")
@@ -840,11 +848,12 @@ def delete_file(
writer.delete_raw_file(storage_key)
else:
logger.warning(
- f"Cannot delete file in local mode without file_path: {document_id}"
+ "Cannot delete file in local mode without file_path: %s",
+ document_id,
)
except Exception as e:
logger.warning(
- f"Failed to delete storage object {storage_key}: {e}"
+ "Failed to delete storage object %s: %s", storage_key, e
)
# Delete from document table
diff --git a/backend/onyx/server/features/build/db/build_session.py b/backend/onyx/server/features/build/db/build_session.py
index 06f1e54ead..f6eb2dd4b8 100644
--- a/backend/onyx/server/features/build/db/build_session.py
+++ b/backend/onyx/server/features/build/db/build_session.py
@@ -55,7 +55,10 @@ def create_build_session__no_commit(
db_session.flush()
logger.info(
- f"Created build session {session.id} for user {user_id} (demo_data={demo_data_enabled})"
+ "Created build session %s for user %s (demo_data=%s)",
+ session.id,
+ user_id,
+ demo_data_enabled,
)
return session
@@ -158,7 +161,7 @@ def update_session_status(
if session:
session.status = status
db_session.commit()
- logger.info(f"Updated build session {session_id} status to {status}")
+ logger.info("Updated build session %s status to %s", session_id, status)
def set_build_session_sharing_scope(
@@ -177,7 +180,7 @@ def set_build_session_sharing_scope(
return None
session.sharing_scope = sharing_scope
db_session.commit()
- logger.info(f"Set build session {session_id} sharing_scope={sharing_scope}")
+ logger.info("Set build session %s sharing_scope=%s", session_id, sharing_scope)
return session
@@ -197,7 +200,7 @@ def delete_build_session__no_commit(
db_session.delete(session)
db_session.flush()
- logger.info(f"Deleted build session {session_id}")
+ logger.info("Deleted build session %s", session_id)
return True
@@ -220,7 +223,7 @@ def update_sandbox_status(
sandbox.container_id = container_id
sandbox.last_heartbeat = datetime.now(tz=timezone.utc)
db_session.commit()
- logger.info(f"Updated sandbox {sandbox_id} status to {status}")
+ logger.info("Updated sandbox %s status to %s", sandbox_id, status)
def update_sandbox_heartbeat(
@@ -253,7 +256,7 @@ def create_artifact(
db_session.commit()
db_session.refresh(artifact)
- logger.info(f"Created artifact {artifact.id} for session {session_id}")
+ logger.info("Created artifact %s for session %s", artifact.id, session_id)
return artifact
@@ -287,7 +290,7 @@ def update_artifact(
artifact.name = name
artifact.updated_at = datetime.now(tz=timezone.utc)
db_session.commit()
- logger.info(f"Updated artifact {artifact_id}")
+ logger.info("Updated artifact %s", artifact_id)
# Message operations
@@ -320,8 +323,12 @@ def create_message(
db_session.refresh(message)
logger.info(
- f"Created {message_type.value} message {message.id} for session {session_id} "
- f"turn={turn_index} type={message_metadata.get('type')}"
+ "Created %s message %s for session %s turn=%s type=%s",
+ message_type.value,
+ message.id,
+ session_id,
+ turn_index,
+ message_metadata.get("type"),
)
return message
@@ -354,7 +361,7 @@ def update_message(
db_session.refresh(message)
logger.info(
- f"Updated message {message_id} metadata type={message_metadata.get('type')}"
+ "Updated message %s metadata type=%s", message_id, message_metadata.get("type")
)
return message
@@ -403,7 +410,9 @@ def upsert_agent_plan(
db_session.commit()
db_session.refresh(existing_plan)
logger.info(
- f"Updated agent_plan_update message {existing_plan.id} for session {session_id}"
+ "Updated agent_plan_update message %s for session %s",
+ existing_plan.id,
+ session_id,
)
return existing_plan
@@ -438,16 +447,16 @@ def _is_port_available(port: int) -> bool:
"""
import socket
- logger.debug(f"Checking if port {port} is available")
+ logger.debug("Checking if port %s is available", port)
# Check IPv4 wildcard (0.0.0.0) - this will detect any IPv4 listener
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", port))
- logger.debug(f"Port {port} IPv4 wildcard bind successful")
+ logger.debug("Port %s IPv4 wildcard bind successful", port)
except OSError as e:
- logger.debug(f"Port {port} IPv4 wildcard not available: {e}")
+ logger.debug("Port %s IPv4 wildcard not available: %s", port, e)
return False
# Check IPv6 wildcard (::) - this will detect any IPv6 listener
@@ -457,12 +466,12 @@ def _is_port_available(port: int) -> bool:
# IPV6_V6ONLY must be False to allow dual-stack behavior
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(("::", port))
- logger.debug(f"Port {port} IPv6 wildcard bind successful")
+ logger.debug("Port %s IPv6 wildcard bind successful", port)
except OSError as e:
- logger.debug(f"Port {port} IPv6 wildcard not available: {e}")
+ logger.debug("Port %s IPv6 wildcard not available: %s", port, e)
return False
- logger.debug(f"Port {port} is available")
+ logger.debug("Port %s is available", port)
return True
@@ -523,7 +532,7 @@ def mark_user_sessions_idle__no_commit(db_session: Session, user_id: UUID) -> in
.update({BuildSession.status: BuildSessionStatus.IDLE})
)
db_session.flush()
- logger.info(f"Marked {result} sessions as IDLE for user {user_id}")
+ logger.info("Marked %s sessions as IDLE for user %s", result, user_id)
return result
@@ -548,7 +557,7 @@ def clear_nextjs_ports_for_user(db_session: Session, user_id: UUID) -> int:
.update({BuildSession.nextjs_port: None})
)
db_session.flush()
- logger.info(f"Cleared {result} nextjs_port allocations for user {user_id}")
+ logger.info("Cleared %s nextjs_port allocations for user %s", result, user_id)
return result
diff --git a/backend/onyx/server/features/build/indexing/persistent_document_writer.py b/backend/onyx/server/features/build/indexing/persistent_document_writer.py
index 3422ec9d48..a61d96f5a1 100644
--- a/backend/onyx/server/features/build/indexing/persistent_document_writer.py
+++ b/backend/onyx/server/features/build/indexing/persistent_document_writer.py
@@ -275,7 +275,7 @@ class PersistentDocumentWriter:
with open(path, "w", encoding="utf-8") as f:
json.dump(content, f, indent=2, default=str)
- logger.debug(f"Wrote document to {path}")
+ logger.debug("Wrote document to %s", path)
def write_raw_file(
self,
@@ -314,7 +314,7 @@ class PersistentDocumentWriter:
with open(full_path, "wb") as f:
f.write(content)
- logger.debug(f"Wrote raw file to {full_path}")
+ logger.debug("Wrote raw file to %s", full_path)
return str(full_path)
def delete_raw_file(self, path: str) -> None:
@@ -336,9 +336,9 @@ class PersistentDocumentWriter:
if full_path.exists():
full_path.unlink()
- logger.debug(f"Deleted raw file at {full_path}")
+ logger.debug("Deleted raw file at %s", full_path)
else:
- logger.warning(f"File not found for deletion: {full_path}")
+ logger.warning("File not found for deletion: %s", full_path)
class S3PersistentDocumentWriter:
@@ -438,9 +438,9 @@ class S3PersistentDocumentWriter:
Body=json_content.encode("utf-8"),
ContentType="application/json",
)
- logger.debug(f"Wrote document to s3://{self.bucket}/{s3_key}")
+ logger.debug("Wrote document to s3://%s/%s", self.bucket, s3_key)
except ClientError as e:
- logger.error(f"Failed to write to S3: {e}")
+ logger.error("Failed to write to S3: %s", e)
raise
def write_raw_file(
@@ -477,10 +477,10 @@ class S3PersistentDocumentWriter:
Body=content,
ContentType=content_type or "application/octet-stream",
)
- logger.debug(f"Wrote raw file to s3://{self.bucket}/{s3_key}")
+ logger.debug("Wrote raw file to s3://%s/%s", self.bucket, s3_key)
return s3_key
except ClientError as e:
- logger.error(f"Failed to write raw file to S3: {e}")
+ logger.error("Failed to write raw file to S3: %s", e)
raise
def delete_raw_file(self, s3_key: str) -> None:
@@ -493,9 +493,9 @@ class S3PersistentDocumentWriter:
try:
s3_client.delete_object(Bucket=self.bucket, Key=s3_key)
- logger.debug(f"Deleted raw file at s3://{self.bucket}/{s3_key}")
+ logger.debug("Deleted raw file at s3://%s/%s", self.bucket, s3_key)
except ClientError as e:
- logger.error(f"Failed to delete raw file from S3: {e}")
+ logger.error("Failed to delete raw file from S3: %s", e)
raise
def delete_raw_file_by_path(self, path: str) -> None:
diff --git a/backend/onyx/server/features/build/sandbox/kubernetes/internal/acp_exec_client.py b/backend/onyx/server/features/build/sandbox/kubernetes/internal/acp_exec_client.py
index 850d448cc0..0d53eeb701 100644
--- a/backend/onyx/server/features/build/sandbox/kubernetes/internal/acp_exec_client.py
+++ b/backend/onyx/server/features/build/sandbox/kubernetes/internal/acp_exec_client.py
@@ -190,7 +190,7 @@ class ACPExecClient:
f"XDG_DATA_HOME={data_dir} exec opencode acp --cwd {safe_cwd}",
]
- logger.info(f"[ACP] Starting client: pod={self._pod_name} cwd={cwd}")
+ logger.info("[ACP] Starting client: pod=%s cwd=%s", self._pod_name, cwd)
try:
self._ws_client = k8s_stream(
@@ -220,9 +220,11 @@ class ACPExecClient:
# Initialize ACP connection (no session creation)
self._initialize(timeout=timeout)
- logger.info(f"[ACP] Client started: pod={self._pod_name}")
+ logger.info("[ACP] Client started: pod=%s", self._pod_name)
except Exception as e:
- logger.error(f"[ACP] Client start failed: pod={self._pod_name} error={e}")
+ logger.error(
+ "[ACP] Client start failed: pod=%s error=%s", self._pod_name, e
+ )
self.stop()
raise RuntimeError(f"Failed to start ACP exec client: {e}") from e
@@ -243,7 +245,9 @@ class ACPExecClient:
stderr_data = self._ws_client.read_stderr(timeout=0.01)
if stderr_data:
logger.warning(
- f"[ACP] stderr pod={self._pod_name}: {stderr_data.strip()[:500]}"
+ "[ACP] stderr pod=%s: %s",
+ self._pod_name,
+ stderr_data.strip()[:500],
)
# Read stdout
@@ -263,23 +267,23 @@ class ACPExecClient:
self._response_queue.put(message)
except json.JSONDecodeError:
logger.warning(
- f"[ACP] Invalid JSON from agent: {line[:100]}"
+ "[ACP] Invalid JSON from agent: %s", line[:100]
)
else:
- logger.warning(f"[ACP] WebSocket closed: pod={self._pod_name}")
+ logger.warning("[ACP] WebSocket closed: pod=%s", self._pod_name)
break
except Exception as e:
if not self._stop_reader.is_set():
- logger.warning(f"[ACP] Reader error: {e}, pod={self._pod_name}")
+ logger.warning("[ACP] Reader error: %s, pod=%s", e, self._pod_name)
break
def stop(self) -> None:
"""Stop the exec session and clean up."""
session_ids = list(self._state.sessions.keys())
logger.info(
- f"[ACP] Stopping client: pod={self._pod_name} sessions={session_ids}"
+ "[ACP] Stopping client: pod=%s sessions=%s", self._pod_name, session_ids
)
self._stop_reader.set()
@@ -408,7 +412,7 @@ class ACPExecClient:
raise RuntimeError("No session ID returned from session/new")
self._state.sessions[session_id] = ACPSession(session_id=session_id, cwd=cwd)
- logger.info(f"[ACP] Created session: acp_session={session_id} cwd={cwd}")
+ logger.info("[ACP] Created session: acp_session=%s cwd=%s", session_id, cwd)
return session_id
@@ -423,10 +427,12 @@ class ACPExecClient:
request_id = self._send_request("session/list", {"cwd": cwd})
result = self._wait_for_response(request_id, timeout)
sessions = result.get("sessions", [])
- logger.info(f"[ACP] session/list: {len(sessions)} sessions for cwd={cwd}")
+ logger.info(
+ "[ACP] session/list: %s sessions for cwd=%s", len(sessions), cwd
+ )
return sessions
except Exception as e:
- logger.info(f"[ACP] session/list unavailable: {e}")
+ logger.info("[ACP] session/list unavailable: %s", e)
return []
def _resume_session(self, session_id: str, cwd: str, timeout: float = 30.0) -> str:
@@ -456,7 +462,7 @@ class ACPExecClient:
resumed_id = result.get("sessionId", session_id)
self._state.sessions[resumed_id] = ACPSession(session_id=resumed_id, cwd=cwd)
- logger.info(f"[ACP] Resumed session: acp_session={resumed_id} cwd={cwd}")
+ logger.info("[ACP] Resumed session: acp_session=%s cwd=%s", resumed_id, cwd)
return resumed_id
def _try_resume_existing_session(self, cwd: str, timeout: float) -> str | None:
@@ -487,14 +493,18 @@ class ACPExecClient:
return None
logger.info(
- f"[ACP] Resuming existing session: acp_session={target_id} (found {len(sessions)})"
+ "[ACP] Resuming existing session: acp_session=%s (found %s)",
+ target_id,
+ len(sessions),
)
try:
return self._resume_session(target_id, cwd, timeout)
except Exception as e:
logger.warning(
- f"[ACP] session/resume failed for {target_id}: {e}, falling back to session/new"
+ "[ACP] session/resume failed for %s: %s, falling back to session/new",
+ target_id,
+ e,
)
return None
@@ -545,7 +555,10 @@ class ACPExecClient:
packet_logger = get_packet_logger()
logger.info(
- f"[ACP] Sending prompt: acp_session={session_id} pod={self._pod_name} queue_backlog={self._response_queue.qsize()}"
+ "[ACP] Sending prompt: acp_session=%s pod=%s queue_backlog=%s",
+ session_id,
+ self._pod_name,
+ self._response_queue.qsize(),
)
prompt_content = [{"type": "text", "text": message}]
@@ -566,13 +579,15 @@ class ACPExecClient:
if remaining <= 0:
completion_reason = "timeout"
logger.warning(
- f"[ACP] Prompt timeout: acp_session={session_id} events={events_yielded}, sending session/cancel"
+ "[ACP] Prompt timeout: acp_session=%s events=%s, sending session/cancel",
+ session_id,
+ events_yielded,
)
try:
self.cancel(session_id=session_id)
except Exception as cancel_err:
logger.warning(
- f"[ACP] session/cancel failed on timeout: {cancel_err}"
+ "[ACP] session/cancel failed on timeout: %s", cancel_err
)
yield Error(code=-1, message="Timeout waiting for response")
break
@@ -600,7 +615,7 @@ class ACPExecClient:
if "error" in message_data:
error_data = message_data["error"]
completion_reason = "jsonrpc_error"
- logger.warning(f"[ACP] Prompt error: {error_data}")
+ logger.warning("[ACP] Prompt error: %s", error_data)
packet_logger.log_jsonrpc_response(
request_id, error=error_data, context="k8s"
)
@@ -618,13 +633,15 @@ class ACPExecClient:
events_yielded += 1
yield prompt_response
except ValidationError as e:
- logger.error(f"[ACP] PromptResponse validation failed: {e}")
+ logger.error("[ACP] PromptResponse validation failed: %s", e)
elapsed_ms = (time.time() - start_time) * 1000
logger.info(
- f"[ACP] Prompt complete: "
- f"reason={completion_reason} acp_session={session_id} "
- f"events={events_yielded} elapsed={elapsed_ms:.0f}ms"
+ "[ACP] Prompt complete: reason=%s acp_session=%s events=%s elapsed=%sms",
+ completion_reason,
+ session_id,
+ events_yielded,
+ format(elapsed_ms, ".0f"),
)
break
@@ -645,16 +662,18 @@ class ACPExecClient:
completion_reason = "prompt_response_via_notification"
elapsed_ms = (time.time() - start_time) * 1000
logger.info(
- f"[ACP] Prompt complete: "
- f"reason={completion_reason} acp_session={session_id} "
- f"events={events_yielded} elapsed={elapsed_ms:.0f}ms"
+ "[ACP] Prompt complete: reason=%s acp_session=%s events=%s elapsed=%sms",
+ completion_reason,
+ session_id,
+ events_yielded,
+ format(elapsed_ms, ".0f"),
)
break
# Handle requests from agent - send error response
elif "method" in message_data and "id" in message_data:
logger.debug(
- f"[ACP] Unsupported agent request: method={message_data['method']}"
+ "[ACP] Unsupported agent request: method=%s", message_data["method"]
)
self._send_error_response(
message_data["id"],
@@ -664,10 +683,10 @@ class ACPExecClient:
else:
logger.warning(
- f"[ACP] Unhandled message: "
- f"id={message_data.get('id')} "
- f"method={message_data.get('method')} "
- f"keys={list(message_data.keys())}"
+ "[ACP] Unhandled message: id=%s method=%s keys=%s",
+ message_data.get("id"),
+ message_data.get("method"),
+ list(message_data.keys()),
)
def _process_session_update(
@@ -697,14 +716,14 @@ class ACPExecClient:
try:
yield cast(ACPEvent, model_class.model_validate(update))
except ValidationError as e:
- logger.warning(f"[ACP] Validation error for {update_type}: {e}")
+ logger.warning("[ACP] Validation error for %s: %s", update_type, e)
elif update_type not in (
"user_message_chunk",
"available_commands_update",
"session_info_update",
"usage_update",
):
- logger.debug(f"[ACP] Unknown update type: {update_type}")
+ logger.debug("[ACP] Unknown update type: %s", update_type)
def _send_error_response(self, request_id: int, code: int, message: str) -> None:
"""Send an error response to an agent request."""
diff --git a/backend/onyx/server/features/build/sandbox/kubernetes/kubernetes_sandbox_manager.py b/backend/onyx/server/features/build/sandbox/kubernetes/kubernetes_sandbox_manager.py
index 068c9f83ef..2e1b9866ee 100644
--- a/backend/onyx/server/features/build/sandbox/kubernetes/kubernetes_sandbox_manager.py
+++ b/backend/onyx/server/features/build/sandbox/kubernetes/kubernetes_sandbox_manager.py
@@ -359,7 +359,9 @@ class KubernetesSandboxManager(SandboxManager):
self._skills_path = Path(__file__).parent / "docker" / "skills"
logger.info(
- f"KubernetesSandboxManager initialized: namespace={self._namespace}, image={self._image}"
+ "KubernetesSandboxManager initialized: namespace=%s, image=%s",
+ self._namespace,
+ self._image,
)
def _get_pod_name(self, sandbox_id: str) -> str:
@@ -697,7 +699,7 @@ done
# Service exists - check if it's being deleted
if svc.metadata.deletion_timestamp:
logger.info(
- f"Service {service_name} is terminating, waiting for deletion"
+ "Service %s is terminating, waiting for deletion", service_name
)
self._wait_for_resource_deletion("service", service_name)
# Now create a fresh service
@@ -706,14 +708,14 @@ done
namespace=self._namespace,
body=service,
)
- logger.info(f"Recreated Service {service_name} after termination")
+ logger.info("Recreated Service %s after termination", service_name)
else:
- logger.debug(f"Service {service_name} already exists and is active")
+ logger.debug("Service %s already exists and is active", service_name)
except ApiException as e:
if e.status == 404:
# Service doesn't exist, create it
- logger.info(f"Creating missing Service {service_name}")
+ logger.info("Creating missing Service %s", service_name)
service = self._create_sandbox_service(sandbox_id, tenant_id)
try:
self._core_api.create_namespaced_service(
@@ -724,7 +726,7 @@ done
if svc_e.status != 409: # Ignore AlreadyExists
raise
logger.debug(
- f"Service {service_name} was created by another request"
+ "Service %s was created by another request", service_name
)
else:
raise
@@ -841,15 +843,15 @@ done
conditions = pod.status.conditions or []
for condition in conditions:
if condition.type == "Ready" and condition.status == "True":
- logger.info(f"Pod {pod_name} is ready")
+ logger.info("Pod %s is ready", pod_name)
return True
- logger.debug(f"Pod {pod_name} status: {phase}, waiting...")
+ logger.debug("Pod %s status: %s, waiting...", pod_name, phase)
except ApiException as e:
if e.status == 404:
raise RuntimeError(f"Pod {pod_name} was deleted")
- logger.warning(f"Error checking pod status: {e}")
+ logger.warning("Error checking pod status: %s", e)
time.sleep(POD_READY_POLL_INTERVAL_SECONDS)
@@ -865,7 +867,7 @@ done
except ApiException:
pass # Pod might be deleted, ignore
- logger.warning(f"Timeout waiting for pod {pod_name} to become ready")
+ logger.warning("Timeout waiting for pod %s to become ready", pod_name)
return False
def _pod_exists_and_healthy(self, pod_name: str) -> bool:
@@ -935,7 +937,10 @@ done
RuntimeError: If provisioning fails
"""
logger.info(
- f"Starting Kubernetes sandbox provisioning for sandbox {sandbox_id}, user {user_id}, tenant {tenant_id}"
+ "Starting Kubernetes sandbox provisioning for sandbox %s, user %s, tenant %s",
+ sandbox_id,
+ user_id,
+ tenant_id,
)
pod_name = self._get_pod_name(str(sandbox_id))
@@ -943,20 +948,20 @@ done
# Check if pod already exists and is healthy (idempotency check)
if self._pod_exists_and_healthy(pod_name):
logger.info(
- f"Pod {pod_name} already exists and is healthy, reusing existing pod"
+ "Pod %s already exists and is healthy, reusing existing pod", pod_name
)
# Ensure service exists and is not terminating
self._ensure_service_exists(sandbox_id, tenant_id)
# Wait for pod to be ready if it's still pending
- logger.info(f"Waiting for existing pod {pod_name} to become ready...")
+ logger.info("Waiting for existing pod %s to become ready...", pod_name)
if not self._wait_for_pod_ready(pod_name):
raise RuntimeError(
f"Timeout waiting for existing sandbox pod {pod_name} to become ready"
)
logger.info(
- f"Reusing existing Kubernetes sandbox {sandbox_id}, pod: {pod_name}"
+ "Reusing existing Kubernetes sandbox %s, pod: %s", sandbox_id, pod_name
)
return SandboxInfo(
sandbox_id=sandbox_id,
@@ -967,7 +972,7 @@ done
try:
# 1. Create Pod (user-level only, no session setup)
- logger.debug(f"Creating Pod {pod_name}")
+ logger.debug("Creating Pod %s", pod_name)
pod = self._create_sandbox_pod(
sandbox_id=str(sandbox_id),
user_id=str(user_id),
@@ -983,19 +988,21 @@ done
# Pod was created by another concurrent request
# Check if it's healthy and reuse it
logger.warning(
- f"Pod {pod_name} already exists (409 conflict, this shouldn't normally happen), "
- "checking if it's healthy..."
+ "Pod %s already exists (409 conflict, this shouldn't normally happen), checking if it's healthy...",
+ pod_name,
)
if self._pod_exists_and_healthy(pod_name):
logger.warning(
- f"During provisioning, discovered that pod {pod_name} already exists. Reusing"
+ "During provisioning, discovered that pod %s already exists. Reusing",
+ pod_name,
)
# Continue to ensure service exists and wait for ready
else:
# Pod exists but is not healthy - this shouldn't happen often
# but could occur if a previous provision failed mid-way
logger.warning(
- f"Pod {pod_name} exists but is not healthy, waiting for it to become ready or fail"
+ "Pod %s exists but is not healthy, waiting for it to become ready or fail",
+ pod_name,
)
else:
raise
@@ -1004,14 +1011,16 @@ done
self._ensure_service_exists(sandbox_id, tenant_id)
# 3. Wait for pod to be ready
- logger.info(f"Waiting for pod {pod_name} to become ready...")
+ logger.info("Waiting for pod %s to become ready...", pod_name)
if not self._wait_for_pod_ready(pod_name):
raise RuntimeError(
f"Timeout waiting for sandbox pod {pod_name} to become ready"
)
logger.info(
- f"Provisioned Kubernetes sandbox {sandbox_id}, pod: {pod_name} (no sessions yet)"
+ "Provisioned Kubernetes sandbox %s, pod: %s (no sessions yet)",
+ sandbox_id,
+ pod_name,
)
return SandboxInfo(
@@ -1026,12 +1035,15 @@ done
# Check if pod is healthy - if so, don't clean up (another request may own it)
if self._pod_exists_and_healthy(pod_name):
logger.warning(
- f"Kubernetes sandbox provisioning failed for sandbox {sandbox_id}: {e}, "
- "but pod is healthy (likely owned by concurrent request), not cleaning up"
+ "Kubernetes sandbox provisioning failed for sandbox %s: %s, but pod is healthy (likely owned by concurrent request), not cleaning up",
+ sandbox_id,
+ e,
)
else:
logger.error(
- f"Kubernetes sandbox provisioning failed for sandbox {sandbox_id}: {e}",
+ "Kubernetes sandbox provisioning failed for sandbox %s: %s",
+ sandbox_id,
+ e,
exc_info=True,
)
self._cleanup_kubernetes_resources(str(sandbox_id))
@@ -1075,20 +1087,27 @@ done
raise ValueError(f"Unknown resource type: {resource_type}")
# Resource still exists, wait and retry
- logger.debug(f"Waiting for {resource_type} {name} to be deleted...")
+ logger.debug("Waiting for %s %s to be deleted...", resource_type, name)
time.sleep(RESOURCE_DELETION_POLL_INTERVAL_SECONDS)
except ApiException as e:
if e.status == 404:
# Resource is gone
- logger.debug(f"{resource_type.capitalize()} {name} fully deleted")
+ logger.debug(
+ "%s %s fully deleted", resource_type.capitalize(), name
+ )
return True
# Other error, log and continue waiting
- logger.warning(f"Error checking {resource_type} {name} status: {e}")
+ logger.warning(
+ "Error checking %s %s status: %s", resource_type, name, e
+ )
time.sleep(RESOURCE_DELETION_POLL_INTERVAL_SECONDS)
logger.warning(
- f"Timeout waiting for {resource_type} {name} to be deleted after {timeout}s"
+ "Timeout waiting for %s %s to be deleted after %ss",
+ resource_type,
+ name,
+ timeout,
)
return False
@@ -1118,14 +1137,14 @@ done
name=service_name,
namespace=self._namespace,
)
- logger.debug(f"Deleted Service {service_name}")
+ logger.debug("Deleted Service %s", service_name)
service_deleted = True
except ApiException as e:
if e.status == 404:
# Already deleted
service_deleted = True
else:
- logger.error(f"Error deleting Service {service_name}: {e}")
+ logger.error("Error deleting Service %s: %s", service_name, e)
raise
pod_deleted = False
@@ -1134,14 +1153,14 @@ done
name=pod_name,
namespace=self._namespace,
)
- logger.debug(f"Deleted Pod {pod_name}")
+ logger.debug("Deleted Pod %s", pod_name)
pod_deleted = True
except ApiException as e:
if e.status == 404:
# Already deleted
pod_deleted = True
else:
- logger.error(f"Error deleting Pod {pod_name}: {e}")
+ logger.error("Error deleting Pod %s: %s", pod_name, e)
raise
# Wait for resources to be fully deleted to prevent 409 conflicts
@@ -1165,7 +1184,7 @@ done
# Clean up Kubernetes resources (needs string for pod/service names)
self._cleanup_kubernetes_resources(str(sandbox_id))
- logger.info(f"Terminated Kubernetes sandbox {sandbox_id}")
+ logger.info("Terminated Kubernetes sandbox %s", sandbox_id)
def setup_session_workspace(
self,
@@ -1217,9 +1236,9 @@ done
"""
if snapshot_path:
logger.warning(
- f"Snapshot restoration requested but not supported in Kubernetes mode. "
- f"Snapshot path {snapshot_path} will be ignored. "
- f"Session {session_id} will start with fresh outputs template."
+ "Snapshot restoration requested but not supported in Kubernetes mode. Snapshot path %s will be ignored. Session %s will start with fresh outputs template.",
+ snapshot_path,
+ session_id,
)
pod_name = self._get_pod_name(str(sandbox_id))
@@ -1360,7 +1379,7 @@ echo "Session workspace setup complete"
"""
logger.info(
- f"Setting up session workspace {session_id} in sandbox {sandbox_id}"
+ "Setting up session workspace %s in sandbox %s", session_id, sandbox_id
)
try:
@@ -1377,14 +1396,17 @@ echo "Session workspace setup complete"
tty=False,
)
- logger.debug(f"Session setup output: {exec_response}")
+ logger.debug("Session setup output: %s", exec_response)
logger.info(
- f"Set up session workspace {session_id} in sandbox {sandbox_id}"
+ "Set up session workspace %s in sandbox %s", session_id, sandbox_id
)
except Exception as e:
logger.error(
- f"Failed to setup session workspace {session_id} in sandbox {sandbox_id}: {e}",
+ "Failed to setup session workspace %s in sandbox %s: %s",
+ session_id,
+ sandbox_id,
+ e,
exc_info=True,
)
raise RuntimeError(
@@ -1427,7 +1449,7 @@ echo "Session cleanup complete"
"""
logger.info(
- f"Cleaning up session workspace {session_id} in sandbox {sandbox_id}"
+ "Cleaning up session workspace %s in sandbox %s", session_id, sandbox_id
)
try:
@@ -1443,19 +1465,21 @@ echo "Session cleanup complete"
tty=False,
)
- logger.debug(f"Session cleanup output: {exec_response}")
+ logger.debug("Session cleanup output: %s", exec_response)
logger.info(
- f"Cleaned up session workspace {session_id} in sandbox {sandbox_id}"
+ "Cleaned up session workspace %s in sandbox %s", session_id, sandbox_id
)
except ApiException as e:
if e.status == 404:
# Pod not found, nothing to clean up
- logger.debug(f"Pod {pod_name} not found, skipping cleanup")
+ logger.debug("Pod %s not found, skipping cleanup", pod_name)
else:
- logger.warning(f"Error cleaning up session workspace {session_id}: {e}")
+ logger.warning(
+ "Error cleaning up session workspace %s: %s", session_id, e
+ )
except Exception as e:
- logger.warning(f"Error cleaning up session workspace {session_id}: {e}")
+ logger.warning("Error cleaning up session workspace %s: %s", session_id, e)
def create_snapshot(
self,
@@ -1527,12 +1551,12 @@ echo "SNAPSHOT_CREATED"
tty=False,
)
- logger.debug(f"Snapshot exec output: {resp}")
+ logger.debug("Snapshot exec output: %s", resp)
# Check if nothing was snapshotted
if "EMPTY_SNAPSHOT" in resp:
logger.info(
- f"No outputs or attachments to snapshot for session {session_id}"
+ "No outputs or attachments to snapshot for session %s", session_id
)
return None
@@ -1550,7 +1574,7 @@ echo "SNAPSHOT_CREATED"
# Storage path must match the S3 upload path (without s3://bucket/ prefix)
storage_path = f"{tenant_id}/snapshots/{session_id_str}/{snapshot_id}.tar.gz"
- logger.info(f"Created snapshot for session {session_id}")
+ logger.info("Created snapshot for session %s", session_id)
return SnapshotResult(
storage_path=storage_path,
@@ -1598,13 +1622,17 @@ echo "SNAPSHOT_CREATED"
result = "WORKSPACE_FOUND" in resp
logger.info(
- f"[WORKSPACE_CHECK] session={session_id}, path={session_path}, raw_resp={resp!r}, result={result}"
+ "[WORKSPACE_CHECK] session=%s, path=%s, raw_resp=%r, result=%s",
+ session_id,
+ session_path,
+ resp,
+ result,
)
return result
except ApiException as e:
logger.warning(
- f"Failed to check session workspace exists for {session_id}: {e}"
+ "Failed to check session workspace exists for %s: %s", session_id, e
)
return False
@@ -1844,7 +1872,10 @@ echo "Session config regeneration complete"
acp_client.start(cwd=session_path)
logger.info(
- f"[SANDBOX-ACP] Created ephemeral ACP client: sandbox={sandbox_id} pod={pod_name} api_pod={_API_SERVER_HOSTNAME}"
+ "[SANDBOX-ACP] Created ephemeral ACP client: sandbox=%s pod=%s api_pod=%s",
+ sandbox_id,
+ pod_name,
+ _API_SERVER_HOSTNAME,
)
return acp_client
@@ -1882,7 +1913,10 @@ echo "Session config regeneration complete"
acp_session_id = acp_client.resume_or_create_session(cwd=session_path)
logger.info(
- f"[SANDBOX-ACP] Sending message: session={session_id} acp_session={acp_session_id} api_pod={_API_SERVER_HOSTNAME}"
+ "[SANDBOX-ACP] Sending message: session=%s acp_session=%s api_pod=%s",
+ session_id,
+ acp_session_id,
+ _API_SERVER_HOSTNAME,
)
# Log the send_message call at sandbox manager level
@@ -1900,22 +1934,26 @@ echo "Session config regeneration complete"
yield event
logger.info(
- f"[SANDBOX-ACP] send_message completed: "
- f"session={session_id} events={events_count} "
- f"got_prompt_response={got_prompt_response}"
+ "[SANDBOX-ACP] send_message completed: session=%s events=%s got_prompt_response=%s",
+ session_id,
+ events_count,
+ got_prompt_response,
)
packet_logger.log_session_end(
session_id, success=True, events_count=events_count
)
except GeneratorExit:
logger.warning(
- f"[SANDBOX-ACP] GeneratorExit: session={session_id} events={events_count}, sending session/cancel"
+ "[SANDBOX-ACP] GeneratorExit: session=%s events=%s, sending session/cancel",
+ session_id,
+ events_count,
)
try:
acp_client.cancel(session_id=acp_session_id)
except Exception as cancel_err:
logger.warning(
- f"[SANDBOX-ACP] session/cancel failed on GeneratorExit: {cancel_err}"
+ "[SANDBOX-ACP] session/cancel failed on GeneratorExit: %s",
+ cancel_err,
)
packet_logger.log_session_end(
session_id,
@@ -1926,13 +1964,17 @@ echo "Session config regeneration complete"
raise
except Exception as e:
logger.error(
- f"[SANDBOX-ACP] Exception: session={session_id} events={events_count} error={e}, sending session/cancel"
+ "[SANDBOX-ACP] Exception: session=%s events=%s error=%s, sending session/cancel",
+ session_id,
+ events_count,
+ e,
)
try:
acp_client.cancel(session_id=acp_session_id)
except Exception as cancel_err:
logger.warning(
- f"[SANDBOX-ACP] session/cancel failed on Exception: {cancel_err}"
+ "[SANDBOX-ACP] session/cancel failed on Exception: %s",
+ cancel_err,
)
packet_logger.log_session_end(
session_id,
@@ -1943,7 +1985,10 @@ echo "Session config regeneration complete"
raise
except BaseException as e:
logger.error(
- f"[SANDBOX-ACP] {type(e).__name__}: session={session_id} error={e}"
+ "[SANDBOX-ACP] %s: session=%s error=%s",
+ type(e).__name__,
+ session_id,
+ e,
)
packet_logger.log_session_end(
session_id,
@@ -1959,7 +2004,9 @@ echo "Session config regeneration complete"
acp_client.stop()
except Exception as e:
logger.warning(
- f"[SANDBOX-ACP] Failed to stop ephemeral ACP client: session={session_id} error={e}"
+ "[SANDBOX-ACP] Failed to stop ephemeral ACP client: session=%s error=%s",
+ session_id,
+ e,
)
def list_directory(
@@ -1991,7 +2038,7 @@ echo "Session config regeneration complete"
# Use shlex.quote to prevent command injection
quoted_path = shlex.quote(target_path)
- logger.info(f"Listing directory {target_path} in pod {pod_name}")
+ logger.info("Listing directory %s in pod %s", target_path, pod_name)
# Use exec to list directory
# -L follows symlinks (important for files/ -> /workspace/demo_data)
@@ -2032,10 +2079,10 @@ echo "Session config regeneration complete"
entries = []
lines = ls_output.strip().split("\n")
- logger.debug(f"Parsing {len(lines)} lines of ls output for {base_path}")
+ logger.debug("Parsing %s lines of ls output for %s", len(lines), base_path)
for line in lines:
- logger.debug(f"Parsing line: {line}")
+ logger.debug("Parsing line: %s", line)
# Skip header line and . / .. entries
if line.startswith("total") or not line:
@@ -2151,7 +2198,7 @@ echo "Session config regeneration complete"
try:
content = base64.b64decode(resp.strip())
except binascii.Error as e:
- logger.error(f"Failed to decode base64 content: {e}")
+ logger.error("Failed to decode base64 content: %s", e)
raise RuntimeError(f"Failed to decode file content: {e}") from e
return content
@@ -2349,11 +2396,11 @@ fi
stdout=True,
tty=False,
)
- logger.debug(f"File sync response: {resp}")
+ logger.debug("File sync response: %s", resp)
# Check if sync succeeded based on output markers
if "SYNC_FAILED" in resp:
- logger.warning(f"File sync failed for sandbox {sandbox_id}")
+ logger.warning("File sync failed for sandbox %s", sandbox_id)
return False
return True
@@ -2416,10 +2463,12 @@ fi
tty=False,
)
logger.debug(
- f"Ensure AGENTS.md attachments section for session {session_id}: {resp.strip()}"
+ "Ensure AGENTS.md attachments section for session %s: %s",
+ session_id,
+ resp.strip(),
)
except ApiException as e:
- logger.warning(f"Failed to ensure AGENTS.md attachments section: {e}")
+ logger.warning("Failed to ensure AGENTS.md attachments section: %s", e)
def upload_file(
self,
@@ -2532,7 +2581,7 @@ echo "$base"
stderr_data += ws_client.read_stderr() or ""
if stderr_data.strip():
- logger.warning(f"Upload stderr: {stderr_data.strip()}")
+ logger.warning("Upload stderr: %s", stderr_data.strip())
# Last line of output is the final filename
final_filename = stdout_data.strip().split("\n")[-1]
@@ -2543,7 +2592,10 @@ echo "$base"
)
logger.info(
- f"Uploaded file to session {session_id}: attachments/{final_filename} ({len(content)} bytes)"
+ "Uploaded file to session %s: attachments/%s (%s bytes)",
+ session_id,
+ final_filename,
+ len(content),
)
# Ensure AGENTS.md has the attachments section
@@ -2616,10 +2668,10 @@ echo "$base"
deleted = "DELETED" in resp
if deleted:
- logger.info(f"Deleted file from session {session_id}: {path}")
+ logger.info("Deleted file from session %s: %s", session_id, path)
else:
logger.debug(
- f"File not found for deletion in session {session_id}: {path}"
+ "File not found for deletion in session %s: %s", session_id, path
)
return deleted
@@ -2684,11 +2736,11 @@ fi
total_size = int(parts[1])
return file_count, total_size
except ValueError:
- logger.warning(f"Failed to parse upload stats: {resp}")
+ logger.warning("Failed to parse upload stats: %s", resp)
return 0, 0
return 0, 0
except ApiException as e:
- logger.warning(f"Failed to get upload stats: {e}")
+ logger.warning("Failed to get upload stats: %s", e)
return 0, 0
diff --git a/backend/onyx/server/features/build/sandbox/local/local_sandbox_manager.py b/backend/onyx/server/features/build/sandbox/local/local_sandbox_manager.py
index 5218fe709a..421d3b7dc1 100644
--- a/backend/onyx/server/features/build/sandbox/local/local_sandbox_manager.py
+++ b/backend/onyx/server/features/build/sandbox/local/local_sandbox_manager.py
@@ -137,8 +137,8 @@ class LocalSandboxManager(SandboxManager):
error_msg += "\n".join(f" - {template}" for template in missing_templates)
raise RuntimeError(error_msg)
- logger.debug(f"Outputs template found at {outputs_path}")
- logger.debug(f"Venv template found at {venv_path}")
+ logger.debug("Outputs template found at %s", outputs_path)
+ logger.debug("Venv template found at %s", venv_path)
def _get_sandbox_path(self, sandbox_id: str | UUID) -> Path:
"""Get the filesystem path for a sandbox based on sandbox_id.
@@ -189,7 +189,7 @@ class LocalSandboxManager(SandboxManager):
excluded_set = {p.lstrip("/") for p in excluded_paths}
if not source_path.exists():
- logger.warning(f"Source path does not exist: {source_path}")
+ logger.warning("Source path does not exist: %s", source_path)
return
# Iterate through top-level items in source
@@ -245,7 +245,7 @@ class LocalSandboxManager(SandboxManager):
if item.is_dir():
# Check if entire directory is excluded
if rel_path in excluded_set:
- logger.debug(f"Excluding directory: user_library/{rel_path}")
+ logger.debug("Excluding directory: user_library/%s", rel_path)
continue
# Recurse into directory - only create if it has content
@@ -260,7 +260,7 @@ class LocalSandboxManager(SandboxManager):
else:
# Check if file is excluded
if rel_path in excluded_set:
- logger.debug(f"Excluding file: user_library/{rel_path}")
+ logger.debug("Excluding file: user_library/%s", rel_path)
continue
# Create parent directory if needed (lazy creation)
@@ -303,16 +303,19 @@ class LocalSandboxManager(SandboxManager):
RuntimeError: If provisioning fails
"""
logger.info(
- f"Starting sandbox provisioning for sandbox {sandbox_id}, user {user_id}, tenant {tenant_id}"
+ "Starting sandbox provisioning for sandbox %s, user %s, tenant %s",
+ sandbox_id,
+ user_id,
+ tenant_id,
)
# Create sandbox directory structure (user-level only)
- logger.info(f"Creating sandbox directory structure for sandbox {sandbox_id}")
+ logger.info("Creating sandbox directory structure for sandbox %s", sandbox_id)
sandbox_path = self._directory_manager.create_sandbox_directory(str(sandbox_id))
- logger.debug(f"Sandbox directory created at {sandbox_path}")
+ logger.debug("Sandbox directory created at %s", sandbox_path)
logger.info(
- f"Provisioned sandbox {sandbox_id} at {sandbox_path} (no sessions yet)"
+ "Provisioned sandbox %s at %s (no sessions yet)", sandbox_id, sandbox_path
)
return SandboxInfo(
@@ -350,7 +353,10 @@ class LocalSandboxManager(SandboxManager):
self._nextjs_processes.pop(key, None)
except Exception as e:
logger.warning(
- f"Failed to stop Next.js for sandbox {sandbox_id}, session {session_id}: {e}"
+ "Failed to stop Next.js for sandbox %s, session %s: %s",
+ sandbox_id,
+ session_id,
+ e,
)
# Stop all ACP clients for this sandbox (keyed by (sandbox_id, session_id))
@@ -365,7 +371,10 @@ class LocalSandboxManager(SandboxManager):
del self._acp_clients[key]
except Exception as e:
logger.warning(
- f"Failed to stop ACP client for sandbox {sandbox_id}, session {key[1]}: {e}"
+ "Failed to stop ACP client for sandbox %s, session %s: %s",
+ sandbox_id,
+ key[1],
+ e,
)
# Cleanup directory
@@ -377,7 +386,7 @@ class LocalSandboxManager(SandboxManager):
f"Failed to cleanup sandbox directory {sandbox_path}: {e}"
) from e
- logger.info(f"Terminated sandbox {sandbox_id}")
+ logger.info("Terminated sandbox %s", sandbox_id)
def setup_session_workspace(
self,
@@ -433,14 +442,16 @@ class LocalSandboxManager(SandboxManager):
)
logger.info(
- f"Setting up session workspace for session {session_id} in sandbox {sandbox_id}"
+ "Setting up session workspace for session %s in sandbox %s",
+ session_id,
+ sandbox_id,
)
# Create session directory
session_path = self._directory_manager.create_session_directory(
sandbox_path, str(session_id)
)
- logger.debug(f"Session directory created at {session_path}")
+ logger.debug("Session directory created at %s", session_path)
try:
# Setup files access - choose between demo data or user files
@@ -449,9 +460,9 @@ class LocalSandboxManager(SandboxManager):
symlink_target = Path(DEMO_DATA_PATH)
if not symlink_target.exists():
logger.warning(
- f"Demo data directory does not exist: {symlink_target}"
+ "Demo data directory does not exist: %s", symlink_target
)
- logger.info(f"Setting up files symlink to demo data: {symlink_target}")
+ logger.info("Setting up files symlink to demo data: %s", symlink_target)
self._directory_manager.setup_files_symlink(
session_path, symlink_target
)
@@ -461,7 +472,8 @@ class LocalSandboxManager(SandboxManager):
if excluded_user_library_paths:
# Create filtered file structure with symlinks to enabled files only
logger.debug(
- f"Setting up filtered files with {len(excluded_user_library_paths)} exclusions"
+ "Setting up filtered files with %s exclusions",
+ len(excluded_user_library_paths),
)
self._setup_filtered_files(
session_path=session_path,
@@ -471,7 +483,7 @@ class LocalSandboxManager(SandboxManager):
else:
# No exclusions: simple symlink to entire directory
logger.debug(
- f"Setting up files symlink to user files: {source_path}"
+ "Setting up files symlink to user files: %s", source_path
)
self._directory_manager.setup_files_symlink(
session_path, source_path
@@ -482,7 +494,9 @@ class LocalSandboxManager(SandboxManager):
# Setup org_info directory with user identity (at session root)
if user_work_area:
- logger.debug(f"Setting up org_info for {user_work_area}/{user_level}")
+ logger.debug(
+ "Setting up org_info for %s/%s", user_work_area, user_level
+ )
self._directory_manager.setup_org_info(
session_path, user_work_area, user_level
)
@@ -502,7 +516,9 @@ class LocalSandboxManager(SandboxManager):
# Setup opencode.json with LLM provider configuration
logger.debug(
- f"Setting up opencode config with provider: {llm_config.provider}, model: {llm_config.model_name}"
+ "Setting up opencode config with provider: %s, model: %s",
+ llm_config.provider,
+ llm_config.model_name,
)
self._directory_manager.setup_opencode_config(
sandbox_path=session_path,
@@ -518,7 +534,9 @@ class LocalSandboxManager(SandboxManager):
web_dir = self._directory_manager.get_web_path(
sandbox_path, str(session_id)
)
- logger.info(f"Starting Next.js server at {web_dir} on port {nextjs_port}")
+ logger.info(
+ "Starting Next.js server at %s on port %s", web_dir, nextjs_port
+ )
nextjs_process = self._process_manager.start_nextjs_server(
web_dir, nextjs_port
@@ -547,15 +565,17 @@ class LocalSandboxManager(SandboxManager):
)
logger.debug("Agent instructions ready")
- logger.info(f"Set up session workspace {session_id} at {session_path}")
+ logger.info("Set up session workspace %s at %s", session_id, session_path)
except Exception as e:
# Cleanup on failure
logger.error(
- f"Session workspace setup failed for session {session_id}: {e}",
+ "Session workspace setup failed for session %s: %s",
+ session_id,
+ e,
exc_info=True,
)
- logger.info(f"Cleaning up session directory at {session_path}")
+ logger.info("Cleaning up session directory at %s", session_path)
self._directory_manager.cleanup_session_directory(
sandbox_path, str(session_id)
)
@@ -598,16 +618,16 @@ class LocalSandboxManager(SandboxManager):
if client:
try:
client.stop()
- logger.debug(f"Stopped ACP client for session {session_id}")
+ logger.debug("Stopped ACP client for session %s", session_id)
except Exception as e:
logger.warning(
- f"Failed to stop ACP client for session {session_id}: {e}"
+ "Failed to stop ACP client for session %s: %s", session_id, e
)
# Cleanup session directory
sandbox_path = self._get_sandbox_path(sandbox_id)
self._directory_manager.cleanup_session_directory(sandbox_path, str(session_id))
- logger.info(f"Cleaned up session workspace {session_id}")
+ logger.info("Cleaned up session workspace %s", session_id)
def _stop_nextjs_process(
self, process: subprocess.Popen[bytes], session_id: UUID
@@ -621,19 +641,23 @@ class LocalSandboxManager(SandboxManager):
if process.poll() is not None:
# Process already terminated
logger.debug(
- f"Next.js server for session {session_id} already terminated (exit code: {process.returncode})"
+ "Next.js server for session %s already terminated (exit code: %s)",
+ session_id,
+ process.returncode,
)
return
try:
logger.info(
- f"Stopping Next.js server (PID {process.pid}) for session {session_id}"
+ "Stopping Next.js server (PID %s) for session %s",
+ process.pid,
+ session_id,
)
self._process_manager.terminate_process(process.pid)
- logger.debug(f"Next.js server stopped for session {session_id}")
+ logger.debug("Next.js server stopped for session %s", session_id)
except Exception as e:
logger.warning(
- f"Failed to stop Next.js server for session {session_id}: {e}"
+ "Failed to stop Next.js server for session %s: %s", session_id, e
)
def _stop_nextjs_server_on_port(self, port: int, session_id: UUID) -> None:
@@ -665,26 +689,35 @@ class LocalSandboxManager(SandboxManager):
]
if pids:
logger.info(
- f"Found {len(pids)} process(es) on port {port} for session {session_id}, stopping all"
+ "Found %s process(es) on port %s for session %s, stopping all",
+ len(pids),
+ port,
+ session_id,
)
for pid in pids:
try:
logger.debug(
- f"Stopping Next.js server (PID {pid}) on port {port} for session {session_id}"
+ "Stopping Next.js server (PID %s) on port %s for session %s",
+ pid,
+ port,
+ session_id,
)
self._process_manager.terminate_process(pid)
except Exception as e:
logger.warning(
- f"Failed to stop process {pid} on port {port}: {e}"
+ "Failed to stop process %s on port %s: %s", pid, port, e
)
return
else:
logger.debug(
- f"No process found on port {port} for session {session_id}"
+ "No process found on port %s for session %s", port, session_id
)
except subprocess.TimeoutExpired:
logger.warning(
- f"lsof timed out after {LSOF_TIMEOUT_SECONDS}s while looking for process on port {port} for session {session_id}"
+ "lsof timed out after %ss while looking for process on port %s for session %s",
+ LSOF_TIMEOUT_SECONDS,
+ port,
+ session_id,
)
except FileNotFoundError:
# lsof not available, try psutil
@@ -708,32 +741,41 @@ class LocalSandboxManager(SandboxManager):
if pids_to_stop:
logger.info(
- f"Found {len(pids_to_stop)} process(es) on port {port} for session {session_id}, stopping all"
+ "Found %s process(es) on port %s for session %s, stopping all",
+ len(pids_to_stop),
+ port,
+ session_id,
)
for pid in pids_to_stop:
try:
logger.debug(
- f"Stopping Next.js server (PID {pid}) on port {port} for session {session_id}"
+ "Stopping Next.js server (PID %s) on port %s for session %s",
+ pid,
+ port,
+ session_id,
)
self._process_manager.terminate_process(pid)
except Exception as e:
logger.warning(
- f"Failed to stop process {pid} on port {port}: {e}"
+ "Failed to stop process %s on port %s: %s", pid, port, e
)
return
logger.debug(
- f"No process found on port {port} for session {session_id}"
+ "No process found on port %s for session %s", port, session_id
)
except ImportError:
logger.warning(
- f"Neither lsof nor psutil available to find process on port {port}"
+ "Neither lsof nor psutil available to find process on port %s", port
)
except Exception as e:
- logger.warning(f"Failed to find process on port {port}: {e}")
+ logger.warning("Failed to find process on port %s: %s", port, e)
except Exception as e:
logger.warning(
- f"Failed to stop Next.js server on port {port} for session {session_id}: {e}"
+ "Failed to stop Next.js server on port %s for session %s: %s",
+ port,
+ session_id,
+ e,
)
def create_snapshot(
@@ -810,14 +852,18 @@ class LocalSandboxManager(SandboxManager):
with httpx.Client(timeout=1.0) as client:
client.get(f"http://localhost:{nextjs_port}")
logger.info(
- f"Port {nextjs_port} already alive for session {session_id} (orphan process) — skipping restart"
+ "Port %s already alive for session %s (orphan process) — skipping restart",
+ nextjs_port,
+ session_id,
)
return
except Exception:
pass # Port is dead; proceed with restart
logger.info(
- f"Starting Next.js for session {session_id} on port {nextjs_port}"
+ "Starting Next.js for session %s on port %s",
+ session_id,
+ nextjs_port,
)
sandbox_path = self._get_sandbox_path(sandbox_id)
web_dir = self._directory_manager.get_web_path(
@@ -825,7 +871,9 @@ class LocalSandboxManager(SandboxManager):
)
if not web_dir.exists():
logger.warning(
- f"Web dir missing for session {session_id}: {web_dir} — cannot restart Next.js"
+ "Web dir missing for session %s: %s — cannot restart Next.js",
+ session_id,
+ web_dir,
)
return
process = self._process_manager.start_nextjs_server(
@@ -834,11 +882,13 @@ class LocalSandboxManager(SandboxManager):
with self._nextjs_lock:
self._nextjs_processes[process_key] = process
logger.info(
- f"Auto-restarted Next.js for session {session_id} on port {nextjs_port}"
+ "Auto-restarted Next.js for session %s on port %s",
+ session_id,
+ nextjs_port,
)
except Exception as e:
logger.error(
- f"Failed to auto-restart Next.js for session {session_id}: {e}"
+ "Failed to auto-restart Next.js for session %s: %s", session_id, e
)
finally:
self._nextjs_starting.discard(process_key)
@@ -929,7 +979,9 @@ class LocalSandboxManager(SandboxManager):
sandbox_id, session_id, str(session_path), context="local"
)
logger.info(
- f"Creating new ACP client for sandbox {sandbox_id}, session {session_id}"
+ "Creating new ACP client for sandbox %s, session %s",
+ sandbox_id,
+ session_id,
)
# Create and start ACP client for this session
@@ -1119,7 +1171,10 @@ class LocalSandboxManager(SandboxManager):
target_path.chmod(0o644)
logger.info(
- f"Uploaded file to session {session_id}: attachments/{filename} ({len(content)} bytes)"
+ "Uploaded file to session %s: attachments/%s (%s bytes)",
+ session_id,
+ filename,
+ len(content),
)
# Inject attachments section into AGENTS.md if not already present
@@ -1204,14 +1259,16 @@ class LocalSandboxManager(SandboxManager):
raise ValueError("Path traversal not allowed")
if not file_path.exists():
- logger.debug(f"File not found for deletion in session {session_id}: {path}")
+ logger.debug(
+ "File not found for deletion in session %s: %s", session_id, path
+ )
return False
if file_path.is_dir():
raise ValueError("Cannot delete directory")
file_path.unlink()
- logger.info(f"Deleted file from session {session_id}: {path}")
+ logger.info("Deleted file from session %s: %s", session_id, path)
return True
@@ -1389,6 +1446,6 @@ class LocalSandboxManager(SandboxManager):
"""
source_info = f" source={source}" if source else ""
logger.debug(
- f"sync_files called for local sandbox {sandbox_id}{source_info} - no-op"
+ "sync_files called for local sandbox %s%s - no-op", sandbox_id, source_info
)
return True
diff --git a/backend/onyx/server/features/build/sandbox/local/process_manager.py b/backend/onyx/server/features/build/sandbox/local/process_manager.py
index 193528f230..e835fa6d3f 100644
--- a/backend/onyx/server/features/build/sandbox/local/process_manager.py
+++ b/backend/onyx/server/features/build/sandbox/local/process_manager.py
@@ -46,25 +46,25 @@ class ProcessManager:
Raises:
RuntimeError: If server fails to start within timeout
"""
- logger.info(f"Starting Next.js server in {web_dir} on port {port}")
+ logger.info("Starting Next.js server in %s on port %s", web_dir, port)
# Clear Next.js cache to avoid stale paths from template
next_cache = web_dir / ".next"
if next_cache.exists():
- logger.debug(f"Clearing Next.js cache at {next_cache}")
+ logger.debug("Clearing Next.js cache at %s", next_cache)
shutil.rmtree(next_cache)
# Verify web_dir exists and has package.json
if not web_dir.exists():
- logger.error(f"Web directory does not exist: {web_dir}")
+ logger.error("Web directory does not exist: %s", web_dir)
raise RuntimeError(f"Web directory does not exist: {web_dir}")
package_json = web_dir / "package.json"
if not package_json.exists():
- logger.error(f"package.json not found in {web_dir}")
+ logger.error("package.json not found in %s", web_dir)
raise RuntimeError(f"package.json not found in {web_dir}")
- logger.debug(f"Starting npm run dev command in {web_dir}")
+ logger.debug("Starting npm run dev command in %s", web_dir)
# CRITICAL: Inherit stdout/stderr (None) to prevent pipe buffer overflow.
# When PIPE is used but never drained, the buffer fills up (64KB on most systems)
# and the subprocess blocks indefinitely on write, causing the server to freeze.
@@ -77,18 +77,21 @@ class ProcessManager:
stdout=None,
stderr=None,
)
- logger.info(f"Next.js process started with PID {process.pid}")
+ logger.info("Next.js process started with PID %s", process.pid)
# Wait for server to be ready
server_url = f"http://localhost:{port}"
- logger.info(f"Waiting for Next.js server at {server_url} (timeout: {timeout}s)")
+ logger.info(
+ "Waiting for Next.js server at %s (timeout: %ss)", server_url, timeout
+ )
if not self._wait_for_server(server_url, timeout=timeout, process=process):
# Check if process died
if process.poll() is not None:
logger.error(
- f"Next.js server process died with code {process.returncode}. "
- f"Check the terminal or logs in {web_dir} for details."
+ "Next.js server process died with code %s. Check the terminal or logs in %s for details.",
+ process.returncode,
+ web_dir,
)
raise RuntimeError(
f"Next.js server process died with code {process.returncode}. Check server logs for details."
@@ -96,14 +99,16 @@ class ProcessManager:
# Process still running but server not responding
logger.error(
- f"Next.js server failed to respond within {timeout} seconds (process still running with PID {process.pid})"
+ "Next.js server failed to respond within %s seconds (process still running with PID %s)",
+ timeout,
+ process.pid,
)
raise RuntimeError(
f"Next.js server failed to start within {timeout} seconds"
)
- logger.info(f"Next.js server is ready at {server_url}")
+ logger.info("Next.js server is ready at %s", server_url)
return process
def _wait_for_server(
@@ -135,8 +140,10 @@ class ProcessManager:
# Check if process died early
if process is not None and process.poll() is not None:
logger.warning(
- f"Process died during wait (exit code: {process.returncode}) "
- f"after {elapsed:.1f}s and {attempt_count} attempts"
+ "Process died during wait (exit code: %s) after %ss and %s attempts",
+ process.returncode,
+ format(elapsed, ".1f"),
+ attempt_count,
)
return False
@@ -144,28 +151,41 @@ class ProcessManager:
with urllib.request.urlopen(url, timeout=2) as response:
if response.status == 200:
logger.debug(
- f"Server ready after {elapsed:.1f}s and {attempt_count} attempts"
+ "Server ready after %ss and %s attempts",
+ format(elapsed, ".1f"),
+ attempt_count,
)
return True
except urllib.error.HTTPError as e:
# Log HTTP errors (server responding but with error)
if time.time() - last_log_time >= 10:
logger.debug(
- f"HTTP error {e.code} from {url} after {elapsed:.1f}s ({attempt_count} attempts)"
+ "HTTP error %s from %s after %ss (%s attempts)",
+ e.code,
+ url,
+ format(elapsed, ".1f"),
+ attempt_count,
)
last_log_time = time.time()
except (urllib.error.URLError, TimeoutError) as e:
# Log connection errors periodically (every 10 seconds)
if time.time() - last_log_time >= 10:
logger.debug(
- f"Still waiting for {url} after {elapsed:.1f}s ({attempt_count} attempts): {type(e).__name__}"
+ "Still waiting for %s after %ss (%s attempts): %s",
+ url,
+ format(elapsed, ".1f"),
+ attempt_count,
+ type(e).__name__,
)
last_log_time = time.time()
time.sleep(poll_interval)
logger.warning(
- f"Server at {url} did not become available within {timeout}s ({attempt_count} attempts)"
+ "Server at %s did not become available within %ss (%s attempts)",
+ url,
+ timeout,
+ attempt_count,
)
return False
diff --git a/backend/onyx/server/features/build/sandbox/manager/directory_manager.py b/backend/onyx/server/features/build/sandbox/manager/directory_manager.py
index abeec8810c..c728547f3d 100644
--- a/backend/onyx/server/features/build/sandbox/manager/directory_manager.py
+++ b/backend/onyx/server/features/build/sandbox/manager/directory_manager.py
@@ -142,7 +142,7 @@ class DirectoryManager:
session_path = sandbox_path / "sessions" / session_id
if session_path.exists():
shutil.rmtree(session_path)
- logger.info(f"Cleaned up session directory: {session_path}")
+ logger.info("Cleaned up session directory: %s", session_path)
def get_session_path(self, sandbox_path: Path, session_id: str) -> Path:
"""Get path to session workspace.
@@ -195,7 +195,9 @@ class DirectoryManager:
persona = get_persona_info(user_work_area, user_level)
if not persona:
logger.debug(
- f"No persona found for work_area={user_work_area}, level={user_level}, skipping org_info setup"
+ "No persona found for work_area=%s, level=%s, skipping org_info setup",
+ user_work_area,
+ user_level,
)
return
@@ -218,11 +220,13 @@ class DirectoryManager:
)
logger.info(
- f"Created org_info with identity: {persona['name']} <{persona['email']}>"
+ "Created org_info with identity: %s <%s>",
+ persona["name"],
+ persona["email"],
)
except Exception as e:
# Don't fail provisioning if org_info setup fails
- logger.warning(f"Failed to setup org_info: {e}")
+ logger.warning("Failed to setup org_info: %s", e)
def setup_outputs_directory(self, sandbox_path: Path) -> None:
"""Copy outputs template and create additional directories.
@@ -316,7 +320,7 @@ class DirectoryManager:
# Write the generated content
agent_md_path.write_text(content)
- logger.debug(f"Generated AGENTS.md at {agent_md_path}")
+ logger.debug("Generated AGENTS.md at %s", agent_md_path)
def setup_skills(self, sandbox_path: Path, overwrite: bool = True) -> None:
"""Copy skills directory to .opencode/skills.
@@ -333,13 +337,15 @@ class DirectoryManager:
if not self._skills_path.exists():
logger.warning(
- f"Skills path {self._skills_path} does not exist, skipping skills setup"
+ "Skills path %s does not exist, skipping skills setup",
+ self._skills_path,
)
return
if not overwrite and skills_dest.exists():
logger.debug(
- f"Skills directory already exists at {skills_dest}, skipping skills setup"
+ "Skills directory already exists at %s, skipping skills setup",
+ skills_dest,
)
return
@@ -355,11 +361,15 @@ class DirectoryManager:
# Verify the copy succeeded
if not skills_dest.exists():
logger.error(
- f"Skills copy failed: destination {skills_dest} does not exist after copy"
+ "Skills copy failed: destination %s does not exist after copy",
+ skills_dest,
)
except Exception as e:
logger.error(
- f"Failed to copy skills from {self._skills_path} to {skills_dest}: {e}",
+ "Failed to copy skills from %s to %s: %s",
+ self._skills_path,
+ skills_dest,
+ e,
exc_info=True,
)
raise
@@ -394,7 +404,7 @@ class DirectoryManager:
config_path = sandbox_path / "opencode.json"
if not overwrite and config_path.exists():
logger.debug(
- f"opencode.json already exists at {config_path}, skipping config setup"
+ "opencode.json already exists at %s, skipping config setup", config_path
)
return
diff --git a/backend/onyx/server/features/build/sandbox/manager/snapshot_manager.py b/backend/onyx/server/features/build/sandbox/manager/snapshot_manager.py
index 32a38b653c..3e2c26882f 100644
--- a/backend/onyx/server/features/build/sandbox/manager/snapshot_manager.py
+++ b/backend/onyx/server/features/build/sandbox/manager/snapshot_manager.py
@@ -102,13 +102,16 @@ class SnapshotManager:
)
logger.info(
- f"Created snapshot {snapshot_id} for sandbox {sandbox_id}, size: {size_bytes} bytes"
+ "Created snapshot %s for sandbox %s, size: %s bytes",
+ snapshot_id,
+ sandbox_id,
+ size_bytes,
)
return snapshot_id, storage_path, size_bytes
except Exception as e:
- logger.error(f"Failed to create snapshot for sandbox {sandbox_id}: {e}")
+ logger.error("Failed to create snapshot for sandbox %s: %s", sandbox_id, e)
raise RuntimeError(f"Failed to create snapshot: {e}") from e
finally:
# Cleanup temp file
@@ -117,7 +120,7 @@ class SnapshotManager:
Path(tmp_path).unlink(missing_ok=True)
except Exception as cleanup_error:
logger.warning(
- f"Failed to cleanup temp file {tmp_path}: {cleanup_error}"
+ "Failed to cleanup temp file %s: %s", tmp_path, cleanup_error
)
def restore_snapshot(
@@ -176,10 +179,10 @@ class SnapshotManager:
)
tar.extractall(target_path)
- logger.info(f"Restored snapshot from {storage_path} to {target_path}")
+ logger.info("Restored snapshot from %s to %s", storage_path, target_path)
except Exception as e:
- logger.error(f"Failed to restore snapshot {storage_path}: {e}")
+ logger.error("Failed to restore snapshot %s: %s", storage_path, e)
raise RuntimeError(f"Failed to restore snapshot: {e}") from e
finally:
# Cleanup temp file
@@ -188,7 +191,7 @@ class SnapshotManager:
Path(tmp_path).unlink(missing_ok=True)
except Exception as cleanup_error:
logger.warning(
- f"Failed to cleanup temp file {tmp_path}: {cleanup_error}"
+ "Failed to cleanup temp file %s: %s", tmp_path, cleanup_error
)
# Close the file IO if it's still open
try:
@@ -208,10 +211,10 @@ class SnapshotManager:
"""
try:
self._file_store.delete_file(storage_path)
- logger.info(f"Deleted snapshot: {storage_path}")
+ logger.info("Deleted snapshot: %s", storage_path)
except Exception as e:
# Log but don't fail if snapshot doesn't exist
- logger.warning(f"Failed to delete snapshot {storage_path}: {e}")
+ logger.warning("Failed to delete snapshot %s: %s", storage_path, e)
raise RuntimeError(f"Failed to delete snapshot: {e}") from e
def get_snapshot_size(self, storage_path: str) -> int | None:
diff --git a/backend/onyx/server/features/build/sandbox/util/agent_instructions.py b/backend/onyx/server/features/build/sandbox/util/agent_instructions.py
index 0f61e49ffc..ebbb6f813e 100644
--- a/backend/onyx/server/features/build/sandbox/util/agent_instructions.py
+++ b/backend/onyx/server/features/build/sandbox/util/agent_instructions.py
@@ -255,7 +255,7 @@ def _scan_skills_directory(skills_path: Path) -> str:
description = extract_skill_description(skill_md)
skills_list.append(f"- **{skill_dir.name}**: {description}")
except Exception as e:
- logger.warning(f"Error scanning skills directory: {e}")
+ logger.warning("Error scanning skills directory: %s", e)
return "Error loading skills."
if not skills_list:
@@ -419,7 +419,7 @@ def build_knowledge_sources_section(files_path: Path) -> str:
sections.append("\n".join(lines))
except Exception as e:
- logger.warning(f"Error building knowledge sources section: {e}")
+ logger.warning("Error building knowledge sources section: %s", e)
return "Error scanning knowledge sources."
if not sections:
@@ -460,7 +460,7 @@ def generate_agent_instructions(
Generated AGENTS.md content with placeholders replaced
"""
if not template_path.exists():
- logger.warning(f"AGENTS.template.md not found at {template_path}")
+ logger.warning("AGENTS.template.md not found at %s", template_path)
return "# Agent Instructions\n\nNo custom instructions provided."
# Read template content
diff --git a/backend/onyx/server/features/build/session/manager.py b/backend/onyx/server/features/build/session/manager.py
index f54f7e24d5..9dd51ca02f 100644
--- a/backend/onyx/server/features/build/session/manager.py
+++ b/backend/onyx/server/features/build/session/manager.py
@@ -342,7 +342,8 @@ class SessionManager:
)
else:
logger.warning(
- f"Requested provider type {requested_provider_type} not found, falling back to default"
+ "Requested provider type %s not found, falling back to default",
+ requested_provider_type,
)
# Fallback to system default
@@ -462,7 +463,10 @@ class SessionManager:
self._db_session.flush()
session_id = str(build_session.id)
logger.info(
- f"Created build session {session_id} for user {user_id} (port: {nextjs_port})"
+ "Created build session %s for user %s (port: %s)",
+ session_id,
+ user_id,
+ nextjs_port,
)
# Check if user already has a sandbox (one sandbox per user model)
@@ -480,7 +484,10 @@ class SessionManager:
):
# Re-provision sandbox (pod doesn't exist or failed)
logger.info(
- f"Re-provisioning {sandbox.status.value} sandbox {sandbox_id} for user {user_id}"
+ "Re-provisioning %s sandbox %s for user %s",
+ sandbox.status.value,
+ sandbox_id,
+ user_id,
)
sandbox_info = self._sandbox_manager.provision(
sandbox_id=sandbox_id,
@@ -496,7 +503,9 @@ class SessionManager:
# Verify pod is healthy before reusing (use short timeout for quick check)
if not self._sandbox_manager.health_check(sandbox_id, timeout=5.0):
logger.warning(
- f"Sandbox {sandbox_id} marked as {sandbox.status} but pod is unhealthy/missing. Entering recovery mode."
+ "Sandbox %s marked as %s but pod is unhealthy/missing. Entering recovery mode.",
+ sandbox_id,
+ sandbox.status,
)
# Terminate to clean up any lingering K8s resources
self._sandbox_manager.terminate(sandbox_id)
@@ -507,7 +516,7 @@ class SessionManager:
)
logger.info(
- f"Re-provisioning sandbox {sandbox_id} for user {user_id}"
+ "Re-provisioning sandbox %s for user %s", sandbox_id, user_id
)
sandbox_info = self._sandbox_manager.provision(
sandbox_id=sandbox_id,
@@ -521,7 +530,10 @@ class SessionManager:
)
else:
logger.info(
- f"Reusing existing sandbox {sandbox_id} (status: {sandbox.status}) for new session {session_id}"
+ "Reusing existing sandbox %s (status: %s) for new session %s",
+ sandbox_id,
+ sandbox.status,
+ session_id,
)
else:
# PROVISIONING status - sandbox is being created by another request
@@ -539,7 +551,9 @@ class SessionManager:
user_id=user_id,
)
sandbox_id = sandbox.id
- logger.info(f"Created sandbox record {sandbox_id} for session {session_id}")
+ logger.info(
+ "Created sandbox record %s for session %s", sandbox_id, session_id
+ )
# Provision sandbox (no DB operations inside)
sandbox_info = self._sandbox_manager.provision(
@@ -556,7 +570,7 @@ class SessionManager:
# Set up session workspace within the sandbox
logger.info(
- f"Setting up session workspace {session_id} in sandbox {sandbox.id}"
+ "Setting up session workspace %s in sandbox %s", session_id, sandbox.id
)
# Fetch user data for personalization in AGENTS.md
user = fetch_user_by_id(self._db_session, user_id)
@@ -572,7 +586,8 @@ class SessionManager:
)
if excluded_user_library_paths:
logger.debug(
- f"Excluding {len(excluded_user_library_paths)} disabled user library paths"
+ "Excluding %s disabled user library paths",
+ len(excluded_user_library_paths),
)
self._sandbox_manager.setup_session_workspace(
@@ -592,7 +607,9 @@ class SessionManager:
sandbox_id = sandbox.id
logger.info(
- f"Successfully created session {session_id} with workspace in sandbox {sandbox.id}"
+ "Successfully created session %s with workspace in sandbox %s",
+ session_id,
+ sandbox.id,
)
return build_session
@@ -636,7 +653,7 @@ class SessionManager:
)
if existing:
logger.info(
- f"Existing empty session {existing.id} found for user {user_id}"
+ "Existing empty session %s found for user %s", existing.id, user_id
)
# Verify sandbox is healthy before returning existing session
sandbox = get_sandbox_by_user_id(self._db_session, user_id)
@@ -654,23 +671,28 @@ class SessionManager:
)
if is_healthy and workspace_exists:
logger.info(
- f"Returning existing empty session {existing.id} for user {user_id}"
+ "Returning existing empty session %s for user %s",
+ existing.id,
+ user_id,
)
return existing
elif not is_healthy:
logger.warning(
- f"Empty session {existing.id} has unhealthy sandbox {sandbox.id}. Deleting and creating fresh session."
+ "Empty session %s has unhealthy sandbox %s. Deleting and creating fresh session.",
+ existing.id,
+ sandbox.id,
)
else:
logger.warning(
- f"Empty session {existing.id} workspace missing in sandbox "
- f"{sandbox.id}. Deleting and creating fresh session."
+ "Empty session %s workspace missing in sandbox %s. Deleting and creating fresh session.",
+ existing.id,
+ sandbox.id,
)
else:
logger.warning(
- f"Empty session {existing.id} has no active sandbox "
- f"(sandbox={'missing' if not sandbox else sandbox.status}). "
- f"Deleting and creating fresh session."
+ "Empty session %s has no active sandbox (sandbox=%s). Deleting and creating fresh session.",
+ existing.id,
+ "missing" if not sandbox else sandbox.status,
)
# Delete the stale empty session - create_session__no_commit will
@@ -702,7 +724,7 @@ class SessionManager:
empty_session = get_empty_session_for_user(user_id, self._db_session)
if not empty_session:
- logger.info(f"No empty session found for user {user_id}")
+ logger.info("No empty session found for user %s", user_id)
return False
session_id = empty_session.id
@@ -717,15 +739,19 @@ class SessionManager:
nextjs_port=empty_session.nextjs_port,
)
logger.info(
- f"Cleaned up session workspace {session_id} in sandbox {sandbox.id}"
+ "Cleaned up session workspace %s in sandbox %s",
+ session_id,
+ sandbox.id,
)
except Exception as e:
# Log but don't fail - session can still be deleted
- logger.warning(f"Failed to cleanup session workspace {session_id}: {e}")
+ logger.warning(
+ "Failed to cleanup session workspace %s: %s", session_id, e
+ )
# Delete session (cascade deletes artifacts)
delete_build_session__no_commit(session_id, user_id, self._db_session)
- logger.info(f"Deleted empty session {session_id} for user {user_id}")
+ logger.info("Deleted empty session %s for user %s", session_id, user_id)
return True
@@ -878,7 +904,7 @@ class SessionManager:
else f"Build Session {str(session_id)[:8]}"
)
except Exception as e:
- logger.warning(f"Failed to generate session name with LLM: {e}")
+ logger.warning("Failed to generate session name with LLM: %s", e)
# Fallback to simple truncation
return user_message[:40].strip() + ("..." if len(user_message) > 40 else "")
@@ -928,7 +954,7 @@ class SessionManager:
return self._parse_suggestions(raw_output)
except Exception as e:
- logger.warning(f"Failed to generate follow-up suggestions with LLM: {e}")
+ logger.warning("Failed to generate follow-up suggestions with LLM: %s", e)
return []
def _parse_suggestions(self, raw_output: str) -> list[dict[str, str]]:
@@ -998,7 +1024,7 @@ class SessionManager:
# Silent fail - return empty list
logger.warning(
- f"Failed to parse suggestions from LLM output: {raw_output[:200]}"
+ "Failed to parse suggestions from LLM output: %s", raw_output[:200]
)
return []
@@ -1038,12 +1064,16 @@ class SessionManager:
nextjs_port=session.nextjs_port,
)
logger.info(
- f"Cleaned up session workspace {session_id} in sandbox {sandbox.id}"
+ "Cleaned up session workspace %s in sandbox %s",
+ session_id,
+ sandbox.id,
)
except Exception as e:
# Log but don't fail - session can still be deleted even if
# workspace cleanup fails (e.g., if pod is already terminated)
- logger.warning(f"Failed to cleanup session workspace {session_id}: {e}")
+ logger.warning(
+ "Failed to cleanup session workspace %s: %s", session_id, e
+ )
# Delete snapshot files from S3 before removing DB records
snapshots = get_snapshots_for_session(self._db_session, session_id)
@@ -1059,7 +1089,9 @@ class SessionManager:
snapshot_manager.delete_snapshot(snapshot.storage_path)
except Exception as e:
logger.warning(
- f"Failed to delete snapshot file {snapshot.storage_path}: {e}"
+ "Failed to delete snapshot file %s: %s",
+ snapshot.storage_path,
+ e,
)
# Delete session (uses flush, caller commits)
@@ -1508,7 +1540,7 @@ class SessionManager:
"error": str(e),
},
)
- logger.exception(f"RuntimeError in build message streaming: {e}")
+ logger.exception("RuntimeError in build message streaming: %s", e)
yield _format_packet_event(error_packet)
except Exception as e:
error_packet = ErrorPacket(message=str(e))
@@ -2241,13 +2273,13 @@ class SessionManager:
return False
if sandbox.status == SandboxStatus.TERMINATED:
- logger.info(f"Sandbox {sandbox.id} already terminated")
+ logger.info("Sandbox %s already terminated", sandbox.id)
return True
try:
# Terminate the sandbox (this cleans up all resources)
self._sandbox_manager.terminate(sandbox.id)
- logger.info(f"Terminated sandbox {sandbox.id} for user {user_id}")
+ logger.info("Terminated sandbox %s for user %s", sandbox.id, user_id)
# Update status in database
update_sandbox_status__no_commit(
@@ -2258,5 +2290,5 @@ class SessionManager:
return True
except Exception as e:
- logger.error(f"Failed to terminate sandbox {sandbox.id}: {e}")
+ logger.error("Failed to terminate sandbox %s: %s", sandbox.id, e)
raise RuntimeError(f"Failed to terminate sandbox: {e}") from e
diff --git a/backend/onyx/server/features/input_prompt/api.py b/backend/onyx/server/features/input_prompt/api.py
index d3546d3308..a8ac00ca9f 100644
--- a/backend/onyx/server/features/input_prompt/api.py
+++ b/backend/onyx/server/features/input_prompt/api.py
@@ -96,7 +96,7 @@ def patch_input_prompt(
)
except ValueError as e:
error_msg = "Error occurred while updated input prompt"
- logger.warning(f"{error_msg}. Stack trace: {e}")
+ logger.warning("%s. Stack trace: %s", error_msg, e)
raise HTTPException(status_code=404, detail=error_msg)
return InputPromptSnapshot.from_model(updated_input_prompt)
@@ -116,7 +116,7 @@ def delete_input_prompt(
except ValueError as e:
error_msg = "Error occurred while deleting input prompt"
- logger.warning(f"{error_msg}. Stack trace: {e}")
+ logger.warning("%s. Stack trace: %s", error_msg, e)
raise HTTPException(status_code=404, detail=error_msg)
@@ -131,7 +131,7 @@ def delete_public_input_prompt(
except ValueError as e:
error_msg = "Error occurred while deleting input prompt"
- logger.warning(f"{error_msg}. Stack trace: {e}")
+ logger.warning("%s. Stack trace: %s", error_msg, e)
raise HTTPException(status_code=404, detail=error_msg)
diff --git a/backend/onyx/server/features/mcp/api.py b/backend/onyx/server/features/mcp/api.py
index 5b6dcbb8d0..6c47fde6fa 100644
--- a/backend/onyx/server/features/mcp/api.py
+++ b/backend/onyx/server/features/mcp/api.py
@@ -452,7 +452,7 @@ def test_mcp_server_credentials(
return False, "Failed to retrieve tools list from server."
except Exception as e:
- logger.error(f"Failed to test MCP server credentials: {e}")
+ logger.error("Failed to test MCP server credentials: %s", e)
return False, f"Connection failed: {str(e)}"
@@ -500,7 +500,7 @@ async def _connect_oauth(
) -> MCPUserOAuthConnectResponse:
"""Connect OAuth flow for per-user MCP server authentication"""
- logger.info(f"Initiating per-user OAuth for server: {request.server_id}")
+ logger.info("Initiating per-user OAuth for server: %s", request.server_id)
try:
server_id = int(request.server_id)
@@ -610,7 +610,7 @@ async def _connect_oauth(
# always make a http request for the initial probe
transport = mcp_server.transport if is_connected else MCPTransport.STREAMABLE_HTTP
probe_url = mcp_server.server_url
- logger.info(f"Probing OAuth server at: {probe_url}")
+ logger.info("Probing OAuth server at: %s", probe_url)
oauth_auth = make_oauth_provider(
mcp_server,
@@ -633,7 +633,7 @@ async def _connect_oauth(
transport=transport,
auth=oauth_auth,
)
- logger.info(f"OAuth initialization completed successfully: {x}")
+ logger.info("OAuth initialization completed successfully: %s", x)
return x
except Exception:
logger.exception("OAuth initialization failed")
@@ -674,21 +674,21 @@ async def _connect_oauth(
try:
init_result = init_task.result()
logger.info(
- f"OAuth initialization completed during timeout: {init_result}"
+ "OAuth initialization completed during timeout: %s", init_result
)
return MCPUserOAuthConnectResponse(
server_id=int(request.server_id),
oauth_url=request.return_path,
)
except Exception as e:
- logger.error(f"OAuth initialization failed during timeout: {e}")
+ logger.error("OAuth initialization failed during timeout: %s", e)
raise HTTPException(
status_code=400, detail=f"OAuth initialization failed: {str(e)}"
)
raise HTTPException(status_code=400, detail="Auth URL retrieval timed out")
logger.info(
- f"Connected to auth url: {oauth_url} for mcp server: {mcp_server.name}"
+ "Connected to auth url: %s for mcp server: %s", oauth_url, mcp_server.name
)
return MCPUserOAuthConnectResponse(
server_id=int(request.server_id), oauth_url=oauth_url
@@ -699,13 +699,13 @@ async def _connect_oauth(
t.cancel()
try:
init_result = init_task.result()
- logger.info(f"OAuth initialization completed without redirect: {init_result}")
+ logger.info("OAuth initialization completed without redirect: %s", init_result)
except Exception as e:
if isinstance(e, ExceptionGroup):
saved_e = log_exception_group(e)
else:
saved_e = e
- logger.error(f"OAuth initialization failed: {saved_e}")
+ logger.error("OAuth initialization failed: %s", saved_e)
# If initialize failed and we also didn't get an auth URL, surface an error
raise HTTPException(
status_code=400, detail=f"Failed to initialize OAuth client: {str(saved_e)}"
@@ -788,7 +788,10 @@ async def process_oauth_callback(
db_session.commit()
logger.info(
- f"server_id={str(mcp_server.id)} server_name={mcp_server.name} return_path={state_data.return_path}"
+ "server_id=%s server_name=%s return_path=%s",
+ str(mcp_server.id),
+ mcp_server.name,
+ state_data.return_path,
)
return MCPOAuthCallbackResponse(
@@ -808,7 +811,7 @@ def save_user_credentials(
) -> MCPApiKeyResponse:
"""Save user credentials for template-based MCP server authentication"""
- logger.info(f"Saving user credentials for server: {request.server_id}")
+ logger.info("Saving user credentials for server: %s", request.server_id)
try:
server_id = request.server_id
@@ -855,7 +858,7 @@ def save_user_credentials(
config_data[field_key] = field_val
except Exception as e:
- logger.error(f"Failed to process authentication template: {e}")
+ logger.error("Failed to process authentication template: %s", e)
raise HTTPException(
status_code=400,
detail=f"Failed to process authentication template: {str(e)}",
@@ -906,7 +909,7 @@ def save_user_credentials(
raise # Re-raise HTTP exceptions
except Exception as e:
logger.warning(
- f"Could not validate credentials for server {mcp_server.name}: {e}"
+ "Could not validate credentials for server %s: %s", mcp_server.name, e
)
validation_message = "Credentials saved but could not be validated"
@@ -920,7 +923,7 @@ def save_user_credentials(
)
logger.info(
- f"User credentials saved for server {mcp_server.name} and user {email}"
+ "User credentials saved for server %s and user %s", mcp_server.name, email
)
db_session.commit()
@@ -934,7 +937,7 @@ def save_user_credentials(
)
except Exception as e:
- logger.error(f"Failed to save user credentials: {e}")
+ logger.error("Failed to save user credentials: %s", e)
raise HTTPException(status_code=500, detail="Failed to save user credentials")
@@ -954,12 +957,16 @@ class ServerToolsResponse(BaseModel):
def _ensure_mcp_server_owner_or_admin(server: DbMCPServer, user: User) -> None:
logger.info(
- f"Ensuring MCP server owner or admin: {server.name} {user} {user.role} server.owner={server.owner}"
+ "Ensuring MCP server owner or admin: %s %s %s server.owner=%s",
+ server.name,
+ user,
+ user.role,
+ server.owner,
)
if user.role == UserRole.ADMIN:
return
- logger.info(f"User email: {user.email} server.owner={server.owner}")
+ logger.info("User email: %s server.owner=%s", user.email, server.owner)
if server.owner != user.email:
raise HTTPException(
status_code=403,
@@ -1029,7 +1036,7 @@ def _db_mcp_server_to_api_mcp_server(
else:
admin_credentials = {}
logger.warning(
- f"No admin client info found for server {db_server.name}"
+ "No admin client info found for server %s", db_server.name
)
else: # currently: per user auth using api key OR oauth
user_config = get_user_connection_config(db_server.id, email, db)
@@ -1070,7 +1077,7 @@ def _db_mcp_server_to_api_mcp_server(
)
elif can_view_admin_credentials:
admin_credentials = {}
- logger.warning(f"No client info found for server {db_server.name}")
+ logger.warning("No client info found for server %s", db_server.name)
# Get auth template if this is a per-user auth server
auth_template = None
@@ -1088,7 +1095,7 @@ def _db_mcp_server_to_api_mcp_server(
)
except Exception as e:
logger.warning(
- f"Failed to parse auth template for server {db_server.name}: {e}"
+ "Failed to parse auth template for server %s: %s", db_server.name, e
)
is_authenticated: bool = (
@@ -1136,7 +1143,7 @@ def get_mcp_servers_for_assistant(
) -> MCPServersResponse:
"""Get MCP servers for an assistant"""
- logger.info(f"Fetching MCP servers for assistant: {assistant_id}")
+ logger.info("Fetching MCP servers for assistant: %s", assistant_id)
try:
persona_id = int(assistant_id)
@@ -1153,7 +1160,7 @@ def get_mcp_servers_for_assistant(
except ValueError:
raise HTTPException(status_code=400, detail="Invalid assistant ID")
except Exception as e:
- logger.error(f"Failed to fetch MCP servers: {e}")
+ logger.error("Failed to fetch MCP servers: %s", e)
raise HTTPException(status_code=500, detail="Failed to fetch MCP servers")
@@ -1277,7 +1284,7 @@ def get_mcp_server_tools_snapshots(
# Re-raise HTTP exceptions (e.g. 401, 400) so they are returned to client
raise e
- logger.error(f"Failed to discover tools for MCP server: {e}")
+ logger.error("Failed to discover tools for MCP server: %s", e)
raise HTTPException(status_code=500, detail="Failed to discover tools")
# Fetch and return tools from database
@@ -1350,7 +1357,7 @@ def _list_mcp_tools_by_id(
user: User,
) -> MCPToolListResponse:
"""List available tools from an existing MCP server"""
- logger.info(f"Listing tools for MCP server: {server_id}")
+ logger.info("Listing tools for MCP server: %s", server_id)
try:
# Get the MCP server
@@ -1412,7 +1419,7 @@ def _list_mcp_tools_by_id(
import time
t1 = time.time()
- logger.info(f"Discovering tools for MCP server: {mcp_server.name}: {t1}")
+ logger.info("Discovering tools for MCP server: %s: %s", mcp_server.name, t1)
server_url = mcp_server.server_url
if mcp_server.transport is None:
@@ -1428,7 +1435,10 @@ def _list_mcp_tools_by_id(
auth=auth,
)
logger.info(
- f"Discovered {len(discovered_tools)} tools for MCP server: {mcp_server.name}: {time.time() - t1}"
+ "Discovered %s tools for MCP server: %s: %s",
+ len(discovered_tools),
+ mcp_server.name,
+ time.time() - t1,
)
update_mcp_server__no_commit(
server_id=server_id,
@@ -1569,7 +1579,7 @@ def _upsert_mcp_server(
)
logger.info(
- f"Updated existing MCP server '{request.name}' with ID {mcp_server.id}"
+ "Updated existing MCP server '%s' with ID %s", request.name, mcp_server.id
)
else:
@@ -1596,7 +1606,9 @@ def _upsert_mcp_server(
db_session=db_session,
)
- logger.info(f"Created new MCP server '{request.name}' with ID {mcp_server.id}")
+ logger.info(
+ "Created new MCP server '%s' with ID %s", request.name, mcp_server.id
+ )
# PT_OAUTH doesn't need stored connection config (uses user's login token)
if (
@@ -1779,7 +1791,7 @@ def update_mcp_server_status(
user: User = Depends(current_curator_or_admin_user),
) -> dict[str, str]:
"""Update the status of an MCP server"""
- logger.info(f"Updating MCP server {server_id} status to {status}")
+ logger.info("Updating MCP server %s status to %s", server_id, status)
try:
mcp_server = get_mcp_server_by_id(server_id, db)
@@ -1795,7 +1807,7 @@ def update_mcp_server_status(
)
db.commit()
- logger.info(f"Successfully updated MCP server {server_id} status to {status}")
+ logger.info("Successfully updated MCP server %s status to %s", server_id, status)
return {"message": f"Server status updated to {status.value}"}
@@ -1820,7 +1832,7 @@ def get_mcp_servers_for_admin(
return MCPServersResponse(mcp_servers=mcp_servers)
except Exception as e:
- logger.error(f"Failed to fetch MCP servers for admin: {type(e)}:{e}")
+ logger.error("Failed to fetch MCP servers for admin: %s:%s", type(e), e)
raise HTTPException(status_code=500, detail="Failed to fetch MCP servers")
@@ -1831,7 +1843,7 @@ def get_mcp_server_db_tools(
user: User = Depends(current_curator_or_admin_user),
) -> ServerToolsResponse:
"""Get existing database tools created for an MCP server"""
- logger.info(f"Getting database tools for MCP server: {server_id}")
+ logger.info("Getting database tools for MCP server: %s", server_id)
try:
# Verify the server exists
@@ -1898,7 +1910,7 @@ def upsert_mcp_server(
action_verb = "Updated" if request.existing_server_id else "Created"
logger.info(
- f"{action_verb} MCP server '{request.name}' with ID {mcp_server.id}"
+ "%s MCP server '%s' with ID %s", action_verb, request.name, mcp_server.id
)
if mcp_server.auth_type is None:
@@ -2070,10 +2082,13 @@ def delete_mcp_server_admin(
# Log tools that will be deleted for debugging
tools_to_delete = get_tools_by_mcp_server_id(server_id, db_session)
logger.info(
- f"Deleting MCP server {server_id} ({server.name}) with {len(tools_to_delete)} tools"
+ "Deleting MCP server %s (%s) with %s tools",
+ server_id,
+ server.name,
+ len(tools_to_delete),
)
for tool in tools_to_delete:
- logger.debug(f" - Tool to delete: {tool.name} (ID: {tool.id})")
+ logger.debug(" - Tool to delete: %s (ID: %s)", tool.name, tool.id)
# Cascade behavior handled by FK ondelete in DB
delete_mcp_server(server_id, db_session)
@@ -2082,12 +2097,14 @@ def delete_mcp_server_admin(
remaining_tools = get_tools_by_mcp_server_id(server_id, db_session)
if remaining_tools:
logger.error(
- f"WARNING: {len(remaining_tools)} tools still exist after deleting MCP server {server_id}"
+ "WARNING: %s tools still exist after deleting MCP server %s",
+ len(remaining_tools),
+ server_id,
)
# Manually delete them as a fallback
for tool in remaining_tools:
logger.info(
- f"Manually deleting orphaned tool: {tool.name} (ID: {tool.id})"
+ "Manually deleting orphaned tool: %s (ID: %s)", tool.name, tool.id
)
delete_tool__no_commit(tool.id, db_session)
db_session.commit()
@@ -2096,5 +2113,5 @@ def delete_mcp_server_admin(
except ValueError:
raise HTTPException(status_code=404, detail="MCP server not found")
except Exception as e:
- logger.error(f"Failed to delete MCP server {server_id}: {e}")
+ logger.error("Failed to delete MCP server %s: %s", server_id, e)
raise HTTPException(status_code=500, detail="Failed to delete MCP server")
diff --git a/backend/onyx/server/features/oauth_config/api.py b/backend/onyx/server/features/oauth_config/api.py
index 51ee1178df..f2df6a4248 100644
--- a/backend/onyx/server/features/oauth_config/api.py
+++ b/backend/onyx/server/features/oauth_config/api.py
@@ -237,13 +237,13 @@ def handle_oauth_callback(
)
except ValueError as e:
- logger.error(f"OAuth callback error: {e}")
+ logger.error("OAuth callback error: %s", e)
return OAuthCallbackResponse(
redirect_url="/chat",
error=str(e),
)
except Exception as e:
- logger.error(f"Unexpected OAuth callback error: {e}")
+ logger.error("Unexpected OAuth callback error: %s", e)
return OAuthCallbackResponse(
redirect_url="/chat",
error="An unexpected error occurred during OAuth callback",
diff --git a/backend/onyx/server/features/persona/api.py b/backend/onyx/server/features/persona/api.py
index dca9a3d460..83daeb2e25 100644
--- a/backend/onyx/server/features/persona/api.py
+++ b/backend/onyx/server/features/persona/api.py
@@ -574,14 +574,17 @@ def get_persona_avatar(
file_record = get_filerecord_by_file_id_optional(file_id, db_session)
if not file_record:
logger.warning(
- f"Persona {persona_id} references avatar file {file_id} with no "
- f"matching FileRecord; rejecting."
+ "Persona %s references avatar file %s with no matching FileRecord; rejecting.",
+ persona_id,
+ file_id,
)
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Avatar not found")
if file_record.file_origin != FileOrigin.CHAT_UPLOAD:
logger.warning(
- f"Persona {persona_id} avatar references file {file_id} with "
- f"unexpected origin {file_record.file_origin}; rejecting."
+ "Persona %s avatar references file %s with unexpected origin %s; rejecting.",
+ persona_id,
+ file_id,
+ file_record.file_origin,
)
raise OnyxError(OnyxErrorCode.NOT_FOUND, "Avatar not found")
diff --git a/backend/onyx/server/features/projects/api.py b/backend/onyx/server/features/projects/api.py
index dd9d27518a..d7bbb22348 100644
--- a/backend/onyx/server/features/projects/api.py
+++ b/backend/onyx/server/features/projects/api.py
@@ -59,7 +59,7 @@ def _trigger_user_file_project_sync(
from onyx.background.task_utils import drain_project_sync_loop
background_tasks.add_task(drain_project_sync_loop, tenant_id)
- logger.info(f"Queued in-process project sync for user_file_id={user_file_id}")
+ logger.info("Queued in-process project sync for user_file_id=%s", user_file_id)
return
from onyx.background.celery.tasks.user_file_processing.tasks import (
@@ -74,9 +74,10 @@ def _trigger_user_file_project_sync(
queue_depth = get_user_file_project_sync_queue_depth(client_app)
if queue_depth > USER_FILE_PROJECT_SYNC_MAX_QUEUE_DEPTH:
logger.warning(
- f"Skipping immediate project sync for user_file_id={user_file_id} due to "
- f"queue depth {queue_depth}>{USER_FILE_PROJECT_SYNC_MAX_QUEUE_DEPTH}. "
- "It will be picked up by beat later."
+ "Skipping immediate project sync for user_file_id=%s due to queue depth %s>%s. It will be picked up by beat later.",
+ user_file_id,
+ queue_depth,
+ USER_FILE_PROJECT_SYNC_MAX_QUEUE_DEPTH,
)
return
@@ -90,11 +91,11 @@ def _trigger_user_file_project_sync(
)
if not enqueued:
logger.info(
- f"Skipped duplicate project sync enqueue for user_file_id={user_file_id}"
+ "Skipped duplicate project sync enqueue for user_file_id=%s", user_file_id
)
return
- logger.info(f"Triggered project sync for user_file_id={user_file_id}")
+ logger.info("Triggered project sync for user_file_id=%s", user_file_id)
@router.get("", tags=PUBLIC_API_TAGS)
@@ -159,7 +160,7 @@ def upload_user_files(
return CategorizedFilesSnapshot.from_result(categorized_files_result)
except Exception as e:
- logger.exception(f"Error uploading files - {type(e).__name__}: {str(e)}")
+ logger.exception("Error uploading files - %s: %s", type(e).__name__, str(e))
raise HTTPException(
status_code=500,
detail="Failed to upload files. Please try again or contact support if the issue persists.",
@@ -480,7 +481,7 @@ def delete_user_file(
from onyx.background.task_utils import drain_delete_loop
bg_tasks.add_task(drain_delete_loop, tenant_id)
- logger.info(f"Queued in-process delete for user_file_id={user_file.id}")
+ logger.info("Queued in-process delete for user_file_id=%s", user_file.id)
else:
from onyx.background.celery.versioned_apps.client import app as client_app
@@ -491,7 +492,9 @@ def delete_user_file(
priority=OnyxCeleryPriority.HIGH,
)
logger.info(
- f"Triggered delete for user_file_id={user_file.id} with task_id={task.id}"
+ "Triggered delete for user_file_id=%s with task_id=%s",
+ user_file.id,
+ task.id,
)
return UserFileDeleteResult(
diff --git a/backend/onyx/server/features/projects/projects_file_utils.py b/backend/onyx/server/features/projects/projects_file_utils.py
index 9552bcfd92..aa8d43fd5d 100644
--- a/backend/onyx/server/features/projects/projects_file_utils.py
+++ b/backend/onyx/server/features/projects/projects_file_utils.py
@@ -49,9 +49,10 @@ def get_upload_size_bytes(upload: UploadFile) -> int | None:
return size
except Exception as e:
logger.warning(
- "Could not determine upload size via stream seek "
- f"(filename='{get_safe_filename(upload)}', "
- f"error_type={type(e).__name__}, error={e})"
+ "Could not determine upload size via stream seek (filename='%s', error_type=%s, error=%s)",
+ get_safe_filename(upload),
+ type(e).__name__,
+ e,
)
return None
@@ -61,7 +62,8 @@ def is_upload_too_large(upload: UploadFile, max_bytes: int) -> bool:
size_bytes = get_upload_size_bytes(upload)
if size_bytes is None:
logger.warning(
- f"Could not determine upload size; skipping size-limit check for '{get_safe_filename(upload)}'"
+ "Could not determine upload size; skipping size-limit check for '%s'",
+ get_safe_filename(upload),
)
return False
return size_bytes > max_bytes
@@ -226,7 +228,7 @@ def categorize_uploaded_files(
token_count = estimate_image_tokens_for_upload(upload)
except (UnidentifiedImageError, OSError) as e:
logger.warning(
- f"Failed to process image file '{filename}': {str(e)}"
+ "Failed to process image file '%s': %s", filename, str(e)
)
results.rejected.append(
RejectedFile(
@@ -256,7 +258,7 @@ def categorize_uploaded_files(
file_name=filename,
extension=extension,
):
- logger.warning(f"{filename} is password protected")
+ logger.warning("%s is password protected", filename)
results.rejected.append(
RejectedFile(
filename=filename, reason="Document is password protected"
@@ -328,11 +330,13 @@ def categorize_uploaded_files(
upload.file.seek(0)
except Exception as e:
logger.warning(
- f"Failed to reset file pointer for '{filename}': {str(e)}"
+ "Failed to reset file pointer for '%s': %s",
+ filename,
+ str(e),
)
continue
- logger.warning(f"No text content extracted from '{filename}'")
+ logger.warning("No text content extracted from '%s'", filename)
results.rejected.append(
RejectedFile(
filename=filename,
@@ -370,11 +374,14 @@ def categorize_uploaded_files(
upload.file.seek(0)
except Exception as e:
logger.warning(
- f"Failed to reset file pointer for '{filename}': {str(e)}"
+ "Failed to reset file pointer for '%s': %s", filename, str(e)
)
except Exception as e:
logger.warning(
- f"Failed to process uploaded file '{get_safe_filename(upload)}' (error_type={type(e).__name__}, error={str(e)})"
+ "Failed to process uploaded file '%s' (error_type=%s, error=%s)",
+ get_safe_filename(upload),
+ type(e).__name__,
+ str(e),
)
results.rejected.append(
RejectedFile(
diff --git a/backend/onyx/server/features/release_notes/utils.py b/backend/onyx/server/features/release_notes/utils.py
index bb99a427c8..81f8c38825 100644
--- a/backend/onyx/server/features/release_notes/utils.py
+++ b/backend/onyx/server/features/release_notes/utils.py
@@ -120,7 +120,7 @@ def get_cached_etag() -> str | None:
return etag.decode("utf-8")
return None
except Exception as e:
- logger.error(f"Failed to get cached etag: {e}")
+ logger.error("Failed to get cached etag: %s", e)
return None
@@ -139,7 +139,7 @@ def get_last_fetch_time() -> datetime | None:
return last_fetch
except Exception as e:
- logger.error(f"Failed to get last fetch time from cache: {e}")
+ logger.error("Failed to get last fetch time from cache: %s", e)
return None
@@ -152,7 +152,7 @@ def save_fetch_metadata(etag: str | None) -> None:
if etag:
cache.set(REDIS_KEY_ETAG, etag, ex=REDIS_CACHE_TTL)
except Exception as e:
- logger.error(f"Failed to save fetch metadata to cache: {e}")
+ logger.error("Failed to save fetch metadata to cache: %s", e)
def is_cache_stale() -> bool:
@@ -229,7 +229,7 @@ def ensure_release_notes_fresh_and_notify(db_session: Session) -> None:
create_release_notifications_for_versions(db_session, entries)
except Exception as e:
- logger.error(f"Failed to check release notes: {e}")
+ logger.error("Failed to check release notes: %s", e)
# Update timestamp even on failure to prevent retry storms
# We don't save etag on failure to allow retry with conditional request
save_fetch_metadata(None)
diff --git a/backend/onyx/server/federated/api.py b/backend/onyx/server/federated/api.py
index b4e6c06799..d5cffe1536 100644
--- a/backend/onyx/server/federated/api.py
+++ b/backend/onyx/server/federated/api.py
@@ -72,7 +72,10 @@ def create_federated_connector(
tenant_id = get_current_tenant_id()
logger.info(
- f"Creating federated connector: source={federated_connector_data.source}, user={user.email}, tenant_id={tenant_id}"
+ "Creating federated connector: source=%s, user=%s, tenant_id=%s",
+ federated_connector_data.source,
+ user.email,
+ tenant_id,
)
try:
@@ -85,7 +88,8 @@ def create_federated_connector(
)
logger.info(
- f"Successfully created federated connector with id={federated_connector.id}"
+ "Successfully created federated connector with id=%s",
+ federated_connector.id,
)
return FederatedConnectorResponse(
@@ -94,11 +98,11 @@ def create_federated_connector(
)
except ValueError as e:
- logger.warning(f"Validation error creating federated connector: {e}")
+ logger.warning("Validation error creating federated connector: %s", e)
db_session.rollback()
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
- logger.error(f"Error creating federated connector: {e}")
+ logger.error("Error creating federated connector: %s", e)
db_session.rollback()
raise HTTPException(status_code=500, detail=str(e))
@@ -141,7 +145,7 @@ def get_entities(
except HTTPException:
raise
except Exception as e:
- logger.error(f"Error fetching entities for federated connector {id}: {e}")
+ logger.error("Error fetching entities for federated connector %s: %s", id, e)
raise HTTPException(status_code=500, detail=str(e))
@@ -185,7 +189,7 @@ def get_credentials_schema(
raise
except Exception as e:
logger.error(
- f"Error fetching credentials schema for federated connector {id}: {e}"
+ "Error fetching credentials schema for federated connector %s: %s", id, e
)
raise HTTPException(status_code=500, detail=str(e))
@@ -214,7 +218,7 @@ def get_configuration_schema_by_source(
return ConfigurationSchemaResponse(configuration=configuration_dict)
except Exception as e:
- logger.error(f"Error fetching configuration schema for source {source}: {e}")
+ logger.error("Error fetching configuration schema for source %s: %s", source, e)
raise HTTPException(status_code=500, detail=str(e))
@@ -245,7 +249,7 @@ def get_credentials_schema_by_source(
except HTTPException:
raise
except Exception as e:
- logger.error(f"Error fetching credentials schema for source {source}: {e}")
+ logger.error("Error fetching credentials schema for source %s: %s", source, e)
raise HTTPException(status_code=500, detail=str(e))
@@ -269,7 +273,7 @@ def validate_credentials(
except HTTPException:
raise
except Exception as e:
- logger.error(f"Error validating credentials for source {source}: {e}")
+ logger.error("Error validating credentials for source %s: %s", source, e)
raise HTTPException(status_code=500, detail=str(e))
@@ -313,7 +317,7 @@ def validate_entities(
except HTTPException:
raise
except Exception as e:
- logger.error(f"Error validating entities for federated connector {id}: {e}")
+ logger.error("Error validating entities for federated connector %s: %s", id, e)
return Response(status_code=500)
@@ -353,7 +357,7 @@ def get_authorize_url(
# Generate state parameter and store session info
logger.info(
- f"Generating OAuth state for federated_connector_id={id}, user_id={user.id}"
+ "Generating OAuth state for federated_connector_id=%s, user_id=%s", id, user.id
)
state = generate_oauth_state(
federated_connector_id=id,
@@ -362,7 +366,7 @@ def get_authorize_url(
# Add state to the OAuth URL
authorize_url = add_state_to_oauth_url(base_authorize_url, state)
- logger.info(f"Generated OAuth authorize URL with state for connector {id}")
+ logger.info("Generated OAuth authorize URL with state for connector %s", id)
return AuthorizeUrlResponse(authorize_url=authorize_url)
@@ -431,7 +435,9 @@ def handle_oauth_callback_generic(
# Store OAuth token in database if we have an access token
if oauth_result.access_token:
logger.info(
- f"Storing OAuth token for federated_connector_id={federated_connector_id}, user_id={oauth_session.user_id}"
+ "Storing OAuth token for federated_connector_id=%s, user_id=%s",
+ federated_connector_id,
+ oauth_session.user_id,
)
update_federated_connector_oauth_token(
db_session=db_session,
@@ -586,7 +592,7 @@ def update_federated_connector_endpoint(
return get_federated_connector_detail(id, user, db_session)
except ValueError as e:
- logger.warning(f"Validation error updating federated connector {id}: {e}")
+ logger.warning("Validation error updating federated connector %s: %s", id, e)
raise HTTPException(status_code=400, detail=str(e))
diff --git a/backend/onyx/server/manage/administrative.py b/backend/onyx/server/manage/administrative.py
index 9f1a63de5b..dc7d73e483 100644
--- a/backend/onyx/server/manage/administrative.py
+++ b/backend/onyx/server/manage/administrative.py
@@ -199,7 +199,8 @@ def create_deletion_attempt_for_connector_id(
)
logger.info(
- f"create_deletion_attempt_for_connector_id - running check_for_connector_deletion: cc_pair={cc_pair.id}"
+ "create_deletion_attempt_for_connector_id - running check_for_connector_deletion: cc_pair=%s",
+ cc_pair.id,
)
if cc_pair.connector.source == DocumentSource.FILE:
diff --git a/backend/onyx/server/manage/discord_bot/utils.py b/backend/onyx/server/manage/discord_bot/utils.py
index 60467f5637..c4c5f2cc0a 100644
--- a/backend/onyx/server/manage/discord_bot/utils.py
+++ b/backend/onyx/server/manage/discord_bot/utils.py
@@ -21,7 +21,7 @@ def generate_discord_registration_key(tenant_id: str) -> str:
encoded_tenant = quote(tenant_id)
random_token = secrets.token_urlsafe(16)
- logger.info(f"Generated Discord registration key for tenant {tenant_id}")
+ logger.info("Generated Discord registration key for tenant %s", tenant_id)
return f"{REGISTRATION_KEY_PREFIX}{encoded_tenant}.{random_token}"
diff --git a/backend/onyx/server/manage/embedding/api.py b/backend/onyx/server/manage/embedding/api.py
index fa2ff9699a..e304f56101 100644
--- a/backend/onyx/server/manage/embedding/api.py
+++ b/backend/onyx/server/manage/embedding/api.py
@@ -59,7 +59,7 @@ def test_embedding_configuration(
except Exception as e:
error_msg = "An error occurred while testing your embedding model. Please check your configuration."
- logger.error(f"{error_msg} Error message: {e}", exc_info=True)
+ logger.error("%s Error message: %s", error_msg, e, exc_info=True)
raise OnyxError(OnyxErrorCode.VALIDATION_ERROR, error_msg)
diff --git a/backend/onyx/server/manage/image_generation/api.py b/backend/onyx/server/manage/image_generation/api.py
index 40e25a94eb..524a27ae87 100644
--- a/backend/onyx/server/manage/image_generation/api.py
+++ b/backend/onyx/server/manage/image_generation/api.py
@@ -282,7 +282,7 @@ def test_image_generation(
except Exception as e:
# Log only exception type to avoid exposing sensitive data
# (LiteLLM errors may contain URLs with API keys or auth tokens)
- logger.warning(f"Image generation test failed: {type(e).__name__}")
+ logger.warning("Image generation test failed: %s", type(e).__name__)
raise HTTPException(
status_code=400,
detail=f"Image generation test failed: {type(e).__name__}",
diff --git a/backend/onyx/server/manage/llm/api.py b/backend/onyx/server/manage/llm/api.py
index da8a00eb08..563d77fc24 100644
--- a/backend/onyx/server/manage/llm/api.py
+++ b/backend/onyx/server/manage/llm/api.py
@@ -171,10 +171,13 @@ def _sync_fetched_models(
)
if new_count > 0:
logger.info(
- f"Added {new_count} new {source_label} models to provider '{provider_name}'"
+ "Added %s new %s models to provider '%s'",
+ new_count,
+ source_label,
+ provider_name,
)
except ValueError as e:
- logger.warning(f"Failed to sync {source_label} models to DB: {e}")
+ logger.warning("Failed to sync %s models to DB: %s", source_label, e)
def _mask_provider_credentials(provider_view: LLMProviderView) -> None:
@@ -402,7 +405,8 @@ def list_llm_providers(
from_model_end = datetime.now(timezone.utc)
from_model_duration = (from_model_end - from_model_start).total_seconds()
logger.debug(
- f"LLMProviderView.from_model took {from_model_duration:.2f} seconds"
+ "LLMProviderView.from_model took %s seconds",
+ format(from_model_duration, ".2f"),
)
_mask_provider_credentials(full_llm_provider)
@@ -410,7 +414,9 @@ def list_llm_providers(
end_time = datetime.now(timezone.utc)
duration = (end_time - start_time).total_seconds()
- logger.debug(f"Completed fetching LLM providers in {duration:.2f} seconds")
+ logger.debug(
+ "Completed fetching LLM providers in %s seconds", format(duration, ".2f")
+ )
return LLMProviderResponse[LLMProviderView].from_models(
providers=llm_provider_list,
@@ -662,7 +668,7 @@ def get_vision_capable_providers(
for provider_id, model_names in provider_models.items()
]
- logger.debug(f"Found {len(vision_provider_response)} vision-capable providers")
+ logger.debug("Found %s vision-capable providers", len(vision_provider_response))
return LLMProviderResponse[VisionProviderResponse].from_models(
providers=vision_provider_response,
@@ -713,7 +719,9 @@ def list_llm_provider_basics(
end_time = datetime.now(timezone.utc)
duration = (end_time - start_time).total_seconds()
logger.debug(
- f"Completed fetching {len(accessible_providers)} user-accessible providers in {duration:.2f} seconds"
+ "Completed fetching %s user-accessible providers in %s seconds",
+ len(accessible_providers),
+ format(duration, ".2f"),
)
return LLMProviderResponse[LLMProviderDescriptor].from_models(
@@ -778,7 +786,7 @@ def list_llm_providers_for_persona(
and should NOT block the UI.
"""
start_time = datetime.now(timezone.utc)
- logger.debug(f"Starting to fetch LLM providers for persona {persona_id}")
+ logger.debug("Starting to fetch LLM providers for persona %s", persona_id)
persona = fetch_persona_with_groups(db_session, persona_id)
if not persona:
@@ -811,7 +819,10 @@ def list_llm_providers_for_persona(
end_time = datetime.now(timezone.utc)
duration = (end_time - start_time).total_seconds()
logger.debug(
- f"Completed fetching {len(llm_provider_list)} LLM providers for persona {persona_id} in {duration:.2f} seconds"
+ "Completed fetching %s LLM providers for persona %s in %s seconds",
+ len(llm_provider_list),
+ persona_id,
+ format(duration, ".2f"),
)
# Get the default model and vision model for the persona
@@ -1010,7 +1021,7 @@ def get_bedrock_available_models(
"supports_image_input": infer_vision_support(profile_id),
}
except Exception as e:
- logger.warning(f"Couldn't fetch inference profiles for Bedrock: {e}")
+ logger.warning("Couldn't fetch inference profiles for Bedrock: %s", e)
# Prefer profiles: de-dupe available models, then add profile IDs
candidates = (available_models - cross_region_models) | profile_ids
diff --git a/backend/onyx/server/manage/search_settings.py b/backend/onyx/server/manage/search_settings.py
index 4ef9978dd4..064a25772c 100644
--- a/backend/onyx/server/manage/search_settings.py
+++ b/backend/onyx/server/manage/search_settings.py
@@ -254,7 +254,7 @@ def update_saved_search_settings(
)
logger.info(
- f"Updated current search settings to {search_settings.model_dump_json()}"
+ "Updated current search settings to %s", search_settings.model_dump_json()
)
# Re-sync default to match PRESENT search settings
@@ -332,7 +332,8 @@ def _sync_default_contextual_model(db_session: Session) -> None:
)
except ValueError as e:
logger.error(
- f"Error syncing default contextual model, defaulting to no contextual model: {e}"
+ "Error syncing default contextual model, defaulting to no contextual model: %s",
+ e,
)
update_no_default_contextual_rag_provider(
db_session=db_session,
diff --git a/backend/onyx/server/manage/users.py b/backend/onyx/server/manage/users.py
index 2b30f3f1a7..c2f1845a3b 100644
--- a/backend/onyx/server/manage/users.py
+++ b/backend/onyx/server/manage/users.py
@@ -508,7 +508,7 @@ def bulk_invite_users(
)(new_invited_emails, tenant_id)
except Exception as e:
- logger.error(f"Failed to add users to tenant {tenant_id}: {str(e)}")
+ logger.error("Failed to add users to tenant %s: %s", tenant_id, str(e))
initial_invited_users = get_invited_users()
@@ -548,7 +548,7 @@ def bulk_invite_users(
send_user_email_invite(email, current_user, AUTH_TYPE)
email_invite_status = EmailInviteStatus.SENT
except Exception as e:
- logger.error(f"Error sending email invite to invited users: {e}")
+ logger.error("Error sending email invite to invited users: %s", e)
email_invite_status = EmailInviteStatus.SEND_FAILED
if MULTI_TENANT and not DEV_MODE:
@@ -559,7 +559,7 @@ def bulk_invite_users(
"onyx.server.tenants.billing", "register_tenant_users", None
)(tenant_id, get_live_users_count(db_session))
except Exception as e:
- logger.error(f"Failed to register tenant users: {str(e)}")
+ logger.error("Failed to register tenant users: %s", str(e))
logger.info(
"Reverting changes: removing users from tenant and resetting invited users"
)
@@ -650,7 +650,7 @@ def deactivate_user_api(
raise HTTPException(status_code=404, detail="User not found")
if user_to_deactivate.is_active is False:
- logger.warning("{} is already deactivated".format(user_to_deactivate.email))
+ logger.warning("%s is already deactivated", user_to_deactivate.email)
deactivate_user(user_to_deactivate, db_session)
@@ -675,9 +675,7 @@ async def delete_user(
raise HTTPException(status_code=404, detail="User not found")
if user_to_delete.is_active is True:
- logger.warning(
- "{} must be deactivated before deleting".format(user_to_delete.email)
- )
+ logger.warning("%s must be deactivated before deleting", user_to_delete.email)
raise HTTPException(
status_code=400, detail="User must be deactivated before deleting"
)
@@ -691,7 +689,7 @@ async def delete_user(
"onyx.server.tenants.user_mapping", "remove_users_from_tenant", None
)([user_email.user_email], tenant_id)
delete_user_from_db(user_to_delete, db_session)
- logger.info(f"Deleted user {user_to_delete.email}")
+ logger.info("Deleted user %s", user_to_delete.email)
# Invalidate license cache so used_seats reflects the new count
# Only for self-hosted (non-multi-tenant) deployments
@@ -702,7 +700,7 @@ async def delete_user(
except Exception as e:
db_session.rollback()
- logger.error(f"Error deleting user {user_to_delete.email}: {str(e)}")
+ logger.error("Error deleting user %s: %s", user_to_delete.email, str(e))
raise HTTPException(status_code=500, detail="Error deleting user")
@@ -719,7 +717,7 @@ def activate_user_api(
raise HTTPException(status_code=404, detail="User not found")
if user_to_activate.is_active is True:
- logger.warning("{} is already activated".format(user_to_activate.email))
+ logger.warning("%s is already activated", user_to_activate.email)
return
# Check seat availability before activating
@@ -816,7 +814,7 @@ def get_current_auth_token_creation_redis(
return token_creation_time
except Exception as e:
- logger.error(f"Error retrieving token expiration from Redis: {e}")
+ logger.error("Error retrieving token expiration from Redis: %s", e)
return None
diff --git a/backend/onyx/server/manage/voice/api.py b/backend/onyx/server/manage/voice/api.py
index 96c89142f3..c4738b837a 100644
--- a/backend/onyx/server/manage/voice/api.py
+++ b/backend/onyx/server/manage/voice/api.py
@@ -141,7 +141,7 @@ async def upsert_voice_provider_endpoint(
raise
except Exception as e:
db_session.rollback()
- logger.error(f"Voice provider credential validation failed on save: {e}")
+ logger.error("Voice provider credential validation failed on save: %s", e)
raise OnyxError(
OnyxErrorCode.VALIDATION_ERROR,
VOICE_PROVIDER_VALIDATION_FAILURE_MESSAGE,
@@ -268,13 +268,13 @@ async def test_voice_provider(
except OnyxError:
raise
except Exception as e:
- logger.error(f"Voice provider connection test failed: {e}")
+ logger.error("Voice provider connection test failed: %s", e)
raise OnyxError(
OnyxErrorCode.VALIDATION_ERROR,
VOICE_PROVIDER_VALIDATION_FAILURE_MESSAGE,
) from e
- logger.info(f"Voice provider test succeeded for {request.provider_type}.")
+ logger.info("Voice provider test succeeded for %s.", request.provider_type)
return VoiceProviderUpdateSuccess()
diff --git a/backend/onyx/server/manage/voice/user_api.py b/backend/onyx/server/manage/voice/user_api.py
index aaed4593a1..16f296c940 100644
--- a/backend/onyx/server/manage/voice/user_api.py
+++ b/backend/onyx/server/manage/voice/user_api.py
@@ -107,7 +107,7 @@ async def transcribe_audio(
f"Speech-to-text not implemented for {provider_db.provider_type}.",
) from exc
except Exception as exc:
- logger.error(f"Transcription failed: {exc}")
+ logger.error("Transcription failed: %s", exc)
raise OnyxError(
OnyxErrorCode.INTERNAL_ERROR,
"Transcription failed. Please try again.",
@@ -154,7 +154,9 @@ async def synthesize_speech(
text = body.text
voice = body.voice
speed = body.speed
- logger.info(f"TTS request: text length={len(text)}, voice={voice}, speed={speed}")
+ logger.info(
+ "TTS request: text length=%s, voice=%s, speed=%s", len(text), voice, speed
+ )
# Use short-lived session to fetch provider config, then release connection
# before starting the long-running streaming response
@@ -188,13 +190,16 @@ async def synthesize_speech(
)
logger.info(
- f"TTS using provider: {provider_db.provider_type}, voice: {final_voice}, speed: {final_speed}"
+ "TTS using provider: %s, voice: %s, speed: %s",
+ provider_db.provider_type,
+ final_voice,
+ final_speed,
)
try:
provider = get_voice_provider(provider_db)
except ValueError as exc:
- logger.error(f"Failed to get voice provider: {exc}")
+ logger.error("Failed to get voice provider: %s", exc)
raise OnyxError(OnyxErrorCode.INTERNAL_ERROR, str(exc)) from exc
# Pull the first chunk before returning the StreamingResponse. If the
@@ -218,7 +223,7 @@ async def synthesize_speech(
async for chunk in stream_iter:
chunk_count += 1
yield chunk
- logger.info(f"TTS streaming complete: {chunk_count} chunks sent")
+ logger.info("TTS streaming complete: %s chunks sent", chunk_count)
return StreamingResponse(
audio_stream(),
diff --git a/backend/onyx/server/manage/voice/websocket_api.py b/backend/onyx/server/manage/voice/websocket_api.py
index bb343c8e3d..827b8bedf3 100644
--- a/backend/onyx/server/manage/voice/websocket_api.py
+++ b/backend/onyx/server/manage/voice/websocket_api.py
@@ -79,7 +79,7 @@ class ChunkedTranscriber:
return " ".join(self.transcripts)
return None
except Exception as e:
- logger.error(f"Transcription error: {e}")
+ logger.error("Transcription error: %s", e)
self.chunk_buffer = io.BytesIO()
self.chunk_bytes = 0
return None
@@ -95,7 +95,7 @@ class ChunkedTranscriber:
if transcript and transcript.strip():
return transcript.strip()
except Exception as e:
- logger.error(f"Final transcription error: {e}")
+ logger.error("Final transcription error: %s", e)
return " ".join(self.transcripts)
@@ -122,7 +122,9 @@ async def handle_streaming_transcription(
if result.text and (result.text != last_transcript or result.is_vad_end):
last_transcript = result.text
logger.debug(
- f"Streaming transcription: got transcript: {result.text[:50]}... (is_vad_end={result.is_vad_end})"
+ "Streaming transcription: got transcript: %s... (is_vad_end=%s)",
+ result.text[:50],
+ result.is_vad_end,
)
await websocket.send_json(
{
@@ -142,7 +144,9 @@ async def handle_streaming_transcription(
if msg_type == "websocket.disconnect":
logger.info(
- f"Streaming transcription: client disconnected after {chunk_count} chunks ({total_bytes} bytes)"
+ "Streaming transcription: client disconnected after %s chunks (%s bytes)",
+ chunk_count,
+ total_bytes,
)
break
@@ -152,7 +156,8 @@ async def handle_streaming_transcription(
# Enforce per-message size limit
if chunk_size > WS_MAX_MESSAGE_SIZE:
logger.warning(
- f"Streaming transcription: message too large ({chunk_size} bytes)"
+ "Streaming transcription: message too large (%s bytes)",
+ chunk_size,
)
await websocket.send_json(
{"type": "error", "message": "Message too large"}
@@ -162,7 +167,8 @@ async def handle_streaming_transcription(
# Enforce total connection size limit
if total_bytes + chunk_size > WS_MAX_TOTAL_BYTES:
logger.warning(
- f"Streaming transcription: total size limit exceeded ({total_bytes + chunk_size} bytes)"
+ "Streaming transcription: total size limit exceeded (%s bytes)",
+ total_bytes + chunk_size,
)
await websocket.send_json(
{"type": "error", "message": "Total size limit exceeded"}
@@ -172,7 +178,10 @@ async def handle_streaming_transcription(
chunk_count += 1
total_bytes += chunk_size
logger.debug(
- f"Streaming transcription: received chunk {chunk_count} ({chunk_size} bytes, total: {total_bytes})"
+ "Streaming transcription: received chunk %s (%s bytes, total: %s)",
+ chunk_count,
+ chunk_size,
+ total_bytes,
)
await transcriber.send_audio(message["bytes"])
@@ -180,7 +189,7 @@ async def handle_streaming_transcription(
try:
data = json.loads(message["text"])
logger.debug(
- f"Streaming transcription: received text message: {data}"
+ "Streaming transcription: received text message: %s", data
)
if data.get("type") == "end":
logger.info(
@@ -189,8 +198,8 @@ async def handle_streaming_transcription(
final_transcript = await transcriber.close()
receive_task.cancel()
logger.info(
- "Streaming transcription: final transcript: "
- f"{final_transcript[:100] if final_transcript else '(empty)'}..."
+ "Streaming transcription: final transcript: %s...",
+ final_transcript[:100] if final_transcript else "(empty)",
)
await websocket.send_json(
{
@@ -208,10 +217,11 @@ async def handle_streaming_transcription(
transcriber.reset_transcript()
except json.JSONDecodeError:
logger.warning(
- f"Streaming transcription: failed to parse JSON: {message.get('text', '')[:100]}"
+ "Streaming transcription: failed to parse JSON: %s",
+ message.get("text", "")[:100],
)
except Exception as e:
- logger.error(f"Streaming transcription: error: {e}", exc_info=True)
+ logger.error("Streaming transcription: error: %s", e, exc_info=True)
raise
finally:
receive_task.cancel()
@@ -220,7 +230,9 @@ async def handle_streaming_transcription(
except asyncio.CancelledError:
pass
logger.info(
- f"Streaming transcription: handler finished. Processed {chunk_count} chunks, {total_bytes} total bytes"
+ "Streaming transcription: handler finished. Processed %s chunks, %s total bytes",
+ chunk_count,
+ total_bytes,
)
@@ -239,7 +251,9 @@ async def handle_chunked_transcription(
if msg_type == "websocket.disconnect":
logger.info(
- f"Chunked transcription: client disconnected after {chunk_count} chunks ({total_bytes} bytes)"
+ "Chunked transcription: client disconnected after %s chunks (%s bytes)",
+ chunk_count,
+ total_bytes,
)
break
@@ -249,7 +263,7 @@ async def handle_chunked_transcription(
# Enforce per-message size limit
if chunk_size > WS_MAX_MESSAGE_SIZE:
logger.warning(
- f"Chunked transcription: message too large ({chunk_size} bytes)"
+ "Chunked transcription: message too large (%s bytes)", chunk_size
)
await websocket.send_json(
{"type": "error", "message": "Message too large"}
@@ -259,7 +273,8 @@ async def handle_chunked_transcription(
# Enforce total connection size limit
if total_bytes + chunk_size > WS_MAX_TOTAL_BYTES:
logger.warning(
- f"Chunked transcription: total size limit exceeded ({total_bytes + chunk_size} bytes)"
+ "Chunked transcription: total size limit exceeded (%s bytes)",
+ total_bytes + chunk_size,
)
await websocket.send_json(
{"type": "error", "message": "Total size limit exceeded"}
@@ -269,13 +284,16 @@ async def handle_chunked_transcription(
chunk_count += 1
total_bytes += chunk_size
logger.debug(
- f"Chunked transcription: received chunk {chunk_count} ({chunk_size} bytes, total: {total_bytes})"
+ "Chunked transcription: received chunk %s (%s bytes, total: %s)",
+ chunk_count,
+ chunk_size,
+ total_bytes,
)
transcript = await transcriber.add_chunk(message["bytes"])
if transcript:
logger.debug(
- f"Chunked transcription: got transcript: {transcript[:50]}..."
+ "Chunked transcription: got transcript: %s...", transcript[:50]
)
await websocket.send_json(
{
@@ -288,12 +306,13 @@ async def handle_chunked_transcription(
elif "text" in message:
try:
data = json.loads(message["text"])
- logger.debug(f"Chunked transcription: received text message: {data}")
+ logger.debug("Chunked transcription: received text message: %s", data)
if data.get("type") == "end":
logger.info("Chunked transcription: end signal received, flushing")
final_transcript = await transcriber.flush()
logger.info(
- f"Chunked transcription: final transcript: {final_transcript[:100] if final_transcript else '(empty)'}..."
+ "Chunked transcription: final transcript: %s...",
+ final_transcript[:100] if final_transcript else "(empty)",
)
await websocket.send_json(
{
@@ -305,11 +324,14 @@ async def handle_chunked_transcription(
break
except json.JSONDecodeError:
logger.warning(
- f"Chunked transcription: failed to parse JSON: {message.get('text', '')[:100]}"
+ "Chunked transcription: failed to parse JSON: %s",
+ message.get("text", "")[:100],
)
logger.info(
- f"Chunked transcription: handler finished. Processed {chunk_count} chunks, {total_bytes} total bytes"
+ "Chunked transcription: handler finished. Processed %s chunks, %s total bytes",
+ chunk_count,
+ total_bytes,
)
@@ -337,7 +359,7 @@ async def websocket_transcribe(
await websocket.accept()
logger.info("WebSocket transcribe: connection accepted")
except Exception as e:
- logger.error(f"WebSocket transcribe: failed to accept connection: {e}")
+ logger.error("WebSocket transcribe: failed to accept connection: %s", e)
return
streaming_transcriber = None
@@ -372,16 +394,18 @@ async def websocket_transcribe(
return
logger.info(
- f"WebSocket transcribe: creating voice provider: {provider_db.provider_type}"
+ "WebSocket transcribe: creating voice provider: %s",
+ provider_db.provider_type,
)
try:
provider = get_voice_provider(provider_db)
logger.info(
- f"WebSocket transcribe: voice provider created, streaming supported: {provider.supports_streaming_stt()}"
+ "WebSocket transcribe: voice provider created, streaming supported: %s",
+ provider.supports_streaming_stt(),
)
except ValueError as e:
logger.error(
- f"WebSocket transcribe: failed to create voice provider: {e}"
+ "WebSocket transcribe: failed to create voice provider: %s", e
)
await websocket.send_json({"type": "error", "message": str(e)})
return
@@ -397,7 +421,8 @@ async def websocket_transcribe(
await handle_streaming_transcription(websocket, streaming_transcriber)
except Exception as e:
logger.error(
- f"WebSocket transcribe: failed to create streaming transcriber: {e}"
+ "WebSocket transcribe: failed to create streaming transcriber: %s",
+ e,
)
if VOICE_DISABLE_STREAMING_FALLBACK:
await websocket.send_json(
@@ -427,7 +452,7 @@ async def websocket_transcribe(
except WebSocketDisconnect:
logger.debug("WebSocket transcribe: client disconnected")
except Exception as e:
- logger.error(f"WebSocket transcribe: unhandled error: {e}", exc_info=True)
+ logger.error("WebSocket transcribe: unhandled error: %s", e, exc_info=True)
try:
# Send generic error to avoid leaking sensitive details
await websocket.send_json(
@@ -464,14 +489,16 @@ async def handle_streaming_synthesis(
audio_chunk = await synthesizer.receive_audio()
if audio_chunk is None:
logger.info(
- f"Streaming synthesis: audio stream ended, sent {chunk_count} chunks, {total_bytes} bytes"
+ "Streaming synthesis: audio stream ended, sent %s chunks, %s bytes",
+ chunk_count,
+ total_bytes,
)
try:
await websocket.send_json({"type": "audio_done"})
logger.info("Streaming synthesis: sent audio_done to client")
except Exception as e:
logger.warning(
- f"Streaming synthesis: failed to send audio_done: {e}"
+ "Streaming synthesis: failed to send audio_done: %s", e
)
break
if audio_chunk: # Skip empty chunks
@@ -481,15 +508,15 @@ async def handle_streaming_synthesis(
await websocket.send_bytes(audio_chunk)
except Exception as e:
logger.warning(
- f"Streaming synthesis: failed to send chunk: {e}"
+ "Streaming synthesis: failed to send chunk: %s", e
)
break
except asyncio.CancelledError:
logger.info(
- f"Streaming synthesis: send_audio cancelled after {chunk_count} chunks"
+ "Streaming synthesis: send_audio cancelled after %s chunks", chunk_count
)
except Exception as e:
- logger.error(f"Streaming synthesis: send_audio error: {e}")
+ logger.error("Streaming synthesis: send_audio error: %s", e)
send_task: asyncio.Task | None = None
disconnected = False
@@ -514,7 +541,8 @@ async def handle_streaming_synthesis(
msg_size = len(message["text"])
if msg_size > WS_MAX_TEXT_MESSAGE_SIZE:
logger.warning(
- f"Streaming synthesis: text message too large ({msg_size} bytes)"
+ "Streaming synthesis: text message too large (%s bytes)",
+ msg_size,
)
await websocket.send_json(
{"type": "error", "message": "Message too large"}
@@ -529,7 +557,8 @@ async def handle_streaming_synthesis(
# Enforce per-text size limit
if len(text) > WS_MAX_TTS_TEXT_LENGTH:
logger.warning(
- f"Streaming synthesis: text too long ({len(text)} chars)"
+ "Streaming synthesis: text too long (%s chars)",
+ len(text),
)
await websocket.send_json(
{"type": "error", "message": "Text too long"}
@@ -541,7 +570,8 @@ async def handle_streaming_synthesis(
if send_task is None:
send_task = asyncio.create_task(send_audio())
logger.debug(
- f"Streaming synthesis: forwarding text chunk ({len(text)} chars)"
+ "Streaming synthesis: forwarding text chunk (%s chars)",
+ len(text),
)
await synthesizer.send_text(text)
@@ -570,13 +600,14 @@ async def handle_streaming_synthesis(
except json.JSONDecodeError:
logger.warning(
- f"Streaming synthesis: failed to parse JSON: {message.get('text', '')[:100]}"
+ "Streaming synthesis: failed to parse JSON: %s",
+ message.get("text", "")[:100],
)
except WebSocketDisconnect:
logger.debug("Streaming synthesis: client disconnected during synthesis")
except Exception as e:
- logger.error(f"Streaming synthesis: error: {e}", exc_info=True)
+ logger.error("Streaming synthesis: error: %s", e, exc_info=True)
finally:
if send_task and not send_task.done():
logger.info("Streaming synthesis: waiting for send_task to finish")
@@ -635,7 +666,7 @@ async def handle_chunked_synthesis(
msg_size = len(message["text"])
if msg_size > WS_MAX_TEXT_MESSAGE_SIZE:
logger.warning(
- f"Chunked synthesis: text message too large ({msg_size} bytes)"
+ "Chunked synthesis: text message too large (%s bytes)", msg_size
)
await websocket.send_json(
{"type": "error", "message": "Message too large"}
@@ -646,7 +677,8 @@ async def handle_chunked_synthesis(
data = json.loads(message["text"])
except json.JSONDecodeError:
logger.warning(
- f"Chunked synthesis: failed to parse JSON: {message.get('text', '')[:100]}"
+ "Chunked synthesis: failed to parse JSON: %s",
+ message.get("text", "")[:100],
)
continue
@@ -656,7 +688,7 @@ async def handle_chunked_synthesis(
# Enforce per-text size limit
if len(text) > WS_MAX_TTS_TEXT_LENGTH:
logger.warning(
- f"Chunked synthesis: text too long ({len(text)} chars)"
+ "Chunked synthesis: text too long (%s chars)", len(text)
)
await websocket.send_json(
{"type": "error", "message": "Text too long"}
@@ -665,7 +697,9 @@ async def handle_chunked_synthesis(
if text:
text_buffer.append(text)
logger.debug(
- f"Chunked synthesis: buffered text ({len(text)} chars), total buffered: {len(text_buffer)} chunks"
+ "Chunked synthesis: buffered text (%s chars), total buffered: %s chunks",
+ len(text),
+ len(text_buffer),
)
if isinstance(data.get("voice"), str) and data["voice"]:
voice = data["voice"]
@@ -682,7 +716,7 @@ async def handle_chunked_synthesis(
chunk_count = 0
total_bytes = 0
logger.info(
- f"Chunked synthesis: sending full text ({len(full_text)} chars)"
+ "Chunked synthesis: sending full text (%s chars)", len(full_text)
)
async for audio_chunk in provider.synthesize_stream(
full_text, voice=voice, speed=speed
@@ -694,13 +728,15 @@ async def handle_chunked_synthesis(
await websocket.send_bytes(audio_chunk)
await websocket.send_json({"type": "audio_done"})
logger.info(
- f"Chunked synthesis: sent audio_done after {chunk_count} chunks, {total_bytes} bytes"
+ "Chunked synthesis: sent audio_done after %s chunks, %s bytes",
+ chunk_count,
+ total_bytes,
)
break
except WebSocketDisconnect:
logger.debug("Chunked synthesis: client disconnected")
except Exception as e:
- logger.error(f"Chunked synthesis: error: {e}", exc_info=True)
+ logger.error("Chunked synthesis: error: %s", e, exc_info=True)
raise
finally:
logger.info("Chunked synthesis: handler finished")
@@ -730,7 +766,7 @@ async def websocket_synthesize(
await websocket.accept()
logger.info("WebSocket synthesize: connection accepted")
except Exception as e:
- logger.error(f"WebSocket synthesize: failed to accept connection: {e}")
+ logger.error("WebSocket synthesize: failed to accept connection: %s", e)
return
streaming_synthesizer: StreamingSynthesizerProtocol | None = None
@@ -765,16 +801,18 @@ async def websocket_synthesize(
return
logger.info(
- f"WebSocket synthesize: creating voice provider: {provider_db.provider_type}"
+ "WebSocket synthesize: creating voice provider: %s",
+ provider_db.provider_type,
)
try:
provider = get_voice_provider(provider_db)
logger.info(
- f"WebSocket synthesize: voice provider created, streaming TTS supported: {provider.supports_streaming_tts()}"
+ "WebSocket synthesize: voice provider created, streaming TTS supported: %s",
+ provider.supports_streaming_tts(),
)
except ValueError as e:
logger.error(
- f"WebSocket synthesize: failed to create voice provider: {e}"
+ "WebSocket synthesize: failed to create voice provider: %s", e
)
await websocket.send_json({"type": "error", "message": str(e)})
return
@@ -805,7 +843,8 @@ async def websocket_synthesize(
await handle_streaming_synthesis(websocket, streaming_synthesizer)
except Exception as e:
logger.error(
- f"WebSocket synthesize: failed to create streaming synthesizer: {e}"
+ "WebSocket synthesize: failed to create streaming synthesizer: %s",
+ e,
)
if VOICE_DISABLE_STREAMING_FALLBACK:
await websocket.send_json(
@@ -836,7 +875,7 @@ async def websocket_synthesize(
except WebSocketDisconnect:
logger.debug("WebSocket synthesize: client disconnected")
except Exception as e:
- logger.error(f"WebSocket synthesize: unhandled error: {e}", exc_info=True)
+ logger.error("WebSocket synthesize: unhandled error: %s", e, exc_info=True)
try:
# Send generic error to avoid leaking sensitive details
await websocket.send_json(
diff --git a/backend/onyx/server/manage/web_search/api.py b/backend/onyx/server/manage/web_search/api.py
index fe74747512..3b6f4dca78 100644
--- a/backend/onyx/server/manage/web_search/api.py
+++ b/backend/onyx/server/manage/web_search/api.py
@@ -449,6 +449,6 @@ def test_content_provider(
) from e
logger.info(
- f"Web content provider test succeeded for {request.provider_type.value}."
+ "Web content provider test succeeded for %s.", request.provider_type.value
)
return {"status": "ok"}
diff --git a/backend/onyx/server/metrics/indexing_pipeline.py b/backend/onyx/server/metrics/indexing_pipeline.py
index 7f1fa57380..9183dc779a 100644
--- a/backend/onyx/server/metrics/indexing_pipeline.py
+++ b/backend/onyx/server/metrics/indexing_pipeline.py
@@ -125,12 +125,14 @@ class _CachedCollector(Collector):
return result
except concurrent.futures.TimeoutError:
logger.warning(
- f"{type(self).__name__}._collect_fresh() timed out after {self._collect_timeout}s, returning stale cache"
+ "%s._collect_fresh() timed out after %ss, returning stale cache",
+ type(self).__name__,
+ self._collect_timeout,
)
return self._cached_result if self._cached_result is not None else []
except Exception:
self._inflight = None
- logger.exception(f"Error in {type(self).__name__}.collect()")
+ logger.exception("Error in %s.collect()", type(self).__name__)
# Return stale cache on error rather than nothing — avoids
# metrics disappearing during transient failures.
return self._cached_result if self._cached_result is not None else []
diff --git a/backend/onyx/server/metrics/indexing_task_metrics.py b/backend/onyx/server/metrics/indexing_task_metrics.py
index cf44be256d..1af3a0f770 100644
--- a/backend/onyx/server/metrics/indexing_task_metrics.py
+++ b/backend/onyx/server/metrics/indexing_task_metrics.py
@@ -160,7 +160,8 @@ def _resolve_connector(cc_pair_id: int, tenant_id: str) -> ConnectorInfo:
return info
except Exception:
logger.debug(
- f"Failed to resolve connector info for cc_pair_id={cc_pair_id}",
+ "Failed to resolve connector info for cc_pair_id=%s",
+ cc_pair_id,
exc_info=True,
)
return _UNKNOWN_CONNECTOR
diff --git a/backend/onyx/server/metrics/metrics_server.py b/backend/onyx/server/metrics/metrics_server.py
index 3c9f00beed..26dad6cbec 100644
--- a/backend/onyx/server/metrics/metrics_server.py
+++ b/backend/onyx/server/metrics/metrics_server.py
@@ -51,12 +51,12 @@ def start_metrics_server(worker_type: str) -> int | None:
with _server_lock:
if _server_started:
- logger.debug(f"Metrics server already started for {worker_type}")
+ logger.debug("Metrics server already started for %s", worker_type)
return None
enabled = os.environ.get("PROMETHEUS_METRICS_ENABLED", "true").lower()
if enabled in ("false", "0", "no"):
- logger.info(f"Prometheus metrics server disabled for {worker_type}")
+ logger.info("Prometheus metrics server disabled for %s", worker_type)
return None
port_str = os.environ.get("PROMETHEUS_METRICS_PORT")
@@ -65,16 +65,17 @@ def start_metrics_server(worker_type: str) -> int | None:
port = int(port_str)
except ValueError:
logger.warning(
- f"Invalid PROMETHEUS_METRICS_PORT '{port_str}' for {worker_type}, "
- "must be a numeric port. Skipping metrics server."
+ "Invalid PROMETHEUS_METRICS_PORT '%s' for %s, must be a numeric port. Skipping metrics server.",
+ port_str,
+ worker_type,
)
return None
elif worker_type in _DEFAULT_PORTS:
port = _DEFAULT_PORTS[worker_type]
else:
logger.info(
- f"No default metrics port for worker type '{worker_type}' "
- "and PROMETHEUS_METRICS_PORT not set. Skipping metrics server."
+ "No default metrics port for worker type '%s' and PROMETHEUS_METRICS_PORT not set. Skipping metrics server.",
+ worker_type,
)
return None
@@ -82,11 +83,11 @@ def start_metrics_server(worker_type: str) -> int | None:
start_http_server(port)
_server_started = True
logger.info(
- f"Prometheus metrics server started on :{port} for {worker_type}"
+ "Prometheus metrics server started on :%s for %s", port, worker_type
)
return port
except OSError as e:
logger.warning(
- f"Failed to start metrics server on :{port} for {worker_type}: {e}"
+ "Failed to start metrics server on :%s for %s: %s", port, worker_type, e
)
return None
diff --git a/backend/onyx/server/metrics/postgres_connection_pool.py b/backend/onyx/server/metrics/postgres_connection_pool.py
index 69e6e0e94f..47b44f2257 100644
--- a/backend/onyx/server/metrics/postgres_connection_pool.py
+++ b/backend/onyx/server/metrics/postgres_connection_pool.py
@@ -240,12 +240,14 @@ def setup_postgres_connection_pool_metrics(
pool = sync_engine.pool
if not isinstance(pool, QueuePool):
logger.info(
- f"Skipping pool metrics for engine '{label}' ({type(pool).__name__} — no pool state)"
+ "Skipping pool metrics for engine '%s' (%s — no pool state)",
+ label,
+ type(pool).__name__,
)
continue
collector.add_pool(label, pool)
_register_pool_events(sync_engine, label)
- logger.info(f"Registered pool metrics for engine '{label}'")
+ logger.info("Registered pool metrics for engine '%s'", label)
REGISTRY.register(collector)
diff --git a/backend/onyx/server/middleware/latency_logging.py b/backend/onyx/server/middleware/latency_logging.py
index ed269a545d..b061a370c8 100644
--- a/backend/onyx/server/middleware/latency_logging.py
+++ b/backend/onyx/server/middleware/latency_logging.py
@@ -17,7 +17,10 @@ def add_latency_logging_middleware(app: FastAPI, logger: logging.LoggerAdapter)
response = await call_next(request)
process_time = time.monotonic() - start_time
logger.debug(
- f"Path: {request.url.path} - Method: {request.method} - "
- f"Status Code: {response.status_code} - Time: {process_time:.4f} secs"
+ "Path: %s - Method: %s - Status Code: %s - Time: %s secs",
+ request.url.path,
+ request.method,
+ response.status_code,
+ format(process_time, ".4f"),
)
return response
diff --git a/backend/onyx/server/pat/api.py b/backend/onyx/server/pat/api.py
index ece3b06e5d..0b71851fac 100644
--- a/backend/onyx/server/pat/api.py
+++ b/backend/onyx/server/pat/api.py
@@ -59,7 +59,7 @@ def create_token(
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
- logger.info(f"User {user.email} created PAT '{request.name}'")
+ logger.info("User %s created PAT '%s'", user.email, request.name)
return CreatedTokenResponse(
id=pat.id,
@@ -85,5 +85,5 @@ def delete_token(
status_code=404, detail="Token not found or not owned by user"
)
- logger.info(f"User {user.email} revoked token {token_id}")
+ logger.info("User %s revoked token %s", user.email, token_id)
return {"message": "Token deleted successfully"}
diff --git a/backend/onyx/server/query_and_chat/chat_backend.py b/backend/onyx/server/query_and_chat/chat_backend.py
index 18e49b1437..ee316bbaa1 100644
--- a/backend/onyx/server/query_and_chat/chat_backend.py
+++ b/backend/onyx/server/query_and_chat/chat_backend.py
@@ -561,7 +561,7 @@ def handle_send_chat_message(
Returns:
StreamingResponse | ChatFullResponse: Either streams or returns complete response.
"""
- logger.debug(f"Received new chat message: {chat_message_req.message}")
+ logger.debug("Received new chat message: %s", chat_message_req.message)
tenant_id = get_current_tenant_id()
mt_cloud_telemetry(
diff --git a/backend/onyx/server/query_and_chat/query_backend.py b/backend/onyx/server/query_and_chat/query_backend.py
index 5176c4c1e7..0c2ee12c3b 100644
--- a/backend/onyx/server/query_and_chat/query_backend.py
+++ b/backend/onyx/server/query_and_chat/query_backend.py
@@ -40,7 +40,7 @@ def admin_search(
tenant_id = get_current_tenant_id()
query = question.query
- logger.notice(f"Received admin search query: {query}")
+ logger.notice("Received admin search query: %s", query)
user_acl_filters = build_access_filters_for_user(user, db_session)
final_filters = IndexFilters(
diff --git a/backend/onyx/server/query_and_chat/session_loading.py b/backend/onyx/server/query_and_chat/session_loading.py
index c803a4b508..5c090a3e59 100644
--- a/backend/onyx/server/query_and_chat/session_loading.py
+++ b/backend/onyx/server/query_and_chat/session_loading.py
@@ -727,7 +727,7 @@ def translate_assistant_message_to_packets(
)
except Exception as e:
- logger.warning(f"Error processing tool call {tool_call.id}: {e}")
+ logger.warning("Error processing tool call %s: %s", tool_call.id, e)
continue
if research_agent_count > 1:
diff --git a/backend/onyx/server/saml.py b/backend/onyx/server/saml.py
index 384ee538b0..db03b4f56b 100644
--- a/backend/onyx/server/saml.py
+++ b/backend/onyx/server/saml.py
@@ -59,7 +59,7 @@ async def upsert_saml_user(email: str) -> User:
SAML users never use this password directly as they authenticate via their
Identity Provider, but we need a valid password to satisfy system requirements.
"""
- logger.debug(f"Attempting to upsert SAML user with email: {email}")
+ logger.debug("Attempting to upsert SAML user with email: %s", email)
get_user_db_context = contextlib.asynccontextmanager(get_user_db)
get_user_manager_context = contextlib.asynccontextmanager(get_user_manager)
diff --git a/backend/onyx/server/settings/store.py b/backend/onyx/server/settings/store.py
index 4e1237b626..8ce4a76192 100644
--- a/backend/onyx/server/settings/store.py
+++ b/backend/onyx/server/settings/store.py
@@ -32,10 +32,10 @@ def load_settings() -> Settings:
)
except KvKeyNotFoundError:
# Default to empty settings if no settings have been set yet
- logger.debug(f"No settings found in KV store for key: {KV_SETTINGS_KEY}")
+ logger.debug("No settings found in KV store for key: %s", KV_SETTINGS_KEY)
settings = Settings()
except Exception as e:
- logger.error(f"Error loading settings from KV store: {str(e)}")
+ logger.error("Error loading settings from KV store: %s", str(e))
settings = Settings()
cache = get_cache_backend()
@@ -48,7 +48,7 @@ def load_settings() -> Settings:
anonymous_user_enabled = False
cache.set(OnyxRedisLocks.ANONYMOUS_USER_ENABLED, "0", ex=SETTINGS_TTL)
except Exception as e:
- logger.error(f"Error loading anonymous user setting from cache: {str(e)}")
+ logger.error("Error loading anonymous user setting from cache: %s", str(e))
anonymous_user_enabled = False
settings.anonymous_user_enabled = anonymous_user_enabled
diff --git a/backend/onyx/setup.py b/backend/onyx/setup.py
index 321f7f7103..e94f0579a3 100644
--- a/backend/onyx/setup.py
+++ b/backend/onyx/setup.py
@@ -102,10 +102,10 @@ def setup_onyx(
# Expire all old embedding models indexing attempts, technically redundant
cancel_indexing_attempts_past_model(db_session)
- logger.notice(f'Using Embedding model: "{search_settings.model_name}"')
+ logger.notice('Using Embedding model: "%s"', search_settings.model_name)
if search_settings.query_prefix or search_settings.passage_prefix:
- logger.notice(f'Query embedding prefix: "{search_settings.query_prefix}"')
- logger.notice(f'Passage embedding prefix: "{search_settings.passage_prefix}"')
+ logger.notice('Query embedding prefix: "%s"', search_settings.query_prefix)
+ logger.notice('Passage embedding prefix: "%s"', search_settings.passage_prefix)
# setup Postgres with default credential, llm providers, etc.
setup_postgres(db_session)
@@ -145,7 +145,9 @@ def setup_onyx(
"Could not connect to a document index within the specified timeout."
)
- logger.notice(f"Model Server: http://{MODEL_SERVER_HOST}:{MODEL_SERVER_PORT}")
+ logger.notice(
+ "Model Server: http://%s:%s", MODEL_SERVER_HOST, MODEL_SERVER_PORT
+ )
if search_settings.provider_type is None:
# In integration tests, do not block API startup on warm-up
warm_up_bi_encoder(
@@ -165,7 +167,7 @@ def mark_reindex_flag(db_session: Session) -> None:
kv_store = get_kv_store()
try:
value = kv_store.load(KV_REINDEX_KEY)
- logger.debug(f"Re-indexing flag has value {value}")
+ logger.debug("Re-indexing flag has value %s", value)
return
except KvKeyNotFoundError:
# Only need to update the flag if it hasn't been set
@@ -200,7 +202,10 @@ def setup_document_indices(
for x in range(num_attempts):
try:
logger.notice(
- f"Setting up document index {document_index.__class__.__name__} (attempt {x + 1}/{num_attempts})..."
+ "Setting up document index %s (attempt %s/%s)...",
+ document_index.__class__.__name__,
+ x + 1,
+ num_attempts,
)
document_index.ensure_indices_exist(
primary_embedding_dim=index_setting.final_embedding_dim,
@@ -218,22 +223,24 @@ def setup_document_indices(
)
logger.notice(
- f"Document index {document_index.__class__.__name__} setup complete."
+ "Document index %s setup complete.",
+ document_index.__class__.__name__,
)
document_index_setup_success = True
break
except Exception:
logger.exception(
- f"Document index {document_index.__class__.__name__} setup did not succeed. "
- "The relevant service may not be ready yet. "
- f"Retrying in {WAIT_SECONDS} seconds."
+ "Document index %s setup did not succeed. The relevant service may not be ready yet. Retrying in %s seconds.",
+ document_index.__class__.__name__,
+ WAIT_SECONDS,
)
time.sleep(WAIT_SECONDS)
if not document_index_setup_success:
logger.error(
- f"Document index {document_index.__class__.__name__} setup did not succeed. "
- f"Attempt limit reached. ({num_attempts})"
+ "Document index %s setup did not succeed. Attempt limit reached. (%s)",
+ document_index.__class__.__name__,
+ num_attempts,
)
return False
@@ -286,18 +293,18 @@ def setup_postgres(db_session: Session) -> None:
def update_default_multipass_indexing(db_session: Session) -> None:
docs_exist = check_docs_exist(db_session)
connectors_exist = check_connectors_exist(db_session)
- logger.debug(f"Docs exist: {docs_exist}, Connectors exist: {connectors_exist}")
+ logger.debug("Docs exist: %s, Connectors exist: %s", docs_exist, connectors_exist)
if not docs_exist and not connectors_exist:
logger.info(
"No existing docs or connectors found. Checking GPU availability for multipass indexing."
)
gpu_available = gpu_status_request(indexing=True)
- logger.info(f"GPU available: {gpu_available}")
+ logger.info("GPU available: %s", gpu_available)
current_settings = get_current_search_settings(db_session)
- logger.notice(f"Updating multipass indexing setting to: {gpu_available}")
+ logger.notice("Updating multipass indexing setting to: %s", gpu_available)
updated_settings = SavedSearchSettings.from_db_model(current_settings)
# Enable multipass indexing if GPU is available or if using a cloud provider
updated_settings.multipass_indexing = (
@@ -309,7 +316,7 @@ def update_default_multipass_indexing(db_session: Session) -> None:
settings = load_settings()
settings.gpu_enabled = gpu_available
store_settings(settings)
- logger.notice(f"Updated settings with GPU availability: {gpu_available}")
+ logger.notice("Updated settings with GPU availability: %s", gpu_available)
else:
logger.debug(
@@ -342,7 +349,7 @@ def setup_vespa_multitenant(supported_indices: list[SupportedEmbeddingModel]) ->
VESPA_ATTEMPTS = 5
for x in range(VESPA_ATTEMPTS):
try:
- logger.notice(f"Setting up Vespa (attempt {x + 1}/{VESPA_ATTEMPTS})...")
+ logger.notice("Setting up Vespa (attempt %s/%s)...", x + 1, VESPA_ATTEMPTS)
VespaIndex.register_multitenant_indices(
indices=[index.index_name for index in supported_indices]
+ [
@@ -362,11 +369,12 @@ def setup_vespa_multitenant(supported_indices: list[SupportedEmbeddingModel]) ->
return True
except Exception:
logger.notice(
- f"Vespa setup did not succeed. The Vespa service may not be ready yet. Retrying in {WAIT_SECONDS} seconds."
+ "Vespa setup did not succeed. The Vespa service may not be ready yet. Retrying in %s seconds.",
+ WAIT_SECONDS,
)
time.sleep(WAIT_SECONDS)
logger.error(
- f"Vespa setup did not succeed. Attempt limit reached. ({VESPA_ATTEMPTS})"
+ "Vespa setup did not succeed. Attempt limit reached. (%s)", VESPA_ATTEMPTS
)
return False
diff --git a/backend/onyx/tools/fake_tools/research_agent.py b/backend/onyx/tools/fake_tools/research_agent.py
index c729a8ac82..4ccf39f5f8 100644
--- a/backend/onyx/tools/fake_tools/research_agent.py
+++ b/backend/onyx/tools/fake_tools/research_agent.py
@@ -260,8 +260,9 @@ def run_research_agent_call(
elapsed_seconds = time.monotonic() - start_time
if elapsed_seconds > RESEARCH_AGENT_FORCE_REPORT_SECONDS:
logger.info(
- f"Research agent exceeded {RESEARCH_AGENT_FORCE_REPORT_SECONDS}s "
- f"(elapsed: {elapsed_seconds:.1f}s), forcing intermediate report generation"
+ "Research agent exceeded %ss (elapsed: %ss), forcing intermediate report generation",
+ RESEARCH_AGENT_FORCE_REPORT_SECONDS,
+ format(elapsed_seconds, ".1f"),
)
break
@@ -608,7 +609,7 @@ def run_research_agent_call(
)
except Exception as e:
- logger.error(f"Error running research agent call: {e}")
+ logger.error("Error running research agent call: %s", e)
emitter.emit(
Packet(
placement=Placement(turn_index=turn_index, tab_index=tab_index),
@@ -633,7 +634,9 @@ def _on_research_agent_timeout(
RESEARCH_AGENT_TASK_KEY, "unknown"
)
logger.warning(
- f"Research agent timed out after {RESEARCH_AGENT_TIMEOUT_SECONDS} seconds for task: {research_task}"
+ "Research agent timed out after %s seconds for task: %s",
+ RESEARCH_AGENT_TIMEOUT_SECONDS,
+ research_task,
)
return ResearchAgentCallResult(
intermediate_report=RESEARCH_AGENT_TIMEOUT_MESSAGE,
@@ -762,9 +765,9 @@ if __name__ == "__main__":
if tool.name != "generate_image"
]
- logger.info(f"Running research agent with prompt: {RESEARCH_PROMPT}")
- logger.info(f"LLM: {llm.config.model_provider}/{llm.config.model_name}")
- logger.info(f"Tools: {[t.name for t in tools]}")
+ logger.info("Running research agent with prompt: %s", RESEARCH_PROMPT)
+ logger.info("LLM: %s/%s", llm.config.model_provider, llm.config.model_name)
+ logger.info("Tools: %s", [t.name for t in tools])
result = run_research_agent_call(
research_agent_call=ToolCallKickoff(
diff --git a/backend/onyx/tools/tool_constructor.py b/backend/onyx/tools/tool_constructor.py
index ceb7086212..59be686270 100644
--- a/backend/onyx/tools/tool_constructor.py
+++ b/backend/onyx/tools/tool_constructor.py
@@ -160,7 +160,10 @@ def _construct_tools_impl(
# Log which tools are attached to the persona for debugging
persona_tool_names = [t.name for t in persona.tools]
logger.debug(
- f"Constructing tools for persona '{persona.name}' (id={persona.id}): {persona_tool_names}"
+ "Constructing tools for persona '%s' (id=%s): %s",
+ persona.name,
+ persona.id,
+ persona_tool_names,
)
mcp_tool_cache: dict[int, dict[int, MCPTool]] = {}
@@ -264,7 +267,7 @@ def _construct_tools_impl(
WebSearchTool(tool_id=db_tool_model.id, emitter=emitter)
]
except ValueError as e:
- logger.error(f"Failed to initialize Internet Search Tool: {e}")
+ logger.error("Failed to initialize Internet Search Tool: %s", e)
raise ValueError(
"Internet search tool requires a search provider API key, please contact your Onyx admin to get it added!"
)
@@ -281,7 +284,7 @@ def _construct_tools_impl(
)
]
except RuntimeError as e:
- logger.error(f"Failed to initialize Open URL Tool: {e}")
+ logger.error("Failed to initialize Open URL Tool: %s", e)
raise ValueError(
"Open URL tool requires a web content provider, please contact your Onyx admin to get it configured!"
)
@@ -335,7 +338,7 @@ def _construct_tools_impl(
if db_tool_model.oauth_config_id:
if user.is_anonymous:
logger.warning(
- f"Anonymous user cannot use OAuth tool {db_tool_model.id}"
+ "Anonymous user cannot use OAuth tool %s", db_tool_model.id
)
continue
oauth_config = get_oauth_config(
@@ -346,15 +349,17 @@ def _construct_tools_impl(
oauth_token_for_tool = token_manager.get_valid_access_token()
if not oauth_token_for_tool:
logger.warning(
- f"No valid OAuth token found for tool {db_tool_model.id} "
- f"with OAuth config {db_tool_model.oauth_config_id}"
+ "No valid OAuth token found for tool %s with OAuth config %s",
+ db_tool_model.id,
+ db_tool_model.oauth_config_id,
)
# Priority 2: Passthrough auth (user's login OAuth token)
elif db_tool_model.passthrough_auth:
if user.is_anonymous:
logger.warning(
- f"Anonymous user cannot use passthrough auth tool {db_tool_model.id}"
+ "Anonymous user cannot use passthrough auth tool %s",
+ db_tool_model.id,
)
continue
oauth_token_for_tool = user_oauth_token
@@ -400,7 +405,8 @@ def _construct_tools_impl(
# Pass-through OAuth: use the user's login OAuth token
if user.is_anonymous:
logger.warning(
- f"Anonymous user cannot use PT_OAUTH MCP server {mcp_server.id}"
+ "Anonymous user cannot use PT_OAUTH MCP server %s",
+ mcp_server.id,
)
continue
mcp_user_oauth_token = user_oauth_token
@@ -451,7 +457,9 @@ def _construct_tools_impl(
tool_dict[saved_tool.id] = [cast(Tool, mcp_tool)]
if db_tool_model.id not in tool_dict:
logger.warning(
- f"Tool '{expected_tool_name}' not found in MCP server '{mcp_server.name}'"
+ "Tool '%s' not found in MCP server '%s'",
+ expected_tool_name,
+ mcp_server.name,
)
if (
diff --git a/backend/onyx/tools/tool_implementations/custom/custom_tool.py b/backend/onyx/tools/tool_implementations/custom/custom_tool.py
index 97ef347a9f..f076ead9b9 100644
--- a/backend/onyx/tools/tool_implementations/custom/custom_tool.py
+++ b/backend/onyx/tools/tool_implementations/custom/custom_tool.py
@@ -79,9 +79,8 @@ class CustomTool(Tool[None]):
)
if has_auth_header and self._user_oauth_token:
logger.warning(
- f"Tool '{self._name}' has both an Authorization "
- "header and OAuth token set. This is likely a configuration "
- "error as the OAuth token will override the custom header."
+ "Tool '%s' has both an Authorization header and OAuth token set. This is likely a configuration error as the OAuth token will override the custom header.",
+ self._name,
)
if self._user_oauth_token:
@@ -206,7 +205,9 @@ class CustomTool(Tool[None]):
message=f"{self._name} action failed because of authentication error",
)
logger.warning(
- f"Auth error from custom tool '{self._name}': HTTP {response.status_code}"
+ "Auth error from custom tool '%s': HTTP %s",
+ self._name,
+ response.status_code,
)
tool_result: Any
@@ -235,14 +236,14 @@ class CustomTool(Tool[None]):
data = tool_result
except JSONDecodeError:
logger.exception(
- f"Failed to parse response as JSON for tool '{self._name}'"
+ "Failed to parse response as JSON for tool '%s'", self._name
)
tool_result = response.text
response_type = "text"
data = tool_result
logger.info(
- f"Returning tool response for {self._name} with type {response_type}"
+ "Returning tool response for %s with type %s", self._name, response_type
)
# Emit CustomToolDelta packet
diff --git a/backend/onyx/tools/tool_implementations/images/image_generation_tool.py b/backend/onyx/tools/tool_implementations/images/image_generation_tool.py
index cbf3d25be1..55239b5e4c 100644
--- a/backend/onyx/tools/tool_implementations/images/image_generation_tool.py
+++ b/backend/onyx/tools/tool_implementations/images/image_generation_tool.py
@@ -181,7 +181,7 @@ class ImageGenerationTool(Tool[None]):
size = "1024x1792"
else:
size = "1024x1024"
- logger.debug(f"Generating image with model: {self.model}, size: {size}")
+ logger.debug("Generating image with model: %s, size: %s", self.model, size)
try:
response = self.img_provider.generate_image(
prompt=prompt,
@@ -215,12 +215,12 @@ class ImageGenerationTool(Tool[None]):
)
except requests.RequestException as e:
- logger.error(f"Error fetching or converting image: {e}")
+ logger.error("Error fetching or converting image: %s", e)
raise ToolExecutionException(
"Failed to fetch or convert the generated image", emit_error_packet=True
)
except Exception as e:
- logger.debug(f"Error occurred during image generation: {e}")
+ logger.debug("Error occurred during image generation: %s", e)
error_message = str(e)
if "OpenAIException" in str(type(e)):
diff --git a/backend/onyx/tools/tool_implementations/mcp/mcp_client.py b/backend/onyx/tools/tool_implementations/mcp/mcp_client.py
index 49a940acc5..0d8fd34152 100644
--- a/backend/onyx/tools/tool_implementations/mcp/mcp_client.py
+++ b/backend/onyx/tools/tool_implementations/mcp/mcp_client.py
@@ -190,7 +190,7 @@ def _call_mcp_client_function_sync(
try:
return run_async_sync_no_cancel(run_client_function())
except Exception as e:
- logger.error(f"Failed to call MCP client function: {e}")
+ logger.error("Failed to call MCP client function: %s", e)
if isinstance(e, ExceptionGroup):
original_exception = e
saved_e = log_exception_group(e)
@@ -288,12 +288,12 @@ async def _discover_mcp_tools(session: ClientSession) -> list[MCPLibTool]:
t1 = time.time()
init_result = await session.initialize() # sends JSON-RPC "initialize"
- logger.info(f"Initialized with server: {init_result.serverInfo}")
- logger.info(f"Initialized with server time: {time.time() - t1}")
+ logger.info("Initialized with server: %s", init_result.serverInfo)
+ logger.info("Initialized with server time: %s", time.time() - t1)
# 2) tools/list
t2 = time.time()
tools_response = await session.list_tools() # sends JSON-RPC "tools/list"
- logger.info(f"Listed tools with server time: {time.time() - t2}")
+ logger.info("Listed tools with server time: %s", time.time() - t2)
return tools_response.tools
diff --git a/backend/onyx/tools/tool_implementations/mcp/mcp_tool.py b/backend/onyx/tools/tool_implementations/mcp/mcp_tool.py
index 168a30593a..1fb7f57cf7 100644
--- a/backend/onyx/tools/tool_implementations/mcp/mcp_tool.py
+++ b/backend/onyx/tools/tool_implementations/mcp/mcp_tool.py
@@ -153,7 +153,9 @@ class MCPTool(Tool[None]):
]
if denylisted_provided:
logger.warning(
- f"MCP tool '{self._name}' received denylisted headers that were filtered: {denylisted_provided}"
+ "MCP tool '%s' received denylisted headers that were filtered: %s",
+ self._name,
+ denylisted_provided,
)
# Priority 2: Base headers from connection config (DB) - overrides request
@@ -187,7 +189,8 @@ class MCPTool(Tool[None]):
f"using this tool."
)
logger.warning(
- f"Authentication required for MCP tool '{self._name}' but no credentials found"
+ "Authentication required for MCP tool '%s' but no credentials found",
+ self._name,
)
error_result = {"error": auth_error_msg}
@@ -224,9 +227,8 @@ class MCPTool(Tool[None]):
):
if self.mcp_server.transport == MCPTransport.SSE:
logger.warning(
- f"MCP tool '{self._name}': OAuth token refresh is not supported "
- f"for SSE transport — auth provider will be ignored. "
- f"Re-authentication may be required after token expiry."
+ "MCP tool '%s': OAuth token refresh is not supported for SSE transport — auth provider will be ignored. Re-authentication may be required after token expiry.",
+ self._name,
)
else:
from onyx.server.features.mcp.api import make_oauth_provider
@@ -252,7 +254,7 @@ class MCPTool(Tool[None]):
auth=auth,
)
- logger.info(f"MCP tool '{self._name}' executed successfully")
+ logger.info("MCP tool '%s' executed successfully", self._name)
# Format the tool result for response
tool_result_dict = {"tool_result": tool_result}
@@ -281,7 +283,7 @@ class MCPTool(Tool[None]):
except Exception as e:
error_str = str(e).lower()
- logger.error(f"Failed to execute MCP tool '{self._name}': {e}")
+ logger.error("Failed to execute MCP tool '%s': %s", self._name, e)
# Check for authentication-related errors
auth_error_indicators = [
diff --git a/backend/onyx/tools/tool_implementations/memory/memory_tool.py b/backend/onyx/tools/tool_implementations/memory/memory_tool.py
index 0cac782ce1..0b8af0c6c9 100644
--- a/backend/onyx/tools/tool_implementations/memory/memory_tool.py
+++ b/backend/onyx/tools/tool_implementations/memory/memory_tool.py
@@ -136,7 +136,7 @@ class MemoryTool(Tool[MemoryToolOverrideKwargs]):
user_role=override_kwargs.user_role,
)
- logger.info(f"New memory to be added: {memory_text}")
+ logger.info("New memory to be added: %s", memory_text)
operation: Literal["add", "update"] = (
"update" if index_to_replace is not None else "add"
diff --git a/backend/onyx/tools/tool_implementations/open_url/firecrawl.py b/backend/onyx/tools/tool_implementations/open_url/firecrawl.py
index ab034953e2..5ba06ca88e 100644
--- a/backend/onyx/tools/tool_implementations/open_url/firecrawl.py
+++ b/backend/onyx/tools/tool_implementations/open_url/firecrawl.py
@@ -156,7 +156,7 @@ class FirecrawlClient(WebContentProvider):
published_date = None
if not text:
- logger.warning(f"Firecrawl returned empty content for url={url}")
+ logger.warning("Firecrawl returned empty content for url=%s", url)
return ExtractedContentFields(
text=text or "",
diff --git a/backend/onyx/tools/tool_implementations/open_url/open_url_tool.py b/backend/onyx/tools/tool_implementations/open_url/open_url_tool.py
index 5374a15fe1..d8a56433c2 100644
--- a/backend/onyx/tools/tool_implementations/open_url/open_url_tool.py
+++ b/backend/onyx/tools/tool_implementations/open_url/open_url_tool.py
@@ -483,7 +483,9 @@ class OpenURLTool(Tool[OpenURLToolOverrideKwargs]):
if len(urls) > override_kwargs.max_urls:
logger.warning(
- f"OpenURL tool received {len(urls)} URLs, but the max is {override_kwargs.max_urls}."
+ "OpenURL tool received %s URLs, but the max is %s.",
+ len(urls),
+ override_kwargs.max_urls,
)
urls = urls[: override_kwargs.max_urls]
@@ -608,7 +610,7 @@ class OpenURLTool(Tool[OpenURLToolOverrideKwargs]):
if failure_descriptions
else "Failed to fetch content from the requested resources."
)
- logger.warning(f"OpenURL tool failed: {failure_msg}")
+ logger.warning("OpenURL tool failed: %s", failure_msg)
return ToolResponse(rich_response=None, llm_facing_response=failure_msg)
for section in inference_sections:
@@ -723,7 +725,9 @@ class OpenURLTool(Tool[OpenURLToolOverrideKwargs]):
)
except Exception as exc:
logger.warning(
- f"Indexed retrieval failed for document IDs {document_ids}: {exc}",
+ "Indexed retrieval failed for document IDs %s: %s",
+ document_ids,
+ exc,
exc_info=True,
)
return IndexedRetrievalResult(
diff --git a/backend/onyx/tools/tool_implementations/python/code_interpreter_client.py b/backend/onyx/tools/tool_implementations/python/code_interpreter_client.py
index 2d177d8d46..bea086d483 100644
--- a/backend/onyx/tools/tool_implementations/python/code_interpreter_client.py
+++ b/backend/onyx/tools/tool_implementations/python/code_interpreter_client.py
@@ -138,7 +138,7 @@ class CodeInterpreterClient:
response.raise_for_status()
result = response.json().get("status") == "ok"
except Exception as e:
- logger.warning(f"Exception caught when checking health, e={e}")
+ logger.warning("Exception caught when checking health, e=%s", e)
result = False
_health_cache[self.base_url] = (time.monotonic(), result)
@@ -223,7 +223,7 @@ class CodeInterpreterClient:
if model_cls is not None:
yield model_cls(**json.loads(data))
else:
- logger.warning(f"Unknown SSE event type: {event_type}")
+ logger.warning("Unknown SSE event type: %s", event_type)
event_type = None
data_lines = []
elif line.startswith("event:"):
@@ -233,7 +233,9 @@ class CodeInterpreterClient:
if event_type is not None or data_lines:
logger.warning(
- f"SSE stream ended with incomplete event: event_type={event_type}, data_lines={data_lines}"
+ "SSE stream ended with incomplete event: event_type=%s, data_lines=%s",
+ event_type,
+ data_lines,
)
def _batch_as_stream(
diff --git a/backend/onyx/tools/tool_implementations/python/python_tool.py b/backend/onyx/tools/tool_implementations/python/python_tool.py
index 2b9fe59f93..06603f1667 100644
--- a/backend/onyx/tools/tool_implementations/python/python_tool.py
+++ b/backend/onyx/tools/tool_implementations/python/python_tool.py
@@ -64,7 +64,7 @@ def _truncate_output(output: str, max_length: int, label: str = "output") -> str
truncated += (
f"\n... [output truncated, {len(output) - max_length} characters omitted]"
)
- logger.debug(f"Truncated {label}: {truncated}")
+ logger.debug("Truncated %s: %s", label, truncated)
return truncated
@@ -201,13 +201,13 @@ class PythonTool(Tool[PythonToolOverrideKwargs]):
# Stage for execution
files_to_stage.append({"path": file_name, "file_id": ci_file_id})
- logger.info(f"Staged file for Python execution: {file_name}")
+ logger.info("Staged file for Python execution: %s", file_name)
except Exception as e:
- logger.warning(f"Failed to stage file {file_name}: {e}")
+ logger.warning("Failed to stage file %s: %s", file_name, e)
try:
- logger.debug(f"Executing code: {code}")
+ logger.debug("Executing code: %s", code)
# Execute code with streaming (falls back to batch if unavailable)
stdout_parts: list[str] = []
@@ -300,7 +300,9 @@ class PythonTool(Tool[PythonToolOverrideKwargs]):
except Exception as e:
logger.error(
- f"Failed to handle generated file {workspace_file.path}: {e}"
+ "Failed to handle generated file %s: %s",
+ workspace_file.path,
+ e,
)
# Cleanup Code Interpreter files (generated files)
@@ -309,7 +311,9 @@ class PythonTool(Tool[PythonToolOverrideKwargs]):
client.delete_file(ci_file_id)
except Exception as e:
logger.error(
- f"Failed to delete Code Interpreter generated file {ci_file_id}: {e}"
+ "Failed to delete Code Interpreter generated file %s: %s",
+ ci_file_id,
+ e,
)
# Note: staged input files are intentionally not deleted here because
@@ -348,7 +352,7 @@ class PythonTool(Tool[PythonToolOverrideKwargs]):
)
except Exception as e:
- logger.error(f"Python execution failed: {e}")
+ logger.error("Python execution failed: %s", e)
error_msg = str(e)
# Emit error delta
diff --git a/backend/onyx/tools/tool_implementations/search/search_tool.py b/backend/onyx/tools/tool_implementations/search/search_tool.py
index 069f93189b..19d839d176 100644
--- a/backend/onyx/tools/tool_implementations/search/search_tool.py
+++ b/backend/onyx/tools/tool_implementations/search/search_tool.py
@@ -212,7 +212,11 @@ def _trim_sections_by_tokens(
break
logger.debug(
- f"Trimmed sections from {len(sections)} to {len(trimmed_sections)} ({total_tokens} tokens, budget: {max_tokens})"
+ "Trimmed sections from %s to %s (%s tokens, budget: %s)",
+ len(sections),
+ len(trimmed_sections),
+ total_tokens,
+ max_tokens,
)
return trimmed_sections
@@ -301,12 +305,13 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
):
entities = mapping.federated_connector.config or {}
found_slack_connector = True
- logger.debug(f"Found Slack federated connector config: {entities}")
+ logger.debug("Found Slack federated connector config: %s", entities)
break
if not found_slack_connector:
logger.debug(
- f"Skipping Slack federated search: no Slack federated connector linked to document sets {document_set_names}"
+ "Skipping Slack federated search: no Slack federated connector linked to document sets %s",
+ document_set_names,
)
return None, None, {}
@@ -337,7 +342,7 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
)
access_token = user_token or bot_token
except Exception as e:
- logger.warning(f"Could not fetch Slack bot tokens: {e}")
+ logger.warning("Could not fetch Slack bot tokens: %s", e)
# Case 2: Web user with federated OAuth (if bot context didn't yield a token)
if not access_token and self.user:
@@ -361,7 +366,7 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
access_token = slack_oauth_token.token.get_value(apply_mask=False)
entities = slack_oauth_token.federated_connector.config or {}
except Exception as e:
- logger.warning(f"Could not fetch Slack OAuth token: {e}")
+ logger.warning("Could not fetch Slack OAuth token: %s", e)
return access_token, bot_token, entities
@@ -405,11 +410,11 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
search_settings=search_settings,
)
- logger.info(f"Slack federated search returned {len(chunks)} chunks")
+ logger.info("Slack federated search returned %s chunks", len(chunks))
return chunks
except Exception as e:
- logger.error(f"Slack federated search error: {e}", exc_info=True)
+ logger.error("Slack federated search error: %s", e, exc_info=True)
return []
def _run_search_for_query(
@@ -650,7 +655,8 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
# End timing for query expansion/rephrase
query_expansion_elapsed = time.time() - query_expansion_start_time
logger.debug(
- f"Search tool - Query expansion/rephrase took {query_expansion_elapsed:.3f} seconds"
+ "Search tool - Query expansion/rephrase took %s seconds",
+ format(query_expansion_elapsed, ".3f"),
)
semantic_query = expansion_results[0] # str
keyword_queries = (
@@ -704,7 +710,9 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
seen_lower.add(query_lower)
logger.debug(
- f"All Queries (sorted by weight): {all_queries}, Keyword queries: {[q for q, _ in deduplicated_keyword_queries]}"
+ "All Queries (sorted by weight): %s, Keyword queries: %s",
+ all_queries,
+ [q for q, _ in deduplicated_keyword_queries],
)
# Emit the queries early so the UI can display them immediately
@@ -854,8 +862,9 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
# End timing for LLM document selection
document_selection_elapsed = time.time() - document_selection_start_time
logger.debug(
- f"Search tool - LLM picking documents took {document_selection_elapsed:.3f} seconds "
- f"(selected {len(selected_sections)} sections)"
+ "Search tool - LLM picking documents took %s seconds (selected %s sections)",
+ format(document_selection_elapsed, ".3f"),
+ len(selected_sections),
)
# Create a set of best document IDs for quick lookup
@@ -896,7 +905,8 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
return expanded_section if expanded_section is not None else section
except Exception as e:
logger.warning(
- f"Error processing section context expansion: {e}. Using original section."
+ "Error processing section context expansion: %s. Using original section.",
+ e,
)
return section
@@ -924,8 +934,9 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
# End timing for document expansion
document_expansion_elapsed = time.time() - document_expansion_start_time
logger.debug(
- f"Search tool - Expansion of selected documents took {document_expansion_elapsed:.3f} seconds "
- f"(expanded {len(expanded_sections)} sections)"
+ "Search tool - Expansion of selected documents took %s seconds (expanded %s sections)",
+ format(document_expansion_elapsed, ".3f"),
+ len(expanded_sections),
)
if not expanded_sections:
@@ -945,10 +956,11 @@ class SearchTool(Tool[SearchToolOverrideKwargs]):
# End overall timing
overall_elapsed = time.time() - overall_start_time
logger.debug(
- f"Search tool - Total execution time: {overall_elapsed:.3f} seconds "
- f"(query expansion: {query_expansion_elapsed:.3f}s, "
- f"document selection: {document_selection_elapsed:.3f}s, "
- f"document expansion: {document_expansion_elapsed:.3f}s)"
+ "Search tool - Total execution time: %s seconds (query expansion: %ss, document selection: %ss, document expansion: %ss)",
+ format(overall_elapsed, ".3f"),
+ format(query_expansion_elapsed, ".3f"),
+ format(document_selection_elapsed, ".3f"),
+ format(document_expansion_elapsed, ".3f"),
)
return ToolResponse(
diff --git a/backend/onyx/tools/tool_implementations/search/search_utils.py b/backend/onyx/tools/tool_implementations/search/search_utils.py
index 3670ccb46e..eb626a6e6c 100644
--- a/backend/onyx/tools/tool_implementations/search/search_utils.py
+++ b/backend/onyx/tools/tool_implementations/search/search_utils.py
@@ -178,7 +178,7 @@ def _retrieve_adjacent_chunks(
# Sort by chunk_id to ensure correct order
chunks_above.sort(key=lambda c: c.chunk_id)
except Exception as e:
- logger.warning(f"Failed to retrieve chunks above section: {e}")
+ logger.warning("Failed to retrieve chunks above section: %s", e)
# Retrieve chunks below (if any)
if num_chunks_below > 0:
@@ -200,7 +200,7 @@ def _retrieve_adjacent_chunks(
# Sort by chunk_id to ensure correct order
chunks_below.sort(key=lambda c: c.chunk_id)
except Exception as e:
- logger.warning(f"Failed to retrieve chunks below section: {e}")
+ logger.warning("Failed to retrieve chunks below section: %s", e)
return chunks_above, chunks_below
@@ -415,21 +415,24 @@ def expand_section_with_context(
if classification == ContextExpansionType.NOT_RELEVANT:
# Filter out this section
logger.debug(
- f"LLM classified section as NOT_RELEVANT: {section.center_chunk.semantic_identifier}"
+ "LLM classified section as NOT_RELEVANT: %s",
+ section.center_chunk.semantic_identifier,
)
return None
elif classification == ContextExpansionType.MAIN_SECTION_ONLY:
# Return original section unchanged
logger.debug(
- f"LLM classified section as MAIN_SECTION_ONLY: {section.center_chunk.semantic_identifier}"
+ "LLM classified section as MAIN_SECTION_ONLY: %s",
+ section.center_chunk.semantic_identifier,
)
return section
elif classification == ContextExpansionType.INCLUDE_ADJACENT_SECTIONS:
# Use the 2 chunks we already retrieved for the prompt
logger.debug(
- f"LLM classified section as INCLUDE_ADJACENT_SECTIONS: {section.center_chunk.semantic_identifier}"
+ "LLM classified section as INCLUDE_ADJACENT_SECTIONS: %s",
+ section.center_chunk.semantic_identifier,
)
all_chunks = chunks_above_for_prompt + section.chunks + chunks_below_for_prompt
@@ -448,11 +451,13 @@ def expand_section_with_context(
# Fetch 5 chunks above and below (optimal single retrieval)
if expand_override:
logger.debug(
- f"Section marked for FULL_DOCUMENT expansion (override): {section.center_chunk.semantic_identifier}"
+ "Section marked for FULL_DOCUMENT expansion (override): %s",
+ section.center_chunk.semantic_identifier,
)
else:
logger.debug(
- f"LLM classified section as FULL_DOCUMENT: {section.center_chunk.semantic_identifier}"
+ "LLM classified section as FULL_DOCUMENT: %s",
+ section.center_chunk.semantic_identifier,
)
chunks_above_full, chunks_below_full = _retrieve_adjacent_chunks(
@@ -467,7 +472,8 @@ def expand_section_with_context(
if not all_chunks:
logger.warning(
- f"No chunks found for full document context expansion: {section.center_chunk.semantic_identifier}"
+ "No chunks found for full document context expansion: %s",
+ section.center_chunk.semantic_identifier,
)
return section
@@ -482,6 +488,7 @@ def expand_section_with_context(
else:
# Unknown classification - default to returning original section
logger.warning(
- f"Unknown context classification {classification}, returning original section"
+ "Unknown context classification %s, returning original section",
+ classification,
)
return section
diff --git a/backend/onyx/tools/tool_implementations/web_search/clients/brave_client.py b/backend/onyx/tools/tool_implementations/web_search/clients/brave_client.py
index 34ae2bcf21..d377624d9d 100644
--- a/backend/onyx/tools/tool_implementations/web_search/clients/brave_client.py
+++ b/backend/onyx/tools/tool_implementations/web_search/clients/brave_client.py
@@ -42,7 +42,7 @@ class BraveClient(WebSearchProvider):
"Accept": "application/json",
"X-Subscription-Token": api_key,
}
- logger.debug(f"Count of results passed to BraveClient: {num_results}")
+ logger.debug("Count of results passed to BraveClient: %s", num_results)
self._num_results = max(1, min(num_results, BRAVE_MAX_RESULTS_PER_REQUEST))
self._timeout_seconds = timeout_seconds
self._country = _normalize_country(country)
diff --git a/backend/onyx/tools/tool_implementations/web_search/clients/google_pse_client.py b/backend/onyx/tools/tool_implementations/web_search/clients/google_pse_client.py
index a0f37d1b68..01e9b6d690 100644
--- a/backend/onyx/tools/tool_implementations/web_search/clients/google_pse_client.py
+++ b/backend/onyx/tools/tool_implementations/web_search/clients/google_pse_client.py
@@ -103,7 +103,9 @@ class GooglePSEClient(WebSearchProvider):
)
except ValueError:
logger.debug(
- f"Failed to parse published_date '{published_str}' for link {link}"
+ "Failed to parse published_date '%s' for link %s",
+ published_str,
+ link,
)
published_date = None
diff --git a/backend/onyx/tools/tool_implementations/web_search/clients/searxng_client.py b/backend/onyx/tools/tool_implementations/web_search/clients/searxng_client.py
index 1d0c32aadb..aec0374585 100644
--- a/backend/onyx/tools/tool_implementations/web_search/clients/searxng_client.py
+++ b/backend/onyx/tools/tool_implementations/web_search/clients/searxng_client.py
@@ -15,7 +15,7 @@ class SearXNGClient(WebSearchProvider):
searxng_base_url: str,
num_results: int = 10,
) -> None:
- logger.debug(f"Initializing SearXNGClient with base URL: {searxng_base_url}")
+ logger.debug("Initializing SearXNGClient with base URL: %s", searxng_base_url)
self._searxng_base_url = searxng_base_url
self._num_results = num_results
@@ -26,7 +26,7 @@ class SearXNGClient(WebSearchProvider):
"format": "json",
}
logger.debug(
- f"Searching with payload: {payload} to {self._searxng_base_url}/search"
+ "Searching with payload: %s to %s/search", payload, self._searxng_base_url
)
response = requests.post(
f"{self._searxng_base_url}/search",
@@ -50,14 +50,17 @@ class SearXNGClient(WebSearchProvider):
def test_connection(self) -> dict[str, str]:
try:
- logger.debug(f"Testing connection to {self._searxng_base_url}/config")
+ logger.debug("Testing connection to %s/config", self._searxng_base_url)
response = requests.get(f"{self._searxng_base_url}/config")
- logger.debug(f"Response: {response.status_code}, text: {response.text}")
+ logger.debug("Response: %s, text: %s", response.status_code, response.text)
response.raise_for_status()
except requests.HTTPError as e:
status_code = e.response.status_code
logger.debug(
- f"HTTPError: status_code={status_code}, e.response={e.response.status_code if e.response else None}, error={e}"
+ "HTTPError: status_code=%s, e.response=%s, error=%s",
+ status_code,
+ e.response.status_code if e.response else None,
+ e,
)
if status_code == 429:
raise HTTPException(
diff --git a/backend/onyx/tools/tool_implementations/web_search/web_search_tool.py b/backend/onyx/tools/tool_implementations/web_search/web_search_tool.py
index 3edec229bd..c950d2f8c1 100644
--- a/backend/onyx/tools/tool_implementations/web_search/web_search_tool.py
+++ b/backend/onyx/tools/tool_implementations/web_search/web_search_tool.py
@@ -192,7 +192,7 @@ class WebSearchTool(Tool[WebSearchToolOverrideKwargs]):
return (results, None)
except Exception as e:
error_msg = str(e)
- logger.warning(f"Web search query '{query}' failed: {error_msg}")
+ logger.warning("Web search query '%s' failed: %s", query, error_msg)
return (None, error_msg)
def run(
@@ -256,8 +256,10 @@ class WebSearchTool(Tool[WebSearchToolOverrideKwargs]):
# Log partial failures but continue if we have at least one success
if failed_queries and valid_results:
logger.warning(
- f"Web search partial failure: {len(failed_queries)}/{len(queries)} "
- f"queries failed. Failed queries: {json.dumps(failed_queries)}"
+ "Web search partial failure: %s/%s queries failed. Failed queries: %s",
+ len(failed_queries),
+ len(queries),
+ json.dumps(failed_queries),
)
# If all queries failed, raise ToolCallException with details
diff --git a/backend/onyx/tools/tool_runner.py b/backend/onyx/tools/tool_runner.py
index 74b605b9eb..4a306bdbc7 100644
--- a/backend/onyx/tools/tool_runner.py
+++ b/backend/onyx/tools/tool_runner.py
@@ -137,7 +137,7 @@ def _safe_run_single_tool(
except ToolCallException as e:
# ToolCallException is an expected error from tool execution
# Use llm_facing_message which is specifically designed for LLM consumption
- logger.error(f"Tool call error for {tool.name}: {e}")
+ logger.error("Tool call error for %s: %s", tool.name, e)
tool_response = ToolResponse(
rich_response=None,
llm_facing_response=GENERIC_TOOL_ERROR_MESSAGE.format(
@@ -160,7 +160,7 @@ def _safe_run_single_tool(
)
except ToolExecutionException as e:
# Unexpected error during tool execution
- logger.error(f"Unexpected error running tool {tool.name}: {e}")
+ logger.error("Unexpected error running tool %s: %s", tool.name, e)
tool_response = ToolResponse(
rich_response=None,
llm_facing_response=GENERIC_TOOL_ERROR_MESSAGE.format(error=str(e)),
@@ -187,7 +187,7 @@ def _safe_run_single_tool(
)
except Exception as e:
# Unexpected error during tool execution
- logger.error(f"Unexpected error running tool {tool.name}: {e}")
+ logger.error("Unexpected error running tool %s: %s", tool.name, e)
tool_response = ToolResponse(
rich_response=None,
llm_facing_response=GENERIC_TOOL_ERROR_MESSAGE.format(error=str(e)),
@@ -293,7 +293,7 @@ def run_tool_calls(
filtered_tool_calls: list[ToolCallKickoff] = []
for tool_call in merged_tool_calls:
if tool_call.tool_name not in tools_by_name:
- logger.warning(f"Tool {tool_call.tool_name} not found in tools list")
+ logger.warning("Tool %s not found in tools list", tool_call.tool_name)
continue
filtered_tool_calls.append(tool_call)
diff --git a/backend/onyx/tracing/framework/_error_tracing.py b/backend/onyx/tracing/framework/_error_tracing.py
index 1dadadcc17..5bd90b0f2e 100644
--- a/backend/onyx/tracing/framework/_error_tracing.py
+++ b/backend/onyx/tracing/framework/_error_tracing.py
@@ -18,4 +18,4 @@ def attach_error_to_current_span(error: SpanError) -> None:
if span:
attach_error_to_span(span, error)
else:
- logger.warning(f"No span to add error {error} to")
+ logger.warning("No span to add error %s to", error)
diff --git a/backend/onyx/tracing/framework/provider.py b/backend/onyx/tracing/framework/provider.py
index 8b7c6f50d8..eb4a5e09c2 100644
--- a/backend/onyx/tracing/framework/provider.py
+++ b/backend/onyx/tracing/framework/provider.py
@@ -56,7 +56,9 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
processor.on_trace_start(trace)
except Exception as e:
logger.error(
- f"Error in trace processor {processor} during on_trace_start: {e}"
+ "Error in trace processor %s during on_trace_start: %s",
+ processor,
+ e,
)
def on_trace_end(self, trace: Trace) -> None:
@@ -68,7 +70,7 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
processor.on_trace_end(trace)
except Exception as e:
logger.error(
- f"Error in trace processor {processor} during on_trace_end: {e}"
+ "Error in trace processor %s during on_trace_end: %s", processor, e
)
def on_span_start(self, span: Span[Any]) -> None:
@@ -80,7 +82,7 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
processor.on_span_start(span)
except Exception as e:
logger.error(
- f"Error in trace processor {processor} during on_span_start: {e}"
+ "Error in trace processor %s during on_span_start: %s", processor, e
)
def on_span_end(self, span: Span[Any]) -> None:
@@ -92,7 +94,7 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
processor.on_span_end(span)
except Exception as e:
logger.error(
- f"Error in trace processor {processor} during on_span_end: {e}"
+ "Error in trace processor %s during on_span_end: %s", processor, e
)
def shutdown(self) -> None:
@@ -100,11 +102,11 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
Called when the application stops.
"""
for processor in self._processors:
- logger.debug(f"Shutting down trace processor {processor}")
+ logger.debug("Shutting down trace processor %s", processor)
try:
processor.shutdown()
except Exception as e:
- logger.error(f"Error shutting down trace processor {processor}: {e}")
+ logger.error("Error shutting down trace processor %s: %s", processor, e)
def force_flush(self) -> None:
"""
@@ -114,7 +116,7 @@ class SynchronousMultiTracingProcessor(TracingProcessor):
try:
processor.force_flush()
except Exception as e:
- logger.error(f"Error flushing trace processor {processor}: {e}")
+ logger.error("Error flushing trace processor %s: %s", processor, e)
class TraceProvider(ABC):
@@ -234,12 +236,12 @@ class DefaultTraceProvider(TraceProvider):
Create a new trace.
"""
if disabled:
- logger.debug(f"Tracing is disabled. Not creating trace {name}")
+ logger.debug("Tracing is disabled. Not creating trace %s", name)
return NoOpTrace()
trace_id = trace_id or self.gen_trace_id()
- logger.debug(f"Creating trace {name} with id {trace_id}")
+ logger.debug("Creating trace %s with id %s", name, trace_id)
return TraceImpl(
name=name,
@@ -260,7 +262,7 @@ class DefaultTraceProvider(TraceProvider):
Create a new span.
"""
if disabled:
- logger.debug(f"Tracing is disabled. Not creating span {span_data}")
+ logger.debug("Tracing is disabled. Not creating span %s", span_data)
return NoOpSpan(span_data)
trace_id: str
@@ -280,7 +282,9 @@ class DefaultTraceProvider(TraceProvider):
current_span, NoOpSpan
):
logger.debug(
- f"Parent {current_span} or {current_trace} is no-op, returning NoOpSpan"
+ "Parent %s or %s is no-op, returning NoOpSpan",
+ current_span,
+ current_trace,
)
return NoOpSpan(span_data)
@@ -289,13 +293,13 @@ class DefaultTraceProvider(TraceProvider):
elif isinstance(parent, Trace):
if isinstance(parent, NoOpTrace):
- logger.debug(f"Parent {parent} is no-op, returning NoOpSpan")
+ logger.debug("Parent %s is no-op, returning NoOpSpan", parent)
return NoOpSpan(span_data)
trace_id = parent.trace_id
parent_id = None
elif isinstance(parent, Span):
if isinstance(parent, NoOpSpan):
- logger.debug(f"Parent {parent} is no-op, returning NoOpSpan")
+ logger.debug("Parent %s is no-op, returning NoOpSpan", parent)
return NoOpSpan(span_data)
parent_id = parent.span_id
trace_id = parent.trace_id
@@ -316,4 +320,4 @@ class DefaultTraceProvider(TraceProvider):
logger.debug("Shutting down trace provider")
self._multi_processor.shutdown()
except Exception as e:
- logger.error(f"Error shutting down trace provider: {e}")
+ logger.error("Error shutting down trace provider: %s", e)
diff --git a/backend/onyx/tracing/langfuse_tracing_processor.py b/backend/onyx/tracing/langfuse_tracing_processor.py
index 52629c4e1b..d62718df9e 100644
--- a/backend/onyx/tracing/langfuse_tracing_processor.py
+++ b/backend/onyx/tracing/langfuse_tracing_processor.py
@@ -81,7 +81,7 @@ class LangfuseTracingProcessor(TracingProcessor):
return mask_sensitive_data(data)
except Exception as e:
- logger.warning(f"Failed to mask data: {e}")
+ logger.warning("Failed to mask data: %s", e)
return data
def _calculate_cost(self, data: GenerationSpanData) -> Optional[float]:
@@ -105,7 +105,7 @@ class LangfuseTracingProcessor(TracingProcessor):
# Convert cents to dollars for Langfuse
return cost_cents / 100.0
except Exception as e:
- logger.debug(f"Failed to calculate cost: {e}")
+ logger.debug("Failed to calculate cost: %s", e)
return None
def on_trace_start(self, trace: Trace) -> None:
@@ -140,7 +140,7 @@ class LangfuseTracingProcessor(TracingProcessor):
# Use trace_id as key for root span's ID (children with no parent_id will use this)
self._langfuse_span_ids[trace.trace_id] = langfuse_span.id
except Exception as e:
- logger.error(f"Error starting Langfuse trace: {e}")
+ logger.error("Error starting Langfuse trace: %s", e)
def on_trace_end(self, trace: Trace) -> None:
"""Called when a trace is finished."""
@@ -163,7 +163,7 @@ class LangfuseTracingProcessor(TracingProcessor):
)
langfuse_span.end()
except Exception as e:
- logger.error(f"Error ending Langfuse trace: {e}")
+ logger.error("Error ending Langfuse trace: %s", e)
def on_span_start(self, span: Span[SpanData]) -> None:
"""Called when a span is started.
@@ -192,7 +192,8 @@ class LangfuseTracingProcessor(TracingProcessor):
# If no trace ID found, we can't create a properly linked span
if langfuse_trace_id is None:
logger.warning(
- f"No Langfuse trace ID found for span {span.span_id}, creating orphan"
+ "No Langfuse trace ID found for span %s, creating orphan",
+ span.span_id,
)
# Fall back to creating an orphan span
# In Langfuse SDK v3, use start_observation instead of start_span
@@ -265,7 +266,7 @@ class LangfuseTracingProcessor(TracingProcessor):
# Store Langfuse span ID for future children to reference
self._langfuse_span_ids[span.span_id] = langfuse_span.id
except Exception as e:
- logger.error(f"Error starting Langfuse span: {e}")
+ logger.error("Error starting Langfuse span: %s", e)
def on_span_end(self, span: Span[SpanData]) -> None:
"""Called when a span is finished."""
@@ -335,7 +336,7 @@ class LangfuseTracingProcessor(TracingProcessor):
self._last_output[trace_id] = output_data
except Exception as e:
- logger.error(f"Error ending Langfuse span: {e}")
+ logger.error("Error ending Langfuse span: %s", e)
def _get_generation_name(self, data: GenerationSpanData) -> str:
"""Get a descriptive name for a generation span."""
@@ -397,7 +398,7 @@ class LangfuseTracingProcessor(TracingProcessor):
if client:
client.flush()
except Exception as e:
- logger.warning(f"Failed to flush Langfuse client: {e}")
+ logger.warning("Failed to flush Langfuse client: %s", e)
def shutdown(self) -> None:
"""Called when the application stops."""
@@ -407,4 +408,4 @@ class LangfuseTracingProcessor(TracingProcessor):
if client:
client.shutdown()
except Exception as e:
- logger.warning(f"Failed to shutdown Langfuse client: {e}")
+ logger.warning("Failed to shutdown Langfuse client: %s", e)
diff --git a/backend/onyx/tracing/setup.py b/backend/onyx/tracing/setup.py
index 6c87329956..3194fcd2a7 100644
--- a/backend/onyx/tracing/setup.py
+++ b/backend/onyx/tracing/setup.py
@@ -35,7 +35,7 @@ def setup_tracing() -> list[str]:
_setup_braintrust()
initialized_providers.append("braintrust")
except Exception as e:
- logger.error(f"Failed to initialize Braintrust tracing: {e}")
+ logger.error("Failed to initialize Braintrust tracing: %s", e)
else:
logger.info("Braintrust API key not provided, skipping Braintrust setup")
@@ -45,7 +45,7 @@ def setup_tracing() -> list[str]:
_setup_langfuse()
initialized_providers.append("langfuse")
except Exception as e:
- logger.error(f"Failed to initialize Langfuse tracing: {e}")
+ logger.error("Failed to initialize Langfuse tracing: %s", e)
else:
logger.info("Langfuse credentials not provided, skipping Langfuse setup")
@@ -53,7 +53,7 @@ def setup_tracing() -> list[str]:
if initialized_providers:
logger.notice(
- f"Tracing initialized with providers: {', '.join(initialized_providers)}"
+ "Tracing initialized with providers: %s", ", ".join(initialized_providers)
)
else:
logger.info("No tracing providers configured")
diff --git a/backend/onyx/utils/error_handling.py b/backend/onyx/utils/error_handling.py
index 87bba28c56..0c9753eeac 100644
--- a/backend/onyx/utils/error_handling.py
+++ b/backend/onyx/utils/error_handling.py
@@ -19,6 +19,6 @@ def handle_connector_error(e: Exception, context: str) -> None:
Raises:
The original exception if CONTINUE_ON_CONNECTOR_FAILURE is False
"""
- logger.error(f"Error in {context}: {e}", exc_info=e)
+ logger.error("Error in %s: %s", context, e, exc_info=e)
if not CONTINUE_ON_CONNECTOR_FAILURE:
raise
diff --git a/backend/onyx/utils/file.py b/backend/onyx/utils/file.py
index f620770630..6ad06def14 100644
--- a/backend/onyx/utils/file.py
+++ b/backend/onyx/utils/file.py
@@ -27,10 +27,10 @@ class OnyxStaticFileManager:
if matches:
mime_type = cast(str, matches[0].mime_type)
except (OSError, FileNotFoundError, PermissionError) as e:
- logger.error(f"Failed to read file {filename}: {e}")
+ logger.error("Failed to read file %s: %s", filename, e)
return None
except Exception as e:
- logger.error(f"Unexpected exception reading file {filename}: {e}")
+ logger.error("Unexpected exception reading file %s: %s", filename, e)
return None
return FileWithMimeType(data=file_content, mime_type=mime_type)
diff --git a/backend/onyx/utils/gpu_utils.py b/backend/onyx/utils/gpu_utils.py
index 10f42b5168..080d493ffc 100644
--- a/backend/onyx/utils/gpu_utils.py
+++ b/backend/onyx/utils/gpu_utils.py
@@ -31,7 +31,7 @@ def _get_gpu_status_from_model_server(indexing: bool) -> bool:
gpu_status = response.json()
return gpu_status["gpu_available"]
except requests.RequestException as e:
- logger.error(f"Error: Unable to fetch GPU status. Error: {str(e)}")
+ logger.error("Error: Unable to fetch GPU status. Error: %s", str(e))
raise # Re-raise exception to trigger a retry
diff --git a/backend/onyx/utils/headers.py b/backend/onyx/utils/headers.py
index 3e939daef8..3da83a12ff 100644
--- a/backend/onyx/utils/headers.py
+++ b/backend/onyx/utils/headers.py
@@ -22,7 +22,7 @@ def clean_header_list(headers_to_clean: list[HeaderItemDict]) -> dict[str, str]:
value = item["value"]
if key in cleaned_headers:
logger.warning(
- f"Duplicate header {key} found in custom headers, ignoring..."
+ "Duplicate header %s found in custom headers, ignoring...", key
)
continue
cleaned_headers[key] = value
diff --git a/backend/onyx/utils/long_term_log.py b/backend/onyx/utils/long_term_log.py
index c7d0435ea1..8b71c606c6 100644
--- a/backend/onyx/utils/long_term_log.py
+++ b/backend/onyx/utils/long_term_log.py
@@ -45,7 +45,7 @@ class LongTermLogger:
# Delete oldest files that exceed the limit
for file in files[self.max_files_per_category :]:
if not file.is_file():
- logger.debug(f"File already deleted: {file}")
+ logger.debug("File already deleted: %s", file)
continue
try:
file.unlink()
diff --git a/backend/onyx/utils/sitemap.py b/backend/onyx/utils/sitemap.py
index 38a11c4a96..435267bd9f 100644
--- a/backend/onyx/utils/sitemap.py
+++ b/backend/onyx/utils/sitemap.py
@@ -22,7 +22,7 @@ def _get_sitemap_locations_from_robots(base_url: str) -> Set[str]:
sitemap_url = line.split(":", 1)[1].strip()
sitemap_urls.add(sitemap_url)
except Exception as e:
- logger.warning(f"Error fetching robots.txt: {e}")
+ logger.warning("Error fetching robots.txt: %s", e)
return sitemap_urls
@@ -54,7 +54,7 @@ def _extract_urls_from_sitemap(sitemap_url: str) -> Set[str]:
urls.add(url.text)
except Exception as e:
- logger.warning(f"Error processing sitemap {sitemap_url}: {e}")
+ logger.warning("Error processing sitemap %s: %s", sitemap_url, e)
return urls
diff --git a/backend/onyx/utils/supervisord_watchdog.py b/backend/onyx/utils/supervisord_watchdog.py
index a9538de5a7..e1a4052bca 100644
--- a/backend/onyx/utils/supervisord_watchdog.py
+++ b/backend/onyx/utils/supervisord_watchdog.py
@@ -21,7 +21,7 @@ def main(key: str, program: str, conf: str) -> None:
consecutive number of times and the last successful lookup is more
than a threshold time, the specified program will be restarted.
"""
- logger.info(f"supervisord_watchdog starting: program={program} conf={conf}")
+ logger.info("supervisord_watchdog starting: program=%s conf=%s", program, conf)
r = get_redis_client()
@@ -39,13 +39,13 @@ def main(key: str, program: str, conf: str) -> None:
heartbeat = r.exists(key)
except Exception:
logger.exception(
- f"Exception checking for celery beat heartbeat: key={key}."
+ "Exception checking for celery beat heartbeat: key=%s.", key
)
continue
# happy path ... just continue
if heartbeat:
- logger.debug(f"Key lookup succeeded: key={key}")
+ logger.debug("Key lookup succeeded: key=%s", key)
last_heartbeat = time.monotonic()
num_lookup_failures = 0
continue
@@ -54,9 +54,10 @@ def main(key: str, program: str, conf: str) -> None:
num_lookup_failures += 1
if num_lookup_failures <= MAX_LOOKUP_FAILURES:
logger.warning(
- f"Key lookup failed: key={key} "
- f"lookup_failures={num_lookup_failures} "
- f"max_lookup_failures={MAX_LOOKUP_FAILURES}"
+ "Key lookup failed: key=%s lookup_failures=%s max_lookup_failures=%s",
+ key,
+ num_lookup_failures,
+ MAX_LOOKUP_FAILURES,
)
continue
@@ -64,22 +65,24 @@ def main(key: str, program: str, conf: str) -> None:
elapsed = now - last_heartbeat
if elapsed <= MAX_AGE_SECONDS:
logger.warning(
- f"Key lookup failed: key={key} "
- f"lookup_failures={num_lookup_failures} "
- f"max_lookup_failures={MAX_LOOKUP_FAILURES} "
- f"elapsed={elapsed:.2f} "
- f"elapsed_threshold={MAX_AGE_SECONDS}"
+ "Key lookup failed: key=%s lookup_failures=%s max_lookup_failures=%s elapsed=%s elapsed_threshold=%s",
+ key,
+ num_lookup_failures,
+ MAX_LOOKUP_FAILURES,
+ format(elapsed, ".2f"),
+ MAX_AGE_SECONDS,
)
continue
# all conditions have been exceeded ... restart the process
logger.warning(
- f"Key lookup failure thresholds exceeded - restarting {program}: "
- f"key={key} "
- f"lookup_failures={num_lookup_failures} "
- f"max_lookup_failures={MAX_LOOKUP_FAILURES} "
- f"elapsed={elapsed:.2f} "
- f"elapsed_threshold={MAX_AGE_SECONDS}"
+ "Key lookup failure thresholds exceeded - restarting %s: key=%s lookup_failures=%s max_lookup_failures=%s elapsed=%s elapsed_threshold=%s",
+ program,
+ key,
+ num_lookup_failures,
+ MAX_LOOKUP_FAILURES,
+ format(elapsed, ".2f"),
+ MAX_AGE_SECONDS,
)
subprocess.call(["supervisorctl", "-c", conf, "restart", program])
diff --git a/backend/onyx/utils/telemetry.py b/backend/onyx/utils/telemetry.py
index 337bc9f6a1..7731dff6b1 100644
--- a/backend/onyx/utils/telemetry.py
+++ b/backend/onyx/utils/telemetry.py
@@ -162,7 +162,9 @@ def mt_cloud_telemetry(
all_properties = {**properties} if properties else {}
if properties and "tenant_id" in properties:
logger.warning(
- f"tenant_id already in properties: {properties}. Overwriting with new value {tenant_id}."
+ "tenant_id already in properties: %s. Overwriting with new value %s.",
+ properties,
+ tenant_id,
)
all_properties["tenant_id"] = tenant_id
diff --git a/backend/onyx/utils/threadpool_concurrency.py b/backend/onyx/utils/threadpool_concurrency.py
index 745189a340..7c72a97967 100644
--- a/backend/onyx/utils/threadpool_concurrency.py
+++ b/backend/onyx/utils/threadpool_concurrency.py
@@ -347,7 +347,7 @@ def run_functions_tuples_in_parallel(
try:
results.append((index, future.result()))
except Exception as e:
- logger.exception(f"Function at index {index} failed due to {e}")
+ logger.exception("Function at index %s failed due to %s", index, e)
results.append((index, None))
if not allow_failures:
raise
@@ -357,7 +357,7 @@ def run_functions_tuples_in_parallel(
index = future_to_index[future]
func, args = functions_with_args[index]
logger.warning(
- f"Function at index {index} timed out after {timeout} seconds"
+ "Function at index %s timed out after %s seconds", index, timeout
)
if timeout_callback:
@@ -378,7 +378,7 @@ def run_functions_tuples_in_parallel(
try:
results.append((index, future.result()))
except Exception as e:
- logger.exception(f"Function at index {index} failed due to {e}")
+ logger.exception("Function at index %s failed due to %s", index, e)
results.append((index, None))
if not allow_failures:
@@ -437,7 +437,7 @@ def run_functions_in_parallel(
try:
results[result_id] = future.result()
except Exception as e:
- logger.exception(f"Function with ID {result_id} failed due to {e}")
+ logger.exception("Function with ID %s failed due to %s", result_id, e)
results[result_id] = None
if not allow_failures:
diff --git a/backend/onyx/utils/timing.py b/backend/onyx/utils/timing.py
index 9a49dabc0c..fe32eb081a 100644
--- a/backend/onyx/utils/timing.py
+++ b/backend/onyx/utils/timing.py
@@ -106,7 +106,7 @@ def log_generator_function_time(
finally:
elapsed_time_str = f"{time.monotonic() - start_time:.3f}"
log_name = func_name or func.__name__
- logger.info(f"{log_name} took {elapsed_time_str} seconds")
+ logger.info("%s took %s seconds", log_name, elapsed_time_str)
if not print_only:
optional_telemetry(
record_type=RecordType.LATENCY,
diff --git a/backend/onyx/utils/url.py b/backend/onyx/utils/url.py
index 74ff3f1842..fd68cd2bd9 100644
--- a/backend/onyx/utils/url.py
+++ b/backend/onyx/utils/url.py
@@ -116,7 +116,7 @@ def _validate_and_resolve_url(url: str) -> tuple[str, str, int]:
try:
addr_info = socket.getaddrinfo(hostname, port)
except socket.gaierror as e:
- logger.warning(f"DNS resolution failed for hostname '{hostname}': {e}")
+ logger.warning("DNS resolution failed for hostname '%s': %s", hostname, e)
raise SSRFException(f"Could not resolve hostname '{hostname}': {e}")
if not addr_info:
diff --git a/backend/onyx/utils/variable_functionality.py b/backend/onyx/utils/variable_functionality.py
index f67210b363..2bb4a14977 100644
--- a/backend/onyx/utils/variable_functionality.py
+++ b/backend/onyx/utils/variable_functionality.py
@@ -192,7 +192,9 @@ def fetch_ee_implementation_or_noop(
try:
return fetch_versioned_implementation(module, attribute)
except Exception as e:
- logger.error(f"Failed to fetch implementation for {module}.{attribute}: {e}")
+ logger.error(
+ "Failed to fetch implementation for %s.%s: %s", module, attribute, e
+ )
raise
diff --git a/backend/onyx/voice/providers/elevenlabs.py b/backend/onyx/voice/providers/elevenlabs.py
index e3918404f4..962b40afc4 100644
--- a/backend/onyx/voice/providers/elevenlabs.py
+++ b/backend/onyx/voice/providers/elevenlabs.py
@@ -110,7 +110,7 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
self._logger = setup_logger()
self._logger.info(
- f"ElevenLabsStreamingTranscriber: initializing with model {model}"
+ "ElevenLabsStreamingTranscriber: initializing with model %s", model
)
self.api_key = api_key
self.model = model
@@ -149,8 +149,11 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
f"&min_silence_duration_ms={DEFAULT_MIN_SILENCE_DURATION_MS}"
)
self._logger.info(
- f"ElevenLabsStreamingTranscriber: connecting to {url} "
- f"(input={self.input_sample_rate}Hz, target={self.target_sample_rate}Hz)"
+ "ElevenLabsStreamingTranscriber: connecting to %s "
+ "(input=%sHz, target=%sHz)",
+ url,
+ self.input_sample_rate,
+ self.target_sample_rate,
)
try:
@@ -159,12 +162,14 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
headers={"xi-api-key": self.api_key},
)
self._logger.info(
- f"ElevenLabsStreamingTranscriber: connected successfully, "
- f"ws.closed={self._ws.closed}, close_code={self._ws.close_code}"
+ "ElevenLabsStreamingTranscriber: connected successfully, "
+ "ws.closed=%s, close_code=%s",
+ self._ws.closed,
+ self._ws.close_code,
)
except Exception as e:
self._logger.error(
- f"ElevenLabsStreamingTranscriber: failed to connect: {e}"
+ "ElevenLabsStreamingTranscriber: failed to connect: %s", e
)
if self._session:
await self._session.close()
@@ -185,7 +190,7 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
try:
async for msg in self._ws:
self._logger.debug(
- f"ElevenLabsStreamingTranscriber: raw message type: {msg.type}"
+ "ElevenLabsStreamingTranscriber: raw message type: %s", msg.type
)
if msg.type == aiohttp.WSMsgType.TEXT:
parsed_data: Any = None
@@ -194,7 +199,8 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
parsed_data = json.loads(msg.data)
except json.JSONDecodeError:
self._logger.error(
- f"ElevenLabsStreamingTranscriber: failed to parse JSON: {msg.data[:200]}"
+ "ElevenLabsStreamingTranscriber: failed to parse JSON: %s",
+ msg.data[:200],
)
continue
if not isinstance(parsed_data, dict):
@@ -207,18 +213,21 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
# ElevenLabs uses message_type field - fail fast if missing
if "message_type" not in data and "type" not in data:
self._logger.error(
- f"ElevenLabsStreamingTranscriber: malformed packet missing 'message_type' field: {data}"
+ "ElevenLabsStreamingTranscriber: malformed packet missing 'message_type' field: %s",
+ data,
)
continue
msg_type = data.get("message_type", data.get("type", ""))
self._logger.info(
- f"ElevenLabsStreamingTranscriber: received message_type: '{msg_type}', data keys: {list(data.keys())}"
+ "ElevenLabsStreamingTranscriber: received message_type: '%s', data keys: %s",
+ msg_type,
+ list(data.keys()),
)
# Check for error in various formats
if "error" in data or msg_type == ElevenLabsSTTMessageType.ERROR:
error_msg = data.get("error", data.get("message", data))
self._logger.error(
- f"ElevenLabsStreamingTranscriber: API error: {error_msg}"
+ "ElevenLabsStreamingTranscriber: API error: %s", error_msg
)
continue
@@ -226,15 +235,18 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
# See https://elevenlabs.io/docs/api-reference/speech-to-text/realtime
if msg_type == ElevenLabsSTTMessageType.SESSION_STARTED:
self._logger.info(
- f"ElevenLabsStreamingTranscriber: session started, "
- f"id={data.get('session_id')}, config={data.get('config')}"
+ "ElevenLabsStreamingTranscriber: session started, "
+ "id=%s, config=%s",
+ data.get("session_id"),
+ data.get("config"),
)
elif msg_type == ElevenLabsSTTMessageType.PARTIAL_TRANSCRIPT:
# Interim result — updated as more audio is processed
text = data.get("text", "")
if text:
self._logger.info(
- f"ElevenLabsStreamingTranscriber: partial_transcript: {text[:50]}..."
+ "ElevenLabsStreamingTranscriber: partial_transcript: %s...",
+ text[:50],
)
self._final_transcript = text
await self._transcript_queue.put(
@@ -245,7 +257,8 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
text = data.get("text", "")
if text:
self._logger.info(
- f"ElevenLabsStreamingTranscriber: committed_transcript: {text[:50]}..."
+ "ElevenLabsStreamingTranscriber: committed_transcript: %s...",
+ text[:50],
)
self._final_transcript = text
await self._transcript_queue.put(
@@ -256,7 +269,8 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
text = data.get("text", "") or self._final_transcript
if text:
self._logger.info(
- f"ElevenLabsStreamingTranscriber: utterance_end: {text[:50]}..."
+ "ElevenLabsStreamingTranscriber: utterance_end: %s...",
+ text[:50],
)
self._final_transcript = text
await self._transcript_queue.put(
@@ -270,37 +284,46 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
else:
# Log unhandled message types with full data for debugging
self._logger.warning(
- f"ElevenLabsStreamingTranscriber: unhandled message_type: {msg_type}, full data: {data}"
+ "ElevenLabsStreamingTranscriber: unhandled message_type: %s, full data: %s",
+ msg_type,
+ data,
)
elif msg.type == aiohttp.WSMsgType.BINARY:
self._logger.debug(
- f"ElevenLabsStreamingTranscriber: received binary message: {len(msg.data)} bytes"
+ "ElevenLabsStreamingTranscriber: received binary message: %s bytes",
+ len(msg.data),
)
elif msg.type == aiohttp.WSMsgType.CLOSED:
close_code = self._ws.close_code if self._ws else "N/A"
self._logger.info(
- f"ElevenLabsStreamingTranscriber: WebSocket closed by server, close_code={close_code}"
+ "ElevenLabsStreamingTranscriber: WebSocket closed by server, close_code=%s",
+ close_code,
)
break
elif msg.type == aiohttp.WSMsgType.ERROR:
self._logger.error(
- f"ElevenLabsStreamingTranscriber: WebSocket error: {self._ws.exception() if self._ws else 'N/A'}"
+ "ElevenLabsStreamingTranscriber: WebSocket error: %s",
+ self._ws.exception() if self._ws else "N/A",
)
break
elif msg.type == aiohttp.WSMsgType.CLOSE:
self._logger.info(
- f"ElevenLabsStreamingTranscriber: WebSocket CLOSE frame received, data={msg.data}, extra={msg.extra}"
+ "ElevenLabsStreamingTranscriber: WebSocket CLOSE frame received, data=%s, extra=%s",
+ msg.data,
+ msg.extra,
)
break
except Exception as e:
self._logger.error(
- f"ElevenLabsStreamingTranscriber: error in receive loop: {e}",
+ "ElevenLabsStreamingTranscriber: error in receive loop: %s",
+ e,
exc_info=True,
)
finally:
close_code = self._ws.close_code if self._ws else "N/A"
self._logger.info(
- f"ElevenLabsStreamingTranscriber: receive loop ended, close_code={close_code}"
+ "ElevenLabsStreamingTranscriber: receive loop ended, close_code=%s",
+ close_code,
)
await self._transcript_queue.put(None) # Signal end
@@ -343,7 +366,7 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
return
if self._ws.closed:
self._logger.warning(
- f"send_audio: WebSocket is closed, close_code={self._ws.close_code}"
+ "send_audio: WebSocket is closed, close_code=%s", self._ws.close_code
)
return
@@ -358,12 +381,15 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
"sample_rate": self.target_sample_rate,
}
self._logger.info(
- f"send_audio: {len(chunk)} bytes -> {len(resampled)} bytes (resampled) -> {len(audio_b64)} chars base64"
+ "send_audio: %s bytes -> %s bytes (resampled) -> %s chars base64",
+ len(chunk),
+ len(resampled),
+ len(audio_b64),
)
await self._ws.send_str(json.dumps(message))
self._logger.info("send_audio: message sent successfully")
except Exception as e:
- self._logger.error(f"send_audio: failed to send: {e}", exc_info=True)
+ self._logger.error("send_audio: failed to send: %s", e, exc_info=True)
raise
async def receive_transcript(self) -> TranscriptResult | None:
@@ -387,7 +413,7 @@ class ElevenLabsStreamingTranscriber(StreamingTranscriberProtocol):
)
await self._ws.close()
except Exception as e:
- self._logger.debug(f"Error closing WebSocket: {e}")
+ self._logger.debug("Error closing WebSocket: %s", e)
if self._receive_task and not self._receive_task.done():
self._receive_task.cancel()
try:
@@ -504,8 +530,11 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
# Check isFinal separately - a message can have both audio AND isFinal
if "isFinal" in data:
self._logger.info(
- f"ElevenLabsStreamingSynthesizer: received isFinal={data['isFinal']}, "
- f"chunks so far: {chunk_count}, bytes: {total_bytes}"
+ "ElevenLabsStreamingSynthesizer: received isFinal=%s, "
+ "chunks so far: %s, bytes: %s",
+ data["isFinal"],
+ chunk_count,
+ total_bytes,
)
if data.get("isFinal"):
self._logger.info(
@@ -516,7 +545,7 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
# Check for errors
if "error" in data or data.get("type") == "error":
self._logger.error(
- f"ElevenLabsStreamingSynthesizer: received error: {data}"
+ "ElevenLabsStreamingSynthesizer: received error: %s", data
)
elif msg.type == aiohttp.WSMsgType.BINARY:
chunk_count += 1
@@ -527,14 +556,17 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
aiohttp.WSMsgType.ERROR,
):
self._logger.info(
- f"ElevenLabsStreamingSynthesizer: WebSocket closed/error, type={msg.type}"
+ "ElevenLabsStreamingSynthesizer: WebSocket closed/error, type=%s",
+ msg.type,
)
break
except Exception as e:
- self._logger.error(f"ElevenLabsStreamingSynthesizer receive error: {e}")
+ self._logger.error("ElevenLabsStreamingSynthesizer receive error: %s", e)
finally:
self._logger.info(
- f"ElevenLabsStreamingSynthesizer: receive loop ended, {chunk_count} chunks, {total_bytes} bytes"
+ "ElevenLabsStreamingSynthesizer: receive loop ended, %s chunks, %s bytes",
+ chunk_count,
+ total_bytes,
)
await self._audio_queue.put(None) # Signal end of stream
@@ -550,7 +582,9 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
"""
if self._ws and not self._closed and text.strip():
self._logger.info(
- f"ElevenLabsStreamingSynthesizer: sending text ({len(text)} chars): '{text}'"
+ "ElevenLabsStreamingSynthesizer: sending text (%s chars): '%s'",
+ len(text),
+ text,
)
# Let ElevenLabs buffer and auto-generate based on chunk_length_schedule
# Don't trigger generation here - wait for flush() at the end
@@ -564,8 +598,11 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
self._logger.info("ElevenLabsStreamingSynthesizer: text sent successfully")
else:
self._logger.warning(
- f"ElevenLabsStreamingSynthesizer: skipping send_text - "
- f"ws={self._ws is not None}, closed={self._closed}, text='{text[:30] if text else ''}'"
+ "ElevenLabsStreamingSynthesizer: skipping send_text - "
+ "ws=%s, closed=%s, text='%s'",
+ self._ws is not None,
+ self._closed,
+ text[:30] if text else "",
)
async def receive_audio(self) -> bytes | None:
@@ -588,7 +625,9 @@ class ElevenLabsStreamingSynthesizer(StreamingSynthesizerProtocol):
self._logger.info("ElevenLabsStreamingSynthesizer: end-of-input sent")
else:
self._logger.warning(
- f"ElevenLabsStreamingSynthesizer: skipping flush - ws={self._ws is not None}, closed={self._closed}"
+ "ElevenLabsStreamingSynthesizer: skipping flush - ws=%s, closed=%s",
+ self._ws is not None,
+ self._closed,
)
async def close(self) -> None:
@@ -691,7 +730,9 @@ class ElevenLabsVoiceProvider(VoiceProviderInterface):
form_data.add_field("model_id", batch_model)
logger.info(
- f"ElevenLabs transcribe: sending {len(audio_data)} bytes, format={audio_format}"
+ "ElevenLabs transcribe: sending %s bytes, format=%s",
+ len(audio_data),
+ audio_format,
)
with traced_llm_call(
@@ -705,14 +746,14 @@ class ElevenLabsVoiceProvider(VoiceProviderInterface):
) as response:
if response.status != 200:
error_text = await response.text()
- logger.error(f"ElevenLabs transcribe failed: {error_text}")
+ logger.error("ElevenLabs transcribe failed: %s", error_text)
raise RuntimeError(
f"ElevenLabs transcription failed: {error_text}"
)
result = await response.json()
text = result.get("text", "")
- logger.info(f"ElevenLabs transcribe: got result: {text[:50]}...")
+ logger.info("ElevenLabs transcribe: got result: %s...", text[:50])
return text
async def synthesize_stream(
@@ -741,7 +782,11 @@ class ElevenLabsVoiceProvider(VoiceProviderInterface):
url = f"{self.api_base}/v1/text-to-speech/{voice_id}/stream"
logger.info(
- f"ElevenLabs TTS: starting synthesis, text='{text[:50]}...', voice={voice_id}, model={self.tts_model}, speed={speed}"
+ "ElevenLabs TTS: starting synthesis, text='%s...', voice=%s, model=%s, speed=%s",
+ text[:50],
+ voice_id,
+ self.tts_model,
+ speed,
)
headers = {
@@ -769,11 +814,13 @@ class ElevenLabsVoiceProvider(VoiceProviderInterface):
async with aiohttp.ClientSession() as session:
async with session.post(url, headers=headers, json=payload) as response:
logger.info(
- f"ElevenLabs TTS: got response status={response.status}, content-type={response.headers.get('content-type')}"
+ "ElevenLabs TTS: got response status=%s, content-type=%s",
+ response.status,
+ response.headers.get("content-type"),
)
if response.status != 200:
error_text = await response.text()
- logger.error(f"ElevenLabs TTS failed: {error_text}")
+ logger.error("ElevenLabs TTS failed: %s", error_text)
raise RuntimeError(f"ElevenLabs TTS failed: {error_text}")
# Use 8192 byte chunks for smoother streaming
@@ -785,7 +832,9 @@ class ElevenLabsVoiceProvider(VoiceProviderInterface):
total_bytes += len(chunk)
yield chunk
logger.info(
- f"ElevenLabs TTS: streaming complete, {chunk_count} chunks, {total_bytes} total bytes"
+ "ElevenLabs TTS: streaming complete, %s chunks, %s total bytes",
+ chunk_count,
+ total_bytes,
)
async def validate_credentials(self) -> None:
diff --git a/backend/onyx/voice/providers/openai.py b/backend/onyx/voice/providers/openai.py
index 214663df8a..6be02b2fee 100644
--- a/backend/onyx/voice/providers/openai.py
+++ b/backend/onyx/voice/providers/openai.py
@@ -73,7 +73,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
self._logger = setup_logger()
self._logger.info(
- f"OpenAIStreamingTranscriber: initializing with model {model}"
+ "OpenAIStreamingTranscriber: initializing with model %s", model
)
self.api_key = api_key
self.model = model
@@ -102,7 +102,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
self._ws = await self._session.ws_connect(url, headers=headers)
self._logger.info("Connected to OpenAI Realtime API")
except Exception as e:
- self._logger.error(f"Failed to connect to OpenAI Realtime API: {e}")
+ self._logger.error("Failed to connect to OpenAI Realtime API: %s", e)
raise
# Configure the session for transcription
@@ -123,7 +123,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
},
}
await self._ws.send_str(json.dumps(config_message))
- self._logger.info(f"Sent config for model: {self.model} with server VAD")
+ self._logger.info("Sent config for model: %s with server VAD", self.model)
# Start receiving transcripts
self._receive_task = asyncio.create_task(self._receive_loop())
@@ -138,12 +138,12 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
if msg.type == aiohttp.WSMsgType.TEXT:
data = json.loads(msg.data)
msg_type = data.get("type", "")
- self._logger.debug(f"Received message type: {msg_type}")
+ self._logger.debug("Received message type: %s", msg_type)
# Handle errors
if msg_type == OpenAIRealtimeMessageType.ERROR:
error = data.get("error", {})
- self._logger.error(f"OpenAI error: {error}")
+ self._logger.error("OpenAI error: %s", error)
continue
# Handle VAD events
@@ -165,7 +165,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
if msg_type == OpenAIRealtimeMessageType.TRANSCRIPTION_DELTA:
delta = data.get("delta", "")
if delta:
- self._logger.info(f"OpenAI: Transcription delta: {delta}")
+ self._logger.info("OpenAI: Transcription delta: %s", delta)
self._current_turn_transcript += delta
# Show accumulated + current turn transcript
full_transcript = self._accumulated_transcript
@@ -179,7 +179,8 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
transcript = data.get("transcript", "")
if transcript:
self._logger.info(
- f"OpenAI: Transcription completed (VAD turn end): {transcript[:50]}..."
+ "OpenAI: Transcription completed (VAD turn end): %s...",
+ transcript[:50],
)
# This is the final transcript for this VAD turn
self._current_turn_transcript = transcript
@@ -202,17 +203,17 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
):
# Log any other message types we might be missing
self._logger.info(
- f"OpenAI: Unhandled message type '{msg_type}': {data}"
+ "OpenAI: Unhandled message type '%s': %s", msg_type, data
)
elif msg.type == aiohttp.WSMsgType.ERROR:
- self._logger.error(f"WebSocket error: {self._ws.exception()}")
+ self._logger.error("WebSocket error: %s", self._ws.exception())
break
elif msg.type == aiohttp.WSMsgType.CLOSED:
self._logger.info("WebSocket closed by server")
break
except Exception as e:
- self._logger.error(f"Error in receive loop: {e}")
+ self._logger.error("Error in receive loop: %s", e)
finally:
await self._transcript_queue.put(None)
@@ -224,8 +225,10 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
# So chunk_bytes / 48000 = duration in seconds
duration_ms = (len(chunk) / 48000) * 1000
self._logger.debug(
- f"Sending {len(chunk)} bytes ({duration_ms:.1f}ms) of audio to OpenAI. "
- f"First 10 bytes: {chunk[:10].hex() if len(chunk) >= 10 else chunk.hex()}"
+ "Sending %s bytes (%sms) of audio to OpenAI. " "First 10 bytes: %s",
+ len(chunk),
+ format(duration_ms, ".1f"),
+ chunk[:10].hex() if len(chunk) >= 10 else chunk.hex(),
)
message = {
"type": "input_audio_buffer.append",
@@ -257,7 +260,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
json.dumps({"type": "input_audio_buffer.commit"})
)
except Exception as e:
- self._logger.debug(f"Error sending commit (may be expected): {e}")
+ self._logger.debug("Error sending commit (may be expected): %s", e)
# Wait for *new* transcription to arrive (up to 5 seconds)
self._logger.info("Waiting for transcription to complete...")
@@ -266,7 +269,7 @@ class OpenAIStreamingTranscriber(StreamingTranscriberProtocol):
await asyncio.sleep(0.1)
if self._accumulated_transcript != transcript_before_commit:
self._logger.info(
- f"Got final transcript: {self._accumulated_transcript[:50]}..."
+ "Got final transcript: %s...", self._accumulated_transcript[:50]
)
break
else:
@@ -387,7 +390,7 @@ class OpenAIStreamingSynthesizer(StreamingSynthesizerProtocol):
except asyncio.CancelledError:
break
except Exception as e:
- self._logger.error(f"Error processing text queue: {e}")
+ self._logger.error("Error processing text queue: %s", e)
async def _synthesize_text(self, text: str) -> None:
"""Make HTTP TTS request and stream audio to queue."""
@@ -413,7 +416,7 @@ class OpenAIStreamingSynthesizer(StreamingSynthesizerProtocol):
) as response:
if response.status != 200:
error_text = await response.text()
- self._logger.error(f"OpenAI TTS error: {error_text}")
+ self._logger.error("OpenAI TTS error: %s", error_text)
return
# Use 8192 byte chunks for smoother streaming
@@ -424,7 +427,7 @@ class OpenAIStreamingSynthesizer(StreamingSynthesizerProtocol):
if chunk:
await self._audio_queue.put(chunk)
except Exception as e:
- self._logger.error(f"OpenAIStreamingSynthesizer synthesis error: {e}")
+ self._logger.error("OpenAIStreamingSynthesizer synthesis error: %s", e)
async def send_text(self, text: str) -> None:
"""Queue text to be synthesized via HTTP streaming."""
diff --git a/backend/scripts/celery_purge_queue.py b/backend/scripts/celery_purge_queue.py
index 0cc13c521d..207ccb80c6 100644
--- a/backend/scripts/celery_purge_queue.py
+++ b/backend/scripts/celery_purge_queue.py
@@ -47,7 +47,7 @@ def celery_purge_queue(queue: str, tenant_id: str) -> None: # noqa: ARG001
length = celery_get_queue_length(queue, r)
- logger.info(f"queue={queue} length={length}")
+ logger.info("queue=%s length=%s", queue, length)
# processed = 0
# deleted = 0
diff --git a/backend/scripts/chat_feedback_dump.py b/backend/scripts/chat_feedback_dump.py
index 71a4ecba7c..87ad1f2117 100644
--- a/backend/scripts/chat_feedback_dump.py
+++ b/backend/scripts/chat_feedback_dump.py
@@ -190,13 +190,13 @@ def process_all_chat_feedback(onyx_url: str, api_key: str | None) -> None:
if not all_users:
raise RuntimeError("manage_users returned None")
- logger.info(f"Accepted users: {len(all_users.accepted)}")
+ logger.info("Accepted users: %s", len(all_users.accepted))
user_ids: list[UUID] = [user.id for user in all_users.accepted]
for user_id in user_ids:
r_sessions = get_chat_sessions(onyx_url, headers, user_id)
- logger.info(f"user={user_id} num_sessions={len(r_sessions.sessions)}")
+ logger.info("user=%s num_sessions=%s", user_id, len(r_sessions.sessions))
for session in r_sessions.sessions:
s: ChatSessionSnapshot
try:
@@ -206,11 +206,12 @@ def process_all_chat_feedback(onyx_url: str, api_key: str | None) -> None:
for m in s.messages: # ty: ignore[possibly-unresolved-reference]
logger.info(
- f"user={user_id} "
- f"session={session.id} "
- f"message={m.message} "
- f"feedback_type={m.feedback_type} "
- f"feedback_text={m.feedback_text}"
+ "user=%s session=%s message=%s feedback_type=%s feedback_text=%s",
+ user_id,
+ session.id,
+ m.message,
+ m.feedback_type,
+ m.feedback_text,
)
diff --git a/backend/scripts/chat_loadtest.py b/backend/scripts/chat_loadtest.py
index d669eef71f..25e29976e4 100644
--- a/backend/scripts/chat_loadtest.py
+++ b/backend/scripts/chat_loadtest.py
@@ -150,7 +150,7 @@ class ChatLoadTester:
parent_message_id = metrics.total_tokens # Simplified for example
except Exception as e:
- logger.error(f"Error in chat session: {e}")
+ logger.error("Error in chat session: %s", e)
async def run_load_test(self) -> None:
"""Run multiple concurrent chat sessions"""
@@ -164,10 +164,10 @@ class ChatLoadTester:
def print_results(self, total_time: float) -> None:
"""Print load test results and metrics"""
logger.info("\n=== Load Test Results ===")
- logger.info(f"Total Time: {total_time:.2f} seconds")
- logger.info(f"Concurrent Sessions: {self.num_concurrent}")
- logger.info(f"Messages per Session: {self.messages_per_session}")
- logger.info(f"Total Messages: {len(self.metrics)}")
+ logger.info("Total Time: %s seconds", format(total_time, ".2f"))
+ logger.info("Concurrent Sessions: %s", self.num_concurrent)
+ logger.info("Messages per Session: %s", self.messages_per_session)
+ logger.info("Total Messages: %s", len(self.metrics))
if self.metrics:
avg_response_time = statistics.mean(m.total_time for m in self.metrics)
@@ -179,10 +179,17 @@ class ChatLoadTester:
m.tokens_per_second for m in self.metrics
)
- logger.info(f"\nAverage Response Time: {avg_response_time:.2f} seconds")
- logger.info(f"Average Time to Documents: {avg_first_doc:.2f} seconds")
- logger.info(f"Average Time to First Answer: {avg_first_answer:.2f} seconds")
- logger.info(f"Average Tokens/Second: {avg_tokens_per_sec:.2f}")
+ logger.info(
+ "\nAverage Response Time: %s seconds", format(avg_response_time, ".2f")
+ )
+ logger.info(
+ "Average Time to Documents: %s seconds", format(avg_first_doc, ".2f")
+ )
+ logger.info(
+ "Average Time to First Answer: %s seconds",
+ format(avg_first_answer, ".2f"),
+ )
+ logger.info("Average Tokens/Second: %s", format(avg_tokens_per_sec, ".2f"))
def main() -> None:
diff --git a/backend/scripts/debugging/onyx_db.py b/backend/scripts/debugging/onyx_db.py
index 09158035a2..d34b32bccb 100644
--- a/backend/scripts/debugging/onyx_db.py
+++ b/backend/scripts/debugging/onyx_db.py
@@ -46,7 +46,7 @@ class SQLAlchemyDebugging:
tenant_ids = get_all_tenant_ids()
num_tenant_ids = len(tenant_ids)
- logger.info(f"Found {num_tenant_ids} tenant id's.")
+ logger.info("Found %s tenant id's.", num_tenant_ids)
num_processed = 0
for tenant_id in tenant_ids:
@@ -81,9 +81,14 @@ class SQLAlchemyDebugging:
total_chunks = total_chunks or 0
logger.info(
- f"{num_processed} of {num_tenant_ids}: Tenant '{tenant_id}': "
- f"first_email={first_email} user_count={user_count} "
- f"docs={total_documents} chunks={total_chunks}"
+ "%s of %s: Tenant '%s': first_email=%s user_count=%s docs=%s chunks=%s",
+ num_processed,
+ num_tenant_ids,
+ tenant_id,
+ first_email,
+ user_count,
+ total_documents,
+ total_chunks,
)
tenants_to_total_chunks[tenant_id] = TenantMetadata(
@@ -93,7 +98,7 @@ class SQLAlchemyDebugging:
num_chunks=total_chunks,
)
except Exception as e:
- logger.error(f"Error processing tenant '{tenant_id}': {e}")
+ logger.error("Error processing tenant '%s': %s", tenant_id, e)
finally:
CURRENT_TENANT_ID_CONTEXTVAR.reset(token)
@@ -120,14 +125,14 @@ class SQLAlchemyDebugging:
metadata.num_chunks,
]
)
- logger.info(f"Successfully wrote statistics to {filename}")
+ logger.info("Successfully wrote statistics to %s", filename)
# output top k by chunks
top_k_tenants = heapq.nlargest(
k, tenants_to_total_chunks.items(), key=lambda x: x[1].num_docs
)
- logger.info(f"Top {k} tenants by total chunks: {top_k_tenants}")
+ logger.info("Top %s tenants by total chunks: %s", k, top_k_tenants)
def main() -> None:
@@ -150,7 +155,7 @@ def main() -> None:
args = parser.parse_args()
- logger.info(f"{args}")
+ logger.info("%s", args)
connection_string = build_connection_string(
db_api=SYNC_DB_API,
diff --git a/backend/scripts/debugging/onyx_redis.py b/backend/scripts/debugging/onyx_redis.py
index 7135a2abc6..21824c39a8 100644
--- a/backend/scripts/debugging/onyx_redis.py
+++ b/backend/scripts/debugging/onyx_redis.py
@@ -126,7 +126,7 @@ def onyx_redis(
return 1
tenant_id = get_current_tenant_id()
- logger.info(f"Purging locks associated with deleting cc_pair={cc_pair_id}.")
+ logger.info("Purging locks associated with deleting cc_pair=%s.", cc_pair_id)
redis_connector = RedisConnector(tenant_id, cc_pair_id)
redis_delete_if_exists_helper(
@@ -181,12 +181,12 @@ def onyx_redis(
if user_email not in current_invited_users:
current_invited_users.append(user_email)
if dry_run:
- logger.info(f"(DRY-RUN) Would add {user_email} to invited users")
+ logger.info("(DRY-RUN) Would add %s to invited users", user_email)
else:
write_invited_users(current_invited_users)
- logger.info(f"Added {user_email} to invited users")
+ logger.info("Added %s to invited users", user_email)
else:
- logger.info(f"{user_email} is already in the invited users list")
+ logger.info("%s is already in the invited users list", user_email)
return 0
else:
pass
@@ -195,7 +195,7 @@ def onyx_redis(
def flush_batch_delete(batch_keys: list[bytes], r: Redis) -> None:
- logger.info(f"Flushing {len(batch_keys)} operations to Redis.")
+ logger.info("Flushing %s operations to Redis.", len(batch_keys))
with r.pipeline() as pipe:
for batch_key in batch_keys:
pipe.delete(batch_key)
@@ -209,13 +209,13 @@ def redis_delete_if_exists_helper(key: str, dry_run: bool, r: Redis) -> bool:
"""
if not r.exists(key):
- logger.info(f"Did not find {key}.")
+ logger.info("Did not find %s.", key)
return False
if dry_run:
- logger.info(f"(DRY-RUN) Deleting {key}.")
+ logger.info("(DRY-RUN) Deleting %s.", key)
else:
- logger.info(f"Deleting {key}.")
+ logger.info("Deleting %s.", key)
r.delete(key)
return True
@@ -229,7 +229,9 @@ def purge_by_match_and_type(
"""
logger.info(
- f"purge_by_match_and_type start: match_pattern={match_pattern} match_type={match_type}"
+ "purge_by_match_and_type start: match_pattern=%s match_type=%s",
+ match_pattern,
+ match_type,
)
# cursor = "0"
@@ -252,10 +254,10 @@ def purge_by_match_and_type(
count += 1
if dry_run:
- logger.info(f"(DRY-RUN) Deleting item {count}: {key_str}")
+ logger.info("(DRY-RUN) Deleting item %s: %s", count, key_str)
continue
- logger.info(f"Deleting item {count}: {key_str}")
+ logger.info("Deleting item %s: %s", count, key_str)
batch_keys.append(key)
@@ -268,10 +270,10 @@ def purge_by_match_and_type(
flush_batch_delete(batch_keys, r)
batch_keys.clear()
- logger.info(f"Deleted {count} matches.")
+ logger.info("Deleted %s matches.", count)
elapsed = time.monotonic() - start
- logger.info(f"Time elapsed: {elapsed:.2f}s")
+ logger.info("Time elapsed: %ss", format(elapsed, ".2f"))
return 0
@@ -311,9 +313,9 @@ def get_user_token_from_redis(r: Redis, user_email: str) -> str | None:
matching_key = key_str
break
except json.JSONDecodeError:
- logger.error(f"Failed to decode JSON for key: {key_str}")
+ logger.error("Failed to decode JSON for key: %s", key_str)
except Exception as e:
- logger.error(f"Error processing JWT for key: {key_str}. Error: {str(e)}")
+ logger.error("Error processing JWT for key: %s. Error: %s", key_str, str(e))
if matching_key:
return matching_key[len(REDIS_AUTH_KEY_PREFIX) :]
@@ -357,19 +359,19 @@ def delete_user_token_from_redis(
matching_key = key_str
break
except json.JSONDecodeError:
- logger.error(f"Failed to decode JSON for key: {key_str}")
+ logger.error("Failed to decode JSON for key: %s", key_str)
except Exception as e:
- logger.error(f"Error processing JWT for key: {key_str}. Error: {str(e)}")
+ logger.error("Error processing JWT for key: %s. Error: %s", key_str, str(e))
if matching_key:
if dry_run:
- logger.info(f"(DRY-RUN) Would delete token key: {matching_key}")
+ logger.info("(DRY-RUN) Would delete token key: %s", matching_key)
else:
r.delete(matching_key)
- logger.info(f"Deleted token for user: {user_email}")
+ logger.info("Deleted token for user: %s", user_email)
return True
else:
- logger.info(f"No token found for user: {user_email}")
+ logger.info("No token found for user: %s", user_email)
return False
diff --git a/backend/scripts/debugging/onyx_vespa_schemas.py b/backend/scripts/debugging/onyx_vespa_schemas.py
index bc765144f4..340a26f465 100644
--- a/backend/scripts/debugging/onyx_vespa_schemas.py
+++ b/backend/scripts/debugging/onyx_vespa_schemas.py
@@ -46,7 +46,7 @@ def write_schema(
with open(index_filename, "w", encoding="utf-8") as f:
f.write(schema)
- logger.info(f"Wrote {index_filename}")
+ logger.info("Wrote %s", index_filename)
def generate_document_entries() -> str:
@@ -85,7 +85,7 @@ def write_cloud_services(cloud_services_template_path: str, output_path: Path) -
with open(services_file, "w", encoding="utf-8") as f:
f.write(services_xml)
- logger.info(f"Wrote {services_file}")
+ logger.info("Wrote %s", services_file)
def main() -> None:
@@ -138,7 +138,7 @@ def main() -> None:
)
num_indexes += 2
- logger.info(f"Wrote {num_indexes} indexes.")
+ logger.info("Wrote %s indexes.", num_indexes)
# Generate cloud services configuration if template is provided
if args.cloud_services_template:
@@ -146,7 +146,7 @@ def main() -> None:
write_cloud_services(args.cloud_services_template, output_path)
else:
logger.error(
- f"Cloud services template not found: {args.cloud_services_template}"
+ "Cloud services template not found: %s", args.cloud_services_template
)
diff --git a/backend/scripts/debugging/opensearch/opensearch_debug.py b/backend/scripts/debugging/opensearch/opensearch_debug.py
index 30e83f4837..b7d148b769 100644
--- a/backend/scripts/debugging/opensearch/opensearch_debug.py
+++ b/backend/scripts/debugging/opensearch/opensearch_debug.py
@@ -18,6 +18,7 @@ Dependencies:
backend/shared_configs/configs.py
backend/onyx/document_index/opensearch/client.py
"""
+
import argparse
import json
import os
diff --git a/backend/scripts/force_delete_connector_by_id.py b/backend/scripts/force_delete_connector_by_id.py
index 23e54638df..0987115fd2 100755
--- a/backend/scripts/force_delete_connector_by_id.py
+++ b/backend/scripts/force_delete_connector_by_id.py
@@ -138,8 +138,10 @@ def _unsafe_deletion(
db_session.commit()
logger.notice(
- "Successfully deleted connector_credential_pair with connector_id:"
- f" '{connector_id}' and credential_id: '{credential_id}'. Deleted {num_docs_deleted} docs."
+ "Successfully deleted connector_credential_pair with connector_id: '%s' and credential_id: '%s'. Deleted %s docs.",
+ connector_id,
+ credential_id,
+ num_docs_deleted,
)
return num_docs_deleted
@@ -151,7 +153,7 @@ def _delete_connector(cc_pair_id: int, db_session: Session) -> None:
Are you SURE you want to continue? (enter 'Y' to continue): "
)
if user_input != "Y":
- logger.notice(f"You entered {user_input}. Exiting!")
+ logger.notice("You entered %s. Exiting!", user_input)
return
logger.notice("Getting connector credential pair")
@@ -161,13 +163,13 @@ def _delete_connector(cc_pair_id: int, db_session: Session) -> None:
)
if not cc_pair:
- logger.error(f"Connector credential pair with ID {cc_pair_id} not found")
+ logger.error("Connector credential pair with ID %s not found", cc_pair_id)
return
if cc_pair.status == ConnectorCredentialPairStatus.ACTIVE:
logger.error(
- f"Connector {cc_pair.connector.name} is active, cannot continue. \
- Please navigate to the connector and pause before attempting again"
+ "Connector %s is active, cannot continue. Please navigate to the connector and pause before attempting again",
+ cc_pair.connector.name,
)
return
@@ -176,8 +178,9 @@ def _delete_connector(cc_pair_id: int, db_session: Session) -> None:
if cc_pair is None:
logger.error(
- f"Connector with ID '{connector_id}' and credential ID "
- f"'{credential_id}' does not exist. Has it already been deleted?",
+ "Connector with ID '%s' and credential ID '%s' does not exist. Has it already been deleted?",
+ connector_id,
+ credential_id,
)
return
@@ -194,8 +197,9 @@ def _delete_connector(cc_pair_id: int, db_session: Session) -> None:
if not validated_cc_pair:
logger.error(
- f"Cannot run deletion attempt - connector_credential_pair with Connector ID: "
- f"{connector_id} and Credential ID: {credential_id} does not exist."
+ "Cannot run deletion attempt - connector_credential_pair with Connector ID: %s and Credential ID: %s does not exist.",
+ connector_id,
+ credential_id,
)
file_ids: list[str] = (
@@ -219,16 +223,16 @@ def _delete_connector(cc_pair_id: int, db_session: Session) -> None:
cc_pair=cc_pair,
pair_id=cc_pair_id,
)
- logger.notice(f"Deleted {files_deleted_count} files!")
+ logger.notice("Deleted %s files!", files_deleted_count)
except Exception as e:
- logger.error(f"Failed to delete connector due to {e}")
+ logger.error("Failed to delete connector due to %s", e)
if file_ids:
logger.notice("Deleting stored files!")
file_store = get_default_file_store()
for file_id in file_ids:
- logger.notice(f"Deleting file {file_id}")
+ logger.notice("Deleting file %s", file_id)
file_store.delete_file(file_id)
db_session.commit()
diff --git a/backend/scripts/reset_indexes.py b/backend/scripts/reset_indexes.py
index af01b02d6e..81694794b7 100644
--- a/backend/scripts/reset_indexes.py
+++ b/backend/scripts/reset_indexes.py
@@ -36,7 +36,7 @@ def wipe_vespa_index() -> bool:
response.raise_for_status()
response_json = response.json()
- logger.info(f"Response: {response_json}")
+ logger.info("Response: %s", response_json)
continuation = response_json.get("continuation")
should_continue = bool(continuation)
@@ -46,7 +46,7 @@ def wipe_vespa_index() -> bool:
logger.exception("Request failed")
sleep(2**attempt) # Exponential backoff
else:
- logger.error(f"Max retries ({RETRIES}) exceeded. Exiting.")
+ logger.error("Max retries (%s) exceeded. Exiting.", RETRIES)
return False
return True
diff --git a/backend/scripts/save_load_state.py b/backend/scripts/save_load_state.py
index ace45ab040..e3255408c1 100644
--- a/backend/scripts/save_load_state.py
+++ b/backend/scripts/save_load_state.py
@@ -40,7 +40,7 @@ def load_postgres(filename: str, container_name: str) -> None:
alembic_cfg = Config("alembic.ini")
command.upgrade(alembic_cfg, "head")
except Exception as e:
- logger.error(f"Alembic upgrade failed: {e}")
+ logger.error("Alembic upgrade failed: %s", e)
host_file_path = os.path.abspath(filename)
diff --git a/backend/tests/external_dependency_unit/file_store/test_file_store_non_mocked.py b/backend/tests/external_dependency_unit/file_store/test_file_store_non_mocked.py
index ef539c3fe3..d9ca248051 100644
--- a/backend/tests/external_dependency_unit/file_store/test_file_store_non_mocked.py
+++ b/backend/tests/external_dependency_unit/file_store/test_file_store_non_mocked.py
@@ -129,7 +129,9 @@ def file_store(
# Initialize the store and ensure bucket exists
store.initialize()
logger.info(
- f"Successfully initialized {backend_config['backend_name']} file store with bucket {TEST_BUCKET_NAME}"
+ "Successfully initialized %s file store with bucket %s",
+ backend_config["backend_name"],
+ TEST_BUCKET_NAME,
)
yield store
@@ -151,10 +153,12 @@ def file_store(
Delete={"Objects": objects_to_delete},
)
logger.info(
- f"Cleaned up {len(objects_to_delete)} test objects from {backend_config['backend_name']}"
+ "Cleaned up %s test objects from %s",
+ len(objects_to_delete),
+ backend_config["backend_name"],
)
except Exception as e:
- logger.warning(f"Failed to cleanup test objects: {e}")
+ logger.warning("Failed to cleanup test objects: %s", e)
class TestS3BackedFileStore:
diff --git a/backend/tests/integration/common_utils/document_acl.py b/backend/tests/integration/common_utils/document_acl.py
index 861d2de11c..6aca1b57ea 100644
--- a/backend/tests/integration/common_utils/document_acl.py
+++ b/backend/tests/integration/common_utils/document_acl.py
@@ -67,27 +67,29 @@ def get_user_document_access_via_acl(
# Get the actual User object from the database
user = fetch_user_by_id(db_session, UUID(test_user.id))
if not user:
- logger.error(f"Could not find user with ID {test_user.id}")
+ logger.error("Could not find user with ID %s", test_user.id)
return []
user_acl = get_user_acl(user, db_session)
- logger.info(f"User {user.email} ACL entries: {user_acl}")
+ logger.info("User %s ACL entries: %s", user.email, user_acl)
# Get document access information
doc_access_map = _get_access_for_documents(document_ids, db_session)
- logger.info(f"Found access info for {len(doc_access_map)} documents")
+ logger.info("Found access info for %s documents", len(doc_access_map))
accessible_docs = []
for doc_id, doc_access in doc_access_map.items():
doc_acl = doc_access.to_acl()
- logger.info(f"Document {doc_id} ACL: {doc_acl}")
+ logger.info("Document %s ACL: %s", doc_id, doc_acl)
# Check if user has any matching ACL entry
if user_acl.intersection(doc_acl):
accessible_docs.append(doc_id)
- logger.info(f"User {user.email} has access to document {doc_id}")
+ logger.info("User %s has access to document %s", user.email, doc_id)
else:
- logger.info(f"User {user.email} does NOT have access to document {doc_id}")
+ logger.info(
+ "User %s does NOT have access to document %s", user.email, doc_id
+ )
return accessible_docs
@@ -113,7 +115,7 @@ def get_all_connector_documents(
result = db_session.execute(stmt)
document_ids = [row[0] for row in result.fetchall()]
logger.info(
- f"Found {len(document_ids)} documents for connector {cc_pair.connector_id}"
+ "Found %s documents for connector %s", len(document_ids), cc_pair.connector_id
)
return document_ids
diff --git a/backend/tests/integration/common_utils/reset.py b/backend/tests/integration/common_utils/reset.py
index f294d012be..51ff106fce 100644
--- a/backend/tests/integration/common_utils/reset.py
+++ b/backend/tests/integration/common_utils/reset.py
@@ -162,7 +162,9 @@ def drop_multitenant_postgres(
TIMEOUT = 40
success = False
for _ in range(NUM_TRIES):
- logger.info(f"drop_multitenant_postgres_task starting... ({_ + 1}/{NUM_TRIES})")
+ logger.info(
+ "drop_multitenant_postgres_task starting... (%s/%s)", _ + 1, NUM_TRIES
+ )
try:
run_with_timeout_multiproc(
drop_multitenant_postgres_task,
@@ -175,11 +177,15 @@ def drop_multitenant_postgres(
break
except TimeoutError:
logger.warning(
- f"drop_multitenant_postgres_task timed out, retrying... ({_ + 1}/{NUM_TRIES})"
+ "drop_multitenant_postgres_task timed out, retrying... (%s/%s)",
+ _ + 1,
+ NUM_TRIES,
)
except RuntimeError:
logger.warning(
- f"drop_multitenant_postgres_task exceptioned, retrying... ({_ + 1}/{NUM_TRIES})"
+ "drop_multitenant_postgres_task exceptioned, retrying... (%s/%s)",
+ _ + 1,
+ NUM_TRIES,
)
if not success:
@@ -258,7 +264,7 @@ def reset_postgres(
TIMEOUT = 40
success = False
for _ in range(NUM_TRIES):
- logger.info(f"Downgrading Postgres... ({_ + 1}/{NUM_TRIES})")
+ logger.info("Downgrading Postgres... (%s/%s)", _ + 1, NUM_TRIES)
try:
run_with_timeout_multiproc(
downgrade_postgres,
@@ -274,11 +280,11 @@ def reset_postgres(
break
except TimeoutError:
logger.warning(
- f"Postgres downgrade timed out, retrying... ({_ + 1}/{NUM_TRIES})"
+ "Postgres downgrade timed out, retrying... (%s/%s)", _ + 1, NUM_TRIES
)
except RuntimeError:
logger.warning(
- f"Postgres downgrade exceptioned, retrying... ({_ + 1}/{NUM_TRIES})"
+ "Postgres downgrade exceptioned, retrying... (%s/%s)", _ + 1, NUM_TRIES
)
if not success:
diff --git a/backend/tests/integration/connector_job_tests/github/test_github_permission_sync.py b/backend/tests/integration/connector_job_tests/github/test_github_permission_sync.py
index 99ff973d62..7eb5042395 100644
--- a/backend/tests/integration/connector_job_tests/github/test_github_permission_sync.py
+++ b/backend/tests/integration/connector_job_tests/github/test_github_permission_sync.py
@@ -54,7 +54,7 @@ def test_github_private_repo_permission_sync(
pytest.fail(f"Failed to change repository {repo_owner}/{repo_name} to private")
# Add test-team to repository at the start
- logger.info(f"Adding test-team to repository {repo_owner}/{repo_name}")
+ logger.info("Adding test-team to repository %s/%s", repo_owner, repo_name)
team_added = github_manager.add_team_to_repository(
repo_owner=repo_owner,
repo_name=repo_name,
@@ -64,7 +64,7 @@ def test_github_private_repo_permission_sync(
if not team_added:
logger.warning(
- f"Failed to add test-team to repository {repo_owner}/{repo_name}"
+ "Failed to add test-team to repository %s/%s", repo_owner, repo_name
)
try:
@@ -104,10 +104,10 @@ def test_github_private_repo_permission_sync(
)
logger.info(
- f"test_user_1 has access to {len(accessible_docs_user1)} documents"
+ "test_user_1 has access to %s documents", len(accessible_docs_user1)
)
logger.info(
- f"test_user_2 has access to {len(accessible_docs_user2)} documents"
+ "test_user_2 has access to %s documents", len(accessible_docs_user2)
)
# test_user_1 (part of test-team) should have access
@@ -125,14 +125,16 @@ def test_github_private_repo_permission_sync(
finally:
# Remove test-team from repository at the end
- logger.info(f"Removing test-team from repository {repo_owner}/{repo_name}")
+ logger.info("Removing test-team from repository %s/%s", repo_owner, repo_name)
team_removed = github_manager.remove_team_from_repository(
repo_owner=repo_owner, repo_name=repo_name, team_slug="test-team"
)
if not team_removed:
logger.warning(
- f"Failed to remove test-team from repository {repo_owner}/{repo_name}"
+ "Failed to remove test-team from repository %s/%s",
+ repo_owner,
+ repo_name,
)
@@ -167,7 +169,7 @@ def test_github_public_repo_permission_sync(
repo_name = github_connector.connector_specific_config["repositories"]
# Change repository to public
- logger.info(f"Changing repository {repo_owner}/{repo_name} to public")
+ logger.info("Changing repository %s/%s to public", repo_owner, repo_name)
success = github_manager.change_repository_visibility(
repo_owner=repo_owner, repo_name=repo_name, visibility="public"
)
@@ -179,7 +181,9 @@ def test_github_public_repo_permission_sync(
current_visibility = github_manager.get_repository_visibility(
repo_owner=repo_owner, repo_name=repo_name
)
- logger.info(f"Repository {repo_owner}/{repo_name} visibility: {current_visibility}")
+ logger.info(
+ "Repository %s/%s visibility: %s", repo_owner, repo_name, current_visibility
+ )
assert (
current_visibility == "public"
), f"Repository should be public, but is {current_visibility}"
@@ -219,8 +223,12 @@ def test_github_public_repo_permission_sync(
db_session=db_session,
)
- logger.info(f"test_user_1 has access to {len(accessible_docs_user1)} documents")
- logger.info(f"test_user_2 has access to {len(accessible_docs_user2)} documents")
+ logger.info(
+ "test_user_1 has access to %s documents", len(accessible_docs_user1)
+ )
+ logger.info(
+ "test_user_2 has access to %s documents", len(accessible_docs_user2)
+ )
# Both users should have access to the public repository documents
assert len(accessible_docs_user1) > 0, (
@@ -273,7 +281,7 @@ def test_github_internal_repo_permission_sync(
repo_name = github_connector.connector_specific_config["repositories"]
# Change repository to internal
- logger.info(f"Changing repository {repo_owner}/{repo_name} to internal")
+ logger.info("Changing repository %s/%s to internal", repo_owner, repo_name)
success = github_manager.change_repository_visibility(
repo_owner=repo_owner, repo_name=repo_name, visibility="internal"
)
@@ -285,7 +293,9 @@ def test_github_internal_repo_permission_sync(
current_visibility = github_manager.get_repository_visibility(
repo_owner=repo_owner, repo_name=repo_name
)
- logger.info(f"Repository {repo_owner}/{repo_name} visibility: {current_visibility}")
+ logger.info(
+ "Repository %s/%s visibility: %s", repo_owner, repo_name, current_visibility
+ )
assert (
current_visibility == "internal"
), f"Repository should be internal, but is {current_visibility}"
@@ -325,8 +335,12 @@ def test_github_internal_repo_permission_sync(
db_session=db_session,
)
- logger.info(f"test_user_1 has access to {len(accessible_docs_user1)} documents")
- logger.info(f"test_user_2 has access to {len(accessible_docs_user2)} documents")
+ logger.info(
+ "test_user_1 has access to %s documents", len(accessible_docs_user1)
+ )
+ logger.info(
+ "test_user_2 has access to %s documents", len(accessible_docs_user2)
+ )
# For internal repositories:
# - test_user_1 should have access (assuming they're part of the organization)
diff --git a/backend/tests/integration/connector_job_tests/github/utils.py b/backend/tests/integration/connector_job_tests/github/utils.py
index bd675333ca..de4bcff28d 100644
--- a/backend/tests/integration/connector_job_tests/github/utils.py
+++ b/backend/tests/integration/connector_job_tests/github/utils.py
@@ -52,7 +52,7 @@ class GitHubManager:
# Check if we have admin permissions
if not repo.permissions.admin:
logger.error(
- f"No admin permissions for repository {repo_owner}/{repo_name}"
+ "No admin permissions for repository %s/%s", repo_owner, repo_name
)
return False
@@ -60,16 +60,19 @@ class GitHubManager:
try:
repo.edit(visibility=visibility)
except GithubException as e:
- logger.warning(f"Could not set repository to {visibility}: {e}")
+ logger.warning("Could not set repository to %s: %s", visibility, e)
return False
logger.info(
- f"Successfully changed {repo_owner}/{repo_name} visibility to {visibility}"
+ "Successfully changed %s/%s visibility to %s",
+ repo_owner,
+ repo_name,
+ visibility,
)
return True
except GithubException as e:
- logger.error(f"Failed to change repository visibility: {e}")
+ logger.error("Failed to change repository visibility: %s", e)
return False
def add_team_to_repository(
@@ -108,12 +111,16 @@ class GitHubManager:
team.set_repo_permission(repo, permission)
logger.info(
- f"Successfully added team {team_slug} to {repo_owner}/{repo_name} with {permission} permissions"
+ "Successfully added team %s to %s/%s with %s permissions",
+ team_slug,
+ repo_owner,
+ repo_name,
+ permission,
)
return True
except GithubException as e:
- logger.error(f"Failed to add team to repository: {e}")
+ logger.error("Failed to add team to repository: %s", e)
return False
def remove_team_from_repository(
@@ -142,12 +149,15 @@ class GitHubManager:
team.remove_from_repos(repo)
logger.info(
- f"Successfully removed team {team_slug} from {repo_owner}/{repo_name}"
+ "Successfully removed team %s from %s/%s",
+ team_slug,
+ repo_owner,
+ repo_name,
)
return True
except GithubException as e:
- logger.error(f"Failed to remove team from repository: {e}")
+ logger.error("Failed to remove team from repository: %s", e)
return False
def get_repository_visibility(
@@ -173,5 +183,5 @@ class GitHubManager:
return "private" if repo.private else "public"
except GithubException as e:
- logger.error(f"Failed to get repository visibility: {e}")
+ logger.error("Failed to get repository visibility: %s", e)
return None
diff --git a/backend/tests/integration/connector_job_tests/sharepoint/test_sharepoint_permissions.py b/backend/tests/integration/connector_job_tests/sharepoint/test_sharepoint_permissions.py
index 6478904599..00196cd88a 100644
--- a/backend/tests/integration/connector_job_tests/sharepoint/test_sharepoint_permissions.py
+++ b/backend/tests/integration/connector_job_tests/sharepoint/test_sharepoint_permissions.py
@@ -49,8 +49,8 @@ def test_public_documents_accessible_by_all_users(
db_session=db_session,
)
- logger.info(f"User 1 has access to {len(accessible_docs_user1)} documents")
- logger.info(f"User 2 has access to {len(accessible_docs_user2)} documents")
+ logger.info("User 1 has access to %s documents", len(accessible_docs_user1))
+ logger.info("User 2 has access to %s documents", len(accessible_docs_user2))
# For public documents, both users should have access to at least some docs
assert len(accessible_docs_user1) == 8, (
@@ -106,8 +106,8 @@ def test_group_based_permissions(
db_session=db_session,
)
- logger.info(f"User 1 has access to {len(accessible_docs_user1)} documents")
- logger.info(f"User 2 has access to {len(accessible_docs_user2)} documents")
+ logger.info("User 1 has access to %s documents", len(accessible_docs_user1))
+ logger.info("User 2 has access to %s documents", len(accessible_docs_user2))
public_docs = get_documents_by_permission_type(all_document_ids, db_session)
diff --git a/backend/tests/unit/onyx/auth/test_verify_auth_setting.py b/backend/tests/unit/onyx/auth/test_verify_auth_setting.py
index a5eaead6da..25082eed82 100644
--- a/backend/tests/unit/onyx/auth/test_verify_auth_setting.py
+++ b/backend/tests/unit/onyx/auth/test_verify_auth_setting.py
@@ -51,4 +51,4 @@ def test_verify_auth_setting_valid_auth_types(
verify_auth_setting()
mock_logger.warning.assert_not_called()
- mock_logger.notice.assert_called_once_with(f"Using Auth Type: {auth_type.value}")
+ mock_logger.notice.assert_called_once_with("Using Auth Type: %s", auth_type.value)
diff --git a/backend/tests/unit/onyx/connectors/salesforce/test_salesforce_sqlite.py b/backend/tests/unit/onyx/connectors/salesforce/test_salesforce_sqlite.py
index cbde6bdb31..cc5534e619 100644
--- a/backend/tests/unit/onyx/connectors/salesforce/test_salesforce_sqlite.py
+++ b/backend/tests/unit/onyx/connectors/salesforce/test_salesforce_sqlite.py
@@ -863,22 +863,27 @@ def test_salesforce_bulk_retrieve() -> None:
# Count data rows
num_data_rows = sum(1 for _ in reader)
logger.info(
- f"Counted {num_data_rows} data rows in {filename}"
+ "Counted %s data rows in %s", num_data_rows, filename
)
total_data_rows += num_data_rows
except StopIteration:
# Handle empty file or file with only header
logger.info(
- f"File {filename} is empty or contains only a header."
+ "File %s is empty or contains only a header.", filename
)
except Exception as e:
- logger.error(f"Error reading or counting rows in {filename}: {e}")
+ logger.error(
+ "Error reading or counting rows in %s: %s", filename, e
+ )
logger.info(
- f"Found {len(csv_files_found)} CSV files for {object_type} in {temp_dir}."
+ "Found %s CSV files for %s in %s.",
+ len(csv_files_found),
+ object_type,
+ temp_dir,
)
logger.info(
- f"Total data rows across all CSVs for {object_type}: {total_data_rows}"
+ "Total data rows across all CSVs for %s: %s", object_type, total_data_rows
)
assert total_data_rows > 1100 and total_data_rows < 1200
@@ -1003,10 +1008,12 @@ def test_salesforce_connector_single() -> None:
# parent_reference_fields_by_type: dict[str, dict[str, list[str]]] = {}
# Step 1 - make a list of all the types to download (parent + direct child + USER_OBJECT_TYPE)
- logger.info(f"Parent object types: num={len(parent_types)} list={parent_types}")
+ logger.info("Parent object types: num=%s list=%s", len(parent_types), parent_types)
for parent_type_working in parent_types:
child_types_working = sf_client.get_children_of_sf_type(parent_type_working)
- logger.debug(f"Found {len(child_types)} child types for {parent_type_working}")
+ logger.debug(
+ "Found %s child types for %s", len(child_types), parent_type_working
+ )
for child_type, child_relationship in child_types_working.items():
# onyx_sf_type = OnyxSalesforceType(child_type, sf_client)
@@ -1032,7 +1039,10 @@ def test_salesforce_connector_single() -> None:
child_types.update(list(child_types_working.keys()))
logger.info(
- f"Child object types: parent={parent_type_working} num={len(child_types_working)} list={child_types_working.keys()}"
+ "Child object types: parent=%s num=%s list=%s",
+ parent_type_working,
+ len(child_types_working),
+ child_types_working.keys(),
)
# queryable_fields_attachment = _get_all_queryable_fields_of_sf_type(sf_client, "Attachment")
@@ -1117,7 +1127,7 @@ def test_salesforce_connector_single() -> None:
result = sf_client.query(query)
print(f"{result=}")
except Exception:
- logger.exception(f"Query failed: {query=}")
+ logger.exception("Query failed: query=%r", query)
for child_relationship in child_relationships_batch:
relationship_status[child_relationship] = False
else:
@@ -1150,7 +1160,7 @@ def test_salesforce_connector_single() -> None:
result = sf_client.query(query)
print(f"{result=}")
except Exception:
- logger.exception(f"Query failed: {query=}")
+ logger.exception("Query failed: query=%r", query)
for child_relationship in child_relationships_batch:
relationship_status[child_relationship] = False
else:
diff --git a/backend/tests/utils/aws_secrets.py b/backend/tests/utils/aws_secrets.py
index a889d953e8..7b1b162187 100644
--- a/backend/tests/utils/aws_secrets.py
+++ b/backend/tests/utils/aws_secrets.py
@@ -124,7 +124,7 @@ def _get_aws_secrets(
secrets[enum_type(key_name)] = secret_value
except ValueError:
logger.warning(
- f"Secret '{key_name}' not in {enum_type.__name__}, skipping"
+ "Secret '%s' not in %s, skipping", key_name, enum_type.__name__
)
for error in response.get("Errors", []):
@@ -132,7 +132,7 @@ def _get_aws_secrets(
error_code = error.get("ErrorCode", "unknown")
message = error.get("Message", "unknown error")
logger.warning(
- f"Failed to fetch secret '{secret_id}': [{error_code}] {message}"
+ "Failed to fetch secret '%s': [%s] %s", secret_id, error_code, message
)
return secrets
@@ -165,15 +165,17 @@ def get_secrets(
if secrets:
local_names = ", ".join(k.value for k in secrets)
- logger.info(f"Resolved {len(secrets)} secret(s) locally: {local_names}")
+ logger.info("Resolved %s secret(s) locally: %s", len(secrets), local_names)
remaining: list[AnySecret] = [k for k in keys if k not in secrets]
if remaining:
aws_secrets = _get_aws_secrets(remaining, enum_type)
secrets.update(aws_secrets)
logger.info(
- f"Fetched {len(aws_secrets)}/{len(remaining)} secret(s) from AWS "
- f"(prefix: {enum_type.aws_prefix()!r})"
+ "Fetched %s/%s secret(s) from AWS (prefix: %r)",
+ len(aws_secrets),
+ len(remaining),
+ enum_type.aws_prefix(),
)
return cast("dict[TestSecret, str] | dict[DeploySecret, str]", secrets)
diff --git a/pyproject.toml b/pyproject.toml
index c45329dedd..bc4820a682 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -234,6 +234,7 @@ select = [
"ARG",
"E",
"F",
+ "G004",
"I",
"S324",
"W",