Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colored output (issues #65) #141

Merged
merged 22 commits into from
Mar 29, 2023
Merged

Colored output (issues #65) #141

merged 22 commits into from
Mar 29, 2023

Conversation

lawrence910426
Copy link
Contributor

Implemented issues #65.

sebs/color.py Outdated
class ColoredPrinter:
@staticmethod
def print(color, logging_instance, message):
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we still display milliseconds in the timestamp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it. Fixed :D

sebs.py Outdated
output_dir = sebs.utils.create_output(output_dir, preserve_out, verbose)
sebs_client.logging.info("Created experiment output at {}".format(output_dir))
output_dir = sebs.utils.create_output(output_dir, preserve_out, verbose)
ColoredPrinter.print(Colors.STATUS, sebs_client.logging, "Created experiment output at {}".format(output_dir))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will work for all calls you replaced in the CLI file sebs.py. All other logging functionalities will not get colors.

We already have a logging base client. All other classes inherit from this class and later call self.logging.{logging_call}. Perhaps
Perhaps we could implement it there, such that every call in every class in the project would go through your coloring scheme?

Copy link
Collaborator

Choose a reason for hiding this comment

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

One possible implementation is to add to the logging base a @property function called logging that would return your colored wrapper instead of the original logger. This should seamlessly affect the entire project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have implemented all wrappers for logging, critical, error, warning, info and debug. Each of them are mapped to the corresponding appropriate colors.

sebs.py Outdated
@@ -121,8 +122,8 @@ def parse_common_params(
logging_filename = os.path.abspath(os.path.join(output_dir, output_file))

sebs_client = sebs.SeBS(cache, output_dir, verbose, logging_filename)
output_dir = sebs.utils.create_output(output_dir, preserve_out, verbose)
sebs_client.logging.info("Created experiment output at {}".format(output_dir))
output_dir = sebs.utils.create_output(output_dir, preserve_out, verbose)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please remove the trailing whitespace :-) Running tools/linting.py sebs should help.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have reverted sebs.py so there is no need to worry about the trailing whitespaces :D

sebs/color.py Outdated
@@ -0,0 +1,17 @@
import click
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like the approach to a dedicated class! What do you think about placing it in sebs/utils.py instead of a separate file? It's quite small.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK :D
I have put it in the very bottom of sebs/utils.py

@mcopik
Copy link
Collaborator

mcopik commented Mar 22, 2023

@lawrence910426 Thank you so much for your contribution! The CLI output looks much better already :-)

I left a few comments on the review - most of them are super simple. I think that if we move the class to LogginBase, this will be a really nice improvement since the entire project will be able to benefit from this improved output.

@lawrence910426
Copy link
Contributor Author

I have added a few more commits and fixed the problems mentioned. Thank you @mcopik again for your advising (^ ^/)

sebs.py Outdated
@@ -17,6 +17,7 @@
from sebs.utils import update_nested_dict, catch_interrupt
from sebs.faas import System as FaaSSystem
from sebs.faas.function import Trigger
from sebs.color import Colors, ColoredPrinter

Choose a reason for hiding this comment

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

@lawrence910426 This line may be unnecessary and may be forgotten to delete.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Good catch - this is now causing import error :)

sebs.py Outdated
@@ -17,6 +17,7 @@
from sebs.utils import update_nested_dict, catch_interrupt
from sebs.faas import System as FaaSSystem
from sebs.faas.function import Trigger
from sebs.color import Colors, ColoredPrinter
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good catch - this is now causing import error :)

sebs/utils.py Outdated
@@ -168,21 +171,26 @@ class LoggingBase:
def __init__(self):
uuid_name = str(uuid.uuid4())[0:4]
if hasattr(self, "typename"):
self.logging = logging.getLogger(f"{self.typename()}-{uuid_name}")
self._logging = logging.getLogger(f"{self.typename()}-{uuid_name}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should also use the typename-uuid combination in the colored printer. It makes it much easier to debug experiments, especially the parallel ones.

Old

01:11:22,963 INFO AWS.HTTPTrigger-6c46: Invoke of function was successful

New, colored

[01:11:22.963650] Invoke of function was successful

The INFO part we do not need :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I got it fixed. Now it would output something like this.

image

sebs/utils.py Outdated

@property
def logging_handlers(self) -> LoggingHandlers:
return self._logging_handlers

@property
def logging(self) -> logging.Logger:
Copy link
Collaborator

Choose a reason for hiding this comment

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

The static return type is not correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it. I have it fixed.

sebs/utils.py Show resolved Hide resolved
sebs/utils.py Outdated

def _print(self, message, color):
timestamp = datetime.datetime.now().strftime("%H:%M:%S.%f")
self.logging_instance.info(message)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think that is the last remaining issue - right now, the output is duplicated because we have defined StreamHandler above. I think your approach of printing to logging_instance is correct because we want to also write to file. But we should now disable StreamHandler and configure the ColorPrinter with verbose flag to decide if debug should be printed or not,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have amended ColoredPrinter to ColoredWrapper, which would only propagate logging instructions to _logger if filename in LoggingHandler is present. Moreover, StreamHandler is removed, and its functions are implemented in ColoredWrapper now.

@mcopik
Copy link
Collaborator

mcopik commented Mar 25, 2023

@lawrence910426 Thanks for your hard work! I think it's almost there :) Please make sure to test to verify that the output is correct, such that we do not get duplicated output :)

Looks really nice on my CLI!

@lawrence910426
Copy link
Contributor Author

Hello @mcopik, I have these issues fixed :)

  1. Output typename-uuid for easier debugs.
  2. The static return type is now ColoredWrapper which is a wrapper that imitate a normal logging instance.
  3. Changed the order of properties for mypy to work
  4. Duplicated output on stdout

I have verified the output and it fits our expectations.
image

Thank you again for your reviewing! This would surely made CLI more beautiful :)

@mcopik
Copy link
Collaborator

mcopik commented Mar 29, 2023

@lawrence910426 LGTM, thank you so much! This will make it much easier to catch warnings and errors, particularly in the verbose output mode :)

@mcopik mcopik merged commit 518fbbf into spcl:master Mar 29, 2023
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.

3 participants