1# 2# Collects debug information in order to create error report files. 3# 4# Copyright (C) 2013 Intel Corporation 5# Author: Andreea Brandusa Proca <andreea.b.proca@intel.com> 6# 7# SPDX-License-Identifier: MIT 8# 9 10ERR_REPORT_DIR ?= "${LOG_DIR}/error-report" 11 12def errorreport_getdata(e): 13 import codecs 14 logpath = e.data.getVar('ERR_REPORT_DIR') 15 datafile = os.path.join(logpath, "error-report.txt") 16 with codecs.open(datafile, 'r', 'utf-8') as f: 17 data = f.read() 18 return data 19 20def errorreport_savedata(e, newdata, file): 21 import json 22 import codecs 23 logpath = e.data.getVar('ERR_REPORT_DIR') 24 datafile = os.path.join(logpath, file) 25 with codecs.open(datafile, 'w', 'utf-8') as f: 26 json.dump(newdata, f, indent=4, sort_keys=True) 27 return datafile 28 29def get_conf_data(e, filename): 30 builddir = e.data.getVar('TOPDIR') 31 filepath = os.path.join(builddir, "conf", filename) 32 jsonstring = "" 33 if os.path.exists(filepath): 34 with open(filepath, 'r') as f: 35 for line in f.readlines(): 36 if line.startswith("#") or len(line.strip()) == 0: 37 continue 38 else: 39 jsonstring=jsonstring + line 40 return jsonstring 41 42def get_common_data(e): 43 data = {} 44 data['machine'] = e.data.getVar("MACHINE") 45 data['build_sys'] = e.data.getVar("BUILD_SYS") 46 data['distro'] = e.data.getVar("DISTRO") 47 data['target_sys'] = e.data.getVar("TARGET_SYS") 48 data['branch_commit'] = str(oe.buildcfg.detect_branch(e.data)) + ": " + str(oe.buildcfg.detect_revision(e.data)) 49 data['bitbake_version'] = e.data.getVar("BB_VERSION") 50 data['layer_version'] = get_layers_branch_rev(e.data) 51 data['local_conf'] = get_conf_data(e, 'local.conf') 52 data['auto_conf'] = get_conf_data(e, 'auto.conf') 53 return data 54 55python errorreport_handler () { 56 import json 57 import codecs 58 59 def nativelsb(): 60 nativelsbstr = e.data.getVar("NATIVELSBSTRING") 61 # provide a bit more host info in case of uninative build 62 if e.data.getVar('UNINATIVE_URL') != 'unset': 63 return '/'.join([nativelsbstr, lsb_distro_identifier(e.data)]) 64 return nativelsbstr 65 66 logpath = e.data.getVar('ERR_REPORT_DIR') 67 datafile = os.path.join(logpath, "error-report.txt") 68 69 if isinstance(e, bb.event.BuildStarted): 70 bb.utils.mkdirhier(logpath) 71 data = {} 72 data = get_common_data(e) 73 data['nativelsb'] = nativelsb() 74 data['failures'] = [] 75 data['component'] = " ".join(e.getPkgs()) 76 lock = bb.utils.lockfile(datafile + '.lock') 77 errorreport_savedata(e, data, "error-report.txt") 78 bb.utils.unlockfile(lock) 79 80 elif isinstance(e, bb.build.TaskFailed): 81 task = e.task 82 taskdata={} 83 log = e.data.getVar('BB_LOGFILE') 84 taskdata['package'] = e.data.expand("${PF}") 85 taskdata['task'] = task 86 if log: 87 try: 88 with codecs.open(log, encoding='utf-8') as logFile: 89 logdata = logFile.read() 90 # Replace host-specific paths so the logs are cleaner 91 for d in ("TOPDIR", "TMPDIR"): 92 s = e.data.getVar(d) 93 if s: 94 logdata = logdata.replace(s, d) 95 except: 96 logdata = "Unable to read log file" 97 else: 98 logdata = "No Log" 99 100 # server will refuse failures longer than param specified in project.settings.py 101 # MAX_UPLOAD_SIZE = "5242880" 102 # use lower value, because 650 chars can be spent in task, package, version 103 max_logdata_size = 5242000 104 # upload last max_logdata_size characters 105 if len(logdata) > max_logdata_size: 106 logdata = "..." + logdata[-max_logdata_size:] 107 taskdata['log'] = logdata 108 lock = bb.utils.lockfile(datafile + '.lock') 109 jsondata = json.loads(errorreport_getdata(e)) 110 jsondata['failures'].append(taskdata) 111 errorreport_savedata(e, jsondata, "error-report.txt") 112 bb.utils.unlockfile(lock) 113 114 elif isinstance(e, bb.event.NoProvider): 115 bb.utils.mkdirhier(logpath) 116 data = {} 117 data = get_common_data(e) 118 data['nativelsb'] = nativelsb() 119 data['failures'] = [] 120 data['component'] = str(e._item) 121 taskdata={} 122 taskdata['log'] = str(e) 123 taskdata['package'] = str(e._item) 124 taskdata['task'] = "Nothing provides " + "'" + str(e._item) + "'" 125 data['failures'].append(taskdata) 126 lock = bb.utils.lockfile(datafile + '.lock') 127 errorreport_savedata(e, data, "error-report.txt") 128 bb.utils.unlockfile(lock) 129 130 elif isinstance(e, bb.event.ParseError): 131 bb.utils.mkdirhier(logpath) 132 data = {} 133 data = get_common_data(e) 134 data['nativelsb'] = nativelsb() 135 data['failures'] = [] 136 data['component'] = "parse" 137 taskdata={} 138 taskdata['log'] = str(e._msg) 139 taskdata['task'] = str(e._msg) 140 data['failures'].append(taskdata) 141 lock = bb.utils.lockfile(datafile + '.lock') 142 errorreport_savedata(e, data, "error-report.txt") 143 bb.utils.unlockfile(lock) 144 145 elif isinstance(e, bb.event.BuildCompleted): 146 lock = bb.utils.lockfile(datafile + '.lock') 147 jsondata = json.loads(errorreport_getdata(e)) 148 bb.utils.unlockfile(lock) 149 failures = jsondata['failures'] 150 if(len(failures) > 0): 151 filename = "error_report_" + e.data.getVar("BUILDNAME")+".txt" 152 datafile = errorreport_savedata(e, jsondata, filename) 153 bb.note("The errors for this build are stored in %s\nYou can send the errors to a reports server by running:\n send-error-report %s [-s server]" % (datafile, datafile)) 154 bb.note("The contents of these logs will be posted in public if you use the above command with the default server. Please ensure you remove any identifying or proprietary information when prompted before sending.") 155} 156 157addhandler errorreport_handler 158errorreport_handler[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskFailed bb.event.NoProvider bb.event.ParseError" 159