debug_rs/
lib.rs

1//! A debug crate for rust inspired by NodeJS [debug](https://github.com/visionmedia/debug) module.
2//!
3//! ## Features
4//! * colored
5//! * including crate name, file name and line
6//! * filtered by glob patterns.
7//!
8//! ## Usage
9//! Here is an simple example in examples folder:
10//!
11//! ```rust
12//! #[macro_use]
13//! extern crate debug_rs;
14//!
15//!
16//! fn main() {
17//!     debug!(666, 33, "aaa");
18//!
19//!     debug!(vec![1, 2, 3]);
20//! }
21//! ```
22//!
23//! Then run it:
24//!
25//! ```sh
26//! DEBUG=* cargo run
27//! ```
28
29#[macro_use]
30extern crate lazy_static;
31extern crate colored;
32extern crate globset;
33use std::collections::hash_map::DefaultHasher;
34use std::hash::{Hash, Hasher};
35use globset::{Glob, GlobMatcher};
36use colored::*;
37
38lazy_static!{
39    static ref DEBUG_MATHERS: (Vec<GlobMatcher>, Vec<GlobMatcher>) = ::std::env::var("DEBUG")
40        .unwrap_or(String::new())
41        .as_str()
42        .split(',')
43        .fold((vec![], vec![]), |mut acc, s| {
44            if s.len() > 1 && &s[0..1] == "-" {
45                acc.1.push(Glob::new(&s[1..])
46                            .unwrap()
47                            .compile_matcher());
48            } else if s.len() > 0 {
49                acc.0.push(Glob::new(s)
50                            .unwrap()
51                            .compile_matcher());
52            }
53            acc
54        });
55}
56
57fn get_color(s: &str) -> &str {
58    let colors = vec![
59        "black",
60        "red",
61        "green",
62        "yellow",
63        "blue",
64        "magenta",
65        "cyan",
66        "white",
67    ];
68    let mut hasher = DefaultHasher::new();
69    s.hash(&mut hasher);
70    let hash = hasher.finish() as usize;
71    return colors[hash % colors.len()];
72}
73
74pub fn debug_meta(pkg: &str, file: &str, line: u32) {
75    print!(
76        "{}:{}:L{} ",
77        String::from(pkg).color(get_color(pkg)).bold(),
78        String::from(file).color(get_color(file)),
79        line
80    );
81}
82
83pub fn is_debug(pkg_name: &str, file: &str) -> bool {
84    let meta = format!("{}:{}", pkg_name, file);
85    return !DEBUG_MATHERS.1.iter().any(|g| g.is_match(&meta)) &&
86        DEBUG_MATHERS.0.iter().any(|g| g.is_match(&meta));
87}
88
89/// Debug variables depends on environment variable `DEBUG`, using glob pattern to filter output.
90///
91/// e.g.
92///
93/// ```
94///   #[macro_use]
95/// extern crate debug_rs;
96///
97/// fn main() {
98///     debug!(666, 33, "aaa");
99///
100///     debug!(vec![1, 2, 3]);
101/// }
102/// ```
103///
104/// Then running:
105///
106/// ```sh
107/// DEBUG=*,-not_this cargo run // for *unix
108/// // or
109/// set DEBUG=*,-not_this; cargo run // for windows
110/// // or
111/// $env:DEBUG = "*,-not_this"; cargo run // for PowerShell
112/// ```
113///
114#[macro_export]
115macro_rules! debug {
116    ( $( $x:expr ),* ) => {
117        #[cfg(any(not(feature = "debug_build_only"), debug_assertions))]
118        #[cfg(not(feature = "disable"))]
119        {
120            let pkg_name = env!("CARGO_PKG_NAME");
121            let file = file!();
122            if $crate::is_debug(pkg_name, file) {
123                $crate::debug_meta(pkg_name, file, line!());
124                $(
125                    print!(" {:?}", $x);
126                )*
127                print!("\n");
128            }
129        }
130    };
131}
132
133#[cfg(test)]
134mod tests {
135    #[test]
136    fn it_works() {
137        debug!("aaa", 123, "bbb");
138
139        debug!(vec![1, 2, 3]);
140    }
141}