Skip to content

Adding ability to configure colors for console#224

Open
noyez wants to merge 43 commits intoestk:mainfrom
noyez:noyez_configurable_highlight_devel
Open

Adding ability to configure colors for console#224
noyez wants to merge 43 commits intoestk:mainfrom
noyez:noyez_configurable_highlight_devel

Conversation

@noyez
Copy link

@noyez noyez commented Jul 10, 2021

(reopening from PR:#204, now includes tests and docs)

Specifically this useful for dark console backgrounds where the default
for 'Blue' for log level INFO is difficult to read.

Most of the changes are in src/encode/patter/mod.rs. I added default
parameters for deserializing. I added a function to describe the default
pattern string, and defined that at the top of the source file.
I added a color_map to the Encoder structs which is a HashMap that
defines the LogLovel->Color mapping. The color_map is of type
HashMap<Level, Option<Color>>, if the Option is None, then no styling
is applied.

Docs were added to src/encode/pattern/mod.rs to the function new_with_colormap()
Also, the test function was added fn check_color_hash() to src/encode/pattern/mod.rs which tests a single change to the default color-map then checks the resulting color-map to make that change was made and that remain default colors are unchanged.

TODO/Future: This patch only allows foreground color to be specified.
There are other aspects of styling like bold,italics,background color.
Does it make sense to allow for more detailed styling? That involves
more work and more work for the maintainer. I think foreground color will
probably cover most everyone's cases.

To use, the relevant config change is as follows:

  pattern: "%m"
  color_map:
    INFO: Blue
    TRACE: Black

Related: issue:#17, PR:#186, PR:#204
Continued from: PR:#194

gadunga and others added 30 commits July 22, 2020 13:44
* Rename to config_parsing

* Add workflows for devel
* Reorganize config

* allow missing docs so tests run

* lint abatement

* some renames
* Use anyhow/thiserror
Co-authored-by: shmapdy <richard.meester@gmail.com>
* WIP custom err handling

* Compiling

* Add an  method to the public api

* re-enable Debug
Co-authored-by: braindead <braindeaded@protonmail.com>
…stk#186)

* pattern encoder: Set trace to default color, reset formatting after

* Fix formatting of last commit

* lol apparently rustfmt doesn't like commas? idk if this will work

* Set trace color to cyan
Specifically this useful for dark console backgrounds where the default
for 'Blue' for log level INFO is difficult to read.

Most of the changes are in `src/encode/patter/mod.rs`. I added default
parameters for deserializing. I added a function to describe the default
pattern string, and defined that at the top of the source file.
I added a `color_map` to the Encoder structs which is a HashMap that
defines the LogLovel->Color mapping. The color_map is of type
`HashMap<Level, Option<Color>>`, if the Option is None, then no styling
is applied.

TODO: Adding a feature means adding documentation, which isn't complete.
I can do this and add to the PR, however before i continue i want to
make sure this is the direction that the maintiner wants to take.

TODO: Other testing may need to be done. I was testing with `cargo test
--features file` with a modified config option in the yaml test config.
As i am not familiar with this code base there may be other cases that
need to be tested.

TODO/Future: This patch only allows foreground color to be specified.
There are other aspects of styling like bold,italics,background color.
Does it make sense to allow for more detailed styling? That involves
more work and more work for the maintiner. I think forground color will
probably cover most everyone's cases.
@noyez
Copy link
Author

noyez commented Apr 30, 2022

Just merged code w/ v1.1.1.

Was there something missing on this patch that you'd like to see before it gets merged? I thought it was ready go to, but if want to see something more or something changed let me know and i'll accommodate.

@estk
Copy link
Owner

estk commented Apr 30, 2022

Thanks @noyez I'll review and let you know. Let's start by getting the CI passing.

#[derive(Derivative)]
#[derivative(Debug)]
#[derive(Clone, Eq, PartialEq, Hash)]
#[derive(Clone, Eq, PartialEq)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove Hash derive?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cargo was returning an error w/ Hash derived. So i removed it and it complied and cargo test fine (at least w/ rustc 1.60).

   --> src/encode/pattern/mod.rs:657:5
    |
652 | #[derive(Clone, Eq, PartialEq, Hash)]
    |                                ---- in this derive macro expansion
...
657 |     color_map: HashMap<Level, Option<Color>>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Hash` is not implemented for `HashMap<Level, std::option::Option<Color>>`
    |
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll need to keep it derived for semver reasons

match record.level() {
Level::Error => {
w.set_style(Style::new().text(Color::Red).intense(true))?;
if let Some(Some(color)) = color_map.get(&record.level()) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when we get None? or Some(None)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the text is not styled and output as regulate unstyled text.

@estk
Copy link
Owner

estk commented Apr 30, 2022

I left a few comments re. changes that will block us from merging for semver reasons. Also, I had a more general thought: I think that instead of using a HashMap<Level, Option<Color>>, we should probably define a

struct ColorMap {
 info: Color,
 ...
}

#[derive(SmartDefault,...)] 
enum Color {
 #[default]
 Black,
...
}

Then here we can write something structurally correct rather than just procedurally. Does that make sense @noyez ?

/// The pattern encoder's configuration.
#[cfg(feature = "config_parsing")]
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, serde::Deserialize)]
#[derive(Clone, Eq, PartialEq, Debug, Default, serde::Deserialize)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove Hash?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to keep this for semver reasons

#[derive(Clone, Eq, PartialEq, Debug, Default, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PatternEncoderConfig {
#[serde(default = "default_pattern")]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we can change the default rn due to semver reasons.

@noyez
Copy link
Author

noyez commented Apr 30, 2022

Does that make sense @noyez ?

Totally, i can work on this. not today but soon. This approach makes sense and i agree that its probably a better way to handle it instead of using hash map. it shouldn't take much time to make this change.

@estk
Copy link
Owner

estk commented Apr 30, 2022

@noyez thanks for that, and thanks for the work on this!

@noyez noyez force-pushed the noyez_configurable_highlight_devel branch from 60eab70 to 8eb53f9 Compare May 5, 2022 13:21
@noyez noyez force-pushed the noyez_configurable_highlight_devel branch from 8eb53f9 to 225c5ee Compare May 5, 2022 14:59
@estk estk marked this pull request as draft May 5, 2022 15:46
@noyez noyez marked this pull request as ready for review May 5, 2022 21:06
@noyez
Copy link
Author

noyez commented May 5, 2022

Ok, now i believe its ready for your review. Pardon my simple usage of github's PRs. I created a new struct ColorMap, its very basic and simple. It has methods for set(level, color), get(level) and unset(level), the latter just sets the styling to None, which is no styling. I'm not sure this is the best interface, you may want to tweak it, just lmk and i will do it. I did not use SmartDefault since writing a default for the color map is pretty trivial, and SmartDefault wasn't an existing dependency. I tried to add some documentation, but i'm not the best with rustdoc. Its all relatively crude, but its also relatively simple so i didn't see the need to complicate it.

@noyez noyez requested a review from estk June 30, 2022 13:39
@akashlama1998-icloud
Copy link

What is the right syntax to add color? I tried finding it in documentation but wasn't able to 😔. Can someone please help me with that.

@Dirreke
Copy link
Contributor

Dirreke commented Dec 7, 2022

You can use {h({l})} to add color. You can check the documents @akashlama1998-icloud

pattern: "%m"
color_map:
info: Blue
trace: Black
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if this is a test, another color than black should be used here I guess, in order not to assume any terminal color-mode. No matter what color is chosen other than white or black.

}
impl Default for Color {
fn default() -> Self {
Color::Black
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be "None" to match either black or white depending on shell color mode ?

/// A simple color map struct
///
/// You can use this struct to define a custom color map.
/// This can be done using a serializer (i.e. config file) or pragmatically.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: programmatically

trace: None,
debug: None,
info: Some(Color::Blue),
warn: Some(Color::Red),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be orange ?

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorMap {
// in future this represent other aspects of style, like bold/italics, etc.
trace: Option<Color>,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make those pub would allow:
let color_map = ColorMap { info: None, ... } directly

///! # feature = "pattern_encoder"))]
///! # fn f() {
///! let mut log_color_map = ColorMap::default()
///! log_color_map.info_color = Some(log4rs::encode::Color::Cyan);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could not get that to work: info_color does not exists, and members seems private anyway here

///! # }
///! # fn main() {}
///! ```
pub fn new_with_colormap(pattern: &str, color_map: ColorMap) -> PatternEncoder {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels weird to combine new and colors here.
How about keep new, and add a with_color method ?
Something along this:
PatternEncoder::new(pattern).with_color(color_map)

#[cfg_attr(feature = "config_parsing", derive(serde::Deserialize))]
#[cfg_attr(feature = "config_parsing", serde(deny_unknown_fields))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColorMap {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess Option<Color> is ok, but that leaves us to only the few defined in the Color struct.
That would require to add a new entry in the struct Color for arbitrary string, that would be a color such as defined by colorful or other module for instance.

@Creative-Difficulty
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants