#bug-report #template-file #error-handling #hyperlink #github #template-generator #terminal-output #embedded #global-state #compile-time

no-std bug

A simple Rust library for printing an error in the event of a bug and allowing users to easily file a bug report via GitHub issues using bug templates

5 unstable releases

Uses new Rust 2024

0.3.1 Sep 3, 2025
0.3.0 Sep 3, 2025
0.2.0 Sep 2, 2025
0.1.1 Sep 2, 2025
0.1.0 Sep 2, 2025

#160 in Template engine

MIT license

74KB
485 lines

bug

Crates.io Documentation License

A Rust library for streamlined bug reporting that generates GitHub issue URLs with pre-filled templates. Works in both std and no_std environments. When bugs occur, bug prints tracing-style error messages to stderr and provides clean GitHub URLs for easy bug reporting.

โœจ Features

  • ๐ŸŽฏ Template-based bug reporting - Define reusable issue templates with named parameters
  • ๐Ÿ“„ File-based templates - Load templates from markdown files using include_str! macro
  • ๐Ÿท๏ธ Label support - Automatically apply labels to GitHub issues
  • โœ… Parameter validation - Ensures all template placeholders are properly filled at compile time
  • ๐ŸŒ URL encoding - Handles special characters in URLs automatically
  • ๐Ÿ“ Multiple templates - Support for different issue types per project
  • ๐Ÿ› ๏ธ no_std support - Works in embedded and no_std environments with --no-default-features
  • ๐Ÿ“ฆ Handle-based API - Alternative API that doesn't rely on global state

๐Ÿ“ฆ Installation

Add this to your Cargo.toml:

[dependencies]
bug = "0.2.0"

no_std Support

For embedded or no_std environments:

[dependencies]
bug = { version = "0.2.0", default-features = false }

๐Ÿš€ Quick Start

use bug::{bug, init, IssueTemplate};

fn main() -> Result<(), &'static str> {
    // Initialize with your GitHub repository
    init("username", "repository")
        .add_template("crash", IssueTemplate::new(
            "Application Crash: {error_type}",
            "## Description\nThe application crashed with error: {error_type}\n\n## Context\n- Function: {function}\n- Line: {line}"
        ).with_labels(vec!["bug".to_string(), "crash".to_string()]))
        .build()?;

    // Later in your code, when a bug occurs:
    let url = bug!("crash", {
        error_type = "NullPointerException",
        function = "calculate_sum",
        line = "42"
    });
    
    println!("Bug report URL: {}", url);
    Ok(())
}

This outputs:

๐Ÿ› BUG ENCOUNTERED in src/main.rs:15
   Template: crash
   Parameters:
     error_type: NullPointerException
     function: calculate_sum
     line: 42
   File a bug report: https://github.com/username/repository/issues/new?title=Application%20Crash%3A%20NullPointerException&body=...

๐Ÿ› ๏ธ no_std and Handle-based API

For no_std environments or when you prefer not to use global state, use the handle-based API:

use bug::{bug_with_handle, init_handle, IssueTemplate, FxHashMap};

fn main() {
    // Create a handle that doesn't use global state
    let bug_handle = init_handle("myorg", "myproject")
        .add_template("crash", IssueTemplate::new(
            "Application Crash: {error_type}",
            "## Description\nThe application crashed with error: {error_type}"
        ))
        .add_template("performance", IssueTemplate::new(
            "Performance Issue: {operation} is too slow",
            "Operation: {operation}\nExpected: {expected}ms\nActual: {actual}ms"
        ));

    // Use the handle to report bugs
    let url = bug_with_handle!(bug_handle, "crash", {
        error_type = "NullPointerException"
    });

    // Or call methods directly with FxHashMap
    let mut params = FxHashMap::default();
    params.insert("operation".to_string(), "database_query".to_string());
    params.insert("expected".to_string(), "100".to_string());
    params.insert("actual".to_string(), "1500".to_string());
    
    let direct_url = bug_handle.generate_url("performance", &params).unwrap();
}

no_std Considerations

In no_std mode:

  • Use FxHashMap instead of std::collections::HashMap
  • Global bug!() macro returns empty string (use bug_with_handle!() instead)
  • Terminal hyperlink detection is disabled (specify HyperlinkMode::Always or Never explicitly)
  • Custom output via the Output trait for logging to different targets

Custom Output in no_std

#[cfg(not(feature = "std"))]
use bug::{Output, BugReportHandle};

struct MyOutput;

impl Output for MyOutput {
    fn write_str(&mut self, s: &str) {
        // Send to your logging system, UART, etc.
        my_log_function(s);
    }
    
    fn write_fmt(&mut self, args: core::fmt::Arguments) {
        // Format and send to your logging system
        my_log_function(&format!("{}", args));
    }
}

let mut output = MyOutput;
let url = bug_handle.report_bug_with_output("crash", &params, file!(), line!(), &mut output);

๐Ÿ“‹ Template Files

Create structured markdown templates for consistent bug reports:

templates/crash_report.md:

Application Crash: {error_type}

## Description
The application crashed with error: {error_type}

## Context
- Function: {function}
- Line: {line}
- OS: {os}
- Version: {version}

## Steps to Reproduce
1. {step1}
2. {step2}
3. {step3}

## Expected Behavior
{expected_behavior}

## Additional Information
{additional_info}

Load in Rust:

