Giter Club home page Giter Club logo

tui-logger's Introduction

Build Status

tui-logger

Logger with smart widget for the tui and ratatui crate

dependency status Build examples

Demo of the widget

Demo

Documentation

Documentation

Important note for tui

The tui crate has been archived and ratatui has taken over. In order to avoid supporting compatibility for an inactive crate, the v0.9.x releases are the last to support tui. In case future bug fixes are needed, the branch tui_legacy has been created to track changes to 0.9.x releases.

Starting with v0.10 tui-logger is ratatui only.

Features

  • Logger implementation for the log crate
  • Logger enable/disable detection via hash table (avoid string compare)
  • Hot logger code only copies enabled log messages with timestamp into a circular buffer
  • Widgets/move_message() retrieve captured log messages from hot circular buffer
  • Lost message detection due to circular buffer
  • Log filtering performed on log record target
  • Simple Widgets to view logs and configure debuglevel per target
  • Logging of enabled logs to file
  • Scrollback in log history
  • Title of target and log pane can be configured
  • slog support, providing a Drain to integrate into your slog infrastructure
  • tracing support
  • Allow configuration of target dependent loglevel specifically for file logging
  • Avoid duplicating of target, module and filename in every log record
  • Simultaneous modification of all targets' display/hot logging loglevel by key command

Smart Widget

Smart widget consists of two widgets. Left is the target selector widget and on the right side the logging messages view scrolling up. The target selector widget can be hidden/shown during runtime via key command. The key command to be provided to the TuiLoggerWidget via transition() function.

The target selector widget looks like this:

widget

It controls:

  • Capturing of log messages by the logger
  • Selection of levels for display in the logging message view

The two columns have the following meaning:

  • Code EWIDT: E stands for Error, W for Warn, Info, Debug and Trace.
    • Inverted characters (EWIDT) are enabled log levels in the view
    • Normal characters show enabled capturing of a log level per target
    • If any of EWIDT are not shown, then the respective log level is not captured
  • Target of the log events can be defined in the log e.g. warn!(target: "demo", "Log message");

Smart Widget Key Commands

|  KEY     | ACTION
|----------|-----------------------------------------------------------|
| h        | Toggles target selector widget hidden/visible
| f        | Toggle focus on the selected target only
| UP       | Select previous target in target selector widget
| DOWN     | Select next target in target selector widget
| LEFT     | Reduce SHOWN (!) log messages by one level
| RIGHT    | Increase SHOWN (!) log messages by one level
| -        | Reduce CAPTURED (!) log messages by one level
| +        | Increase CAPTURED (!) log messages by one level
| PAGEUP   | Enter Page Mode and scroll approx. half page up in log history.
| PAGEDOWN | Only in page mode: scroll 10 events down in log history.
| ESCAPE   | Exit page mode and go back to scrolling mode
| SPACE    | Toggles hiding of targets, which have logfilter set to off

The mapping of key to action has to be done in the application. The respective TuiWidgetEvent has to be provided to TuiWidgetState::transition().

Remark to the page mode: The timestamp of the event at event history's bottom line is used as reference. This means, changing the filters in the EWIDT/focus from the target selector window should work as expected without jumps in the history. The page next/forward advances as per visibility of the events.

Basic usage to initialize logger-system:

#[macro_use]
extern crate log;
//use tui_logger;

fn main() {
    // Early initialization of the logger

    // Set max_log_level to Trace
    tui_logger::init_logger(log::LevelFilter::Trace).unwrap();

    // Set default level for unknown targets to Trace
    tui_logger::set_default_level(log::LevelFilter::Trace);

    // code....
}

For use of the widget please check examples/demo.rs

Demo

Run demo using termion:

cargo run --example demo --features termion

Run demo with crossterm:

cargo run --example demo --features crossterm

slog support

tui-logger provides a TuiSlogDrain which implements slog::Drain and will route all records it receives to the tui-logger widget.

Enabled by feature "slog-support"

tracing-subscriber support

tui-logger provides a TuiTracingSubscriberLayer which implements tracing_subscriber::Layer and will collect all events it receives to the tui-logger widget

Enabled by feature "tracing-support"

