160 lines
5.7 KiB
Python
Executable File
160 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (C) 2023 The Android Open Source Project
|
|
#
|
|
# 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.
|
|
#
|
|
|
|
import argparse
|
|
from datetime import datetime
|
|
import yaml
|
|
import os
|
|
import report_pb2
|
|
import sys
|
|
import traceback
|
|
|
|
# Usage: python3 progress_report.py --logcat logcat.txt --config config.yaml --output_dir report_dir
|
|
#
|
|
# logcat.txt should contain the "boot_progress_start" and "boot_progress_enable_screen"".
|
|
# config.yaml contains all the keywords to be extracted.
|
|
# report_dir will contain three generated files:
|
|
#
|
|
# timestamp_log.txt: contains the same content as logcat.txt, but the timestamp is replaced
|
|
# with relative time with boot_progress_start time.
|
|
#
|
|
# report_proto.txt: contains the report for the events related to the keywords.
|
|
#
|
|
# report.txt: contains logcat messages corresponding to the events captured in report_proto.txt
|
|
|
|
def init_arguments():
|
|
parser = argparse.ArgumentParser(
|
|
prog = 'progrocess_report.py',
|
|
description='Extract timing information and generate a report.')
|
|
parser.add_argument(
|
|
'--logcat', type=str, required=True,
|
|
help = 'logcat file name')
|
|
parser.add_argument(
|
|
'--config', type=str, required=True,
|
|
help = 'configuration file for keywords')
|
|
parser.add_argument(
|
|
'--output_dir', type= str, required=True,
|
|
help = 'directory name to store the generated files')
|
|
return parser.parse_args()
|
|
|
|
# Find boot_progress_start line and boot_progress_enable_screen find the time difference
|
|
# return the start time string
|
|
def find_boot_progress_start_end(fp):
|
|
start = ""
|
|
end = ""
|
|
for line in fp:
|
|
if "boot_progress_start" in line:
|
|
start = line
|
|
if "boot_progress_enable_screen" in line and len(start):
|
|
end = line
|
|
break
|
|
|
|
missing_error = ""
|
|
if start == "":
|
|
missing_error = "******logcat file missing boot_progress_start\n"
|
|
elif end == "":
|
|
missing_error += "******logcat file missing boot_progress_end "
|
|
if missing_error != "":
|
|
sys.exit("Missing required message in the logcat:\n" + missing_error)
|
|
return [start, end]
|
|
|
|
# TODO(b/262259622): passing a tuple of (startDate, endDate)
|
|
def replace_timestamp_abs(line, timestamp_str, date_time_obj0):
|
|
index = line.find(" ", 6)
|
|
if index <= 0:
|
|
return line
|
|
substr0 = line[:index]
|
|
substr1 = line[index:]
|
|
|
|
try:
|
|
date_time_obj = datetime.strptime(substr0, '%m-%d %H:%M:%S.%f')
|
|
except ValueError:
|
|
return line
|
|
|
|
date_time_delta = date_time_obj - date_time_obj0
|
|
date_time_delta_str = str(date_time_delta)
|
|
return date_time_delta_str + substr1
|
|
|
|
def in_time_range(start, end, line):
|
|
try:
|
|
current_time = datetime.strptime(line[:18], '%m-%d %H:%M:%S.%f')
|
|
except ValueError:
|
|
return False
|
|
|
|
if current_time >= start and current_time <= end:
|
|
return True
|
|
|
|
return False
|
|
|
|
# Here is an example of event we would like extract:
|
|
# 09-15 16:04:15.655 root 991 991 I boot_progress_preload_start: 5440
|
|
# for each event, it is a tuple of(timestamp, event_name, timing)
|
|
def extract_event(line, keywords):
|
|
words = line.split(" ")
|
|
for keyword in keywords:
|
|
if keyword in words[-2]:
|
|
return (words[0], words[-2], words[-1])
|
|
return ()
|
|
|
|
def write_to_new_file(timestamps, keywords, logcat_fp, timestamp_fixed_logcat_fp, report_fp,
|
|
report_proto_fp):
|
|
start_timestamp_obj = datetime.strptime(timestamps[0][:18], '%m-%d %H:%M:%S.%f')
|
|
end_timestamp_obj = datetime.strptime(timestamps[1][:18], '%m-%d %H:%M:%S.%f')
|
|
report = report_pb2.Report()
|
|
for line in logcat_fp:
|
|
ts_fixed_line = replace_timestamp_abs(line, timestamps[0][:18], start_timestamp_obj)
|
|
timestamp_fixed_logcat_fp.write(ts_fixed_line)
|
|
if in_time_range(start_timestamp_obj, end_timestamp_obj, line):
|
|
event = extract_event(ts_fixed_line, keywords)
|
|
if len(event) == 0:
|
|
continue
|
|
|
|
report_fp.write(ts_fixed_line)
|
|
record = report.record.add()
|
|
record.timestamp = event[0]
|
|
record.event = event[1]
|
|
record.timing = int(event[2])
|
|
report_proto_fp.write(str(report))
|
|
|
|
def main():
|
|
args = init_arguments()
|
|
|
|
keywords = []
|
|
with open(args.config, 'r') as file:
|
|
keywords = yaml.safe_load(file)
|
|
|
|
if not os.path.isdir(args.output_dir):
|
|
os.mkdir(args.output_dir)
|
|
timestamp_fixed_logcat_fp = open(os.path.join(args.output_dir, "timestamp_fixed_log.txt"), 'w')
|
|
report_fp = open(os.path.join(args.output_dir, "report.txt"), 'w')
|
|
report_proto_fp = open(os.path.join(args.output_dir, "report_proto.txt"), 'w')
|
|
try:
|
|
with open(args.logcat, 'r', errors = 'ignore') as logcat_fp:
|
|
timestamps = find_boot_progress_start_end(logcat_fp)
|
|
logcat_fp.seek(0)
|
|
write_to_new_file(timestamps, keywords, logcat_fp, timestamp_fixed_logcat_fp, report_fp, report_proto_fp)
|
|
except Exception as e:
|
|
traceresult = traceback.format_exc()
|
|
print("Caught an exception: {}".format(traceback.format_exc()))
|
|
|
|
timestamp_fixed_logcat_fp.close()
|
|
report_fp.close()
|
|
report_proto_fp.close()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|