1#!/usr/bin/env python3 2# 3# Copyright (c) 2021 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7""" 8Log Parser for Dictionary-based Logging 9 10This uses the JSON database file to decode the input binary 11log data and print the log messages. 12""" 13 14import argparse 15import binascii 16import logging 17import sys 18 19import dictionary_parser 20from dictionary_parser.log_database import LogDatabase 21 22 23LOGGER_FORMAT = "%(message)s" 24logger = logging.getLogger("parser") 25 26LOG_HEX_SEP = "##ZLOGV1##" 27 28 29def parse_args(): 30 """Parse command line arguments""" 31 argparser = argparse.ArgumentParser(allow_abbrev=False) 32 33 argparser.add_argument("dbfile", help="Dictionary Logging Database file") 34 argparser.add_argument("logfile", help="Log Data file") 35 argparser.add_argument("--hex", action="store_true", 36 help="Log Data file is in hexadecimal strings") 37 argparser.add_argument("--rawhex", action="store_true", 38 help="Log file only contains hexadecimal log data") 39 argparser.add_argument("--debug", action="store_true", 40 help="Print extra debugging information") 41 42 return argparser.parse_args() 43 44 45def read_log_file(args): 46 """ 47 Read the log from file 48 """ 49 logdata = None 50 51 # Open log data file for reading 52 if args.hex: 53 if args.rawhex: 54 # Simply log file with only hexadecimal data 55 logdata = dictionary_parser.utils.convert_hex_file_to_bin(args.logfile) 56 else: 57 hexdata = '' 58 59 with open(args.logfile, "r", encoding="iso-8859-1") as hexfile: 60 for line in hexfile.readlines(): 61 hexdata += line.strip() 62 63 if LOG_HEX_SEP not in hexdata: 64 logger.error("ERROR: Cannot find start of log data, exiting...") 65 sys.exit(1) 66 67 idx = hexdata.index(LOG_HEX_SEP) + len(LOG_HEX_SEP) 68 hexdata = hexdata[idx:] 69 70 if len(hexdata) % 2 != 0: 71 # Make sure there are even number of characters 72 idx = int(len(hexdata) / 2) * 2 73 hexdata = hexdata[:idx] 74 75 idx = 0 76 while idx < len(hexdata): 77 # When running QEMU via west or ninja, there may be additional 78 # strings printed by QEMU, west or ninja (for example, QEMU 79 # is terminated, or user interrupted, etc). So we need to 80 # figure out where the end of log data stream by 81 # trying to convert from hex to bin. 82 idx += 2 83 84 try: 85 binascii.unhexlify(hexdata[:idx]) 86 except binascii.Error: 87 idx -= 2 88 break 89 90 logdata = binascii.unhexlify(hexdata[:idx]) 91 else: 92 logfile = open(args.logfile, "rb") 93 if not logfile: 94 logger.error("ERROR: Cannot open binary log data file: %s, exiting...", args.logfile) 95 sys.exit(1) 96 97 logdata = logfile.read() 98 99 logfile.close() 100 101 return logdata 102 103 104def main(): 105 """Main function of log parser""" 106 args = parse_args() 107 108 # Setup logging for parser 109 logging.basicConfig(format=LOGGER_FORMAT) 110 if args.debug: 111 logger.setLevel(logging.DEBUG) 112 else: 113 logger.setLevel(logging.INFO) 114 115 # Read from database file 116 database = LogDatabase.read_json_database(args.dbfile) 117 if database is None: 118 logger.error("ERROR: Cannot open database file: %s, exiting...", args.dbfile) 119 sys.exit(1) 120 121 logdata = read_log_file(args) 122 if logdata is None: 123 logger.error("ERROR: cannot read log from file: %s, exiting...", args.logfile) 124 sys.exit(1) 125 126 log_parser = dictionary_parser.get_parser(database) 127 if log_parser is not None: 128 logger.debug("# Build ID: %s", database.get_build_id()) 129 logger.debug("# Target: %s, %d-bit", database.get_arch(), database.get_tgt_bits()) 130 if database.is_tgt_little_endian(): 131 logger.debug("# Endianness: Little") 132 else: 133 logger.debug("# Endianness: Big") 134 135 ret = log_parser.parse_log_data(logdata, debug=args.debug) 136 if not ret: 137 logger.error("ERROR: there were error(s) parsing log data") 138 sys.exit(1) 139 else: 140 logger.error("ERROR: Cannot find a suitable parser matching database version!") 141 sys.exit(1) 142 143 144if __name__ == "__main__": 145 main() 146