Custom filtering

#[macro_use]
extern crate log;
//use tui_logger;
use env_logger;

fn main() {
    // Early initialization of the logger
    let drain = tui_logger::Drain::new();
    // instead of tui_logger::init_logger, we use `env_logger`
    env_logger::Builder::default()
        .format(move |buf, record|
            // patch the env-logger entry through our drain to the tui-logger
            Ok(drain.log(record))
        ).init(); // make this the global logger
    // code....
}

Applications using tui-logger

THANKS TO

Star History

Star History Chart

License: MIT

tui-logger's People

Contributors

abusch avatar afonso360 avatar ahadnagy avatar ajsyp avatar alvinhochun avatar angelonfira avatar bbigras avatar brooksmtownsend avatar dylan-dpc avatar gin66 avatar gnunicorn avatar ilaborie avatar jaskij avatar jlongmore-cog avatar joshka avatar kibouo avatar noyez avatar orhun avatar purephantom avatar rhysd avatar robofiddle avatar wuelle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

tui-logger's Issues

Allow log scrolling

Currently, if logs scroll out of the frame, there is no way (other than changing log levels) to view logs that have scrolled out of the frame. This can be problematic in just-noisy-enough applications where there are enough logs to overflow out of the window, as there's no way to view if they were successful or not.

It would be awesome if there was a way to scroll the output log (potentially by focusing on the log widget, and using a KeyModifier + UP/DOWN). I see in your implementation that you use the offset field of TuiWidgetInnerState to control how far the window has scrolled, but since that field is private I was unable to make any manual modifications.

I'm using the logger widget pretty extensively in the wash project on GitHub, and would be happy to contribute a PR if we wanted to talk about a solution here... I implemented scrolling in an output window by using the SHIFT+UP/DOWN key combination to increase/decrease the scroll offset. Code for scrolling up.

It would also be neat to be able to set the title log / title target attributes of the TuiLoggerSmartWidget. I don't intend on replacing them, but simply buffering them with a space character on each side increases readability with the widget borders in my opinion. You can see below the r seems almost connects with the border.
image

Also, please let me know if I'm missing an obvious way to scroll or do this as the crate exists today (I'm using version 0.4.13 with the "tui-crossterm" feature).

Thanks for the awesome project.

Slog support

It'd be nice if slogger was supported alongside log

Use without tui widget

Hello! Love this crate, we've been using it to log to our TUI app.

I'm wondering if it's possible to simply display the log output to the terminal without running with TUI? Sometimes we disable TUI for debug purposes. I tried running without launching TUI using RUST_LOG=info cargo run but no log info is output to the terminal.

Ratatui.rs widget showcase

