kopia lustrzana https://github.com/espressif/esp-idf
tools: Some additions to IDF Monitor's timestamps
Additions to https://github.com/espressif/esp-idf/pull/7021pull/6904/head
rodzic
f91bde97c1
commit
483f51cdd0
|
@ -52,6 +52,9 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t
|
||||||
* - * Ctrl+L
|
* - * Ctrl+L
|
||||||
- Stop/resume log output saved to file
|
- Stop/resume log output saved to file
|
||||||
- Creates a file in the project directory and the output is written to that file until this is disabled with the same keyboard shortcut (or IDF Monitor exits).
|
- Creates a file in the project directory and the output is written to that file until this is disabled with the same keyboard shortcut (or IDF Monitor exits).
|
||||||
|
* - * Ctrl+I (or I)
|
||||||
|
- Stop/resume printing timestamps
|
||||||
|
- IDF Monitor can print a timestamp in the beginning of each line. The timestamp format can be changed by the --timestamp-format command line argument.
|
||||||
* - * Ctrl+H (or H)
|
* - * Ctrl+H (or H)
|
||||||
- Display all keyboard shortcuts
|
- Display all keyboard shortcuts
|
||||||
-
|
-
|
||||||
|
@ -268,7 +271,6 @@ Known Issues with IDF Monitor
|
||||||
Issues Observed on Windows
|
Issues Observed on Windows
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
- If in the Windows environment you receive the error "winpty: command not found", fix it by running ``pacman -S winpty``.
|
|
||||||
- Arrow keys, as well as some other keys, do not work in GDB due to Windows Console limitations.
|
- Arrow keys, as well as some other keys, do not work in GDB due to Windows Console limitations.
|
||||||
- Occasionally, when "idf.py" or "make" exits, it might stall for up to 30 seconds before IDF Monitor resumes.
|
- Occasionally, when "idf.py" or "make" exits, it might stall for up to 30 seconds before IDF Monitor resumes.
|
||||||
- When "gdb" is run, it might stall for a short time before it begins communicating with the GDBStub.
|
- When "gdb" is run, it might stall for a short time before it begins communicating with the GDBStub.
|
||||||
|
|
|
@ -41,7 +41,7 @@ import subprocess
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from builtins import bytes, object
|
from builtins import bytes, object
|
||||||
from typing import BinaryIO, Callable, List, Optional, Union
|
from typing import AnyStr, BinaryIO, Callable, List, Optional, Union
|
||||||
|
|
||||||
import serial.tools.miniterm as miniterm
|
import serial.tools.miniterm as miniterm
|
||||||
from idf_monitor_base import (COREDUMP_DECODE_DISABLE, COREDUMP_DECODE_INFO, COREDUMP_DONE, COREDUMP_IDLE,
|
from idf_monitor_base import (COREDUMP_DECODE_DISABLE, COREDUMP_DECODE_INFO, COREDUMP_DONE, COREDUMP_IDLE,
|
||||||
|
@ -53,8 +53,8 @@ from idf_monitor_base.chip_specific_config import get_chip_config
|
||||||
from idf_monitor_base.console_parser import ConsoleParser
|
from idf_monitor_base.console_parser import ConsoleParser
|
||||||
from idf_monitor_base.console_reader import ConsoleReader
|
from idf_monitor_base.console_reader import ConsoleReader
|
||||||
from idf_monitor_base.constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET,
|
from idf_monitor_base.constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET,
|
||||||
CMD_STOP, CMD_TOGGLE_LOGGING, CTRL_H, CTRL_T, TAG_CMD, TAG_KEY, TAG_SERIAL,
|
CMD_STOP, CMD_TOGGLE_LOGGING, CMD_TOGGLE_TIMESTAMPS, CTRL_H, CTRL_T, TAG_CMD,
|
||||||
TAG_SERIAL_FLUSH)
|
TAG_KEY, TAG_SERIAL, TAG_SERIAL_FLUSH)
|
||||||
from idf_monitor_base.exceptions import SerialStopException
|
from idf_monitor_base.exceptions import SerialStopException
|
||||||
from idf_monitor_base.line_matcher import LineMatcher
|
from idf_monitor_base.line_matcher import LineMatcher
|
||||||
from idf_monitor_base.output_helpers import normal_print, red_print, yellow_print
|
from idf_monitor_base.output_helpers import normal_print, red_print, yellow_print
|
||||||
|
@ -88,14 +88,23 @@ class Monitor(object):
|
||||||
Main difference is that all event processing happens in the main thread, not the worker threads.
|
Main difference is that all event processing happens in the main thread, not the worker threads.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, serial_instance, elf_file, print_filter, make='make', encrypted=False,
|
def __init__(
|
||||||
toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, eol='CRLF',
|
self,
|
||||||
decode_coredumps=COREDUMP_DECODE_INFO,
|
serial_instance, # type: serial.Serial
|
||||||
decode_panic=PANIC_DECODE_DISABLE,
|
elf_file, # type: str
|
||||||
target='esp32',
|
print_filter, # type: str
|
||||||
websocket_client=None, enable_address_decoding=True,
|
make='make', # type: str
|
||||||
timestamps=False):
|
encrypted=False, # type: bool
|
||||||
# type: (serial.Serial, str, str, str, bool, str, str, str, str, str, WebSocketClient, bool) -> None
|
toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, # type: str
|
||||||
|
eol='CRLF', # type: str
|
||||||
|
decode_coredumps=COREDUMP_DECODE_INFO, # type: str
|
||||||
|
decode_panic=PANIC_DECODE_DISABLE, # type: str
|
||||||
|
target='esp32', # type: str
|
||||||
|
websocket_client=None, # type: WebSocketClient
|
||||||
|
enable_address_decoding=True, # type: bool
|
||||||
|
timestamps=False, # type: bool
|
||||||
|
timestamp_format='' # type: str
|
||||||
|
):
|
||||||
super(Monitor, self).__init__()
|
super(Monitor, self).__init__()
|
||||||
self.event_queue = queue.Queue() # type: queue.Queue
|
self.event_queue = queue.Queue() # type: queue.Queue
|
||||||
self.cmd_queue = queue.Queue() # type: queue.Queue
|
self.cmd_queue = queue.Queue() # type: queue.Queue
|
||||||
|
@ -144,6 +153,7 @@ class Monitor(object):
|
||||||
self.gdb_exit = False
|
self.gdb_exit = False
|
||||||
self.start_cmd_sent = False
|
self.start_cmd_sent = False
|
||||||
self._timestamps = timestamps
|
self._timestamps = timestamps
|
||||||
|
self._timestamp_format = timestamp_format
|
||||||
|
|
||||||
def invoke_processing_last_line(self):
|
def invoke_processing_last_line(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
|
@ -568,6 +578,9 @@ class Monitor(object):
|
||||||
else:
|
else:
|
||||||
self.start_logging()
|
self.start_logging()
|
||||||
|
|
||||||
|
def toggle_timestamps(self): # type: () -> None
|
||||||
|
self._timestamps = not self._timestamps
|
||||||
|
|
||||||
def start_logging(self): # type: () -> None
|
def start_logging(self): # type: () -> None
|
||||||
if not self._log_file:
|
if not self._log_file:
|
||||||
name = 'log.{}.{}.txt'.format(os.path.splitext(os.path.basename(self.elf_file))[0],
|
name = 'log.{}.{}.txt'.format(os.path.splitext(os.path.basename(self.elf_file))[0],
|
||||||
|
@ -589,22 +602,25 @@ class Monitor(object):
|
||||||
finally:
|
finally:
|
||||||
self._log_file = None
|
self._log_file = None
|
||||||
|
|
||||||
def _print(self, string, console_printer=None): # type: (Union[str, bytes], Optional[Callable]) -> None
|
def _print(self, string, console_printer=None): # type: (AnyStr, Optional[Callable]) -> None
|
||||||
if console_printer is None:
|
if console_printer is None:
|
||||||
console_printer = self.console.write_bytes
|
console_printer = self.console.write_bytes
|
||||||
if self._output_enabled:
|
if self._timestamps and (self._output_enabled or self._log_file):
|
||||||
if self._timestamps:
|
t = datetime.datetime.now().strftime(self._timestamp_format)
|
||||||
t = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ")
|
# "string" is not guaranteed to be a full line. Timestamps should be only at the beginning of lines.
|
||||||
if isinstance(string, type(u'')):
|
if isinstance(string, type(u'')):
|
||||||
console_printer(t + string)
|
search_patt = '\n'
|
||||||
else:
|
replacement = '\n' + t + ' '
|
||||||
console_printer(t.encode('ascii') + string)
|
|
||||||
else:
|
else:
|
||||||
|
search_patt = b'\n' # type: ignore
|
||||||
|
replacement = b'\n' + t.encode('ascii') + b' ' # type: ignore
|
||||||
|
string = string.replace(search_patt, replacement)
|
||||||
|
if self._output_enabled:
|
||||||
console_printer(string)
|
console_printer(string)
|
||||||
if self._log_file:
|
if self._log_file:
|
||||||
try:
|
try:
|
||||||
if isinstance(string, type(u'')):
|
if isinstance(string, type(u'')):
|
||||||
string = string.encode()
|
string = string.encode() # type: ignore
|
||||||
self._log_file.write(string) # type: ignore
|
self._log_file.write(string) # type: ignore
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
red_print('\nCannot write to file: {}'.format(e))
|
red_print('\nCannot write to file: {}'.format(e))
|
||||||
|
@ -638,6 +654,8 @@ class Monitor(object):
|
||||||
self.output_toggle()
|
self.output_toggle()
|
||||||
elif cmd == CMD_TOGGLE_LOGGING:
|
elif cmd == CMD_TOGGLE_LOGGING:
|
||||||
self.toggle_logging()
|
self.toggle_logging()
|
||||||
|
elif cmd == CMD_TOGGLE_TIMESTAMPS:
|
||||||
|
self.toggle_timestamps()
|
||||||
elif cmd == CMD_ENTER_BOOT:
|
elif cmd == CMD_ENTER_BOOT:
|
||||||
self.serial.setDTR(high) # IO0=HIGH
|
self.serial.setDTR(high) # IO0=HIGH
|
||||||
self.serial.setRTS(low) # EN=LOW, chip in reset
|
self.serial.setRTS(low) # EN=LOW, chip in reset
|
||||||
|
@ -744,6 +762,12 @@ def main(): # type: () -> None
|
||||||
default=False,
|
default=False,
|
||||||
action='store_true')
|
action='store_true')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--timestamp-format',
|
||||||
|
default=os.environ.get('ESP_IDF_MONITOR_TIMESTAMP_FORMAT', '%Y-%m-%d %H:%M:%S'),
|
||||||
|
help='Set a strftime()-compatible timestamp format'
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# GDB uses CreateFile to open COM port, which requires the COM name to be r'\\.\COMx' if the COM
|
# GDB uses CreateFile to open COM port, which requires the COM name to be r'\\.\COMx' if the COM
|
||||||
|
@ -787,7 +811,7 @@ def main(): # type: () -> None
|
||||||
args.toolchain_prefix, args.eol,
|
args.toolchain_prefix, args.eol,
|
||||||
args.decode_coredumps, args.decode_panic, args.target,
|
args.decode_coredumps, args.decode_panic, args.target,
|
||||||
ws, enable_address_decoding=not args.disable_address_decoding,
|
ws, enable_address_decoding=not args.disable_address_decoding,
|
||||||
timestamps=args.timestamps)
|
timestamps=args.timestamps, timestamp_format=args.timestamp_format)
|
||||||
|
|
||||||
yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(p=serial_instance))
|
yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(p=serial_instance))
|
||||||
yellow_print('--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
|
yellow_print('--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
|
||||||
|
|
|
@ -22,8 +22,8 @@ except ImportError:
|
||||||
import serial.tools.miniterm as miniterm
|
import serial.tools.miniterm as miniterm
|
||||||
|
|
||||||
from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
|
from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
|
||||||
CMD_TOGGLE_LOGGING, CTRL_A, CTRL_F, CTRL_H, CTRL_L, CTRL_P, CTRL_R, CTRL_RBRACKET, CTRL_T,
|
CMD_TOGGLE_LOGGING, CMD_TOGGLE_TIMESTAMPS, CTRL_A, CTRL_F, CTRL_H, CTRL_I, CTRL_L, CTRL_P,
|
||||||
CTRL_X, CTRL_Y, TAG_CMD, TAG_KEY, __version__)
|
CTRL_R, CTRL_RBRACKET, CTRL_T, CTRL_X, CTRL_Y, TAG_CMD, TAG_KEY, __version__)
|
||||||
from .output_helpers import red_print, yellow_print
|
from .output_helpers import red_print, yellow_print
|
||||||
|
|
||||||
key_description = miniterm.key_description
|
key_description = miniterm.key_description
|
||||||
|
@ -72,6 +72,8 @@ class ConsoleParser(object):
|
||||||
ret = (TAG_CMD, CMD_OUTPUT_TOGGLE)
|
ret = (TAG_CMD, CMD_OUTPUT_TOGGLE)
|
||||||
elif c == CTRL_L: # Toggle saving output into file
|
elif c == CTRL_L: # Toggle saving output into file
|
||||||
ret = (TAG_CMD, CMD_TOGGLE_LOGGING)
|
ret = (TAG_CMD, CMD_TOGGLE_LOGGING)
|
||||||
|
elif c in [CTRL_I, 'i', 'I']: # Toggle printing timestamps
|
||||||
|
ret = (TAG_CMD, CMD_TOGGLE_TIMESTAMPS)
|
||||||
elif c == CTRL_P:
|
elif c == CTRL_P:
|
||||||
yellow_print('Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart')
|
yellow_print('Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart')
|
||||||
# to fast trigger pause without press menu key
|
# to fast trigger pause without press menu key
|
||||||
|
@ -99,6 +101,7 @@ class ConsoleParser(object):
|
||||||
--- {appmake:14} Build & flash app only
|
--- {appmake:14} Build & flash app only
|
||||||
--- {output:14} Toggle output display
|
--- {output:14} Toggle output display
|
||||||
--- {log:14} Toggle saving output into file
|
--- {log:14} Toggle saving output into file
|
||||||
|
--- {timestamps:14} Toggle printing timestamps
|
||||||
--- {pause:14} Reset target into bootloader to pause app via RTS line
|
--- {pause:14} Reset target into bootloader to pause app via RTS line
|
||||||
--- {menuexit:14} Exit program
|
--- {menuexit:14} Exit program
|
||||||
""".format(version=__version__,
|
""".format(version=__version__,
|
||||||
|
@ -109,6 +112,7 @@ class ConsoleParser(object):
|
||||||
appmake=key_description(CTRL_A) + ' (or A)',
|
appmake=key_description(CTRL_A) + ' (or A)',
|
||||||
output=key_description(CTRL_Y),
|
output=key_description(CTRL_Y),
|
||||||
log=key_description(CTRL_L),
|
log=key_description(CTRL_L),
|
||||||
|
timestamps=key_description(CTRL_I) + ' (or I)',
|
||||||
pause=key_description(CTRL_P),
|
pause=key_description(CTRL_P),
|
||||||
menuexit=key_description(CTRL_X) + ' (or X)')
|
menuexit=key_description(CTRL_X) + ' (or X)')
|
||||||
return textwrap.dedent(text)
|
return textwrap.dedent(text)
|
||||||
|
|
|
@ -17,6 +17,7 @@ CTRL_A = '\x01'
|
||||||
CTRL_B = '\x02'
|
CTRL_B = '\x02'
|
||||||
CTRL_F = '\x06'
|
CTRL_F = '\x06'
|
||||||
CTRL_H = '\x08'
|
CTRL_H = '\x08'
|
||||||
|
CTRL_I = '\x09'
|
||||||
CTRL_R = '\x12'
|
CTRL_R = '\x12'
|
||||||
CTRL_T = '\x14'
|
CTRL_T = '\x14'
|
||||||
CTRL_Y = '\x19'
|
CTRL_Y = '\x19'
|
||||||
|
@ -33,6 +34,7 @@ CMD_APP_FLASH = 4
|
||||||
CMD_OUTPUT_TOGGLE = 5
|
CMD_OUTPUT_TOGGLE = 5
|
||||||
CMD_TOGGLE_LOGGING = 6
|
CMD_TOGGLE_LOGGING = 6
|
||||||
CMD_ENTER_BOOT = 7
|
CMD_ENTER_BOOT = 7
|
||||||
|
CMD_TOGGLE_TIMESTAMPS = 8
|
||||||
|
|
||||||
# Tags for tuples in queues
|
# Tags for tuples in queues
|
||||||
TAG_KEY = 0
|
TAG_KEY = 0
|
||||||
|
|
|
@ -71,7 +71,7 @@ def action_extensions(base_actions, project_path):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def monitor(action, ctx, args, print_filter, monitor_baud, encrypted):
|
def monitor(action, ctx, args, print_filter, monitor_baud, encrypted, timestamps, timestamp_format):
|
||||||
"""
|
"""
|
||||||
Run idf_monitor.py to watch build output
|
Run idf_monitor.py to watch build output
|
||||||
"""
|
"""
|
||||||
|
@ -118,6 +118,12 @@ def action_extensions(base_actions, project_path):
|
||||||
if encrypted:
|
if encrypted:
|
||||||
monitor_args += ['--encrypted']
|
monitor_args += ['--encrypted']
|
||||||
|
|
||||||
|
if timestamps:
|
||||||
|
monitor_args += ['--timestamps']
|
||||||
|
|
||||||
|
if timestamp_format:
|
||||||
|
monitor_args += ['--timestamp-format', timestamp_format]
|
||||||
|
|
||||||
idf_py = [PYTHON] + _get_commandline_options(ctx) # commands to re-run idf.py
|
idf_py = [PYTHON] + _get_commandline_options(ctx) # commands to re-run idf.py
|
||||||
monitor_args += ['-m', ' '.join("'%s'" % a for a in idf_py)]
|
monitor_args += ['-m', ' '.join("'%s'" % a for a in idf_py)]
|
||||||
|
|
||||||
|
@ -214,7 +220,17 @@ def action_extensions(base_actions, project_path):
|
||||||
'IDF Monitor will invoke encrypted-flash and encrypted-app-flash targets '
|
'IDF Monitor will invoke encrypted-flash and encrypted-app-flash targets '
|
||||||
'if this option is set. This option is set by default if IDF Monitor was invoked '
|
'if this option is set. This option is set by default if IDF Monitor was invoked '
|
||||||
'together with encrypted-flash or encrypted-app-flash target.'),
|
'together with encrypted-flash or encrypted-app-flash target.'),
|
||||||
|
}, {
|
||||||
|
'names': ['--timestamps'],
|
||||||
|
'is_flag': True,
|
||||||
|
'help': 'Print a time stamp in the beginning of each line.',
|
||||||
|
}, {
|
||||||
|
'names': ['--timestamp-format'],
|
||||||
|
'help': ('Set the formatting of timestamps compatible with strftime(). '
|
||||||
|
'For example, "%Y-%m-%d %H:%M:%S".'),
|
||||||
|
'default': None
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
'order_dependencies': [
|
'order_dependencies': [
|
||||||
'flash',
|
'flash',
|
||||||
|
|
Ładowanie…
Reference in New Issue