Skip to content

Commit 2c6fd7c

Browse files
committed
Add Workflow URL to Temporal Sentry errors
1 parent 5140187 commit 2c6fd7c

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

sentry/interceptor.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@
1515
with workflow.unsafe.imports_passed_through():
1616
import sentry_sdk
1717

18-
1918
logger = logging.getLogger(__name__)
2019

20+
TEMPORAL_UI_URL = "https://cloud.temporal.io"
21+
22+
23+
def _build_temporal_workflow_url(namespace: str, workflow_id: str, run_id: str) -> str | None:
24+
"""Build a URL to the Temporal UI for a specific workflow execution."""
25+
# URL encode the workflow_id in case it contains special characters
26+
encoded_workflow_id = quote(workflow_id, safe="")
27+
return f"{TEMPORAL_UI_URL}/namespaces/{namespace}/workflows/{encoded_workflow_id}/{run_id}"
28+
2129

2230
class _SentryActivityInboundInterceptor(ActivityInboundInterceptor):
2331
async def execute_activity(self, input: ExecuteActivityInput) -> Any:
@@ -35,6 +43,27 @@ async def execute_activity(self, input: ExecuteActivityInput) -> Any:
3543
"temporal.workflow.namespace", activity_info.workflow_namespace
3644
)
3745
scope.set_tag("temporal.workflow.run_id", activity_info.workflow_run_id)
46+
47+
# Build workflow URL for easy navigation from Sentry
48+
workflow_url = _build_temporal_workflow_url(
49+
namespace=activity_info.workflow_namespace,
50+
workflow_id=activity_info.workflow_id,
51+
run_id=activity_info.workflow_run_id,
52+
)
53+
54+
if workflow_url:
55+
scope.set_tag("temporal.workflow.url", workflow_url)
56+
scope.set_context(
57+
"Temporal Workflow",
58+
{
59+
"name": activity_info.workflow_type,
60+
"url": workflow_url,
61+
"workflow_id": activity_info.workflow_id,
62+
"run_id": activity_info.workflow_run_id,
63+
"activity": activity_info.activity_type,
64+
},
65+
)
66+
3867
try:
3968
return await super().execute_activity(input)
4069
except Exception as e:
@@ -61,6 +90,28 @@ async def execute_workflow(self, input: ExecuteWorkflowInput) -> Any:
6190
scope.set_tag("temporal.workflow.task_queue", workflow_info.task_queue)
6291
scope.set_tag("temporal.workflow.namespace", workflow_info.namespace)
6392
scope.set_tag("temporal.workflow.run_id", workflow_info.run_id)
93+
94+
# Build workflow URL for easy navigation from Sentry
95+
# Note: We need to access settings inside sandbox_unrestricted for workflow context
96+
with workflow.unsafe.sandbox_unrestricted():
97+
workflow_url = _build_temporal_workflow_url(
98+
namespace=workflow_info.namespace,
99+
workflow_id=workflow_info.workflow_id,
100+
run_id=workflow_info.run_id,
101+
)
102+
103+
if workflow_url:
104+
scope.set_tag("temporal.workflow.url", workflow_url)
105+
scope.set_context(
106+
"Temporal Workflow",
107+
{
108+
"name": workflow_info.workflow_type,
109+
"url": workflow_url,
110+
"workflow_id": workflow_info.workflow_id,
111+
"run_id": workflow_info.run_id,
112+
},
113+
)
114+
64115
try:
65116
return await super().execute_workflow(input)
66117
except Exception as e:

0 commit comments

Comments
 (0)