├── .github ├── FUNDING.yml └── workflows │ ├── build_examples.yml │ ├── build_examples_latest.yml │ ├── cargo_test.yml │ ├── docs.yml │ └── semver_checks.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── DEV_NOTES.md ├── LICENSE ├── README.md ├── bacon.toml ├── doc ├── demo-short.tape ├── demo.tape ├── demo_v0.14.4.gif └── example.png ├── examples ├── demo.rs └── slog.rs_outdated ├── src ├── circular.rs ├── config │ ├── level_config.rs │ └── mod.rs ├── file.rs ├── lib.rs ├── logger │ ├── api.rs │ ├── logger.rs │ └── mod.rs ├── slog.rs ├── tracing_subscriber.rs └── widget │ ├── inner.rs │ ├── logformatter.rs │ ├── mod.rs │ ├── smart.rs │ ├── standard.rs │ ├── standard_formatter.rs │ └── target.rs └── tests ├── envfilter.rs ├── formatter_wrap.rs ├── scroll.rs ├── scroll_long_wrap.rs ├── scroll_wrap.rs └── simple.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [gin66] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/workflows/build_examples.yml: -------------------------------------------------------------------------------- 1 | name: Build examples 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | - name: Check rust version 17 | run: rustup show 18 | - name: Build examples with termion 19 | run: cargo build --examples --features termion 20 | - name: Build example with crossterm 21 | run: cargo build --examples --features crossterm 22 | - name: Build examples with termion and custom formatter 23 | run: cargo build --examples --features termion,formatter 24 | -------------------------------------------------------------------------------- /.github/workflows/build_examples_latest.yml: -------------------------------------------------------------------------------- 1 | name: Build examples with latest rust version 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | - name: Check rust version 17 | run: rustup show 18 | - name: Update rust 19 | run: rustup update 20 | - name: Build examples with ratatui and termion 21 | run: cargo build --examples --features termion 22 | - name: Build example with ratatui and crossterm 23 | run: cargo build --examples --features crossterm 24 | -------------------------------------------------------------------------------- /.github/workflows/cargo_test.yml: -------------------------------------------------------------------------------- 1 | name: cargo test 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | - name: Check rust version 17 | run: rustup show 18 | - name: Run tests 19 | run: | 20 | cargo test 21 | cargo test -F tracing-support --doc 22 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | check-docs: 11 | name: Check 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Install cargo-rdme 16 | uses: taiki-e/install-action@v2 17 | with: 18 | tool: cargo-rdme 19 | - name: Check README.md is up-to-date 20 | run: cargo rdme --check 21 | -------------------------------------------------------------------------------- /.github/workflows/semver_checks.yml: -------------------------------------------------------------------------------- 1 | name: Semver Checks 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | semver-checks: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | - name: Check semver 16 | uses: obi1kenobi/cargo-semver-checks-action@v2 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.17.3](https://github.com/gin66/tui-logger/compare/v0.17.2...v0.17.3) - 2025-05-24 11 | 12 | ### Other 13 | 14 | - update Readme 15 | - add ai generated documentation reference 16 | - add attributes of the current span for tracing subscriber (#90) 17 | - work on Readme 18 | 19 | ## [0.17.2](https://github.com/gin66/tui-logger/compare/v0.17.1...v0.17.2) - 2025-04-23 20 | 21 | ### Other 22 | 23 | - update README 24 | - Fix invalid docs for TuiTracingSubscriverLayer (#87) 25 | 26 | ## [0.17.1](https://github.com/gin66/tui-logger/compare/v0.17.0...v0.17.1) - 2025-04-13 27 | 28 | ### Other 29 | 30 | - run cargo fmt 31 | - use env_filter for configuration by environment variable as proposed by [#86](https://github.com/gin66/tui-logger/pull/86) 32 | - remove stray comment line in tests 33 | 34 | ## [0.17.0](https://github.com/gin66/tui-logger/compare/v0.16.0...v0.17.0) - 2025-03-11 35 | 36 | ### Other 37 | 38 | - file/module_path/line are now Option, because log::Record defines them as such, too 39 | 40 | ## [0.16.0](https://github.com/gin66/tui-logger/compare/v0.15.0...v0.16.0) - 2025-03-10 41 | 42 | ### Other 43 | 44 | - ExtLogRecord stores for file and module_path their static strings, if available. In addition provides module_path getter 45 | - provide accessors for the strings 46 | - update DEV_NOTES 47 | 48 | ## [0.15.0](https://github.com/gin66/tui-logger/compare/v0.14.5...v0.15.0) - 2025-03-08 49 | 50 | ### Fixed 51 | 52 | - fix bug with page up at top 53 | 54 | ### Other 55 | 56 | - lib.rs factoring complete 57 | - refactor TuiLoggerError out of lib.rs 58 | - refactor TuiLogger API out of lib.rs 59 | - refactor TuiLogger out of lib.rs 60 | - refactor LevelConfig out of lib.rs 61 | - refactor TuiLoggerTargetWidget out of lib.rs 62 | - reduce visibility of internal structures 63 | - add test case for log message being larger than widget 64 | - turn off debugging 65 | - add test case with standard formatter 66 | - add test with wrapped lines 67 | - disable println in lib code with render_debug switch 68 | - intermediate version with debug prints 69 | - circular buffer allows absolute indexing 70 | - test cases for standard widget display and scroll 71 | 72 | ## [0.14.5](https://github.com/gin66/tui-logger/compare/v0.14.4...v0.14.5) - 2025-02-22 73 | 74 | ### Other 75 | 76 | - update Changelog and Readme 77 | - Made target width also use unicode_segmentation 78 | - Use unicode-segmentation for splitting chars 79 | - Split lines safely 80 | - change &mut to & reference in TuiWidgetState.transition as [#83](https://github.com/gin66/tui-logger/pull/83) 81 | - Update mermaid diagram in README.md 82 | - Update lib.rs for readme change 83 | - Update README.md 84 | - Update README.md with mermaid diagram 85 | - rename dev_notes.md 86 | - cleanup files in doc 87 | - udpate readme 88 | - new demo of the widget using vhs 89 | - rename cargo test workflow 90 | - remove stray space in github action 91 | 92 | ## [0.14.4](https://github.com/gin66/tui-logger/compare/v0.14.3...v0.14.4) - 2025-01-31 93 | 94 | ### Fixed 95 | 96 | - fix cargo test 97 | 98 | ### Other 99 | 100 | - update Readme for custom formatter example in demo 101 | - example demo extended to use custom formatter in one of the widgets 102 | - run cargo test in github actions 103 | 104 | ## [0.14.3](https://github.com/gin66/tui-logger/compare/v0.14.2...v0.14.3) - 2025-01-31 105 | 106 | ### Other 107 | 108 | - work on Readme and add formatter() to smartwidget 109 | - standard formatter appears to work as before, but using Line/Span 110 | - assure LogFormatter Send+Sync 111 | - implement formatter trait as discussed in [#77](https://github.com/gin66/tui-logger/pull/77) and [#82](https://github.com/gin66/tui-logger/pull/82) 112 | 113 | ## [0.14.2](https://github.com/gin66/tui-logger/compare/v0.14.1...v0.14.2) - 2025-01-30 114 | 115 | ### Fixed 116 | 117 | - fix warnings 118 | 119 | ### Other 120 | 121 | - split lib.rs into several files 122 | - Merge pull request [#77](https://github.com/gin66/tui-logger/pull/77) from tofubert/add_style_for_file 123 | - Merge pull request [#78](https://github.com/gin66/tui-logger/pull/78) from andrei-ng/fix-order-of-fields-tracing-feature 124 | - Merge pull request [#79](https://github.com/gin66/tui-logger/pull/79) from andrei-ng/skip-printing-message-key 125 | 126 | - use env::temp_dir for demo log file target 127 | - do not print the 'message' key in the formatter for tracing support 128 | - fix formatter for tracing events 129 | - make comment for file logging a bit better 130 | - give file logging format options 131 | - Update CHANGELOG.md 132 | 133 | 0.14.1: 134 | - re-export log::LevelFilter 135 | 136 | 0.14.0: 137 | - Update version of ratatui 138 | 139 | 0.13.2: 140 | - fix tracing support 141 | 142 | 0.13.1: 143 | - fix missing `move_events()` on half full buffer in case hot buffer capacity was odd 144 | 145 | 0.13.0: 146 | - `move_events()` is not published anymore, but called by a cyclic internal task. 147 | This task is called by timeout (10ms) unless the hot buffer is half full. 148 | - `init_logger()` returns now `Result<(), TuiLoggerError>` 149 | 150 | 0.12.1: 151 | - fix for issue #69: avoid unwrap panic by using default level 152 | - add `set_buffer_depth()` to modify circular buffer size 153 | 154 | 0.12.0: 155 | - update ratatui to 0.28 156 | 157 | 0.11.2: 158 | - update ratatui to 0.27 159 | 160 | 0.11.1: 161 | - one line error report for demo example, if feature flag crossterm or termion not given 162 | - use cargo readme and test in github build 163 | - Fix of issue #60: panic on too small widget size 164 | 165 | 0.11.0: 166 | - BREAKING CHANGE: TuiWidgetEvent::transition() method now takes a TuiWidgetEvent by value instead of by reference. 167 | - update ratatui to 0.25 168 | 169 | 0.10.1: 170 | - update ratatui to ^0.25.0 171 | 172 | 0.10.0: 173 | - Remove support for tui legacy crate 174 | - Use `Cell::set_symbol()` as performance optimization from ratatui 175 | - Require chrono >= 0.4.20 for avoid security vulnerability (https://rustsec.org/advisories/RUSTSEC-2020-0159.html) 176 | 177 | 0.9.6: 178 | - update ratatui to 0.23.0 179 | 180 | 0.9.5: 181 | - rework examples/demo to not use termion 182 | 183 | 0.9.4: 184 | - fix breaking change in 0.9.3 as reported by issue #43 185 | 186 | 0.9.3: 187 | - update to ratatui 0.22 and fix clippy warnings 188 | 189 | 0.9.2: 190 | - update to ratatui 0.21 191 | 192 | 0.9.1: 193 | - Implement Eq for TuiWidgetEvent 194 | - suppport `border_type()` for TuiLoggerSmartWidget 195 | - Disable default features of chrono to avoid import of `time` v0.1.x 196 | 197 | 0.9.0: 198 | - support for tracing-subscriber 199 | - add optional ratatui support as proposed by (#32) 200 | - slog is NOT a default feature anymore. Enable with `slog-support` 201 | 202 | 0.8.3: 203 | - Make `TuiWidgetState.set_default_display_level()` work for TuiLoggerWidget (#30) 204 | 205 | 0.8.2: 206 | - Allow TuiLoggerWidget to be controlled with TuiWidgetState by calling state() builder function (#30) 207 | - Extend demo for an example for this TuiLoggerWidget control 208 | 209 | 0.8.1: 210 | - Update to tui-rs 0.19 and slog to 2.7.0 211 | 212 | 0.8.0: 213 | - Update to tui-rs 0.18 214 | 215 | 0.7.1: 216 | - Update to tui-rs 0.17 217 | 218 | 0.7.0: 219 | - Update rust edition in Cargo.toml to 2021 220 | - Fix all warnings from cargo clippy 221 | - new function for TuiWidgetState to set the default display level - not impacting the recording 222 | ```rust 223 | set_default_display_level(self, levelfilter: LevelFilter) -> TuiWidgetState 224 | - changed signature for TuiWidgetState function from 225 | ```rust 226 | set_level_for_target(&self, target: &str, levelfilter: LevelFilter) -> &TuiWidgetState 227 | ``` 228 | to 229 | ```rust 230 | set_level_for_target(self, target: &str, levelfilter: LevelFilter) -> TuiWidgetState 231 | ``` 232 | 233 | 234 | 0.6.6: 235 | - Add functions to format output of log data as discussed in [issue #19](https://github.com/gin66/tui-logger/issues/19) 236 | The functions are with their default values: 237 | ``` 238 | output_separator(':') 239 | output_timestamp(Some("%H:%M:%S".to_string())) 240 | output_level(Some(TuiLoggerLevelOutput::Long)) 241 | output_target(true) 242 | output_file(true) 243 | output_line(true) 244 | ``` 245 | 246 | 0.6.5: 247 | - Use thread safe counterparts for Rc/RefCell 248 | 249 | 0.6.4: 250 | - Bump version up for update to tui 0.16 251 | 252 | 0.6.3: 253 | - Removed verbose timestamp info log (issue #16) 254 | 255 | 0.6.2: 256 | - Fix by Wuelle to avoid panic on line wrapping inside a utf8 character 257 | 258 | 0.6.1: 259 | - Changes in README 260 | 261 | 0.6.0: 262 | - Support Scrollback in log history with TuiWidgetEvent::PrevPageKey, NextPageKey and EscapeKey 263 | - log and target panes' title can be set via .title_log(String) and .title_target(String) 264 | 265 | 0.5.1: 266 | - TuiWidgetEvent is now Debug, Clone, PartialEq, Hash 267 | 268 | 0.5.0: 269 | - Remove dispatcher completely 270 | - Get rid of dependency to termion and crossterm 271 | - KeyCommands to be translated by the application into KeyEvents for TuiWidgetState::transition() 272 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tui-logger" 3 | version = "0.17.3" 4 | authors = ["Jochen Kiemes "] 5 | edition = "2021" 6 | license = "MIT" 7 | description = "Logger with smart widget for the `ratatui` crate" 8 | documentation = "https://docs.rs/tui-logger/latest/tui_logger/" 9 | repository = "https://github.com/gin66/tui-logger" 10 | readme = "README.md" 11 | keywords = ["tui", "log", "logger", "widget", "dispatcher"] 12 | 13 | [dependencies] 14 | log = "0.4" 15 | chrono = { version = "^0.4.38", default-features = false, features = ["clock"] } 16 | ratatui = { version = "0.29", default-features = false} 17 | tracing = {version = "0.1.40", optional = true} 18 | tracing-subscriber = {version = "0.3", optional = true} 19 | lazy_static = "1.5" 20 | fxhash = "0.2" 21 | parking_lot = "0.12" 22 | slog = { version = "2.7.0", optional = true } 23 | unicode-segmentation = "1.12.0" 24 | env_filter = "0.1.3" 25 | 26 | [dev-dependencies] 27 | # the crate is compatible with ratatui >=0.25.0, but the demo uses features from 0.27.0 28 | ratatui = { version = "0.29", default-features = false} 29 | anyhow = "1.0.91" 30 | env_logger = "0.11.5" 31 | termion = {version = "4.0.3" } 32 | crossterm = {version = "0.28"} 33 | 34 | [features] 35 | slog-support = ["slog"] 36 | tracing-support = ["tracing", "tracing-subscriber"] 37 | 38 | # only necessary for the demo, the crate does has no dependencies on these 39 | # 40 | # feature_crossterm_or_termion_must_be_selected to generate one line error message 41 | # instead of many compile error messages, if neither crossterm nor termion are selected. 42 | feature_crossterm_or_termion_must_be_selected = [] 43 | crossterm = ["ratatui/crossterm", "feature_crossterm_or_termion_must_be_selected"] 44 | termion = ["ratatui/termion", "feature_crossterm_or_termion_must_be_selected"] 45 | formatter = [] 46 | 47 | # Docs.rs-specific configuration required to enable documentation of 48 | # code requiring optional features. 49 | [package.metadata.docs.rs] 50 | # Document all features 51 | all-features = true 52 | # Defines the configuration attribute `docsrs` 53 | rustdoc-args = ["--cfg", "docsrs"] 54 | 55 | [[example]] 56 | name="demo" 57 | required-features=["feature_crossterm_or_termion_must_be_selected"] 58 | -------------------------------------------------------------------------------- /DEV_NOTES.md: -------------------------------------------------------------------------------- 1 | # Release process 2 | 3 | ## Prepare documentation 4 | 5 | Run first `cargo rdme` and then decide on `cargo rdme --force` 6 | 7 | ## Update Changelog and Cargo.toml 8 | 9 | Execute along the lines of: 10 | 1. `release-plz update`, then check in the versioned files. 11 | 2. `git push` 12 | 3. wait for github runners are completed 13 | 4. `git tag` and `git push --tags` 14 | 5. `cargo publish` 15 | 16 | # Update demo.gif 17 | 18 | In `doc` folder run `vhs demo.tape`. 19 | Then rename `demo.gif` to current version and update Readme - currently via lib.rs 20 | 21 | There is another `demo-short.tape`, which is used for the demo in ratatui website. 22 | 23 | # Needed tools on macos 24 | 25 | ```sh 26 | cargo install release-plz 27 | cargo install cargo-rdme 28 | brew install vhs 29 | ``` 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jochen Kiemes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tui-logger 2 | 3 | 4 | 5 | ## Logger with smart widget for the `tui` and `ratatui` crate 6 | 7 | [![dependency status](https://deps.rs/repo/github/gin66/tui-logger/status.svg?service=github&nocache=0_9_1)](https://deps.rs/repo/github/gin66/tui-logger) 8 | ![Build examples](https://github.com/gin66/tui-logger/workflows/Build%20examples/badge.svg?service=github) 9 | 10 | 11 | ### Demo of the widget 12 | 13 | ![Demo](https://github.com/gin66/tui-logger/blob/master/doc/demo_v0.14.4.gif?raw=true) 14 | 15 | ### Documentation 16 | 17 | [Documentation](https://docs.rs/tui-logger/latest/tui_logger/) 18 | 19 | I have stumbled over an excellent AI-generated description of `tui-logger`, which provides surprisingly deep and (mostly) correct implementation details. 20 | It would have costed me many days to write an equally good description with so many details and diagrams. 21 | This docu can be found [here](https://deepwiki.com/gin66/tui-logger). 22 | 23 | ### Important note for `tui` 24 | 25 | The `tui` crate has been archived and `ratatui` has taken over. 26 | In order to avoid supporting compatibility for an inactive crate, 27 | the v0.9.x releases are the last to support `tui`. In case future bug fixes 28 | are needed, the branch `tui_legacy` has been created to track changes to 0.9.x releases. 29 | 30 | Starting with v0.10 `tui-logger` is `ratatui` only. 31 | 32 | ### Features 33 | 34 | - [X] Logger implementation for the `log` crate 35 | - [X] Logger enable/disable detection via hash table (avoid string compare) 36 | - [X] Hot logger code only copies enabled log messages with timestamp into a circular buffer 37 | - [X] Widgets/move_message() retrieve captured log messages from hot circular buffer 38 | - [X] Lost message detection due to circular buffer 39 | - [X] Log filtering performed on log record target 40 | - [X] Simple Widgets to view logs and configure debuglevel per target 41 | - [X] Logging of enabled logs to file 42 | - [X] Scrollback in log history 43 | - [x] Title of target and log pane can be configured 44 | - [X] `slog` support, providing a Drain to integrate into your `slog` infrastructure 45 | - [X] `tracing` support 46 | - [X] Support to use custom formatter for log events 47 | - [X] Configurable by environment variables 48 | - [ ] Allow configuration of target dependent loglevel specifically for file logging 49 | - [X] Avoid duplicating of module_path and filename in every log record 50 | - [ ] Simultaneous modification of all targets' display/hot logging loglevel by key command 51 | 52 | ### Smart Widget 53 | 54 | Smart widget consists of two widgets. Left is the target selector widget and 55 | on the right side the logging messages view scrolling up. The target selector widget 56 | can be hidden/shown during runtime via key command. 57 | The key command to be provided to the TuiLoggerWidget via transition() function. 58 | 59 | The target selector widget looks like this: 60 | 61 | ![widget](https://github.com/gin66/tui-logger/blob/master/doc/example.png?raw=true) 62 | 63 | It controls: 64 | 65 | - Capturing of log messages by the logger 66 | - Selection of levels for display in the logging message view 67 | 68 | The two columns have the following meaning: 69 | 70 | - Code EWIDT: E stands for Error, W for Warn, Info, Debug and Trace. 71 | + Inverted characters (EWIDT) are enabled log levels in the view 72 | + Normal characters show enabled capturing of a log level per target 73 | + If any of EWIDT are not shown, then the respective log level is not captured 74 | - Target of the log events can be defined in the log e.g. `warn!(target: "demo", "Log message");` 75 | 76 | ### Smart Widget Key Commands 77 | ```rust 78 | | KEY | ACTION 79 | |----------|-----------------------------------------------------------| 80 | | h | Toggles target selector widget hidden/visible 81 | | f | Toggle focus on the selected target only 82 | | UP | Select previous target in target selector widget 83 | | DOWN | Select next target in target selector widget 84 | | LEFT | Reduce SHOWN (!) log messages by one level 85 | | RIGHT | Increase SHOWN (!) log messages by one level 86 | | - | Reduce CAPTURED (!) log messages by one level 87 | | + | Increase CAPTURED (!) log messages by one level 88 | | PAGEUP | Enter Page Mode and scroll approx. half page up in log history. 89 | | PAGEDOWN | Only in page mode: scroll 10 events down in log history. 90 | | ESCAPE | Exit page mode and go back to scrolling mode 91 | | SPACE | Toggles hiding of targets, which have logfilter set to off 92 | ``` 93 | 94 | The mapping of key to action has to be done in the application. The respective TuiWidgetEvent 95 | has to be provided to TuiWidgetState::transition(). 96 | 97 | Remark to the page mode: The timestamp of the event at event history's bottom line is used as 98 | reference. This means, changing the filters in the EWIDT/focus from the target selector window 99 | should work as expected without jumps in the history. The page next/forward advances as 100 | per visibility of the events. 101 | 102 | ### Basic usage to initialize logger-system: 103 | ```rust 104 | #[macro_use] 105 | extern crate log; 106 | //use tui_logger; 107 | 108 | fn main() { 109 | // Early initialization of the logger 110 | 111 | // Set max_log_level to Trace 112 | tui_logger::init_logger(log::LevelFilter::Trace).unwrap(); 113 | 114 | // Set default level for unknown targets to Trace 115 | tui_logger::set_default_level(log::LevelFilter::Trace); 116 | 117 | // code.... 118 | } 119 | ``` 120 | 121 | For use of the widget please check examples/demo.rs 122 | 123 | ### Demo 124 | 125 | Run demo using termion: 126 | 127 | ```rust 128 | cargo run --example demo --features termion 129 | ``` 130 | 131 | Run demo with crossterm: 132 | 133 | ```rust 134 | cargo run --example demo --features crossterm 135 | ``` 136 | 137 | Run demo using termion and simple custom formatter in bottom right log widget: 138 | 139 | ```rust 140 | cargo run --example demo --features termion,formatter 141 | ``` 142 | 143 | ### Configuration by environment variables 144 | 145 | `tui.logger` uses `env-filter` crate to support configuration by a string or an environment variable. 146 | This is an opt-in by call to one of these two functions. 147 | ```rust 148 | pub fn set_env_filter_from_string(filterstring: &str) {} 149 | pub fn set_env_filter_from_env(env_name: Option<&str>) {} 150 | ``` 151 | Default environment variable name is `RUST_LOG`. 152 | 153 | ### `slog` support 154 | 155 | `tui-logger` provides a [`TuiSlogDrain`] which implements `slog::Drain` and will route all records 156 | it receives to the `tui-logger` widget. 157 | 158 | Enabled by feature "slog-support" 159 | 160 | ### `tracing-subscriber` support 161 | 162 | `tui-logger` provides a [`TuiTracingSubscriberLayer`] which implements 163 | `tracing_subscriber::Layer` and will collect all events 164 | it receives to the `tui-logger` widget 165 | 166 | Enabled by feature "tracing-support" 167 | 168 | ### Custom filtering 169 | ```rust 170 | #[macro_use] 171 | extern crate log; 172 | //use tui_logger; 173 | use env_logger; 174 | 175 | fn main() { 176 | // Early initialization of the logger 177 | let drain = tui_logger::Drain::new(); 178 | // instead of tui_logger::init_logger, we use `env_logger` 179 | env_logger::Builder::default() 180 | .format(move |buf, record| 181 | // patch the env-logger entry through our drain to the tui-logger 182 | Ok(drain.log(record)) 183 | ).init(); // make this the global logger 184 | // code.... 185 | } 186 | ``` 187 | 188 | ### Custom formatting 189 | 190 | For experts only ! Configure along the lines: 191 | ```rust 192 | use tui_logger::LogFormatter; 193 | 194 | let formatter = MyLogFormatter(); 195 | 196 | TuiLoggerWidget::default() 197 | .block(Block::bordered().title("Filtered TuiLoggerWidget")) 198 | .formatter(formatter) 199 | .state(&filter_state) 200 | .render(left, buf); 201 | ``` 202 | The example demo can be invoked to use a custom formatter as example for the bottom right widget. 203 | 204 | 205 | 206 | ### Internals 207 | 208 | For logging there are two circular buffers in use: 209 | * "hot" buffer, which is written to during any logging macro invocation 210 | * main buffer, which holds events to be displayed by the widgets. 211 | 212 | The size of the "hot" buffer is 1000 and can be modified by `set_hot_buffer_depth()`. 213 | The size of the main buffer is 10000 and can be modified by `set_buffer_depth()`. 214 | 215 | Reason for this scheme: The main buffer is locked for a while during widget updates. 216 | In order to avoid blocking the log-macros, this scheme is in use. 217 | 218 | The copy from "hot" buffer to main buffer is performed by a call to `move_events()`, 219 | which is done in a cyclic task, which repeats every 10 ms, or when the hot buffer is half full. 220 | 221 | In versions <0.13 log messages may have been lost, if the widget wasn't drawn. 222 | 223 | ```mermaid 224 | flowchart LR 225 | Logging["Logging Macros"] --> Capture["CAPTURE Filter"] --> HotBuffer["Hot Buffer (1000 entries)"] 226 | 227 | MoveEvents["move_events()"] 228 | HotBuffer --> MoveEvents 229 | MoveEvents --> MainBuffer["Main Buffer (10000 entries)"] 230 | 231 | MainBuffer --- Show1["SHOW Filter"] --- Widget1["Widget 1"] 232 | MainBuffer --- Show2["SHOW Filter"] --- Widget2["Widget 2"] 233 | MainBuffer --- ShowN["SHOW Filter"] --- Widget3["Widget N"] 234 | 235 | Config1["set_hot_buffer_depth()"] -.-> HotBuffer 236 | Config2["set_buffer_depth()"] -.-> MainBuffer 237 | 238 | subgraph Triggers["Triggers"] 239 | direction TB 240 | T1["Every 10ms"] 241 | T2["Hot buffer 50% full"] 242 | end 243 | 244 | Triggers -.-> MoveEvents 245 | 246 | note["Note: Main buffer locks during widget updates"] 247 | note -.-> MainBuffer 248 | ``` 249 | 250 | ### THANKS TO 251 | 252 | * [Florian Dehau](https://github.com/fdehau) for his great crate [tui-rs](https://github.com/fdehau/tui-rs) 253 | * [Antoine Büsch](https://github.com/abusch) for providing the patches to tui-rs v0.3.0 and v0.6.0 254 | * [Adam Sypniewski](https://github.com/ajsyp) for providing the patches to tui-rs v0.6.2 255 | * [James aka jklong](https://github.com/jklong) for providing the patch to tui-rs v0.7 256 | * [icy-ux](https://github.com/icy-ux) for adding slog support and example 257 | * [alvinhochun](https://github.com/alvinhochun) for updating to tui 0.10 and crossterm support 258 | * [brooksmtownsend](https://github.com/brooksmtownsend) Patch to remove verbose timestamp info 259 | * [Kibouo](https://github.com/Kibouo) Patch to change Rc/Refcell to thread-safe counterparts 260 | * [Afonso Bordado](https://github.com/afonso360) for providing the patch to tui-rs v0.17 261 | * [Benjamin Kampmann](https://github.com/gnunicorn) for providing patch to tui-rs v0.18 262 | * [Paul Sanders](https://github.com/pms1969) for providing patch in [issue #30](https://github.com/gin66/tui-logger/issues/30) 263 | * [Ákos Hadnagy](https://github.com/ahadnagy) for providing patch in [#31](https://github.com/gin66/tui-logger/issues/31) for tracing-subscriber support 264 | * [Orhun Parmaksız](https://github.com/orhun) for providing patches in [#33](https://github.com/gin66/tui-logger/issues/33), [#34](https://github.com/gin66/tui-logger/issues/34), [#37](https://github.com/gin66/tui-logger/issues/37) and [#46](https://github.com/gin66/tui-logger/issues/46) 265 | * [purephantom](https://github.com/purephantom) for providing patch in [#42](https://github.com/gin66/tui-logger/issues/42) for ratatui update 266 | * [Badr Bouslikhin](https://github.com/badrbouslikhin) for providing patch in [#47](https://github.com/gin66/tui-logger/issues/47) for ratatui update 267 | * [ganthern](https://github.com/ganthern) for providing patch in [#49](https://github.com/gin66/tui-logger/issues/49) for tui support removal 268 | * [Linda_pp](https://github.com/rhysd) for providing patch in [#51](https://github.com/gin66/tui-logger/issues/51) for Cell:set_symbol 269 | * [Josh McKinney](https://github.com/joshka) for providing patch in 270 | [#56](https://github.com/gin66/tui-logger/issues/56) for Copy on TuiWidgetEvent and 271 | TuiLoggerWidget 272 | * [nick42d](https://github.com/nick42d) for providing patch in 273 | [#63](https://github.com/gin66/tui-logger/issues/63) for semver checks, [#74](https://github.com/gin66/tui-logger/pull/74) and [#87](https://github.com/gin66/tui-logger/issues/87) 274 | * [Tom Groenwoldt](https://github.com/tomgroenwoldt) for providing patch in [#65](https://github.com/gin66/tui-logger/issues/65) for ratatui update 275 | * [Kevin](https://github.com/doesnotcompete) for providing patch in [#71](https://github.com/issues/71) 276 | * [urizennnn](https://github.com/urizennnn) for providing patch in [#72](https://github.com/issues/72) 277 | * [Earthgames](https://github.com/Earthgames) for providing patch in [#84](https://github.com/issues/84) to fix panic for unicode characters 278 | 279 | ### Star History 280 | 281 | [![Star History Chart](https://api.star-history.com/svg?repos=gin66/tui-logger&type=Date)](https://star-history.com/#gin66/tui-logger&Date) 282 | 283 | License: MIT 284 | -------------------------------------------------------------------------------- /bacon.toml: -------------------------------------------------------------------------------- 1 | # This is a configuration file for the bacon tool 2 | # 3 | # Bacon repository: https://github.com/Canop/bacon 4 | # Complete help on configuration: https://dystroy.org/bacon/config/ 5 | # You can also check bacon's own bacon.toml file 6 | # as an example: https://github.com/Canop/bacon/blob/main/bacon.toml 7 | 8 | default_job = "check" 9 | 10 | [jobs.check] 11 | command = ["cargo", "check", "--color", "always"] 12 | need_stdout = false 13 | 14 | # This is a helpful job to check that the demo compiles with the crossterm 15 | # feature enabled. This and the termion feature are mutually exclusive. 16 | [jobs.check-crossterm] 17 | command = ["cargo", "check", "--all-targets", "--features", "crossterm", "--color", "always"] 18 | need_stdout = false 19 | 20 | # This is a helpful job to check that the demo compiles with the termion 21 | # feature enabled. This and the crossterm feature are mutually exclusive. 22 | [jobs.check-termion] 23 | command = ["cargo", "check", "--all-targets", "--features", "termion", "--color", "always"] 24 | need_stdout = false 25 | 26 | [jobs.clippy] 27 | command = [ 28 | "cargo", "clippy", 29 | "--color", "always", 30 | ] 31 | need_stdout = false 32 | 33 | [jobs.test] 34 | command = [ 35 | "cargo", "test", "--libs", "--color", "always", 36 | "--", "--color", "always", # see https://github.com/Canop/bacon/issues/124 37 | ] 38 | need_stdout = true 39 | 40 | [jobs.doc] 41 | command = ["cargo", "doc", "--color", "always", "--no-deps"] 42 | need_stdout = false 43 | 44 | # If the doc compiles, then it opens in your browser and bacon switches 45 | # to the previous job 46 | [jobs.doc-open] 47 | command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] 48 | need_stdout = false 49 | on_success = "back" # so that we don't open the browser at each change 50 | 51 | # You may define here keybindings that would be specific to 52 | # a project, for example a shortcut to launch a specific job. 53 | # Shortcuts to internal functions (scrolling, toggling, etc.) 54 | # should go in your personal global prefs.toml file instead. 55 | [keybindings] 56 | # alt-m = "job:my-job" 57 | 1 = "job:check-crossterm" 58 | 2 = "job:check-termion" 59 | -------------------------------------------------------------------------------- /doc/demo-short.tape: -------------------------------------------------------------------------------- 1 | # VHS documentation 2 | # 3 | # Output: 4 | # Output .gif Create a GIF output at the given 5 | # Output .mp4 Create an MP4 output at the given 6 | # Output .webm Create a WebM output at the given 7 | # 8 | # Require: 9 | # Require Ensure a program is on the $PATH to proceed 10 | # 11 | # Settings: 12 | # Set FontSize Set the font size of the terminal 13 | # Set FontFamily Set the font family of the terminal 14 | # Set Height Set the height of the terminal 15 | # Set Width Set the width of the terminal 16 | # Set LetterSpacing Set the font letter spacing (tracking) 17 | # Set LineHeight Set the font line height 18 | # Set LoopOffset % Set the starting frame offset for the GIF loop 19 | # Set Theme Set the theme of the terminal 20 | # Set Padding Set the padding of the terminal 21 | # Set Framerate Set the framerate of the recording 22 | # Set PlaybackSpeed Set the playback speed of the recording 23 | # Set MarginFill Set the file or color the margin will be filled with. 24 | # Set Margin Set the size of the margin. Has no effect if MarginFill isn't set. 25 | # Set BorderRadius Set terminal border radius, in pixels. 26 | # Set WindowBar Set window bar type. (one of: Rings, RingsRight, Colorful, ColorfulRight) 27 | # Set WindowBarSize Set window bar size, in pixels. Default is 40. 28 | # Set TypingSpeed