Skip to content

Commit e5c45de

Browse files
authored
♻️ Enhances various error messages on webserver (#7860)
1 parent 494336a commit e5c45de

File tree

9 files changed

+68
-33
lines changed

9 files changed

+68
-33
lines changed

packages/service-library/src/servicelib/logging_errors.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,22 @@ def create_troubleshotting_log_message(
2727
error_context -- Additional context surrounding the exception, such as environment variables or function-specific data. This can be derived from exc.error_context() (relevant when using the OsparcErrorMixin)
2828
tip -- Helpful suggestions or possible solutions explaining why the error may have occurred and how it could potentially be resolved
2929
"""
30+
31+
def _collect_causes(exc: BaseException) -> str:
32+
causes = []
33+
current = exc.__cause__
34+
while current is not None:
35+
causes.append(f"[{type(current).__name__}]'{current}'")
36+
current = getattr(current, "__cause__", None)
37+
return " <- ".join(causes)
38+
3039
debug_data = json_dumps(
3140
{
3241
"exception_type": f"{type(error)}",
3342
"exception_details": f"{error}",
3443
"error_code": error_code,
3544
"context": error_context,
45+
"causes": _collect_causes(error),
3646
"tip": tip,
3747
},
3848
default=representation_encoder,

services/web/server/src/simcore_service_webserver/application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ def create_application() -> web.Application:
8585
# core modules
8686
setup_app_tracing(app) # WARNING: must be UPPERMOST middleware
8787
setup_db(app)
88-
setup_long_running_tasks(app)
8988
setup_redis(app)
9089
setup_session(app)
9190
setup_security(app)
9291
setup_rest(app)
92+
setup_long_running_tasks(app)
9393
setup_rabbitmq(app)
9494

9595
# front-end products

services/web/server/src/simcore_service_webserver/catalog/_service.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,12 @@ async def batch_get_my_services(
106106
product_name=product_name,
107107
ids=services_ids,
108108
)
109+
109110
except RPCServerError as err:
110111
raise CatalogNotAvailableError(
111112
user_id=user_id,
112113
product_name=product_name,
114+
services_ids=services_ids,
113115
) from err
114116

115117

services/web/server/src/simcore_service_webserver/director_v2/_director_v2_service.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pydantic import TypeAdapter
1616
from pydantic.types import PositiveInt
1717
from servicelib.aiohttp import status
18+
from servicelib.logging_errors import create_troubleshotting_log_kwargs
1819
from servicelib.logging_utils import log_decorator
1920
from simcore_postgres_database.utils_groups_extra_properties import (
2021
GroupExtraProperties,
@@ -76,10 +77,12 @@ async def create_or_update_pipeline(
7677
return computation_task_out
7778

7879
except DirectorV2ServiceError as exc:
79-
_logger.error( # noqa: TRY400
80-
"could not create pipeline from project %s: %s",
81-
project_id,
82-
exc,
80+
_logger.exception(
81+
**create_troubleshotting_log_kwargs(
82+
f"Could not create pipeline from project {project_id}",
83+
error=exc,
84+
error_context={**body, "backend_url": backend_url},
85+
)
8386
)
8487
return None
8588

services/web/server/src/simcore_service_webserver/groups/_classifiers_service.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""
2-
- Every group has a set of "official" classifiers and its users tag studies with them
3-
- Classifiers can be defined in two ways:
4-
1. a static bundle that is stored in group_classifiers.c.bundle
5-
2. using research resources from scicrunch.org (see group_classifiers.c.uses_scicrunch )
6-
- The API Classifiers model returned in
7-
1. is the bundle
8-
2. a dynamic tree built from validated RRIDs (in ResearchResourceRepository)
2+
- Every group has a set of "official" classifiers and its users tag studies with them
3+
- Classifiers can be defined in two ways:
4+
1. a static bundle that is stored in group_classifiers.c.bundle
5+
2. using research resources from scicrunch.org (see group_classifiers.c.uses_scicrunch )
6+
- The API Classifiers model returned in
7+
1. is the bundle
8+
2. a dynamic tree built from validated RRIDs (in ResearchResourceRepository)
99
"""
1010

1111
import logging
@@ -23,6 +23,7 @@
2323
ValidationError,
2424
field_validator,
2525
)
26+
from servicelib.logging_errors import create_troubleshotting_log_kwargs
2627
from simcore_postgres_database.models.classifiers import group_classifiers
2728

2829
from ..db.plugin import get_database_engine
@@ -97,12 +98,15 @@ async def get_classifiers_from_bundle(self, gid: int) -> dict[str, Any]:
9798
exclude_unset=True, exclude_none=True
9899
)
99100
except ValidationError as err:
100-
_logger.error(
101-
"DB corrupt data in 'groups_classifiers' table. "
102-
"Invalid classifier for gid=%d: %s. "
103-
"Returning empty bundle.",
104-
gid,
105-
err,
101+
_logger.exception(
102+
**create_troubleshotting_log_kwargs(
103+
f"DB corrupt data in 'groups_classifiers' table. Invalid classifier for gid={gid}. Returning empty bundle.",
104+
error=err,
105+
error_context={
106+
"gid": gid,
107+
"bundle": bundle,
108+
},
109+
)
106110
)
107111
return {}
108112

services/web/server/src/simcore_service_webserver/projects/_projects_service.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,10 @@ async def _open_project() -> bool:
14261426
>= max_number_of_studies_per_user
14271427
):
14281428
raise ProjectTooManyProjectOpenedError(
1429-
max_num_projects=max_number_of_studies_per_user
1429+
max_num_projects=max_number_of_studies_per_user,
1430+
user_id=user_id,
1431+
project_uuid=project_uuid,
1432+
client_session_id=client_session_id,
14301433
)
14311434

