1515with workflow .unsafe .imports_passed_through ():
1616 import sentry_sdk
1717
18-
1918logger = 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
2230class _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