A signal will be provided to a handler iff ALL of the following are true: 1. Signal (creation) is allowed by compile-time filters 2. Signal (creation) is allowed by runtime filters 3. Signal (handling) is allowed by handler filters 4. Signal middleware does not suppress the signal (return nil) 5. Handler middleware does not suppress the signal (return nil) For 1-3, filtering may depend on (in order): Sample rate → namespace → kind → id → level → when form/fn → rate limit Compile-time vs runtime filtering: Compile-time filtering is an advanced feature that can be tricky to set and use correctly. Most folks will want ONLY runtime filtering. Compile-time filtering works by eliding (completely removing the code for) disallowed signals. This means zero performance cost for these signals, but also means that compile-time filtering is PERMANENT once applied. So if you set `:info` as the compile-time minimum level, that'll REMOVE CODE for every signal call below `:info` level. To decrease that minimum level, you'll need to rebuild. Compile-time filtering can be set ONLY with environmental config (JVM properties, environment variables, or classpath resources). Signal and handler sampling is multiplicative: Both signals and handlers can have independent sample rates, and these MULTIPLY! If a signal is created with 20% sampling and a handler handles 50% of received signals, then 10% of possible signals will be handled (50% of 20%). The multiplicative rate is helpfully reflected in each signal's final `:sample-rate` value. For more info: - Signal visual flowchart, Ref. - On signal filters, see: `help:signal-filters` docstring - On handler filters, see: `help:signal-handlers` docstring If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!