14321435
# Assign project_id to current_session

services/web/server/src/simcore_service_webserver/resource_manager/user_sessions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def managed_resource(
226226
registry = UserSessionResourcesRegistry(int(user_id), client_session_id, app)
227227
yield registry
228228
except Exception:
229-
_logger.exception(
229+
_logger.debug(
230230
"Error in web-socket for user:%s, session:%s",
231231
user_id,
232232
client_session_id,

services/web/server/src/simcore_service_webserver/scicrunch/errors.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,30 @@ def map_to_scicrunch_error(rrid: str, error_code: int, message: str) -> Scicrunc
4747
<= status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
4848
), error_code # nosec
4949

50-
custom_error = ScicrunchError(reason="Unexpected error in scicrunch.org")
50+
custom_error = ScicrunchError(
51+
reason="Unexpected error in scicrunch.org", original_message=message
52+
)
5153

5254
if error_code == web_exceptions.HTTPBadRequest.status_code:
53-
custom_error = InvalidRRIDError(rrid=rrid)
55+
custom_error = InvalidRRIDError(rrid=rrid, original_message=message)
5456

5557
elif error_code == web_exceptions.HTTPNotFound.status_code:
56-
custom_error = InvalidRRIDError(msg_template=f"Did not find any '{rrid}'")
58+
custom_error = InvalidRRIDError(
59+
msg_template=f"Did not find any '{rrid}'", original_message=message
60+
)
5761

5862
elif error_code == web_exceptions.HTTPUnauthorized.status_code:
5963
custom_error = ScicrunchConfigError(
6064
reason="osparc was not authorized to access scicrunch.org."
61-
"Please check API access tokens."
65+
"Please check API access tokens.",
66+
original_message=message,
6267
)
6368

6469
elif (
6570
error_code >= status.HTTP_500_INTERNAL_SERVER_ERROR
6671
): # scicrunch.org server error
6772
custom_error = ScicrunchServiceError(
68-
reason="scicrunch.org cannot perform our requests"
73+
reason="scicrunch.org cannot perform our requests", original_message=message
6974
)
7075

71-
_logger.error("%s: %s", custom_error, message)
7276
return custom_error

services/web/server/src/simcore_service_webserver/studies_dispatcher/_projects.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from models_library.projects_nodes_io import DownloadLink, NodeID, PortLink
2020
from models_library.services import ServiceKey, ServiceVersion
2121
from pydantic import AnyUrl, HttpUrl, TypeAdapter
22+
from servicelib.logging_errors import create_troubleshotting_log_kwargs
2223
from servicelib.logging_utils import log_decorator
2324

2425
from ..projects._projects_repository_legacy import ProjectDBAPI
@@ -281,16 +282,24 @@ async def get_or_create_project_with_file_and_service(
281282
if is_valid:
282283
exists = True
283284
else:
285+
http_500_error = web.HTTPInternalServerError()
284286
_logger.error(
285-
"Project %s exists but does not seem to be a viewer generated by this module."
286-
" user: %s, viewer:%s, download_link:%s",
287-
project_uid,
288-
user,
289-
viewer,
290-
download_link,
287+
**create_troubleshotting_log_kwargs(
288+
f"Project {project_uid} exists but does not seem to be a viewer generated by this module.",
289+
error=http_500_error,
290+
error_context={
291+
"user": user,
292+
"viewer": viewer,
293+
"download_link": download_link,
294+
"project_db_workbench_keys": list(
295+
project_db.get("workbench", {}).keys()
296+
),
297+
"expected_keys": [file_picker_id, service_id],
298+
},
299+
)
291300
)
292301
# FIXME: CANNOT GUARANTEE!!, DELETE?? ERROR?? and cannot be viewed until verified?
293-
raise web.HTTPInternalServerError
302+
raise http_500_error
294303

295304
except (ProjectNotFoundError, ProjectInvalidRightsError):
296305
exists = False

0 commit comments

Comments
 (0)