slog_try/
lib.rs

1// Copyright (c) 2021 slog-try developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9//! Convenience macros for logging with optional slog `Logger`s.
10//!
11//! # Example
12//!
13//! ```
14//! # use slog::{Discard, Drain, Logger, o};
15//! # use slog_try::try_info;
16//! #
17//! # fn main() {
18//! #[derive(Default)]
19//! struct HasOptLogger {
20//!     logger: Option<Logger>,
21//! }
22//!
23//! let mut opt_logger: HasOptLogger = Default::default();
24//! try_info!(opt_logger.logger, "You won't see me output.  The logger is None."; "opt" => "None");
25//! try_info!(opt_logger.logger, #"imatag", "You won't see me output.  The logger is None."; "opt" => "None");
26//!
27//! // Setup a `Logger`
28//! # let logger = Logger::root(Discard, o!());
29//! opt_logger.logger = Some(logger);
30//! try_info!(opt_logger.logger, "You will see me output!"; "opt" => "Some");
31//! try_info!(opt_logger.logger, #"imatag", "You will see me output!"; "opt" => "Some");
32//! # }
33//! ```
34// rustc lints
35#![cfg_attr(
36    all(msrv, feature = "unstable", nightly),
37    feature(
38        c_unwind,
39        lint_reasons,
40        must_not_suspend,
41        non_exhaustive_omitted_patterns_lint,
42        strict_provenance
43    )
44)]
45#![cfg_attr(
46    msrv,
47    deny(
48        absolute_paths_not_starting_with_crate,
49        anonymous_parameters,
50        array_into_iter,
51        asm_sub_register,
52        bad_asm_style,
53        bare_trait_objects,
54        bindings_with_variant_name,
55        // box_pointers,
56        break_with_label_and_loop,
57        clashing_extern_declarations,
58        coherence_leak_check,
59        confusable_idents,
60        const_evaluatable_unchecked,
61        const_item_mutation,
62        dead_code,
63        deprecated,
64        deprecated_in_future,
65        deprecated_where_clause_location,
66        deref_into_dyn_supertrait,
67        deref_nullptr,
68        drop_bounds,
69        duplicate_macro_attributes,
70        dyn_drop,
71        elided_lifetimes_in_paths,
72        ellipsis_inclusive_range_patterns,
73        explicit_outlives_requirements,
74        exported_private_dependencies,
75        forbidden_lint_groups,
76        function_item_references,
77        illegal_floating_point_literal_pattern,
78        improper_ctypes,
79        improper_ctypes_definitions,
80        incomplete_features,
81        indirect_structural_match,
82        inline_no_sanitize,
83        invalid_doc_attributes,
84        invalid_value,
85        irrefutable_let_patterns,
86        keyword_idents,
87        large_assignments,
88        late_bound_lifetime_arguments,
89        legacy_derive_helpers,
90        let_underscore_drop,
91        macro_use_extern_crate,
92        meta_variable_misuse,
93        missing_abi,
94        missing_copy_implementations,
95        missing_debug_implementations,
96        missing_docs,
97        mixed_script_confusables,
98        named_arguments_used_positionally,
99        no_mangle_generic_items,
100        non_ascii_idents,
101        non_camel_case_types,
102        non_fmt_panics,
103        non_shorthand_field_patterns,
104        non_snake_case,
105        non_upper_case_globals,
106        nontrivial_structural_match,
107        noop_method_call,
108        overlapping_range_endpoints,
109        path_statements,
110        pointer_structural_match,
111        private_in_public,
112        redundant_semicolons,
113        renamed_and_removed_lints,
114        repr_transparent_external_private_fields,
115        rust_2021_incompatible_closure_captures,
116        rust_2021_incompatible_or_patterns,
117        rust_2021_prefixes_incompatible_syntax,
118        rust_2021_prelude_collisions,
119        semicolon_in_expressions_from_macros,
120        single_use_lifetimes,
121        special_module_name,
122        stable_features,
123        suspicious_auto_trait_impls,
124        temporary_cstring_as_ptr,
125        trivial_bounds,
126        trivial_casts,
127        trivial_numeric_casts,
128        type_alias_bounds,
129        tyvar_behind_raw_pointer,
130        uncommon_codepoints,
131        unconditional_recursion,
132        unexpected_cfgs,
133        uninhabited_static,
134        unknown_lints,
135        unnameable_test_items,
136        unreachable_code,
137        unreachable_patterns,
138        unreachable_pub,
139        unsafe_code,
140        unsafe_op_in_unsafe_fn,
141        unstable_name_collisions,
142        unstable_syntax_pre_expansion,
143        unsupported_calling_conventions,
144        unused_allocation,
145        unused_assignments,
146        unused_attributes,
147        unused_braces,
148        unused_comparisons,
149        unused_crate_dependencies,
150        unused_doc_comments,
151        unused_extern_crates,
152        unused_features,
153        unused_import_braces,
154        unused_imports,
155        unused_labels,
156        unused_lifetimes,
157        unused_macro_rules,
158        unused_macros,
159        unused_must_use,
160        unused_mut,
161        unused_parens,
162        unused_qualifications,
163        unused_results,
164        unused_tuple_struct_fields,
165        unused_unsafe,
166        unused_variables,
167        variant_size_differences,
168        where_clauses_object_safety,
169        while_true,
170))]
171// If nightly and unstable, allow `unstable_features`
172#![cfg_attr(all(msrv, feature = "unstable", nightly), allow(unstable_features))]
173// The unstable features
174#![cfg_attr(
175    all(msrv, feature = "unstable", nightly),
176    deny(
177        ffi_unwind_calls,
178        fuzzy_provenance_casts,
179        lossy_provenance_casts,
180        must_not_suspend,
181        non_exhaustive_omitted_patterns,
182        unfulfilled_lint_expectations,
183    )
184)]
185// If nightly and not unstable, deny `unstable_features`
186#![cfg_attr(all(msrv, not(feature = "unstable"), nightly), deny(unstable_features))]
187// nightly only lints
188// #![cfg_attr(all(msrv, nightly),deny())]
189// nightly or beta only lints
190#![cfg_attr(
191    all(msrv, any(beta, nightly)),
192    deny(for_loops_over_fallibles, opaque_hidden_inferred_bound)
193)]
194// beta only lints
195// #![cfg_attr( all(msrv, beta), deny())]
196// beta or stable only lints
197// #![cfg_attr(all(msrv, any(beta, stable)), deny())]
198// stable only lints
199// #![cfg_attr(all(msrv, stable), deny())]
200// clippy lints
201#![cfg_attr(msrv, deny(clippy::all, clippy::pedantic))]
202// #![cfg_attr(msrv, allow())]
203
204#[cfg(test)]
205mod drain;
206
207pub use slog::{crit, debug, error, info, trace, warn};
208
209#[macro_export]
210/// Log a trace level message if the given logger is `Some`, otherwise do nothing.
211macro_rules! try_trace(
212    ($l:expr, #$tag:expr, $($args:tt)+) => {
213        if let Some(ref log) = $l {
214            $crate::trace!(log, #$tag, $($args)+);
215        }
216    };
217    ($l:expr, $($args:tt)+) => {
218        if let Some(ref log) = $l {
219            $crate::trace!(log, $($args)+);
220        }
221    };
222);
223
224#[macro_export]
225/// Log a debug level message if the given logger is `Some`, otherwise do nothing.
226macro_rules! try_debug(
227    ($l:expr, #$tag:expr, $($args:tt)+) => {
228        if let Some(ref log) = $l {
229            $crate::debug!(log, #$tag, $($args)+);
230        }
231    };
232    ($l:expr, $($args:tt)+) => {
233        if let Some(ref log) = $l {
234            $crate::debug!(log, $($args)+);
235        }
236    };
237);
238
239#[macro_export]
240/// Log an info level message if the given logger is `Some`, otherwise do nothing.
241macro_rules! try_info(
242    ($l:expr, #$tag:expr, $($args:tt)+) => {
243        if let Some(ref log) = $l {
244            $crate::info!(log, #$tag, $($args)+);
245        }
246    };
247    ($l:expr, $($args:tt)+) => {
248        if let Some(ref log) = $l {
249            $crate::info!(log, $($args)+);
250        }
251    };
252);
253
254#[macro_export]
255/// Log a warn level message if the given logger is `Some`, otherwise do nothing.
256macro_rules! try_warn(
257    ($l:expr, #$tag:expr, $($args:tt)+) => {
258        if let Some(ref log) = $l {
259            $crate::warn!(log, #$tag, $($args)+);
260        }
261    };
262    ($l:expr, $($args:tt)+) => {
263        if let Some(ref log) = $l {
264            $crate::warn!(log, $($args)+);
265        }
266    };
267);
268
269#[macro_export]
270/// Log an error level message if the given logger is `Some`, otherwise do nothing.
271macro_rules! try_error(
272    ($l:expr, #$tag:expr, $($args:tt)+) => {
273        if let Some(ref log) = $l {
274            $crate::error!(log, #$tag, $($args)+);
275        }
276    };
277    ($l:expr, $($args:tt)+) => {
278        if let Some(ref log) = $l {
279            $crate::error!(log, $($args)+);
280        }
281    };
282);
283
284#[macro_export]
285/// Log a crit level message if the given logger is `Some`,, otherwise do nothing.
286macro_rules! try_crit(
287    ($l:expr, #$tag:expr, $($args:tt)+) => {
288        if let Some(ref log) = $l {
289            $crate::crit!(log, #$tag, $($args)+);
290        }
291    };
292    ($l:expr, $($args:tt)+) => {
293        if let Some(ref log) = $l {
294            $crate::crit!(log, $($args)+);
295        }
296    };
297);
298
299#[cfg(test)]
300mod tests {
301    use crate::drain::Buffer;
302    use slog::{o, Logger};
303
304    #[test]
305    fn trace() {
306        let buffer = Buffer::default();
307        let logger = Logger::root(buffer.clone(), o!());
308        let mut opt_logger: Option<Logger> = Some(logger);
309        try_trace!(opt_logger, "SUCCESS: trace");
310        try_trace!(opt_logger, #"tag", "SUCCESS: trace with tag");
311        opt_logger = None;
312        try_trace!(opt_logger, "FAILED: trace");
313        try_trace!(opt_logger, #"tag", "FAILED: trace with tag");
314        assert_eq!(
315            "SUCCESS: traceSUCCESS: trace with tag",
316            format!("{}", buffer)
317        );
318    }
319
320    #[test]
321    fn debug() {
322        let buffer = Buffer::default();
323        let logger = Logger::root(buffer.clone(), o!());
324        let mut opt_logger: Option<Logger> = Some(logger);
325        try_debug!(opt_logger, "SUCCESS: debug");
326        try_debug!(opt_logger, #"tag", "SUCCESS: debug with tag");
327        opt_logger = None;
328        try_debug!(opt_logger, "FAILED: debug");
329        try_debug!(opt_logger, #"tag", "FAILED: debug with tag");
330        assert_eq!(
331            "SUCCESS: debugSUCCESS: debug with tag",
332            format!("{}", buffer)
333        );
334    }
335
336    #[test]
337    fn info() {
338        let buffer = Buffer::default();
339        let logger = Logger::root(buffer.clone(), o!());
340        let mut opt_logger: Option<Logger> = Some(logger);
341        try_info!(opt_logger, "SUCCESS: info");
342        try_info!(opt_logger, #"tag", "SUCCESS: info with tag");
343        opt_logger = None;
344        try_info!(opt_logger, "FAILED: info");
345        try_info!(opt_logger, #"tag", "FAILED: info with tag");
346        assert_eq!("SUCCESS: infoSUCCESS: info with tag", format!("{}", buffer));
347    }
348
349    #[test]
350    fn warn() {
351        let buffer = Buffer::default();
352        let logger = Logger::root(buffer.clone(), o!());
353        let mut opt_logger: Option<Logger> = Some(logger);
354        try_warn!(opt_logger, "SUCCESS: warn");
355        try_warn!(opt_logger, #"tag", "SUCCESS: warn with tag");
356        opt_logger = None;
357        try_warn!(opt_logger, "FAILED: warn");
358        try_warn!(opt_logger, #"tag", "FAILED: warn with tag");
359        assert_eq!("SUCCESS: warnSUCCESS: warn with tag", format!("{}", buffer));
360    }
361
362    #[test]
363    fn error() {
364        let buffer = Buffer::default();
365        let logger = Logger::root(buffer.clone(), o!());
366        let mut opt_logger: Option<Logger> = Some(logger);
367        try_error!(opt_logger, "SUCCESS: error");
368        try_error!(opt_logger, #"tag", "SUCCESS: error with tag");
369        opt_logger = None;
370        try_error!(opt_logger, "FAILED: error");
371        try_error!(opt_logger, #"tag", "FAILED: error with tag");
372        assert_eq!(
373            "SUCCESS: errorSUCCESS: error with tag",
374            format!("{}", buffer)
375        );
376    }
377
378    #[test]
379    fn crit() {
380        let buffer = Buffer::default();
381        let logger = Logger::root(buffer.clone(), o!());
382        let mut opt_logger: Option<Logger> = Some(logger);
383        try_crit!(opt_logger, "SUCCESS: crit");
384        try_crit!(opt_logger, #"tag", "SUCCESS: crit with tag");
385        opt_logger = None;
386        try_crit!(opt_logger, "FAILED: crit");
387        try_crit!(opt_logger, #"tag", "FAILED: crit with tag");
388        assert_eq!("SUCCESS: critSUCCESS: crit with tag", format!("{}", buffer));
389    }
390}