use bug::{init, template_file};

fn main() -> Result<(), &'static str> {
    init("myorg", "myproject")
        .add_template_file("crash", template_file!("templates/crash_report.md", labels: ["bug", "crash"]))
        .build()?;
    Ok(())
}

๐ŸŽฏ Usage Examples

Multiple Template Types

use bug::{init, IssueTemplate, template_file};

fn main() -> Result<(), &'static str> {
    init("myorg", "myproject")
        // Simple inline template
        .add_template("simple", IssueTemplate::new(
            "Simple Issue: {title}",
            "Description: {description}"
        ))
        // File-based templates with labels
        .add_template_file("crash", template_file!("templates/crash_report.md", labels: ["bug", "crash"]))
        .add_template_file("performance", template_file!("templates/performance_issue.md", labels: ["performance", "optimization"]))
        .build()?;
    Ok(())
}

Comprehensive Bug Reports

// Performance issue reporting
let url = bug!("performance", {
    operation = "database_query",
    expected = "100",
    actual = "1500", 
    ratio = "15",
    os = std::env::consts::OS,
    version = env!("CARGO_PKG_VERSION"),
    hardware = "Intel i7-12700K, 32GB RAM",
    profiling_data = "CPU: 45%, Memory: 2.1GB, Disk I/O: 150MB/s",
    impact_description = "User experience is significantly degraded"
});

// Simple usage without parameters  
bug!("error");

๐Ÿ“Š Output Format

The bug!() macro prints structured information to stderr:

๐Ÿ› BUG ENCOUNTERED in src/database.rs:127
   Template: performance
   Parameters:
     operation: database_query
     expected: 100
     actual: 1500
     ratio: 15
     os: windows
     version: 0.1.0
   File a bug report: https://github.com/myorg/myproject/issues/new?title=Performance%20Issue...

Generated GitHub URLs can be quite long (800+ characters) due to URL-encoded template content, making log messages verbose and cluttering terminal output. Terminal hyperlink support using ANSI escape sequences to display clean, clickable text while hiding the long URL underneath.

Configure how links are displayed:

use bug::{init, HyperlinkMode};

// Auto-detect terminal hyperlink support (default)
init("user", "repo")
    .hyperlinks(HyperlinkMode::Auto)
    .build()?;

// Always use hyperlinks  
init("user", "repo")
    .hyperlinks(HyperlinkMode::Always)
    .build()?;

// Never use hyperlinks (show full URLs)
init("user", "repo")
    .hyperlinks(HyperlinkMode::Never)
    .build()?;

๐Ÿ“บ Supported Terminals

Automatic detection works with:

  • Windows Terminal
  • iTerm2 (macOS)
  • WezTerm
  • Alacritty
  • VS Code Integrated Terminal
  • Most xterm-compatible terminals

๐Ÿ“„ Output Comparison

With Hyperlinks (clean):

๐Ÿ› BUG ENCOUNTERED in src/main.rs:45
   Template: crash
   Parameters:
     error_type: NullPointerException
     function: calculate_sum
   File a bug report

Without Hyperlinks (traditional):

๐Ÿ› BUG ENCOUNTERED in src/main.rs:45
   Template: crash  
   Parameters:
     error_type: NullPointerException
     function: calculate_sum
   File a bug report: https://github.com/user/repo/issues/new?title=Application%20Crash...

The hyperlink text "File a bug report" becomes clickable and opens the full GitHub issue URL when clicked, keeping your logs clean while maintaining full functionality.

๐Ÿ“š API Reference

Core Functions

  • init(owner, repo) - Initialize bug reporting configuration (std only)
  • init_handle(owner, repo) - Create a bug report handle (std and no_std)
  • bug!(template, {params}) - Report a bug with given template and parameters (std only)
  • bug_with_handle!(handle, template, {params}) - Report bug using handle (std and no_std)
  • create_terminal_hyperlink(url, text) - Create ANSI hyperlink escape sequence
  • supports_hyperlinks() - Detect terminal hyperlink support (std only, no_std returns false)

Structs

  • IssueTemplate - Represents a GitHub issue template
  • TemplateFile - File-based template with validation
  • BugReportConfigBuilder - Fluent API for configuration (std only)
  • BugReportHandle - Handle-based bug reporting (std and no_std)
  • HyperlinkMode - Configure hyperlink display behavior

Types

  • FxHashMap<K, V> - HashMap type used by the API (re-exported from hashbrown)
  • Output - Trait for custom output in no_std environments

Enums

  • HyperlinkMode::Auto - Auto-detect terminal support (default, std only)
  • HyperlinkMode::Always - Always use hyperlinks
  • HyperlinkMode::Never - Always show full URLs

Macros

  • template_file!(path, labels: [...]) - Load template from file
  • bug!(template, {key = value, ...}) - Report bug with parameters (std only)
  • bug_with_handle!(handle, template, {key = value, ...}) - Report bug with handle (std and no_std)

Feature Flags

  • std (default) - Enable std support with global state and environment detection
  • When std is disabled: no_std mode with handle-based API only

๐Ÿงช Examples

See the examples/ directory for complete working examples:

Run examples:

cargo run --example basic_usage
cargo run --example handle_usage
cargo run --example template_file_usage

For no_std examples:

cargo run --example handle_usage --no-default-features

๐Ÿค Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Dependencies

~655KB