mirror of
https://github.com/langgenius/dify.git
synced 2026-10-29 18:07:39 +08:00
fix(api): attach exc_info=True to logger.warning sites that drop the traceback (#41068)
This commit is contained in:
@@ -167,8 +167,8 @@ class ApolloClient:
|
||||
old_value = old_kv.get(key)
|
||||
if old_value is None:
|
||||
self._change_listener("add", namespace, key, new_value)
|
||||
except BaseException as e:
|
||||
logger.warning(str(e))
|
||||
except BaseException:
|
||||
logger.warning("Apollo config change listener failed", exc_info=True)
|
||||
|
||||
def _path_checker(self) -> None:
|
||||
if not os.path.isdir(self._cache_file_path):
|
||||
@@ -235,8 +235,8 @@ class ApolloClient:
|
||||
return
|
||||
else:
|
||||
logger.warning("Sleep...")
|
||||
except Exception as e:
|
||||
logger.warning(str(e))
|
||||
except Exception:
|
||||
logger.warning("Apollo long polling failed", exc_info=True)
|
||||
|
||||
def _get_net_and_set_local(self, namespace: str, n_id: int, call_change: bool = False) -> None:
|
||||
namespace_data = self.get_json_from_net(namespace)
|
||||
|
||||
@@ -686,8 +686,8 @@ class WorkflowAppGenerator(BaseAppGenerator):
|
||||
try:
|
||||
with active_workflow_task(application_generate_entity.task_id):
|
||||
runner.run()
|
||||
except GenerateTaskStoppedError as e:
|
||||
logger.warning("Task stopped: %s", str(e))
|
||||
except GenerateTaskStoppedError:
|
||||
logger.warning("Task stopped", exc_info=True)
|
||||
pass
|
||||
except InvokeAuthorizationError:
|
||||
queue_manager.publish_error(
|
||||
|
||||
@@ -90,8 +90,8 @@ class AnnotationReplyFeature:
|
||||
)
|
||||
|
||||
return annotation
|
||||
except Exception as e:
|
||||
logger.warning("Query annotation failed, exception: %s.", str(e))
|
||||
except Exception:
|
||||
logger.warning("Query annotation failed.", exc_info=True)
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
@@ -486,8 +486,8 @@ class ProviderConfiguration(BaseModel):
|
||||
next_number = max(numbers, default=0) + 1
|
||||
return f"API KEY {next_number}"
|
||||
|
||||
except Exception as e:
|
||||
logger.warning("Error generating next credential name: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Error generating next credential name", exc_info=True)
|
||||
return "API KEY 1"
|
||||
|
||||
def _get_provider_names(self):
|
||||
|
||||
@@ -923,8 +923,8 @@ class LBModelManager:
|
||||
provider=self._provider,
|
||||
credential_type=PluginCredentialType.MODEL,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Load balancing config %s failed policy compliance check: %s", config.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Load balancing config %s failed policy compliance check", config.id, exc_info=True)
|
||||
cooldown_load_balancing_configs.append(config)
|
||||
if len(cooldown_load_balancing_configs) >= len(self._load_balancing_configs):
|
||||
# all configs are in cooldown or failed policy compliance
|
||||
|
||||
@@ -131,8 +131,8 @@ class WordExtractor(BaseExtractor):
|
||||
continue
|
||||
try:
|
||||
response = remote_fetcher.make_request("GET", url)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to download image from URL: %s: %s", url, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to download image from URL: %s", url, exc_info=True)
|
||||
continue
|
||||
if response.status_code == 200:
|
||||
image_ext = mimetypes.guess_extension(response.headers.get("Content-Type", ""))
|
||||
|
||||
@@ -468,8 +468,8 @@ class ParagraphIndexProcessor(BaseIndexProcessor):
|
||||
file, image_detail_config=ImagePromptMessageContent.DETAIL.LOW
|
||||
)
|
||||
prompt_message_contents.append(file_content)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to convert image file to prompt message content: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to convert image file to prompt message content", exc_info=True)
|
||||
continue
|
||||
|
||||
# Add text content
|
||||
@@ -572,8 +572,8 @@ class ParagraphIndexProcessor(BaseIndexProcessor):
|
||||
access_controller=_file_access_controller,
|
||||
)
|
||||
file_objects.append(file_obj)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to create File object from UploadFile %s: %s", upload_file.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to create File object from UploadFile %s", upload_file.id, exc_info=True)
|
||||
continue
|
||||
|
||||
return file_objects
|
||||
@@ -629,8 +629,8 @@ class ParagraphIndexProcessor(BaseIndexProcessor):
|
||||
storage_key=upload_file.key,
|
||||
)
|
||||
file_objects.append(file_obj)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to create File object from UploadFile %s: %s", upload_file.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to create File object from UploadFile %s", upload_file.id, exc_info=True)
|
||||
continue
|
||||
|
||||
return file_objects
|
||||
|
||||
@@ -86,7 +86,7 @@ class TraceClient:
|
||||
logger.warning("AliyunTrace API check failed: Unexpected status code: %s", response.status_code)
|
||||
return False
|
||||
except httpx.RequestError as e:
|
||||
logger.warning("AliyunTrace API check failed: %s", str(e))
|
||||
logger.warning("AliyunTrace API check failed", exc_info=True)
|
||||
raise ValueError(f"AliyunTrace API check failed: {str(e)}")
|
||||
|
||||
def get_project_url(self) -> str:
|
||||
|
||||
@@ -243,8 +243,8 @@ class SummaryIndexService:
|
||||
tokens_list = embedding_model.get_text_embedding_num_tokens([summary_content])
|
||||
raw_embedding_tokens = tokens_list[0] if tokens_list else 0
|
||||
embedding_tokens = raw_embedding_tokens if isinstance(raw_embedding_tokens, int) else 0
|
||||
except Exception as e:
|
||||
logger.warning("Failed to calculate embedding tokens for summary: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to calculate embedding tokens for summary", exc_info=True)
|
||||
|
||||
# Create document with summary content and metadata
|
||||
summary_document = Document(
|
||||
@@ -914,8 +914,8 @@ class SummaryIndexService:
|
||||
try:
|
||||
vector = Vector(dataset, session=session)
|
||||
vector.delete_by_ids(summary_node_ids)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to remove summary vectors: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to remove summary vectors", exc_info=True)
|
||||
|
||||
# Disable summary records (don't delete)
|
||||
now = naive_utc_now()
|
||||
|
||||
@@ -128,8 +128,8 @@ def add_document_to_index_task(dataset_document_id: str):
|
||||
dataset=dataset,
|
||||
segment_ids=segment_ids_list,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to enable summaries for document %s: %s", dataset_document.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to enable summaries for document %s", dataset_document.id, exc_info=True)
|
||||
|
||||
end_at = time.perf_counter()
|
||||
logger.info(
|
||||
|
||||
@@ -73,8 +73,8 @@ def disable_segment_from_index_task(segment_id: str):
|
||||
segment_ids=[segment.id],
|
||||
disabled_by=segment.disabled_by,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to disable summary for segment %s: %s", segment.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to disable summary for segment %s", segment.id, exc_info=True)
|
||||
|
||||
end_at = time.perf_counter()
|
||||
logger.info(
|
||||
|
||||
@@ -81,8 +81,8 @@ def disable_segments_from_index_task(segment_ids: list, dataset_id: str, documen
|
||||
segment_ids=segment_ids_list,
|
||||
disabled_by=disabled_by,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to disable summaries for segments: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to disable summaries for segments", exc_info=True)
|
||||
|
||||
end_at = time.perf_counter()
|
||||
logger.info(click.style(f"Segments removed from index latency: {end_at - start_at}", fg="green"))
|
||||
|
||||
@@ -117,8 +117,8 @@ def enable_segment_to_index_task(segment_id: str):
|
||||
dataset=dataset,
|
||||
segment_ids=[segment.id],
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to enable summary for segment %s: %s", segment.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to enable summary for segment %s", segment.id, exc_info=True)
|
||||
|
||||
end_at = time.perf_counter()
|
||||
logger.info(click.style(f"Segment enabled to index: {segment.id} latency: {end_at - start_at}", fg="green"))
|
||||
|
||||
@@ -117,8 +117,8 @@ def enable_segments_to_index_task(segment_ids: list, dataset_id: str, document_i
|
||||
dataset=dataset,
|
||||
segment_ids=segment_ids_list,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to enable summaries for segments: %s", str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to enable summaries for segments", exc_info=True)
|
||||
|
||||
end_at = time.perf_counter()
|
||||
logger.info(click.style(f"Segments enabled to index latency: {end_at - start_at}", fg="green"))
|
||||
|
||||
@@ -58,8 +58,8 @@ def remove_document_from_index_task(document_id: str):
|
||||
segment_ids=segment_ids_list,
|
||||
disabled_by=document.disabled_by,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to disable summaries for document %s: %s", document.id, str(e))
|
||||
except Exception:
|
||||
logger.warning("Failed to disable summaries for document %s", document.id, exc_info=True)
|
||||
|
||||
index_node_ids = [segment.index_node_id for segment in segments if segment.index_node_id]
|
||||
if index_node_ids:
|
||||
|
||||
@@ -712,6 +712,32 @@ class TestParagraphIndexProcessor:
|
||||
assert files == []
|
||||
assert sum(1 for r in caplog.records if r.levelno == logging.WARNING) == 1
|
||||
|
||||
def test_extract_images_from_text_warning_carries_traceback(self, caplog: pytest.LogCaptureFixture) -> None:
|
||||
"""The build failure is logged at WARNING with the traceback attached, not just str(exception)."""
|
||||
text = ""
|
||||
session = self.session
|
||||
session.add(self._upload_file(file_id="11111111-1111-1111-1111-111111111111"))
|
||||
session.flush()
|
||||
|
||||
with (
|
||||
patch(
|
||||
"core.rag.index_processor.processor.paragraph_index_processor.build_from_mapping",
|
||||
side_effect=RuntimeError("build failed"),
|
||||
),
|
||||
caplog.at_level(logging.WARNING, logger="core.rag.index_processor.processor.paragraph_index_processor"),
|
||||
):
|
||||
ParagraphIndexProcessor._extract_images_from_text("tenant-1", text, session)
|
||||
|
||||
record = next(r for r in caplog.records if r.levelno == logging.WARNING)
|
||||
assert record.exc_info is not None
|
||||
_, exc_value, exc_traceback = record.exc_info
|
||||
assert isinstance(exc_value, RuntimeError)
|
||||
assert exc_traceback is not None
|
||||
# The formatted output carries the call chain, and the message itself no longer inlines the exception.
|
||||
assert "Traceback (most recent call last)" in caplog.text
|
||||
assert "RuntimeError: build failed" in caplog.text
|
||||
assert "build failed" not in record.getMessage()
|
||||
|
||||
def test_extract_images_from_segment_attachments(self, caplog: pytest.LogCaptureFixture) -> None:
|
||||
session = self.session
|
||||
uploads = [
|
||||
|
||||
Reference in New Issue
Block a user