feat(verbosity): Allow setting silent or verbose output levels

This commit is contained in:
Radim Karniš
2025-05-21 16:05:53 +02:00
parent 61464101c6
commit 90e3770c67
6 changed files with 114 additions and 24 deletions

View File

@@ -468,11 +468,11 @@ Here is a sample extract, showing a READ_REG command and response:
::
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=1400f43f
TRACE +0.000 Write 14 bytes: c0000a0400000000001400f43fc0
TRACE +0.005 Read 1 bytes: c0
TRACE +0.000 Read 11 bytes: 010a0200620100000000c0
TRACE +0.000 Received full packet: 010a0200620100000000
TRACE +0.000 --- Cmd READ_REG (0x0a) | data_len 4 | wait_response 1 | timeout 3.000 | data 00100040 ---
TRACE +0.000 Write 14 bytes: c0000a04000000000000100040c0
TRACE +0.046 Read 1 bytes: c0
TRACE +0.000 Read 11 bytes: 010a0200090000000000c0
TRACE +0.000 Received full packet: 010a0200090000000000
The +X.XXX value is the time delta (in seconds) since the last trace line.
@@ -485,18 +485,18 @@ Here is a second example showing part of the initial synchronization sequence (l
::
TRACE +0.000 Write 46 bytes:
c000082400000000 0007071220555555 | ...$........ UUU
5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU
5555555555555555 5555555555c0 | UUUUUUUUUUUUU.
TRACE +0.011 Read 1 bytes: c0
TRACE +0.000 Read 63 bytes:
0108040007122055 00000000c0c00108 | ...... U........
0400071220550000 0000c0c001080400 | .... U..........
0712205500000000 c0c0010804000712 | .. U............
205500000000c0c0 01080400071220 | U............
TRACE +0.000 Received full packet: 010804000712205500000000
TRACE +0.000 Received full packet: 010804000712205500000000
TRACE +0.000 Write 46 bytes:
c000082400000000 0007071220555555 | ...$........ UUU
5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU
5555555555555555 5555555555c0 | UUUUUUUUUUUUU.
TRACE +0.012 Read 1 bytes: c0
TRACE +0.000 Read 63 bytes:
0108040007071220 00000000c0c00108 | ....... ........
0400070712200000 0000c0c001080400 | ..... ..........
0707122000000000 c0c0010804000707 | ... ............
122000000000c0c0 01080400070712 | . .............
TRACE +0.000 Received full packet: 010804000707122000000000
TRACE +0.000 Received full packet: 010804000707122000000000
.. important::

View File

@@ -162,3 +162,30 @@ at least one FilterValue for each specified FilterType to be considered. Example
* ``--port-filter serial=7c98d1065267ee11bcc4c8ab93cd958c`` matches ports where the serial number contains the specified text.
See also the `Espressif USB customer-allocated PID repository <https://github.com/espressif/usb-pids>`_
Output Verbosity
----------------
Output verbosity can be controlled using the ``--verbose`` and ``--silent`` flags.
Verbose output: ``--verbose``, ``-v``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _verbose:
The ``--verbose``, ``-v`` flag can be used to show all output without any overwriting or collapsing stages into a single line:
.. code-block:: bash
esptool.py --verbose flash-id
See :ref:`the trace option <tracing-communications>` if you want to dump all serial interactions to the standard output for debugging purposes.
Silent output: ``--silent``, ``-s``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _silent:
The ``--silent``, ``-s`` flag can be used to limit the output to errors only:
.. code-block:: bash
esptool.py -s write-flash 0x0 image.bin

View File

@@ -328,6 +328,10 @@ Esptool allows redirecting output by implementing a custom logger class. This ca
percent = f"{100 * (cur_iter / float(total_iters)):.1f}"
self.print(f"Finished: {percent}%")
def set_verbosity(self, verbosity):
# Set verbosity level not needed in this example
pass
# Replace the default logger with the custom logger
log.set_logger(CustomLogger())
@@ -344,9 +348,10 @@ To ensure compatibility with esptool, the custom logger should re-implement (or
- ``error``: Logs error messages.
- ``stage``: Starts or ends a collapsible output stage.
- ``progress_bar``: Displays a progress bar.
- ``set_verbosity``: Sets the verbosity level for logging.
.. autoclass:: esptool.logger.EsptoolLogger
:members: print, note, warning, error, stage, progress_bar
:members: print, note, warning, error, stage, progress_bar, set_verbosity
:member-order: bysource
These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all output printing should be made using ``log.print()`` (or the respective method, such as ``log.info()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks.

View File

@@ -364,6 +364,18 @@ def check_flash_size(esp: ESPLoader, address: int, size: int) -> None:
is_flag=True,
help="Enable trace-level output of esptool.py interactions.",
)
@click.option(
"--verbose",
"-v",
is_flag=True,
help="Print all output, disable collapsing output stages.",
)
@click.option(
"--silent",
"-s",
is_flag=True,
help="Silence all output except for errors.",
)
@click.option(
"--override-vddsdio",
type=click.Choice(ESP32ROM.OVERRIDE_VDDSDIO_CHOICES),
@@ -383,6 +395,18 @@ def cli(
):
ctx.ensure_object(dict)
ctx.obj.update(kwargs)
if ctx.obj["verbose"] and ctx.obj["silent"]:
raise FatalError(
"Cannot use both --verbose and --silent options at the same time."
)
if ctx.obj["trace"] and ctx.obj["silent"]:
raise FatalError(
"Cannot use both --trace and --silent options at the same time."
)
if ctx.obj["verbose"]:
log.set_verbosity("verbose")
elif ctx.obj["silent"]:
log.set_verbosity("silent")
ctx.obj["invoked_subcommand"] = ctx.invoked_subcommand
ctx.obj["esp"] = getattr(ctx, "esp", None)
log.print(f"esptool.py v{__version__}")

View File

@@ -57,6 +57,13 @@ class TemplateLogger(ABC):
"""
pass
@abstractmethod
def set_verbosity(self, verbosity: str):
"""
Set the verbosity level.
"""
pass
class EsptoolLogger(TemplateLogger):
ansi_red: str = ""
@@ -72,6 +79,8 @@ class EsptoolLogger(TemplateLogger):
_kept_lines: list[str] = []
_smart_features: bool = False
_verbosity: str | None = None
_print_anyway: bool = False
def __new__(cls):
"""
@@ -79,7 +88,7 @@ class EsptoolLogger(TemplateLogger):
"""
if not hasattr(cls, "instance"):
cls.instance = super(EsptoolLogger, cls).__new__(cls)
cls.instance._set_smart_features()
cls.instance.set_verbosity("auto")
return cls.instance
@classmethod
@@ -138,6 +147,8 @@ class EsptoolLogger(TemplateLogger):
"""
Log a plain message. Count newlines if in a collapsing stage.
"""
if self._verbosity == "silent" and not self._print_anyway:
return
if self._stage_active:
# Count the number of newlines in the message
message = "".join(map(str, args))
@@ -145,12 +156,12 @@ class EsptoolLogger(TemplateLogger):
if kwargs.get("end", "\n") == "\n":
self._newline_count += 1
print(*args, **kwargs)
self._print_anyway = False
def note(self, message: str):
"""
Log a Note: message in blue and white.
"""
formatted_message = f"{self.ansi_blue}Note:{self.ansi_normal} {message}"
if self._stage_active:
self._kept_lines.append(formatted_message)
@@ -160,7 +171,6 @@ class EsptoolLogger(TemplateLogger):
"""
Log a Warning: message in yellow and white.
"""
formatted_message = f"{self.ansi_yellow}Warning:{self.ansi_normal} {message}"
if self._stage_active:
self._kept_lines.append(formatted_message)
@@ -170,8 +180,8 @@ class EsptoolLogger(TemplateLogger):
"""
Log an error message in red to stderr.
"""
formatted_message = f"{self.ansi_red}{message}{self.ansi_normal}"
self._print_anyway = True
self.print(formatted_message, file=sys.stderr)
def stage(self, finish: bool = False):
@@ -182,7 +192,6 @@ class EsptoolLogger(TemplateLogger):
Warnings and notes will be saved and printed at the end of the stage.
If terminal doesn't support ANSI escape codes, no collapsing happens.
"""
if finish:
if not self._stage_active:
return
@@ -219,7 +228,6 @@ class EsptoolLogger(TemplateLogger):
Call in a loop to print a progress bar overwriting itself in place.
If terminal doesn't support ANSI escape codes, no overwriting happens.
"""
filled = int(bar_length * cur_iter // total_iters)
if filled == bar_length:
bar = "=" * bar_length
@@ -238,5 +246,28 @@ class EsptoolLogger(TemplateLogger):
def set_logger(self, new_logger):
self.__class__ = new_logger.__class__
def set_verbosity(self, verbosity: str):
"""
Set the verbosity level to one of the following:
- "auto": Enable smart terminal features and colors if supported by the terminal
- "verbose": Enable verbose output (no collapsing output)
- "silent": Disable all output except errors
- "compact": Enable smart terminal features and colors even if not supported
"""
if verbosity == self._verbosity:
return
self._verbosity = verbosity
if verbosity == "auto":
self._set_smart_features()
elif verbosity == "verbose":
self._set_smart_features(override=False)
elif verbosity == "silent":
pass
elif verbosity == "compact":
self._set_smart_features(override=True)
else:
raise ValueError(f"Invalid verbosity level: {verbosity}")
log = EsptoolLogger()

View File

@@ -42,6 +42,9 @@ class CustomLogger(TemplateLogger):
):
pass
def set_verbosity(self, verbosity: str):
pass
# Custom logger that doesn't implement all methods
class CustomLoggerIncomplete: