[//]: # (auto_md_to_doc_comments segment start A) # Rust macro pretty_dbg!() [//]: # (auto_cargo_toml_to_md start) **pretty_dbg! is a copy of dbg!, just modified :#? to :# for pretty print. format_dbg! works like eprintln! with added file, line and column** ***version: 1.0.54 date: 2024-02-22 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/bestia-dev/pretty_dbg)*** [//]: # (auto_cargo_toml_to_md end) ![maintained](https://img.shields.io/badge/maintained-green) ![ready_for_use](https://img.shields.io/badge/ready_for_use-green) [![crates.io](https://img.shields.io/crates/v/pretty_dbg.svg)](https://crates.io/crates/pretty_dbg) [![Documentation](https://docs.rs/pretty_dbg/badge.svg)](https://docs.rs/pretty_dbg/) [![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/pretty_dbg.svg)](https://web.crev.dev/rust-reviews/crate/pretty_dbg/) [![RustActions](https://github.com/bestia-dev/pretty_dbg/actions/workflows/rust_fmt_auto_build_test.yml/badge.svg)](https://github.com/bestia-dev/pretty_dbg/) [![latest doc](https://img.shields.io/badge/latest_docs-GitHub-orange.svg)](https://bestia-dev.github.io/pretty_dbg/pretty_dbg/index.html) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bestia-dev/pretty_dbg/blob/main/LICENSE) ![pretty_dbg](https://bestia.dev/webpage_hit_counter/get_svg_image/1350166552.svg) [//]: # (auto_lines_of_code start) [![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-30-green.svg)](https://github.com/bestia-dev/pretty_dbg/) [![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-3-blue.svg)](https://github.com/bestia-dev/pretty_dbg/) [![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-8-purple.svg)](https://github.com/bestia-dev/pretty_dbg/) [![Lines in examples](https://img.shields.io/badge/Lines_in_examples-77-yellow.svg)](https://github.com/bestia-dev/pretty_dbg/) [![Lines in tests](https://img.shields.io/badge/Lines_in_tests-142-orange.svg)](https://github.com/bestia-dev/pretty_dbg/) [//]: # (auto_lines_of_code end) Hashtags: #rustlang #tutorial My projects on GitHub are more like a tutorial than a finished product: [bestia-dev tutorials](https://github.com/bestia-dev/tutorials_rust_wasm). ## Motivation I love using the macro `dbg!()` in Rust. It is an easy way to temporarily print a value on the screen while programming and debugging. When not needed anymore it is easy to search for all `dbg!` and erase or comment them. In my last project, I had some JSON data. The macro from the standard library printed a humanly unreadable long string. This is not pretty! Even multiline strings are printed in one single line making it unreadable. Run this code in the [rust playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a8f5eb34d97ec5818550f59af9a3c545): ```rust fn main() { let json_str = r#" { owner: 'bestia-dev', repository_details: { general: { description: 'testing the creation of a github repo', }, }, } "#; dbg!(json_str); } ``` This is the unreadable output for a string: ```output [src/main.rs:12] json_str = "\n {\n owner: 'bestia-dev',\n repository_details: {\n general: {\n description: 'testing the creation of a github repo',\n },\n },\n }\n" ``` Now let's try with the serde_json::Value: Run this code in the [rust playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c88ade301a7aa16bf27e7b8b9b6790ac): ```rust use serde_json; use anyhow::Result; fn main() -> Result<(), anyhow::Error>{ let response_text = r#"{ "id": 1296269, "homepage": "https://github.com" }"#; let parsed_json_value: serde_json::Value = serde_json::from_str(response_text)?; dbg!(&parsed_json_value); Ok(()) } ``` This returns also an unreadable output: ```output [src/main.rs:11] &parsed_json_value = Object { "homepage": String("https://github.com"), "id": Number(1296269), } ``` I know that `dbg!` under the hood is just a simple `eprintln!("{:#?}, json")`. And I know that I can print pretty JSON using `eprintln!("{:#}, json")` but then I don't express neatly my intent to `dbg!`. And I lose the possibility to search for `dbg!`. I found a crate that colors the `dbg!` output and is really pretty: [dbg-pls](https://github.com/conradludgate/dbg-pls). That is maybe too much for my little project. ## new pretty_dbg! macro So I decided to copy the original macro `dbg!`, modify it a little bit, and give it the name `pretty_dbg!`. Run this code in the [rust playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9ef982465f717d9c5b642aead94a4ff): ```rust /// copy of the macro dbg!, just modified :#? to :# for pretty print #[macro_export] macro_rules! pretty_dbg { () => { std::eprintln!("[{}:{}:{}]", std::file!(), std::line!(), std::column!()) }; ($val:expr $(,)?) => { match $val { tmp => { std::eprintln!("[{}:{}:{}] {} = {:#}", std::file!(), std::line!(), std::column!(), std::stringify!($val), &tmp); tmp } } }; ($($val:expr),+ $(,)?) => { ($(std::pretty_dbg!($val)),+,) }; } fn main() { let json_str = r#" { owner: 'bestia-dev', repository_details: { general: { description: 'testing the creation of a github repo', }, }, } "#; pretty_dbg!(json_str); } ``` The output is now very pretty: ```output [src/main.rs:32] json_str = { owner: 'bestia-dev', repository_details: { general: { description: 'testing the creation of a github repo', }, }, } ``` Now let's try with the serde_json::Value: Run this code in the [rust playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d5d5e264b9143f4fde16594eaea1fa09): ```rust use serde_json; use anyhow::Result; /// copy of the macro dbg!, just modified :#? to :# for pretty print #[macro_export] macro_rules! pretty_dbg { () => { std::eprintln!("[{}:{}:{}]", std::file!(), std::line!(), std::column!()) }; ($val:expr $(,)?) => { match $val { tmp => { std::eprintln!("[{}:{}:{}] {} = {:#}", std::file!(), std::line!(), std::column!(), std::stringify!($val), &tmp); tmp } } }; ($($val:expr),+ $(,)?) => { ($(std::pretty_dbg!($val)),+,) }; } fn main() -> Result<(), anyhow::Error>{ let response_text = r#"{ "id": 1296269, "homepage": "https://github.com" }"#; let parsed_json_value: serde_json::Value = serde_json::from_str(response_text)?; pretty_dbg!(&parsed_json_value); Ok(()) } ``` The output is now pretty: ```output [src/main.rs:31] &parsed_json_value = { "homepage": "https://github.com", "id": 1296269 } ``` ## New format_dbg! macro Sometimes when debugging I want to write some string to the output and not only a variable. The macro `dbg!` and consequently `pretty_dbg!` are not the right tools for that. Again I could use simply the `eprintln!`, but then it is not easy to find and remove this debugging code. Let's make another macro `format_dbg!`. It is just a simpler `dbg!` with another name. Run this code in the [rust playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=89ac8ec47ac972d4812e28846c803628): ```rust fn main() { /// copy of the macro dbg!, just modified :#? to :# for pretty print #[macro_export] macro_rules! pretty_dbg { () => { std::eprintln!("[{}:{}:{}]", std::file!(), std::line!(), std::column!()) }; ($val:expr $(,)?) => { match $val { tmp => { std::eprintln!("[{}:{}:{}] {} = {:#}", std::file!(), std::line!(), std::column!(), std::stringify!($val), &tmp); tmp } } }; ($($val:expr),+ $(,)?) => { ($(std::pretty_dbg!($val)),+,) }; } /// format_dbg! is a version of dbg! that uses the formatting rules from the macro eprintln! /// Just like dbg!, it prefixes the stderr output with file!, line! and column! #[macro_export] macro_rules! format_dbg { ($($arg:tt)*) => {{ std::eprint!("[{}:{}:{}] ", std::file!(), std::line!(), std::column!()); std::eprintln!($($arg)*); }}; } let val="123456789"; dbg!("using the dbg! macro : {val}"); pretty_dbg!("using the pretty_dbg! macro : {val}"); format_dbg!("using the format_dbg! macro : {val}"); } ``` ## New crate in crates.io or not I think this is maybe too small to be made in a new crate. It is just a small macro. For now, I am just adding the code for this macro in my projects where I need it. I changed my mind. I will publish a micro crate and I will make it exemplary because it is so small. I will add tests, examples, playground code, documentation,... as well as I could. ## Playing with the Rust Playground Trying short Rust code in the Rust playground is great! It is fast and easy. It works just with a browser. Fantastic to show examples of real code, not just hypothetical code. I first created Github Gists for my code examples. Every example must be in a separate Gist. Then I copy the Gist identification number into the playground link like this: and it just works. Great! I want to avoid using `unwrap()` in my examples. Unwrap is a bad, bad habit. Instead, I will use the crate `anyhow` and its types `Result` and `Error` directly in the main() function. So I can use the error propagation symbol `?` in the code like a pro. ## Integration tests for err/std output Integration tests by default capture the std output and run in parallel. In my case, this is exactly what I don't want. I need to capture the err/std output because this is the whole point of how the pretty_dbg! macro works. When working with the std/err output, code must not run in parallel because it would mix the output from different code and make it like scrambled eggs. It took a while to modify the code in my automation tasks and the calling parameters to run the tests in this non-standard way. I found the crate `gag` that can capture err/std output and I used a macro for my integration tests. This will come in handy for a lot of tests for CLI apps. ## Development details Read the development details in a separate md file: [DEVELOPMENT.md](https://github.com/bestia-dev/pretty_dbg/blob/main/DEVELOPMENT.md) ## Releases changelog Read the changelog in a separate md file: [RELEASES.md](https://github.com/bestia-dev/pretty_dbg/blob/main/RELEASES.md) ## TODO Nothing big in the near future. ## Open-source and free as a beer My open-source projects are free as a beer (MIT license). I just love programming. But I need also to drink. If you find my projects and tutorials helpful, please buy me a beer by donating to my [PayPal](https://paypal.me/LucianoBestia). You know the price of a beer in your local bar ;-) So I can drink a free beer for your health :-) [Na zdravje!](https://translate.google.com/?hl=en&sl=sl&tl=en&text=Na%20zdravje&op=translate) [Alla salute!](https://dictionary.cambridge.org/dictionary/italian-english/alla-salute) [Prost!](https://dictionary.cambridge.org/dictionary/german-english/prost) [Nazdravlje!](https://matadornetwork.com/nights/how-to-say-cheers-in-50-languages/) 🍻 [//bestia.dev](https://bestia.dev) [//github.com/bestia-dev](https://github.com/bestia-dev) [//bestiadev.substack.com](https://bestiadev.substack.com) [//youtube.com/@bestia-dev-tutorials](https://youtube.com/@bestia-dev-tutorials) [//]: # (auto_md_to_doc_comments segment end A)