libdd-crashtracker 2.0.0

Detects program crashes and reports them to datadog backend.
Documentation
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

//! This module implements a crashtracker based on catching UNIX signals and
//! uploading the result to the backend.
//!
//! Architecturally, it consists of two parts:
//! 1. A signal handler, which catches a UNIX signal (SIGSEGV, SIGBUS, SIGABRT)
//!    associated with a crash, and and collects information about the state of
//!    the program at crash time.  The signal handler runs under a constrained
//!    environment where many standard operations are illegal.
//!    <https://man7.org/linux/man-pages/man7/signal-safety.7.html>
//!    In particular, memory allocation, and synchronization such as mutexes, are
//!    potentially UB.  The signal handler therefore does as little as possible
//!    in process, and instead writes data across a socket to a separate receiver
//!    process.
//!    The signal handler then waits for the receiver process to exit in order to reap its exit
//!    status (otherwise, upon the termination of the crashing process the child will be
//!    re-parented to PID 1 in the current PID namespace, which can be problematic for some user
//!    applications) and restores the previous signal handler.
//!    Once the receiver has completed, the crash-handler returns, allowing the
//!    previous crash handler (if any) to execute, maintaining the customer
//!    experience as much as possible.
//! 2. The receiver process, which is spawned by the signal handler.  It is connected by an
//!    anynomous AF_UNIX `socketpair()` to the parent process. When a crash occurs, the receiver
//!    gathers the information from the pipe, adds additional data about the system state (e.g.
//!    /proc/cpuinfo and /proc/meminfo), formats it into a crash report, uploads it to the backend,
//!    and then exits. The signal handler must wait for the receiver in order to reap its exit
//!    status.
//!
//! Data collected:
//! 1. The data collected by the crash-handler includes:
//!    1. The signal type leading to the crash
//!    2. The stacktrace at time of crash (for the crashing thread). Depending on a flag, this can
//!       either be resolved, or raw addresses. Resolving addresses provide more data, but sometimes
//!       crashes the crash handler (ironic).
//!    3. System level info (e.g. /proc/self/maps).
//!    4. The result of counters describing the current state of the profiler.
//! 2. Data augmented by the receiver includes:
//!    1. Metadata provided by the caller (e.g. library & profiler versions).
//!    2. System info: OS version, /proc/cpuinfo /proc/meminfo, etc.
//!    3. A timestamp and GUID for tracking the crash report.
//!
//! Handling of forks
//! Safety issues

#![cfg_attr(not(test), deny(clippy::panic))]
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
#![cfg_attr(not(test), deny(clippy::expect_used))]
#![cfg_attr(not(test), deny(clippy::todo))]
#![cfg_attr(not(test), deny(clippy::unimplemented))]

extern crate alloc;

#[cfg(all(unix, feature = "collector"))]
mod collector;
#[cfg(all(windows, feature = "collector_windows"))]
mod collector_windows;
#[cfg(unix)]
mod common;
mod crash_info;
#[cfg(all(unix, feature = "receiver"))]
mod receiver;
mod runtime_callback;

// Keep this module private to avoid exposing blazesym to users of the crate
#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
#[cfg(not(feature = "benchmarking"))]
mod shared;

// Make this module public when benchmarking is enabled to allow access to constants
#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
#[cfg(feature = "benchmarking")]
pub mod shared;

#[cfg(all(unix, feature = "collector"))]
pub use collector::{
    begin_op, clear_additional_tags, clear_spans, clear_traces, consume_and_emit_additional_tags,
    default_signals, disable, enable, end_op, get_expected_receiver_pid, init,
    insert_additional_tag, insert_span, insert_trace, on_fork, reconfigure, remove_additional_tag,
    remove_span, remove_trace, report_unhandled_exception, reset_counters,
    set_expected_receiver_pid, update_config, update_metadata, OpTypes, DEFAULT_SYMBOLS,
};

#[cfg(all(windows, feature = "collector_windows"))]
pub use collector_windows::api::{exception_event_callback, init_crashtracking_windows};

pub use crash_info::*;
pub use runtime_callback::*;

#[cfg(all(unix, feature = "receiver"))]
pub use receiver::{
    async_receiver_entry_point_stream, async_receiver_entry_point_unix_listener,
    async_receiver_entry_point_unix_socket, get_receiver_unix_socket, receiver_entry_point_stdin,
    receiver_entry_point_unix_socket,
};

#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
pub use shared::configuration::{
    default_max_threads, CrashtrackerConfiguration, CrashtrackerConfigurationBuilder,
    CrashtrackerReceiverConfig, StacktraceCollection,
};

#[cfg(all(unix, feature = "benchmarking"))]
pub use receiver::benchmark;

#[cfg(unix)]
pub use common::{get_tests_folder_path, SharedLibrary};