blob: c8bafd1652e4f5016a10a7191fa02389fb455feb [file] [log] [blame]
Andrei Litvin756b5e52021-03-04 15:43:14 -05001#!/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
29import argparse
30import coloredlogs
31import logging
32import serial
33
34
35class 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 Litvin756b5e52021-03-04 15:43:14 -050054 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
80def main():
Song GUOf0315002021-08-12 23:31:58 +080081 """Main task if executed standalone."""
82 parser = argparse.ArgumentParser(
83 description='Output nicely colored logs from esp32')
Andrei Litvin756b5e52021-03-04 15:43:14 -050084
Song GUOf0315002021-08-12 23:31:58 +080085 parser.add_argument(
86 '--device',
87 default='/dev/ttyUSB0',
88 type=str,
89 help='What serial device to open.')
Andrei Litvin756b5e52021-03-04 15:43:14 -050090
Song GUOf0315002021-08-12 23:31:58 +080091 parser.add_argument(
92 '--baudrate',
93 default=115200,
94 type=int,
95 help='Baudrate for the serial device.')
Andrei Litvin756b5e52021-03-04 15:43:14 -050096
Song GUOf0315002021-08-12 23:31:58 +080097 parser.add_argument(
98 '--log-level',
99 default=logging.DEBUG,
100 type=lambda x: getattr(logging, x),
101 help='Log filtering to apply.')
Andrei Litvin756b5e52021-03-04 15:43:14 -0500102
Song GUOf0315002021-08-12 23:31:58 +0800103 args = parser.parse_args()
Andrei Litvin756b5e52021-03-04 15:43:14 -0500104
Song GUOf0315002021-08-12 23:31:58 +0800105 # 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 Litvin756b5e52021-03-04 15:43:14 -0500108
Song GUOf0315002021-08-12 23:31:58 +0800109 logger = logging.getLogger(args.device)
110 logger.setLevel(args.log_level)
Andrei Litvin756b5e52021-03-04 15:43:14 -0500111
Song GUOf0315002021-08-12 23:31:58 +0800112 printer = LogPrinter(logger)
113 ser = serial.Serial(args.device, args.baudrate)
114 while True:
115 data = ser.readline()
116 printer.Log(data)
Andrei Litvin756b5e52021-03-04 15:43:14 -0500117
118
119if __name__ == '__main__':
Song GUOf0315002021-08-12 23:31:58 +0800120 # execute only if run as a script
121 main()