blob: 3ac7905b52c8cefafdc15ce04f0a70885b712cca [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Required modules:
# pyserial
# coloredlogs
#
# Example usage to show only warning and above messages:
#
# ./scripts/esp32_log_cat.py --log-level WARNING
#
import argparse
import logging
import coloredlogs
import serial
class LogPrinter:
"""Converts raw bytes from a serial output to python log outputs."""
def __init__(self, logger):
# a severity state is kept to account for multiline messages
self.severity = 'I'
self.logger = logger
def ExtractSeverity(self, log_line: str):
if len(log_line) < 2:
return
# Log line expected to start like 'E ', 'I ', ...
if log_line[1] != ' ':
return
if log_line[0] in 'EWIV':
self.severity = log_line[0]
def Log(self, raw):
"""Converts raw bytes from serial output into python logging.
Strips out any color encoding from the line and uses the prefix to decide
log type.
"""
# ESP32 serial lines already contain color encoding information and look like:
# b'\x1b[0;32mI (4921) app-devicecallbacks: Current free heap: 125656\r\n'
# b'\x1b[0;31mE (1491) chip[DL]: Long dispatch time: 635 ms\x1b[0m'
if raw.startswith(b'\x1b['):
raw = raw[raw.find(b'm')+1:]
raw = raw.decode('utf8').strip()
self.ExtractSeverity(raw)
if self.severity == 'E':
self.logger.error('%s', raw)
elif self.severity == 'W':
self.logger.warning('%s', raw)
elif self.severity == 'I':
self.logger.info('%s', raw)
elif self.severity == 'V':
self.logger.debug('%s', raw)
def main():
"""Main task if executed standalone."""
parser = argparse.ArgumentParser(
description='Output nicely colored logs from esp32')
parser.add_argument(
'--device',
default='/dev/ttyUSB0',
type=str,
help='What serial device to open.')
parser.add_argument(
'--baudrate',
default=115200,
type=int,
help='Baudrate for the serial device.')
parser.add_argument(
'--log-level',
default=logging.DEBUG,
type=lambda x: getattr(logging, x),
help='Log filtering to apply.')
args = parser.parse_args()
# Ensures somewhat pretty logging of what is going on
logging.basicConfig(level=args.log_level)
coloredlogs.install(fmt='%(asctime)s %(name)s %(levelname)-7s %(message)s')
logger = logging.getLogger(args.device)
logger.setLevel(args.log_level)
printer = LogPrinter(logger)
ser = serial.Serial(args.device, args.baudrate)
while True:
data = ser.readline()
printer.Log(data)
if __name__ == '__main__':
# execute only if run as a script
main()