1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python 2*6777b538SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Workerimport os 7*6777b538SAndroid Build Coastguard Workerimport re 8*6777b538SAndroid Build Coastguard Workerimport sys 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard WorkerkUsage = '''Usage: truncate_net_log.py INPUT_FILE OUTPUT_FILE TRUNCATED_SIZE 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard WorkerCreates a smaller version of INPUT_FILE (which is a chrome-net-export-log.json 13*6777b538SAndroid Build Coastguard Workerformatted NetLog file) and saves it to OUTPUT_FILE. Note that this works by 14*6777b538SAndroid Build Coastguard Workerreading the file line by line and not fully parsing the JSON, so it must match 15*6777b538SAndroid Build Coastguard Workerthe exact format (whitespace and all). 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard WorkerFile truncation is done by dropping the oldest events and keeping everything 18*6777b538SAndroid Build Coastguard Workerelse. 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard WorkerParameters: 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker INPUT_FILE: 23*6777b538SAndroid Build Coastguard Worker Path to net-export JSON file 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker OUTPUT_FILE: 26*6777b538SAndroid Build Coastguard Worker Path to save truncated file to 27*6777b538SAndroid Build Coastguard Worker 28*6777b538SAndroid Build Coastguard Worker TRUNCATED_SIZE: 29*6777b538SAndroid Build Coastguard Worker The desired (approximate) size for the truncated file. May use a suffix to 30*6777b538SAndroid Build Coastguard Worker indicate units. Examples: 31*6777b538SAndroid Build Coastguard Worker 2003 --> 2003 bytes 32*6777b538SAndroid Build Coastguard Worker 100K --> 100 KiB 33*6777b538SAndroid Build Coastguard Worker 8M --> 8 MiB 34*6777b538SAndroid Build Coastguard Worker 1.5m --> 1.5 MiB 35*6777b538SAndroid Build Coastguard Worker''' 36*6777b538SAndroid Build Coastguard Worker 37*6777b538SAndroid Build Coastguard Workerdef get_file_size(path): 38*6777b538SAndroid Build Coastguard Worker '''Returns the filesize of |path| in bytes''' 39*6777b538SAndroid Build Coastguard Worker return os.stat(path).st_size 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard Workerdef truncate_log_file(in_path, out_path, desired_size): 43*6777b538SAndroid Build Coastguard Worker '''Copies |in_path| to |out_path| such that it is approximately 44*6777b538SAndroid Build Coastguard Worker |desired_size| bytes large. This is accomplished by dropping the oldest 45*6777b538SAndroid Build Coastguard Worker events first. The final file size may not be exactly |desired_size| as only 46*6777b538SAndroid Build Coastguard Worker complete event lines are skipped.''' 47*6777b538SAndroid Build Coastguard Worker orig_size = get_file_size(in_path) 48*6777b538SAndroid Build Coastguard Worker bytes_to_truncate = orig_size - desired_size 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard Worker # This variable is True if the current line being processed is an Event line. 51*6777b538SAndroid Build Coastguard Worker inside_events = False 52*6777b538SAndroid Build Coastguard Worker with open(out_path, 'w') as out_file: 53*6777b538SAndroid Build Coastguard Worker with open(in_path, 'r') as in_file: 54*6777b538SAndroid Build Coastguard Worker for line in in_file: 55*6777b538SAndroid Build Coastguard Worker # The final line before polledData closes the events array, and hence 56*6777b538SAndroid Build Coastguard Worker # ends in "],". The check for polledData is more for documentation 57*6777b538SAndroid Build Coastguard Worker # sake. 58*6777b538SAndroid Build Coastguard Worker if inside_events and (line.startswith('"polledData": {' or 59*6777b538SAndroid Build Coastguard Worker line.endswith('],\n'))): 60*6777b538SAndroid Build Coastguard Worker inside_events = False 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker # If this is an event line and need to drop more bytes, go ahead and 63*6777b538SAndroid Build Coastguard Worker # skip the line. Otherwise copy it to the output file. 64*6777b538SAndroid Build Coastguard Worker if inside_events and bytes_to_truncate > 0: 65*6777b538SAndroid Build Coastguard Worker bytes_to_truncate -= len(line) 66*6777b538SAndroid Build Coastguard Worker else: 67*6777b538SAndroid Build Coastguard Worker out_file.write(line) 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker # All lines after this are events (up until the closing square 70*6777b538SAndroid Build Coastguard Worker # bracket). 71*6777b538SAndroid Build Coastguard Worker if line.startswith('"events": ['): 72*6777b538SAndroid Build Coastguard Worker inside_events = True 73*6777b538SAndroid Build Coastguard Worker 74*6777b538SAndroid Build Coastguard Worker sys.stdout.write( 75*6777b538SAndroid Build Coastguard Worker 'Truncated file from %d to %d bytes\n' % (orig_size, 76*6777b538SAndroid Build Coastguard Worker get_file_size(out_path))) 77*6777b538SAndroid Build Coastguard Worker 78*6777b538SAndroid Build Coastguard Workerdef parse_filesize_str(filesize_str): 79*6777b538SAndroid Build Coastguard Worker '''Parses a string representation of a file size into a byte value, or None 80*6777b538SAndroid Build Coastguard Worker on failure''' 81*6777b538SAndroid Build Coastguard Worker filesize_str = filesize_str.lower() 82*6777b538SAndroid Build Coastguard Worker m = re.match('([0-9\.]+)([km]?)', filesize_str) 83*6777b538SAndroid Build Coastguard Worker 84*6777b538SAndroid Build Coastguard Worker if not m: 85*6777b538SAndroid Build Coastguard Worker return None 86*6777b538SAndroid Build Coastguard Worker 87*6777b538SAndroid Build Coastguard Worker # Try to parse as decimal (regex above accepts some invalid decimals too). 88*6777b538SAndroid Build Coastguard Worker float_value = 0.0 89*6777b538SAndroid Build Coastguard Worker try: 90*6777b538SAndroid Build Coastguard Worker float_value = float(m.group(1)) 91*6777b538SAndroid Build Coastguard Worker except ValueError: 92*6777b538SAndroid Build Coastguard Worker return None 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker kSuffixValueBytes = { 95*6777b538SAndroid Build Coastguard Worker 'k': 1024, 96*6777b538SAndroid Build Coastguard Worker 'm': 1024 * 1024, 97*6777b538SAndroid Build Coastguard Worker '': 1, 98*6777b538SAndroid Build Coastguard Worker } 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker suffix = m.group(2) 101*6777b538SAndroid Build Coastguard Worker return int(float_value * kSuffixValueBytes[suffix]) 102*6777b538SAndroid Build Coastguard Worker 103*6777b538SAndroid Build Coastguard Worker 104*6777b538SAndroid Build Coastguard Workerdef main(): 105*6777b538SAndroid Build Coastguard Worker if len(sys.argv) != 4: 106*6777b538SAndroid Build Coastguard Worker sys.stderr.write('ERROR: Requires 3 command line arguments\n') 107*6777b538SAndroid Build Coastguard Worker sys.stderr.write(kUsage) 108*6777b538SAndroid Build Coastguard Worker sys.exit(1) 109*6777b538SAndroid Build Coastguard Worker 110*6777b538SAndroid Build Coastguard Worker in_path = os.path.normpath(sys.argv[1]) 111*6777b538SAndroid Build Coastguard Worker out_path = os.path.normpath(sys.argv[2]) 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker if in_path == out_path: 114*6777b538SAndroid Build Coastguard Worker sys.stderr.write('ERROR: OUTPUT_FILE must be different from INPUT_FILE\n') 115*6777b538SAndroid Build Coastguard Worker sys.stderr.write(kUsage) 116*6777b538SAndroid Build Coastguard Worker sys.exit(1) 117*6777b538SAndroid Build Coastguard Worker 118*6777b538SAndroid Build Coastguard Worker size_str = sys.argv[3] 119*6777b538SAndroid Build Coastguard Worker size_bytes = parse_filesize_str(size_str) 120*6777b538SAndroid Build Coastguard Worker if size_bytes is None: 121*6777b538SAndroid Build Coastguard Worker sys.stderr.write('ERROR: Could not parse TRUNCATED_SIZE: %s\n' % size_str) 122*6777b538SAndroid Build Coastguard Worker sys.stderr.write(kUsage) 123*6777b538SAndroid Build Coastguard Worker sys.exit(1) 124*6777b538SAndroid Build Coastguard Worker 125*6777b538SAndroid Build Coastguard Worker truncate_log_file(in_path, out_path, size_bytes) 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 129*6777b538SAndroid Build Coastguard Worker main() 130