Hey there,
I'm putting together a widget showcase page at https://ratatui.rs/showcase/third-party-widgets/ and would like to add tui-logger. The demo right now seems a bit complex to use as it shows all the possible features. Would you be interested in creating a simpler demo that just shows the main aspect in a small area like the examples we have on the site already? I'm happy to create the actual gif if you have a good simple demo (though the process is fairly simple - see https://github.com/ratatui-org/website/tree/main/code/widget-showcase-third-party)

Migrate from tui to ratatui

With the recent release of ratatui, the tui-rs revival project, I think it would be best to support the new version to help people convert over.

There are a few other crates moving already, like ansi-to-tui.

Multiple log widgets displaying different log targets.

Firstly, Thank you for producing this crate. I have thus far found it excellent.

What I'd like to do is have 2 separate log widgets, both displaying different log data dependent on the log target. I'm pretty sure I know the answer is that it's just not possible, but I was wondering if you could shed some insight as to what I might need to do to achieve that goal.

I basically want log::info!(target: "x", "This is log X"); and log::info!(target: "y", "This is log Y"); to show up in different log panes (widgets).

 ---Logs 1-----------------------Logs 2-----------------------
| This is log X              | This is log Y                  |
|                            |                                |
 -------------------------------------------------------------

☝️ A bit like that; stylistic hell I know 😃

using tui-logger with tracing

Thanks for putting together this package.

I'm not able to get this to work with tracing unfortunately. Do you have any idea what might be going on?

I have the following code in the main.rs:

use tracing_subscriber::{
  self, filter::EnvFilter, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer,
};

fn main() {
  let directory = ...;
  let log_path = directory.join("debug.log");
  let log_file = std::fs::File::create(&log_path)?;
  let file_subscriber = tracing_subscriber::fmt::layer()
    .with_file(true)
    .with_line_number(true)
    .with_writer(log_file)
    .with_target(false)
    .with_ansi(false)
    .with_filter(EnvFilter::from_default_env());
  tracing_subscriber::registry().with(file_subscriber).with(tui_logger::tracing_subscriber_layer()).init();
  ...
}

And I'm using the following render function:

  fn render(f: &mut super::Frame<'_>, rect: tui::layout::Rect) {
    let state = TuiWidgetState::new().set_default_display_level(LevelFilter::Trace);
    let w = TuiLoggerWidget::default()
      .style_error(Style::default().fg(Color::Red))
      .style_debug(Style::default().fg(Color::Green))
      .style_warn(Style::default().fg(Color::Yellow))
      .style_trace(Style::default().fg(Color::Magenta))
      .style_info(Style::default().fg(Color::Cyan))
      .state(&state);
    f.render_widget(w, rect);
  }

I'm not getting any log output if I do this. If I use the SmartWidget, I get the borders but no logs. I'm getting logs in my file from tracing, just not in the TuiLoggerWidget.

Any idea what might be going on here?

Breaking change, termion dependency for ratatui

0.9.3, change introduced in c3ef34e, enables termion in ratatui when using ratatui-support feature. This is breaking change on systems which are not supported by termion (i.e., mainly Windows). This could be avoided by allowing users to just use ratatui feature, but this crate doesn't compile properly with it since it uses #[cfg(not(feature = "ratatui-support"))].
I think either all cfg expressions should be changed to #[cfg(not(feature = "ratatui"))] or even better #[cfg(feature = "ratatui")], or the latest change in Cargo.toml should be reverted/reconsidered.

Set ratatui as default feature in place of tui

As for 6 August 2023 tui repository is archived fdehau/tui-rs#654.
I think it's time to make ratatui feature default one and tui support as legacy feature.
It might make it easier to keep up with new versions of ratatui (as for now tui-logger 0.9.5 doesn't work with ratatui 0.23.0.

Terminal window resize may crash the program

Quickly resizing from big window to small (~25 chars width) crashes the program. Tested using Kitty terminal.

thread 'main' panicked at /home/.../tui-logger-0.11.0/src/lib.rs:1203:33:
attempt to subtract with overflow

After upgrading ratatui from 0.20.1 to 0.21.1: trait bound `TuiLoggerWidget<'_>: Widget` is not satisfied

error[E0277]: the trait bound `TuiLoggerWidget<'_>: Widget` is not satisfied
   --> src/ui.rs:125:21
    |
125 |     f.render_widget(tui_w, chunks[4]);
    |       ------------- ^^^^^ the trait `Widget` is not implemented for `TuiLoggerWidget<'_>`
    |       |
    |       required by a bound introduced by this call
    |
    = help: the following other types implement trait `Widget`:
              BarChart<'a>
              Canvas<'a, F>
              Chart<'a>
              Gauge<'a>
              LineGauge<'a>
              List<'a>
              Paragraph<'a>
              Sparkline<'a>
            and 4 others
    let tui_w: TuiLoggerWidget = TuiLoggerWidget::default()
        .block(
            Block::default()
                .title("Logs")
                .border_style(Style::default().fg(Color::White))
                .borders(Borders::ALL),
        )
        .output_separator('|')
        .output_timestamp(Some("%F %H:%M:%S".to_string()))
        .output_level(Some(TuiLoggerLevelOutput::Long))
        .output_target(false)
        .output_file(false)
        .output_line(false)
        .style_error(Style::default().fg(Color::Red))
        .style_debug(Style::default().fg(Color::Green))
        .style_warn(Style::default().fg(Color::Yellow))
        .style_trace(Style::default().fg(Color::Magenta))
        .style_info(Style::default().fg(Color::Cyan))
        .state(&app.states[0]);

// ..

f.render_widget(tui_w, chunks[4]);

RUSTSEC-2020-0071: Potential segfault in the time crate

There is a medium level security advisory for tui-logger:

$ cargo audit

Crate:     time
Version:   0.1.45
Title:     Potential segfault in the time crate
Date:      2020-11-18
ID:        RUSTSEC-2020-0071
URL:       https://rustsec.org/advisories/RUSTSEC-2020-0071
Severity:  6.2 (medium)
Solution:  Upgrade to >=0.2.23
Dependency tree:
time 0.1.45
└── chrono 0.4.24
    └── tui-logger 0.9.0

error: 1 vulnerability found!

crossterm feature uses termion?

I tried compiling your examples with

cargo run --example demo --no-default-features -F ratatui-support,examples-ratatui-crossterm

and

cargo run --example demo --no-default-features -F tui-rs,examples-tui-crossterm

Both give errors that look like termion is still being used instead of crossterm

❯ cargo run --example demo --no-default-features -F ratatui-support,examples-ratatui-crossterm                                                                    09:54:21
   Compiling crossterm_winapi v0.9.1
   Compiling winapi-util v0.1.5
   Compiling termion v1.5.6
   Compiling regex-automata v0.3.6
   Compiling chrono v0.4.26
   Compiling is-terminal v0.4.9
error[E0433]: failed to resolve: maybe a missing crate `sys`?
  --> C:\Users\username\.cargo\registry\src\index.crates.io-6f17d22bba15001f\termion-1.5.6\src\lib.rs:24:9
   |
24 | pub use sys::size::terminal_size;
   |         ^^^ maybe a missing crate `sys`?
   |
   = help: consider adding `extern crate sys` to use the `sys` crate

error[E0433]: failed to resolve: maybe a missing crate `sys`?
  --> C:\Users\username\.cargo\registry\src\index.crates.io-6f17d22bba15001f\termion-1.5.6\src\lib.rs:27:9
   |
27 | pub use sys::tty::{is_tty, get_tty};
   |         ^^^ maybe a missing crate `sys`?
   |
   = help: consider adding `extern crate sys` to use the `sys` crate

error[E0433]: failed to resolve: maybe a missing crate `sys`?
 --> C:\Users\username\.cargo\registry\src\index.crates.io-6f17d22bba15001f\termion-1.5.6\src\async.rs:5:5
  |
5 | use sys::tty::get_tty;
  |     ^^^ maybe a missing crate `sys`?
  |
  = help: consider adding `extern crate sys` to use the `sys` crate

... several more of these

Is there a way to compile without termion?

latest version of tui-rs

tui-rs is now 0.6.2 while this crate depends on 0.4.0.
it would complains about 2 different version of tui-rs.

    |
121 |     .block(Block::default().borders(Borders::ALL).title("log"))
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `tui::widgets::block::Block`, found a different struct `tui::widgets::block::Block`
    |
    = note: expected type `tui::widgets::block::Block<'_>` (struct `tui::widgets::block::Block`)
               found type `tui::widgets::block::Block<'_>` (struct `tui::widgets::block::Block`)
note: Perhaps two different versions of crate `tui` are being used?

Add the ability to specify log message formatting

I think tui-logger would greatly benefit from the ability to customize the format of logged messages. It seems that the message format is hardcoded. In my specific case, I'm logging messages from multiple child processes that are sent back to the parent via a pipe. For things like warnings and errors, the "location" that the log is printed from is of no use because it's the same line(s) every time (the place in the parent where the message is read from the pipe and logged in the parent). Additionally, in my case, the logging of the target is redundant noise and I would prefer if it wasn't there. Finally, in long running processes, I can see where H:M:S time stamps aren't enough (think about a process that has uptime in the days, weeks, or longer).

In the absence of a formal way to specify the formatting a simple compromise would be a "passthrough" mode that just logs the string passed to log without any additional formatting or text added (but keeps the coloring / style set).

How to set log format for log file?

I want to include millisecond in the timestamp of log file. It seems that tui-logger doesn't expose this function for file log, buy only output_timestamp for tui.

Cool project!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.