Skip to content

Commit c47dcee

Browse files
author
Omri Sarig
committed
scripts/logging: Extend log_parser_uart to live_log_parser
Update the implementation of log_parser_uart to be able to also support reading log messages from files, and rename the script accordingly to be named live_log_parser, as it now supports different sources. This commit adds the functionality of seeing live logs from files as well, with reading stdin by default. In addition to this change, the commit rework the main loop in the script to be based on "select" instead of sleeping, which causes the lop messages to appear as they are written, instead of once every second. Signed-off-by: Omri Sarig <[email protected]>
1 parent fe7ba45 commit c47dcee

File tree

2 files changed

+130
-69
lines changed

2 files changed

+130
-69
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2024 Nordic Semiconductor ASA
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
"""
8+
Log Parser for Dictionary-based Logging
9+
10+
This uses the JSON database file to decode the binary
11+
log data taken directly from input serialport and print
12+
the log messages.
13+
"""
14+
15+
import argparse
16+
import logging
17+
import sys
18+
import select
19+
import os
20+
21+
import parserlib
22+
import serial
23+
24+
LOGGER_FORMAT = "%(message)s"
25+
logger = logging.getLogger("parser")
26+
27+
28+
class SerialReader:
29+
"""Class to read data from serial port and parse it"""
30+
31+
def __init__(self, serial_port, baudrate):
32+
self.serial = serial.Serial(serial_port, baudrate)
33+
34+
def close(self):
35+
self.serial.close()
36+
37+
def fileno(self):
38+
return self.serial.fileno()
39+
40+
def read_non_blocking(self):
41+
size = self.serial.in_waiting
42+
return self.serial.read(size)
43+
44+
45+
class FileReader:
46+
"""Class to read data from serial port and parse it"""
47+
48+
def __init__(self, filepath):
49+
if filepath is not None:
50+
self.file = open(filepath, 'rb')
51+
else:
52+
sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
53+
self.file = sys.stdin
54+
55+
def close(self):
56+
self.file.close()
57+
58+
def fileno(self):
59+
return self.file.fileno()
60+
61+
def read_non_blocking(self):
62+
# Read available data using a reasonable buffer size (without buffer size, this blocks
63+
# forever, but with buffer size it returns even when less data than the buffer read was
64+
# available).
65+
return self.file.read(1024)
66+
67+
68+
def parse_args():
69+
"""Parse command line arguments"""
70+
parser = argparse.ArgumentParser(allow_abbrev=False)
71+
72+
parser.add_argument("dbfile", help="Dictionary Logging Database file")
73+
parser.add_argument("--debug", action="store_true", help="Print extra debugging information")
74+
75+
# Create subparsers for different input modes
76+
subparsers = parser.add_subparsers(dest="mode", required=True, help="Input source mode")
77+
78+
# Serial subparser
79+
serial_parser = subparsers.add_parser("serial", help="Read from serial port")
80+
serial_parser.add_argument("port", help="Serial port")
81+
serial_parser.add_argument("baudrate", type=int, help="Baudrate")
82+
83+
# File subparser
84+
file_parser = subparsers.add_parser("file", help="Read from file")
85+
file_parser.add_argument("filepath", nargs="?", default=None,
86+
help="Input file path, leave empty for stdin")
87+
88+
return parser.parse_args()
89+
90+
91+
def main():
92+
"""function of serial parser"""
93+
args = parse_args()
94+
95+
if args.dbfile is None or '.json' not in args.dbfile:
96+
logger.error("ERROR: invalid log database path: %s, exiting...", args.dbfile)
97+
sys.exit(1)
98+
99+
logging.basicConfig(format=LOGGER_FORMAT)
100+
101+
if args.debug:
102+
logger.setLevel(logging.DEBUG)
103+
else:
104+
logger.setLevel(logging.INFO)
105+
106+
database = parserlib.get_database(args.dbfile)
107+
log_parser = parserlib.get_log_parser(database, logger)
108+
109+
data = b''
110+
111+
if args.mode == "serial":
112+
reader = SerialReader(args.port, args.baudrate)
113+
elif args.mode == "file":
114+
reader = FileReader(args.filepath)
115+
else:
116+
raise ValueError("Invalid mode selected. Use 'serial' or 'file'.")
117+
118+
try:
119+
while True:
120+
ready, _, _ = select.select([reader], [], [])
121+
if ready:
122+
data += reader.read_non_blocking()
123+
parsed_data_offset = parserlib.parser(data, database, log_parser, logger)
124+
data = data[parsed_data_offset:]
125+
finally:
126+
reader.close()
127+
128+
129+
if __name__ == "__main__":
130+
main()

scripts/logging/dictionary/log_parser_uart.py

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)