url_cleaner_engine/tutorial/debugging.rs
1//! # Debugging
2//!
3//! ## Local
4//!
5//! Most components have a variant called `Debug` that takes one of itself.
6//!
7//! `Debug` variants print information about the current state, the component's inputs (if any), the resulting value of what it modified (if any), and its return value.
8//!
9//! `Debug` variants are one of the few states a component will be in that will cause [`Cleaner::assert_suitability`] to panic. This is to ensure `Debug` variants aren't accidentally committed to the default cleaner.
10//!
11//! For example, the action `{"Debug": "None"}` will print the following to STDERR
12//!
13//! ```Text
14//! === Action::Debug ===
15//! Old task_state: TaskStateDebugHelper { url: "https://example.com/", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
16//! Return value: Ok(())
17//! New task_state: TaskStateDebugHelper { url: "https://example.com/", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
18//! ```
19//!
20//! As with most debugging features, the exact format is not stable or intended to be machine parsable.
21//!
22//! ## Global
23//!
24//! To check our intuition for the [reverted changes example of repeating](repeat#reverted-changes), it's useful to compile URL Cleaner Engine with the `debug` feature enabled to print debug info to STDERR.
25//!
26//! For example, here is the output of using the cleaner from the [reverted changes](repeat#reverted-changes) example cleaner with `https://example.com` as the input.
27//!
28//! ```Text
29//! 0- - -Action::apply
30//! - self: Repeat { actions: [SetQueryParam { query_param: QueryParamSelector { name: "unused_parameter", index: 0 }, value: String("whatever") }, RemoveQueryParam(String("unused_parameter"))], limit: 10 }
31//! - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
32//! 1- - -|---Action::apply
33//! | - self: SetQueryParam { query_param: QueryParamSelector { name: "unused_parameter", index: 0 }, value: String("whatever") }
34//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
35//! 2- - -|---Action::apply
36//! | - self: RemoveQueryParam(String("unused_parameter"))
37//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/?unused_parameter=whatever", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
38//! ```
39//!
40//! There's 3 calls to [`Action::apply`] here, marked 0, 1, and 2. Let's call them entries.
41//! Entry 0 is the [`Action::Repeat`], entry 1 is the [`Action::SetQueryParam`]action, and entry 2 is the [`Action::RemoveQueryParam`].
42//!
43//! If we were to intentionally give it a URL with an `unused_parameter` query parameter, we see the following:
44//!
45//! ```Text
46//! 0- - -Action::apply
47//! - self: Repeat { actions: [SetQueryParam { query_param: QueryParamSelector { name: "unused_parameter", index: 0 }, value: String("whatever") }, RemoveQueryParam(String("unused_parameter"))], limit: 10 }
48//! - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/?unused_parameter=a", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
49//! 1- - -|---Action::apply
50//! | - self: SetQueryParam { query_param: QueryParamSelector { name: "unused_parameter", index: 0 }, value: String("whatever") }
51//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/?unused_parameter=a", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
52//! 2- - -|---Action::apply
53//! | - self: RemoveQueryParam(String("unused_parameter"))
54//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/?unused_parameter=whatever", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
55//! 3- - -|---Action::apply
56//! | - self: SetQueryParam { query_param: QueryParamSelector { name: "unused_parameter", index: 0 }, value: String("whatever") }
57//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
58//! 4- 1- 2-|---Action::apply
59//! | - self: RemoveQueryParam(String("unused_parameter"))
60//! | - task_state.debug_helper(): TaskStateDebugHelper { url: "https://example.com/?unused_parameter=whatever", scratchpad: Scratchpad { flags: {}, vars: {} }, common_args: None }
61//! ```
62//!
63//! Entries 0, 1, and 2 are the same as before.
64//!
65//! Entry 3 is the same action as entry 1, but with a different [task state](task_state) (the URL being cleaned and some other details).
66//!
67//! Entry 4 is the same as entry 2 and is being applied to an identical task state. The `1` column means "this action and state combo has been repeated once" and the `2` column is the last entry that combo was found in.
68//!
69//! In general, you should try to write cleaners such that "repeat count" and "repeat of" columns are always empty. If they are, then you aren't ever entering the same state twice for (usually) no reason.
70//!
71//! The exact format isn't stable, but I'm reasonably happy with how it is now.
72
73pub(crate) use super::*;