Skip to content

Commit 7f8cdca

Browse files
committed
Milestone 4 - Step 1
codetracer-python-recorder/src/monitoring/api.rs: codetracer-python-recorder/src/monitoring/callbacks.rs: codetracer-python-recorder/src/monitoring/install.rs: codetracer-python-recorder/src/monitoring/mod.rs: codetracer-python-recorder/src/monitoring/tracer.rs: design-docs/codetracer-architecture-refactor-implementation-plan.status.md: Signed-off-by: Tzanko Matev <[email protected]>
1 parent 48bb213 commit 7f8cdca

File tree

6 files changed

+262
-242
lines changed

6 files changed

+262
-242
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
//! Monitoring API abstractions.
2+
3+
use std::any::Any;
4+
5+
use crate::code_object::CodeObjectWrapper;
6+
use pyo3::prelude::*;
7+
use pyo3::types::PyAny;
8+
9+
use super::{CallbackOutcome, CallbackResult, EventSet, MonitoringEvents, NO_EVENTS};
10+
11+
/// Trait implemented by tracing backends.
12+
///
13+
/// Each method corresponds to an event from `sys.monitoring`. Default
14+
/// implementations allow implementers to only handle the events they care
15+
/// about.
16+
///
17+
/// Every callback returns a `CallbackResult` so implementations can propagate
18+
/// Python exceptions or request that CPython disables future events for a
19+
/// location by yielding the `CallbackOutcome::DisableLocation` sentinel.
20+
pub trait Tracer: Send + Any {
21+
/// Downcast support for implementations that need to be accessed
22+
/// behind a `Box<dyn Tracer>` (e.g., for flushing/finishing).
23+
fn as_any(&mut self) -> &mut dyn Any
24+
where
25+
Self: 'static,
26+
Self: Sized,
27+
{
28+
self
29+
}
30+
31+
/// Return the set of events the tracer wants to receive.
32+
fn interest(&self, _events: &MonitoringEvents) -> EventSet {
33+
NO_EVENTS
34+
}
35+
36+
/// Called on Python function calls.
37+
fn on_call(
38+
&mut self,
39+
_py: Python<'_>,
40+
_code: &CodeObjectWrapper,
41+
_offset: i32,
42+
_callable: &Bound<'_, PyAny>,
43+
_arg0: Option<&Bound<'_, PyAny>>,
44+
) -> CallbackResult {
45+
Ok(CallbackOutcome::Continue)
46+
}
47+
48+
/// Called on line execution.
49+
fn on_line(
50+
&mut self,
51+
_py: Python<'_>,
52+
_code: &CodeObjectWrapper,
53+
_lineno: u32,
54+
) -> CallbackResult {
55+
Ok(CallbackOutcome::Continue)
56+
}
57+
58+
/// Called when an instruction is about to be executed (by offset).
59+
fn on_instruction(
60+
&mut self,
61+
_py: Python<'_>,
62+
_code: &CodeObjectWrapper,
63+
_offset: i32,
64+
) -> CallbackResult {
65+
Ok(CallbackOutcome::Continue)
66+
}
67+
68+
/// Called when a jump in the control flow graph is made.
69+
fn on_jump(
70+
&mut self,
71+
_py: Python<'_>,
72+
_code: &CodeObjectWrapper,
73+
_offset: i32,
74+
_destination_offset: i32,
75+
) -> CallbackResult {
76+
Ok(CallbackOutcome::Continue)
77+
}
78+
79+
/// Called when a conditional branch is considered.
80+
fn on_branch(
81+
&mut self,
82+
_py: Python<'_>,
83+
_code: &CodeObjectWrapper,
84+
_offset: i32,
85+
_destination_offset: i32,
86+
) -> CallbackResult {
87+
Ok(CallbackOutcome::Continue)
88+
}
89+
90+
/// Called at start of a Python function (frame on stack).
91+
///
92+
/// Implementations should fail fast on irrecoverable conditions
93+
/// (e.g., inability to access the current frame/locals) by
94+
/// returning an error.
95+
fn on_py_start(
96+
&mut self,
97+
_py: Python<'_>,
98+
_code: &CodeObjectWrapper,
99+
_offset: i32,
100+
) -> CallbackResult {
101+
Ok(CallbackOutcome::Continue)
102+
}
103+
104+
/// Notify the tracer that an unrecoverable error occurred and the runtime
105+
/// is transitioning into a detach/disable flow.
106+
fn notify_failure(&mut self, _py: Python<'_>) -> PyResult<()> {
107+
Ok(())
108+
}
109+
110+
/// Called on resumption of a generator/coroutine (not via throw()).
111+
fn on_py_resume(
112+
&mut self,
113+
_py: Python<'_>,
114+
_code: &CodeObjectWrapper,
115+
_offset: i32,
116+
) -> CallbackResult {
117+
Ok(CallbackOutcome::Continue)
118+
}
119+
120+
/// Called immediately before a Python function returns.
121+
fn on_py_return(
122+
&mut self,
123+
_py: Python<'_>,
124+
_code: &CodeObjectWrapper,
125+
_offset: i32,
126+
_retval: &Bound<'_, PyAny>,
127+
) -> CallbackResult {
128+
Ok(CallbackOutcome::Continue)
129+
}
130+
131+
/// Called immediately before a Python function yields.
132+
fn on_py_yield(
133+
&mut self,
134+
_py: Python<'_>,
135+
_code: &CodeObjectWrapper,
136+
_offset: i32,
137+
_retval: &Bound<'_, PyAny>,
138+
) -> CallbackResult {
139+
Ok(CallbackOutcome::Continue)
140+
}
141+
142+
/// Called when a Python function is resumed by throw().
143+
fn on_py_throw(
144+
&mut self,
145+
_py: Python<'_>,
146+
_code: &CodeObjectWrapper,
147+
_offset: i32,
148+
_exception: &Bound<'_, PyAny>,
149+
) -> CallbackResult {
150+
Ok(CallbackOutcome::Continue)
151+
}
152+
153+
/// Called when exiting a Python function during exception unwinding.
154+
fn on_py_unwind(
155+
&mut self,
156+
_py: Python<'_>,
157+
_code: &CodeObjectWrapper,
158+
_offset: i32,
159+
_exception: &Bound<'_, PyAny>,
160+
) -> CallbackResult {
161+
Ok(CallbackOutcome::Continue)
162+
}
163+
164+
/// Called when an exception is raised (excluding STOP_ITERATION).
165+
fn on_raise(
166+
&mut self,
167+
_py: Python<'_>,
168+
_code: &CodeObjectWrapper,
169+
_offset: i32,
170+
_exception: &Bound<'_, PyAny>,
171+
) -> CallbackResult {
172+
Ok(CallbackOutcome::Continue)
173+
}
174+
175+
/// Called when an exception is re-raised.
176+
fn on_reraise(
177+
&mut self,
178+
_py: Python<'_>,
179+
_code: &CodeObjectWrapper,
180+
_offset: i32,
181+
_exception: &Bound<'_, PyAny>,
182+
) -> CallbackResult {
183+
Ok(CallbackOutcome::Continue)
184+
}
185+
186+
/// Called when an exception is handled.
187+
fn on_exception_handled(
188+
&mut self,
189+
_py: Python<'_>,
190+
_code: &CodeObjectWrapper,
191+
_offset: i32,
192+
_exception: &Bound<'_, PyAny>,
193+
) -> CallbackResult {
194+
Ok(CallbackOutcome::Continue)
195+
}
196+
197+
/// Called on return from any non-Python callable.
198+
fn on_c_return(
199+
&mut self,
200+
_py: Python<'_>,
201+
_code: &CodeObjectWrapper,
202+
_offset: i32,
203+
_callable: &Bound<'_, PyAny>,
204+
_arg0: Option<&Bound<'_, PyAny>>,
205+
) -> CallbackResult {
206+
Ok(CallbackOutcome::Continue)
207+
}
208+
209+
/// Called when an exception is raised from any non-Python callable.
210+
fn on_c_raise(
211+
&mut self,
212+
_py: Python<'_>,
213+
_code: &CodeObjectWrapper,
214+
_offset: i32,
215+
_callable: &Bound<'_, PyAny>,
216+
_arg0: Option<&Bound<'_, PyAny>>,
217+
) -> CallbackResult {
218+
Ok(CallbackOutcome::Continue)
219+
}
220+
221+
/// Flush any buffered state to storage. Default is a no-op.
222+
fn flush(&mut self, _py: Python<'_>) -> PyResult<()> {
223+
Ok(())
224+
}
225+
226+
/// Finish and close any underlying writers. Default is a no-op.
227+
fn finish(&mut self, _py: Python<'_>) -> PyResult<()> {
228+
Ok(())
229+
}
230+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//! sys.monitoring callback shims (Milestone 4 scaffolding).
2+
3+
pub use super::{events_union, CallbackFn, CallbackOutcome, CallbackResult};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//! Tracer installation plumbing (Milestone 4 scaffolding).
2+
3+
pub use super::tracer::{flush_installed_tracer, install_tracer, uninstall_tracer};

codetracer-python-recorder/src/monitoring/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ use pyo3::prelude::*;
44
use pyo3::types::PyCFunction;
55
use std::sync::OnceLock;
66

7+
pub mod api;
8+
pub mod callbacks;
9+
pub mod install;
710
mod tracer;
811

9-
pub use tracer::{flush_installed_tracer, install_tracer, uninstall_tracer, Tracer};
12+
pub use api::Tracer;
13+
pub use install::{flush_installed_tracer, install_tracer, uninstall_tracer};
1014

1115
const MONITORING_TOOL_NAME: &str = "codetracer";
1216

0 commit comments

Comments
 (0)