Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # |
| 4 | # Copyright (c) 2021 Project CHIP Authors |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | # you may not use this file except in compliance with the License. |
| 8 | # You may obtain a copy of the License at |
| 9 | # |
| 10 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | # See the License for the specific language governing permissions and |
| 16 | # limitations under the License. |
| 17 | # |
| 18 | |
| 19 | # |
| 20 | # Required modules: |
| 21 | # pyserial |
| 22 | # coloredlogs |
| 23 | # |
| 24 | # Example usage to show only warning and above messages: |
| 25 | # |
| 26 | # ./scripts/esp32_log_cat.py --log-level WARNING |
| 27 | # |
| 28 | |
| 29 | import argparse |
| 30 | import coloredlogs |
| 31 | import logging |
| 32 | import serial |
| 33 | |
| 34 | |
| 35 | class LogPrinter: |
| 36 | """Converts raw bytes from a serial output to python log outputs.""" |
| 37 | |
| 38 | def __init__(self, logger): |
| 39 | # a severity state is kept to account for multiline messages |
| 40 | self.severity = 'I' |
| 41 | self.logger = logger |
| 42 | |
| 43 | def ExtractSeverity(self, log_line: str): |
| 44 | if len(log_line) < 2: |
| 45 | return |
| 46 | |
| 47 | # Log line expected to start like 'E ', 'I ', ... |
| 48 | if log_line[1] != ' ': |
| 49 | return |
| 50 | |
| 51 | if log_line[0] in 'EWIV': |
| 52 | self.severity = log_line[0] |
| 53 | |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 54 | def Log(self, raw): |
| 55 | """Converts raw bytes from serial output into python logging. |
| 56 | |
| 57 | Strips out any color encoding from the line and uses the prefix to decide |
| 58 | log type. |
| 59 | """ |
| 60 | # ESP32 serial lines already contain color encoding information and look like: |
| 61 | # b'\x1b[0;32mI (4921) app-devicecallbacks: Current free heap: 125656\r\n' |
| 62 | # b'\x1b[0;31mE (1491) chip[DL]: Long dispatch time: 635 ms\x1b[0m' |
| 63 | |
| 64 | if raw.startswith(b'\x1b['): |
| 65 | raw = raw[raw.find(b'm')+1:] |
| 66 | raw = raw.decode('utf8').strip() |
| 67 | |
| 68 | self.ExtractSeverity(raw) |
| 69 | |
| 70 | if self.severity == 'E': |
| 71 | self.logger.error('%s', raw) |
| 72 | elif self.severity == 'W': |
| 73 | self.logger.warning('%s', raw) |
| 74 | elif self.severity == 'I': |
| 75 | self.logger.info('%s', raw) |
| 76 | elif self.severity == 'V': |
| 77 | self.logger.debug('%s', raw) |
| 78 | |
| 79 | |
| 80 | def main(): |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 81 | """Main task if executed standalone.""" |
| 82 | parser = argparse.ArgumentParser( |
| 83 | description='Output nicely colored logs from esp32') |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 84 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 85 | parser.add_argument( |
| 86 | '--device', |
| 87 | default='/dev/ttyUSB0', |
| 88 | type=str, |
| 89 | help='What serial device to open.') |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 90 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 91 | parser.add_argument( |
| 92 | '--baudrate', |
| 93 | default=115200, |
| 94 | type=int, |
| 95 | help='Baudrate for the serial device.') |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 96 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 97 | parser.add_argument( |
| 98 | '--log-level', |
| 99 | default=logging.DEBUG, |
| 100 | type=lambda x: getattr(logging, x), |
| 101 | help='Log filtering to apply.') |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 102 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 103 | args = parser.parse_args() |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 104 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 105 | # Ensures somewhat pretty logging of what is going on |
| 106 | logging.basicConfig(level=args.log_level) |
| 107 | coloredlogs.install(fmt='%(asctime)s %(name)s %(levelname)-7s %(message)s') |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 108 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 109 | logger = logging.getLogger(args.device) |
| 110 | logger.setLevel(args.log_level) |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 111 | |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 112 | printer = LogPrinter(logger) |
| 113 | ser = serial.Serial(args.device, args.baudrate) |
| 114 | while True: |
| 115 | data = ser.readline() |
| 116 | printer.Log(data) |
Andrei Litvin | 756b5e5 | 2021-03-04 15:43:14 -0500 | [diff] [blame] | 117 | |
| 118 | |
| 119 | if __name__ == '__main__': |
Song GUO | f031500 | 2021-08-12 23:31:58 +0800 | [diff] [blame] | 120 | # execute only if run as a script |
| 121 | main() |