1eb8dc403SDave Cobbley# 2eb8dc403SDave Cobbley# Collects debug information in order to create error report files. 3eb8dc403SDave Cobbley# 4eb8dc403SDave Cobbley# Copyright (C) 2013 Intel Corporation 5eb8dc403SDave Cobbley# Author: Andreea Brandusa Proca <andreea.b.proca@intel.com> 6eb8dc403SDave Cobbley# 792b42cb3SPatrick Williams# SPDX-License-Identifier: MIT 892b42cb3SPatrick Williams# 9eb8dc403SDave Cobbley 10eb8dc403SDave CobbleyERR_REPORT_DIR ?= "${LOG_DIR}/error-report" 11eb8dc403SDave Cobbley 12eb8dc403SDave Cobbleydef errorreport_getdata(e): 13eb8dc403SDave Cobbley import codecs 14eb8dc403SDave Cobbley logpath = e.data.getVar('ERR_REPORT_DIR') 15eb8dc403SDave Cobbley datafile = os.path.join(logpath, "error-report.txt") 16eb8dc403SDave Cobbley with codecs.open(datafile, 'r', 'utf-8') as f: 17eb8dc403SDave Cobbley data = f.read() 18eb8dc403SDave Cobbley return data 19eb8dc403SDave Cobbley 20eb8dc403SDave Cobbleydef errorreport_savedata(e, newdata, file): 21eb8dc403SDave Cobbley import json 22eb8dc403SDave Cobbley import codecs 23eb8dc403SDave Cobbley logpath = e.data.getVar('ERR_REPORT_DIR') 24eb8dc403SDave Cobbley datafile = os.path.join(logpath, file) 25eb8dc403SDave Cobbley with codecs.open(datafile, 'w', 'utf-8') as f: 26eb8dc403SDave Cobbley json.dump(newdata, f, indent=4, sort_keys=True) 27eb8dc403SDave Cobbley return datafile 28eb8dc403SDave Cobbley 29a34c030eSBrad Bishopdef get_conf_data(e, filename): 30a34c030eSBrad Bishop builddir = e.data.getVar('TOPDIR') 31a34c030eSBrad Bishop filepath = os.path.join(builddir, "conf", filename) 32a34c030eSBrad Bishop jsonstring = "" 33a34c030eSBrad Bishop if os.path.exists(filepath): 34a34c030eSBrad Bishop with open(filepath, 'r') as f: 35a34c030eSBrad Bishop for line in f.readlines(): 36a34c030eSBrad Bishop if line.startswith("#") or len(line.strip()) == 0: 37a34c030eSBrad Bishop continue 38a34c030eSBrad Bishop else: 39a34c030eSBrad Bishop jsonstring=jsonstring + line 40a34c030eSBrad Bishop return jsonstring 41a34c030eSBrad Bishop 428e7b46e2SPatrick Williamsdef get_common_data(e): 438e7b46e2SPatrick Williams data = {} 448e7b46e2SPatrick Williams data['machine'] = e.data.getVar("MACHINE") 458e7b46e2SPatrick Williams data['build_sys'] = e.data.getVar("BUILD_SYS") 468e7b46e2SPatrick Williams data['distro'] = e.data.getVar("DISTRO") 478e7b46e2SPatrick Williams data['target_sys'] = e.data.getVar("TARGET_SYS") 488e7b46e2SPatrick Williams data['branch_commit'] = str(oe.buildcfg.detect_branch(e.data)) + ": " + str(oe.buildcfg.detect_revision(e.data)) 498e7b46e2SPatrick Williams data['bitbake_version'] = e.data.getVar("BB_VERSION") 508e7b46e2SPatrick Williams data['layer_version'] = get_layers_branch_rev(e.data) 518e7b46e2SPatrick Williams data['local_conf'] = get_conf_data(e, 'local.conf') 528e7b46e2SPatrick Williams data['auto_conf'] = get_conf_data(e, 'auto.conf') 538e7b46e2SPatrick Williams return data 548e7b46e2SPatrick Williams 55eb8dc403SDave Cobbleypython errorreport_handler () { 56eb8dc403SDave Cobbley import json 57eb8dc403SDave Cobbley import codecs 58eb8dc403SDave Cobbley 59eb8dc403SDave Cobbley def nativelsb(): 60eb8dc403SDave Cobbley nativelsbstr = e.data.getVar("NATIVELSBSTRING") 61eb8dc403SDave Cobbley # provide a bit more host info in case of uninative build 62eb8dc403SDave Cobbley if e.data.getVar('UNINATIVE_URL') != 'unset': 63eb8dc403SDave Cobbley return '/'.join([nativelsbstr, lsb_distro_identifier(e.data)]) 64eb8dc403SDave Cobbley return nativelsbstr 65eb8dc403SDave Cobbley 66eb8dc403SDave Cobbley logpath = e.data.getVar('ERR_REPORT_DIR') 67eb8dc403SDave Cobbley datafile = os.path.join(logpath, "error-report.txt") 68eb8dc403SDave Cobbley 69eb8dc403SDave Cobbley if isinstance(e, bb.event.BuildStarted): 70eb8dc403SDave Cobbley bb.utils.mkdirhier(logpath) 71eb8dc403SDave Cobbley data = {} 728e7b46e2SPatrick Williams data = get_common_data(e) 73eb8dc403SDave Cobbley data['nativelsb'] = nativelsb() 74eb8dc403SDave Cobbley data['failures'] = [] 75eb8dc403SDave Cobbley data['component'] = " ".join(e.getPkgs()) 76eb8dc403SDave Cobbley lock = bb.utils.lockfile(datafile + '.lock') 77eb8dc403SDave Cobbley errorreport_savedata(e, data, "error-report.txt") 78eb8dc403SDave Cobbley bb.utils.unlockfile(lock) 79eb8dc403SDave Cobbley 80eb8dc403SDave Cobbley elif isinstance(e, bb.build.TaskFailed): 81eb8dc403SDave Cobbley task = e.task 82eb8dc403SDave Cobbley taskdata={} 83eb8dc403SDave Cobbley log = e.data.getVar('BB_LOGFILE') 84*96e4b4e1SPatrick Williams taskdata['recipe'] = e.data.expand("${PN}") 85eb8dc403SDave Cobbley taskdata['package'] = e.data.expand("${PF}") 86eb8dc403SDave Cobbley taskdata['task'] = task 87eb8dc403SDave Cobbley if log: 88eb8dc403SDave Cobbley try: 8964c979e8SBrad Bishop with codecs.open(log, encoding='utf-8') as logFile: 90eb8dc403SDave Cobbley logdata = logFile.read() 91eb8dc403SDave Cobbley # Replace host-specific paths so the logs are cleaner 92eb8dc403SDave Cobbley for d in ("TOPDIR", "TMPDIR"): 93eb8dc403SDave Cobbley s = e.data.getVar(d) 94eb8dc403SDave Cobbley if s: 95eb8dc403SDave Cobbley logdata = logdata.replace(s, d) 96eb8dc403SDave Cobbley except: 97eb8dc403SDave Cobbley logdata = "Unable to read log file" 98eb8dc403SDave Cobbley else: 99eb8dc403SDave Cobbley logdata = "No Log" 100eb8dc403SDave Cobbley 101eb8dc403SDave Cobbley # server will refuse failures longer than param specified in project.settings.py 102eb8dc403SDave Cobbley # MAX_UPLOAD_SIZE = "5242880" 103eb8dc403SDave Cobbley # use lower value, because 650 chars can be spent in task, package, version 104eb8dc403SDave Cobbley max_logdata_size = 5242000 105eb8dc403SDave Cobbley # upload last max_logdata_size characters 106eb8dc403SDave Cobbley if len(logdata) > max_logdata_size: 107eb8dc403SDave Cobbley logdata = "..." + logdata[-max_logdata_size:] 108eb8dc403SDave Cobbley taskdata['log'] = logdata 109eb8dc403SDave Cobbley lock = bb.utils.lockfile(datafile + '.lock') 110eb8dc403SDave Cobbley jsondata = json.loads(errorreport_getdata(e)) 111eb8dc403SDave Cobbley jsondata['failures'].append(taskdata) 112eb8dc403SDave Cobbley errorreport_savedata(e, jsondata, "error-report.txt") 113eb8dc403SDave Cobbley bb.utils.unlockfile(lock) 114eb8dc403SDave Cobbley 1158e7b46e2SPatrick Williams elif isinstance(e, bb.event.NoProvider): 1168e7b46e2SPatrick Williams bb.utils.mkdirhier(logpath) 1178e7b46e2SPatrick Williams data = {} 1188e7b46e2SPatrick Williams data = get_common_data(e) 1198e7b46e2SPatrick Williams data['nativelsb'] = nativelsb() 1208e7b46e2SPatrick Williams data['failures'] = [] 1218e7b46e2SPatrick Williams data['component'] = str(e._item) 1228e7b46e2SPatrick Williams taskdata={} 1238e7b46e2SPatrick Williams taskdata['log'] = str(e) 1248e7b46e2SPatrick Williams taskdata['package'] = str(e._item) 1258e7b46e2SPatrick Williams taskdata['task'] = "Nothing provides " + "'" + str(e._item) + "'" 1268e7b46e2SPatrick Williams data['failures'].append(taskdata) 1278e7b46e2SPatrick Williams lock = bb.utils.lockfile(datafile + '.lock') 1288e7b46e2SPatrick Williams errorreport_savedata(e, data, "error-report.txt") 1298e7b46e2SPatrick Williams bb.utils.unlockfile(lock) 1308e7b46e2SPatrick Williams 1318e7b46e2SPatrick Williams elif isinstance(e, bb.event.ParseError): 1328e7b46e2SPatrick Williams bb.utils.mkdirhier(logpath) 1338e7b46e2SPatrick Williams data = {} 1348e7b46e2SPatrick Williams data = get_common_data(e) 1358e7b46e2SPatrick Williams data['nativelsb'] = nativelsb() 1368e7b46e2SPatrick Williams data['failures'] = [] 1378e7b46e2SPatrick Williams data['component'] = "parse" 1388e7b46e2SPatrick Williams taskdata={} 1398e7b46e2SPatrick Williams taskdata['log'] = str(e._msg) 1408e7b46e2SPatrick Williams taskdata['task'] = str(e._msg) 1418e7b46e2SPatrick Williams data['failures'].append(taskdata) 1428e7b46e2SPatrick Williams lock = bb.utils.lockfile(datafile + '.lock') 1438e7b46e2SPatrick Williams errorreport_savedata(e, data, "error-report.txt") 1448e7b46e2SPatrick Williams bb.utils.unlockfile(lock) 1458e7b46e2SPatrick Williams 146eb8dc403SDave Cobbley elif isinstance(e, bb.event.BuildCompleted): 147eb8dc403SDave Cobbley lock = bb.utils.lockfile(datafile + '.lock') 148eb8dc403SDave Cobbley jsondata = json.loads(errorreport_getdata(e)) 149eb8dc403SDave Cobbley bb.utils.unlockfile(lock) 150eb8dc403SDave Cobbley failures = jsondata['failures'] 151eb8dc403SDave Cobbley if(len(failures) > 0): 152eb8dc403SDave Cobbley filename = "error_report_" + e.data.getVar("BUILDNAME")+".txt" 153eb8dc403SDave Cobbley datafile = errorreport_savedata(e, jsondata, filename) 154eb8dc403SDave Cobbley 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)) 155eb8dc403SDave Cobbley 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.") 156eb8dc403SDave Cobbley} 157eb8dc403SDave Cobbley 158eb8dc403SDave Cobbleyaddhandler errorreport_handler 1598e7b46e2SPatrick Williamserrorreport_handler[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskFailed bb.event.NoProvider bb.event.ParseError" 160