@@ -7,7 +7,7 @@ use std::sync::Once;
77use std:: time:: Duration ;
88
99use datadog_crashtracker:: {
10- is_runtime_callback_registered, register_runtime_stack_callback , CallbackError , CallbackType ,
10+ is_runtime_callback_registered, register_runtime_frame_callback , register_runtime_stacktrace_string_callback , CallbackError ,
1111 CrashtrackerConfiguration , CrashtrackerReceiverConfig , Metadata , RuntimeStackFrame ,
1212 StacktraceCollection ,
1313} ;
@@ -322,66 +322,12 @@ pub fn crashtracker_receiver() -> anyhow::Result<()> {
322322#[ derive( Debug , PartialEq , Eq ) ]
323323pub enum CallbackResult {
324324 Ok ,
325- NullCallback ,
326- UnknownError ,
325+ Error ,
327326}
328327
329328impl From < CallbackError > for CallbackResult {
330- fn from ( error : CallbackError ) -> Self {
331- match error {
332- CallbackError :: NullCallback => CallbackResult :: NullCallback ,
333- }
334- }
335- }
336-
337- /// Runtime-specific stack frame representation for FFI
338- ///
339- /// This struct is used to pass runtime stack frame information from language
340- /// runtimes to the crashtracker during crash handling.
341- #[ pyclass( name = "RuntimeStackFrame" , module = "datadog.internal._native" ) ]
342- #[ derive( Debug , Clone ) ]
343- pub struct RuntimeStackFramePy {
344- pub function_name : Option < String > ,
345- pub file_name : Option < String > ,
346- pub line_number : u32 ,
347- pub column_number : u32 ,
348- }
349-
350- #[ pymethods]
351- impl RuntimeStackFramePy {
352- #[ new]
353- fn new (
354- function_name : Option < String > ,
355- file_name : Option < String > ,
356- line_number : u32 ,
357- column_number : u32 ,
358- ) -> Self {
359- Self {
360- function_name,
361- file_name,
362- line_number,
363- column_number,
364- }
365- }
366-
367- #[ getter]
368- fn get_function_name ( & self ) -> Option < String > {
369- self . function_name . clone ( )
370- }
371-
372- #[ getter]
373- fn get_file_name ( & self ) -> Option < String > {
374- self . file_name . clone ( )
375- }
376-
377- #[ getter]
378- fn get_line_number ( & self ) -> u32 {
379- self . line_number
380- }
381-
382- #[ getter]
383- fn get_column_number ( & self ) -> u32 {
384- self . column_number
329+ fn from ( _error : CallbackError ) -> Self {
330+ CallbackResult :: Error
385331 }
386332}
387333
@@ -471,117 +417,6 @@ fn parse_traceback_line(
471417 0
472418}
473419
474- // Parse traceback text and emit frames
475- unsafe fn parse_and_emit_traceback (
476- traceback_text : & str ,
477- emit_frame : unsafe extern "C" fn ( * const RuntimeStackFrame ) ,
478- ) {
479- let lines: Vec < & str > = traceback_text. lines ( ) . collect ( ) ;
480- let mut frame_count = 0 ;
481-
482- for line in lines {
483- if frame_count >= MAX_FRAMES {
484- break ;
485- }
486-
487- // Look for lines that start with " File " - these are stack frame lines
488- if line. trim_start ( ) . starts_with ( "File " ) {
489- let mut function_buf = StackBuffer :: new ( ) ;
490- let mut file_buf = StackBuffer :: new ( ) ;
491-
492- let line_number = parse_traceback_line ( line, & mut function_buf, & mut file_buf) ;
493-
494- let c_frame = RuntimeStackFrame {
495- function_name : function_buf. as_ptr ( ) ,
496- file_name : file_buf. as_ptr ( ) ,
497- line_number,
498- column_number : 0 ,
499- } ;
500-
501- emit_frame ( & c_frame) ;
502- frame_count += 1 ;
503- }
504- }
505- }
506-
507- unsafe fn dump_python_traceback_via_cpython_api (
508- emit_frame : unsafe extern "C" fn ( * const RuntimeStackFrame ) ,
509- ) {
510- let mut pipefd: [ c_int ; 2 ] = [ 0 , 0 ] ;
511- if pipe ( & mut pipefd as * mut [ c_int ; 2 ] ) != 0 {
512- emit_fallback_frame ( emit_frame, "<pipe_creation_failed>" ) ;
513- return ;
514- }
515-
516- let read_fd = pipefd[ 0 ] ;
517- let write_fd = pipefd[ 1 ] ;
518-
519- // Make the read end non-blocking
520- fcntl ( read_fd, F_SETFL , O_NONBLOCK ) ;
521-
522- // Get the current thread state safely - same approach as CPython's faulthandler
523- // SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and
524- // are thus delivered to the thread that caused the fault.
525- let current_tstate = crashtracker_get_current_tstate ( ) ;
526-
527- // Call the CPython internal API via our C wrapper
528- // Pass NULL for interpreter state since _Py_DumpTracebackThreads handle it internally
529- let error_msg = crashtracker_dump_traceback_threads ( write_fd, ptr:: null_mut ( ) , current_tstate) ;
530-
531- close ( write_fd) ;
532-
533- if !error_msg. is_null ( ) {
534- close ( read_fd) ;
535- let error_str = std:: ffi:: CStr :: from_ptr ( error_msg) ;
536- if let Ok ( error_string) = error_str. to_str ( ) {
537- emit_fallback_frame ( emit_frame, error_string) ;
538- } else {
539- emit_fallback_frame ( emit_frame, "<cpython_api_error>" ) ;
540- }
541- return ;
542- }
543-
544- let mut buffer = vec ! [ 0u8 ; MAX_TRACEBACK_SIZE ] ;
545- let bytes_read = read (
546- read_fd,
547- buffer. as_mut_ptr ( ) as * mut c_void ,
548- MAX_TRACEBACK_SIZE ,
549- ) ;
550-
551- close ( read_fd) ;
552-
553- if bytes_read > 0 {
554- buffer. truncate ( bytes_read as usize ) ;
555- if let Ok ( traceback_text) = std:: str:: from_utf8 ( & buffer) {
556- parse_and_emit_traceback ( traceback_text, emit_frame) ;
557- return ;
558- }
559- }
560-
561- // If we get here, something went wrong with reading the output
562- emit_fallback_frame ( emit_frame, "<traceback_read_failed>" ) ;
563- }
564-
565- // Helper function to emit a fallback frame with error information
566- unsafe fn emit_fallback_frame (
567- emit_frame : unsafe extern "C" fn ( * const RuntimeStackFrame ) ,
568- error_msg : & str ,
569- ) {
570- let mut function_buf = StackBuffer :: new ( ) ;
571- let mut file_buf = StackBuffer :: new ( ) ;
572- function_buf. set_from_str ( error_msg) ;
573- file_buf. set_from_str ( "<crashtracker_fallback>" ) ;
574-
575- let fallback_frame = RuntimeStackFrame {
576- function_name : function_buf. as_ptr ( ) ,
577- file_name : file_buf. as_ptr ( ) ,
578- line_number : 0 ,
579- column_number : 0 ,
580- } ;
581-
582- emit_frame ( & fallback_frame) ;
583- }
584-
585420/// Dump Python traceback as a complete string
586421///
587422/// This function captures the Python traceback via CPython's internal API
@@ -645,30 +480,42 @@ unsafe fn dump_python_traceback_as_string(
645480}
646481
647482unsafe extern "C" fn native_runtime_stack_callback (
648- _emit_frame : unsafe extern "C" fn ( * const RuntimeStackFrame ) ,
649483 emit_stacktrace_string : unsafe extern "C" fn ( * const c_char ) ,
650484) {
651485 dump_python_traceback_as_string ( emit_stacktrace_string) ;
652- // dump_python_traceback_via_cpython_api(emit_frame);
653486}
654487
655- /// Register the native runtime stack collection callback
488+ /// Frame-based callback implementation for runtime stack collection
489+ ///
490+ /// This callback collects Python stack frames individually and emits them
491+ /// one by one for detailed stack trace information.
492+ // unsafe extern "C" fn native_runtime_frame_callback(
493+ // emit_frame: unsafe extern "C" fn(*const RuntimeStackFrame),
494+ // ) {
495+ // dump_python_traceback_via_cpython_api(emit_frame);
496+ // }
497+
498+ /// Register the native runtime stack collection callback (string-based)
656499///
657500/// This function registers a native callback that directly collects Python runtime
658- /// stack traces without requiring Python callback functions. It uses frame-by-frame
659- /// collection for detailed stack information.
501+ /// stack traces as complete strings without requiring Python callback functions.
660502///
661503/// # Returns
662504/// - `CallbackResult::Ok` if registration succeeds (replaces any existing callback)
663505#[ pyfunction( name = "crashtracker_register_native_runtime_callback" ) ]
664506pub fn crashtracker_register_native_runtime_callback ( ) -> CallbackResult {
665- match register_runtime_stack_callback (
507+ match register_runtime_stacktrace_string_callback (
666508 native_runtime_stack_callback,
667- CallbackType :: StacktraceString ,
668509 ) {
669510 Ok ( ( ) ) => CallbackResult :: Ok ,
670511 Err ( e) => e. into ( ) ,
671512 }
513+ // match register_runtime_frame_callback(
514+ // native_runtime_frame_callback,
515+ // ) {
516+ // Ok(()) => CallbackResult::Ok,
517+ // Err(e) => e.into(),
518+ // }
672519}
673520
674521/// Check if a runtime callback is currently registered
0 commit comments