unbug

A crate to programmatically invoke debugging breakpoints with helping macros

1 unstable release

0.1.0 Sep 9, 2024

#240 in Debugging

Download history 106/week @ 2024-09-05 39/week @ 2024-09-12 12/week @ 2024-09-19 13/week @ 2024-09-26 7/week @ 2024-10-03

77 downloads per month

MIT/Apache

11KB
89 lines

Unbug

A crate to programmatically invoke debugging breakpoints with helping macros.

These macros are designed to help developers catch errors during debugging sessions that would otherwise be a panic (which may not be desirable in certain contexts) or simply a log message (which may go unnoticed).

This crate's internals are disabled by default, there are shims provided so breakpoints will not be compiled outside of a debugging context. This means that the macros in this crate can be used freely throughout your code without having to conditionally compile them out yourself.

NOTICE

You must use the enable feature of this crate (deactivated by default) to activate the breakpoints. This crate cannot detect the presence of a debugger.

BREAKPOINTS REQUIRE NIGHTLY RUST

BREAKPOINTS REQUIRE ENABLING THE EXPERIMENTAL core_intrinsics FEATURE

Additonally, debugging may not land on the macro statements themselves. This can have the consequence that the debgger may pause on an internal module. To avoid this, return or continue immediately following a macro invocation. Alternatively, use your debugger's "step-out" feature until you reenter the scope of your code.

Error messages are logged when used in conjuction with Tracing

Examples

// trigger the debugger
unbug::breakpoint!();

let some_bool = false;

for i in 0..5 {
    // ensure! will only trigger the debugger once when the expression argument is false
    unbug::ensure!(some_bool);

    // ensure_always! will trigger the debugger every time
    unbug::ensure_always!(some_bool);
}

let my_var: Option<()> = None;

// Use the tracing_subscriber crate to log error messages from the fail! and fail_always! macros.
tracing_subscriber::fmt::init();

let Some(out_var) = my_var else {
    // fail! pauses and logs an error message, will also only trigger once
    // fail! will continue to log in non-debug builds
    unbug::fail!("failed to get some option");
    return;
};

let Some(other_out_var) = my_var else {
    // fail_always! will do the same, but will trigger every time
    unbug::fail_always!("failed to get some option");
    return;
};

Setup

Prepare your environment for debugging Rust.

If you are using VSCode you will need the Rust Analyzer and Code LLDB extensions. See Microsoft's Documentation on Rust Debugging in VSCode.

1. Enable Nightly Rust:

rustup install nightly
rustup default nightly

2. Create a debug feature in your project that will only be active in the context of a debugger, i.e. not enabled by default.

Cargo.toml:

[features]
default = []
my_debug_feature = [
    "unbug/enable"
]

3. enable the core_intrinsics feature in the root of your crate (main.rs or lib.rs)

main.rs:

#![cfg_attr(all(debug_assertions, feature = "my_debug_feature"), feature(core_intrinsics))]

this configuration will only activate core_intrinsics for debug builds when your debug feature is active

4. Pass your feature flag to cargo during your debug build.

Sample VSCode launch.json with LLDB:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug",
            "cargo": {
                "args": [
                    "build",
                    "--bin=my_project",
                    "--package=my_project",
                    "--features=my_debug_feature"
                ],
                "filter": {
                    "name": "my_project",
                    "kind": "bin"
                }
            },
            "args": [],
            "cwd": "${workspaceFolder}",
            "env": {
                "CARGO_MANIFEST_DIR": "${workspaceFolder}"
            }
        }
    ]
}

License

Unbug is free and open source. All code in this repository is dual-licensed under either:

at your option.

Dependencies

~305–410KB