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 42*8e7b46e2SPatrick Williamsdef get_common_data(e): 43*8e7b46e2SPatrick Williams data = {} 44*8e7b46e2SPatrick Williams data['machine'] = e.data.getVar("MACHINE") 45*8e7b46e2SPatrick Williams data['build_sys'] = e.data.getVar("BUILD_SYS") 46*8e7b46e2SPatrick Williams data['distro'] = e.data.getVar("DISTRO") 47*8e7b46e2SPatrick Williams data['target_sys'] = e.data.getVar("TARGET_SYS") 48*8e7b46e2SPatrick Williams data['branch_commit'] = str(oe.buildcfg.detect_branch(e.data)) + ": " + str(oe.buildcfg.detect_revision(e.data)) 49*8e7b46e2SPatrick Williams data['bitbake_version'] = e.data.getVar("BB_VERSION") 50*8e7b46e2SPatrick Williams data['layer_version'] = get_layers_branch_rev(e.data) 51*8e7b46e2SPatrick Williams data['local_conf'] = get_conf_data(e, 'local.conf') 52*8e7b46e2SPatrick Williams data['auto_conf'] = get_conf_data(e, 'auto.conf') 53*8e7b46e2SPatrick Williams return data 54*8e7b46e2SPatrick 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 = {} 72*8e7b46e2SPatrick 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') 84eb8dc403SDave Cobbley taskdata['package'] = e.data.expand("${PF}") 85eb8dc403SDave Cobbley taskdata['task'] = task 86eb8dc403SDave Cobbley if log: 87eb8dc403SDave Cobbley try: 8864c979e8SBrad Bishop with codecs.open(log, encoding='utf-8') as logFile: 89eb8dc403SDave Cobbley logdata = logFile.read() 90eb8dc403SDave Cobbley # Replace host-specific paths so the logs are cleaner 91eb8dc403SDave Cobbley for d in ("TOPDIR", "TMPDIR"): 92eb8dc403SDave Cobbley s = e.data.getVar(d) 93eb8dc403SDave Cobbley if s: 94eb8dc403SDave Cobbley logdata = logdata.replace(s, d) 95eb8dc403SDave Cobbley except: 96eb8dc403SDave Cobbley logdata = "Unable to read log file" 97eb8dc403SDave Cobbley else: 98eb8dc403SDave Cobbley logdata = "No Log" 99eb8dc403SDave Cobbley 100eb8dc403SDave Cobbley # server will refuse failures longer than param specified in project.settings.py 101eb8dc403SDave Cobbley # MAX_UPLOAD_SIZE = "5242880" 102eb8dc403SDave Cobbley # use lower value, because 650 chars can be spent in task, package, version 103eb8dc403SDave Cobbley max_logdata_size = 5242000 104eb8dc403SDave Cobbley # upload last max_logdata_size characters 105eb8dc403SDave Cobbley if len(logdata) > max_logdata_size: 106eb8dc403SDave Cobbley logdata = "..." + logdata[-max_logdata_size:] 107eb8dc403SDave Cobbley taskdata['log'] = logdata 108eb8dc403SDave Cobbley lock = bb.utils.lockfile(datafile + '.lock') 109eb8dc403SDave Cobbley jsondata = json.loads(errorreport_getdata(e)) 110eb8dc403SDave Cobbley jsondata['failures'].append(taskdata) 111eb8dc403SDave Cobbley errorreport_savedata(e, jsondata, "error-report.txt") 112eb8dc403SDave Cobbley bb.utils.unlockfile(lock) 113eb8dc403SDave Cobbley 114*8e7b46e2SPatrick Williams elif isinstance(e, bb.event.NoProvider): 115*8e7b46e2SPatrick Williams bb.utils.mkdirhier(logpath) 116*8e7b46e2SPatrick Williams data = {} 117*8e7b46e2SPatrick Williams data = get_common_data(e) 118*8e7b46e2SPatrick Williams data['nativelsb'] = nativelsb() 119*8e7b46e2SPatrick Williams data['failures'] = [] 120*8e7b46e2SPatrick Williams data['component'] = str(e._item) 121*8e7b46e2SPatrick Williams taskdata={} 122*8e7b46e2SPatrick Williams taskdata['log'] = str(e) 123*8e7b46e2SPatrick Williams taskdata['package'] = str(e._item) 124*8e7b46e2SPatrick Williams taskdata['task'] = "Nothing provides " + "'" + str(e._item) + "'" 125*8e7b46e2SPatrick Williams data['failures'].append(taskdata) 126*8e7b46e2SPatrick Williams lock = bb.utils.lockfile(datafile + '.lock') 127*8e7b46e2SPatrick Williams errorreport_savedata(e, data, "error-report.txt") 128*8e7b46e2SPatrick Williams bb.utils.unlockfile(lock) 129*8e7b46e2SPatrick Williams 130*8e7b46e2SPatrick Williams elif isinstance(e, bb.event.ParseError): 131*8e7b46e2SPatrick Williams bb.utils.mkdirhier(logpath) 132*8e7b46e2SPatrick Williams data = {} 133*8e7b46e2SPatrick Williams data = get_common_data(e) 134*8e7b46e2SPatrick Williams data['nativelsb'] = nativelsb() 135*8e7b46e2SPatrick Williams data['failures'] = [] 136*8e7b46e2SPatrick Williams data['component'] = "parse" 137*8e7b46e2SPatrick Williams taskdata={} 138*8e7b46e2SPatrick Williams taskdata['log'] = str(e._msg) 139*8e7b46e2SPatrick Williams taskdata['task'] = str(e._msg) 140*8e7b46e2SPatrick Williams data['failures'].append(taskdata) 141*8e7b46e2SPatrick Williams lock = bb.utils.lockfile(datafile + '.lock') 142*8e7b46e2SPatrick Williams errorreport_savedata(e, data, "error-report.txt") 143*8e7b46e2SPatrick Williams bb.utils.unlockfile(lock) 144*8e7b46e2SPatrick Williams 145eb8dc403SDave Cobbley elif isinstance(e, bb.event.BuildCompleted): 146eb8dc403SDave Cobbley lock = bb.utils.lockfile(datafile + '.lock') 147eb8dc403SDave Cobbley jsondata = json.loads(errorreport_getdata(e)) 148eb8dc403SDave Cobbley bb.utils.unlockfile(lock) 149eb8dc403SDave Cobbley failures = jsondata['failures'] 150eb8dc403SDave Cobbley if(len(failures) > 0): 151eb8dc403SDave Cobbley filename = "error_report_" + e.data.getVar("BUILDNAME")+".txt" 152eb8dc403SDave Cobbley datafile = errorreport_savedata(e, jsondata, filename) 153eb8dc403SDave 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)) 154eb8dc403SDave 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.") 155eb8dc403SDave Cobbley} 156eb8dc403SDave Cobbley 157eb8dc403SDave Cobbleyaddhandler errorreport_handler 158*8e7b46e2SPatrick Williamserrorreport_handler[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskFailed bb.event.NoProvider bb.event.ParseError" 159