1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# Collects debug information in order to create error report files. 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (C) 2013 Intel Corporation 5*4882a593Smuzhiyun# Author: Andreea Brandusa Proca <andreea.b.proca@intel.com> 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# Licensed under the MIT license, see COPYING.MIT for details 8*4882a593Smuzhiyun 9*4882a593SmuzhiyunERR_REPORT_DIR ?= "${LOG_DIR}/error-report" 10*4882a593Smuzhiyun 11*4882a593Smuzhiyundef errorreport_getdata(e): 12*4882a593Smuzhiyun import codecs 13*4882a593Smuzhiyun logpath = e.data.getVar('ERR_REPORT_DIR') 14*4882a593Smuzhiyun datafile = os.path.join(logpath, "error-report.txt") 15*4882a593Smuzhiyun with codecs.open(datafile, 'r', 'utf-8') as f: 16*4882a593Smuzhiyun data = f.read() 17*4882a593Smuzhiyun return data 18*4882a593Smuzhiyun 19*4882a593Smuzhiyundef errorreport_savedata(e, newdata, file): 20*4882a593Smuzhiyun import json 21*4882a593Smuzhiyun import codecs 22*4882a593Smuzhiyun logpath = e.data.getVar('ERR_REPORT_DIR') 23*4882a593Smuzhiyun datafile = os.path.join(logpath, file) 24*4882a593Smuzhiyun with codecs.open(datafile, 'w', 'utf-8') as f: 25*4882a593Smuzhiyun json.dump(newdata, f, indent=4, sort_keys=True) 26*4882a593Smuzhiyun return datafile 27*4882a593Smuzhiyun 28*4882a593Smuzhiyundef get_conf_data(e, filename): 29*4882a593Smuzhiyun builddir = e.data.getVar('TOPDIR') 30*4882a593Smuzhiyun filepath = os.path.join(builddir, "conf", filename) 31*4882a593Smuzhiyun jsonstring = "" 32*4882a593Smuzhiyun if os.path.exists(filepath): 33*4882a593Smuzhiyun with open(filepath, 'r') as f: 34*4882a593Smuzhiyun for line in f.readlines(): 35*4882a593Smuzhiyun if line.startswith("#") or len(line.strip()) == 0: 36*4882a593Smuzhiyun continue 37*4882a593Smuzhiyun else: 38*4882a593Smuzhiyun jsonstring=jsonstring + line 39*4882a593Smuzhiyun return jsonstring 40*4882a593Smuzhiyun 41*4882a593Smuzhiyunpython errorreport_handler () { 42*4882a593Smuzhiyun import json 43*4882a593Smuzhiyun import codecs 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun def nativelsb(): 46*4882a593Smuzhiyun nativelsbstr = e.data.getVar("NATIVELSBSTRING") 47*4882a593Smuzhiyun # provide a bit more host info in case of uninative build 48*4882a593Smuzhiyun if e.data.getVar('UNINATIVE_URL') != 'unset': 49*4882a593Smuzhiyun return '/'.join([nativelsbstr, lsb_distro_identifier(e.data)]) 50*4882a593Smuzhiyun return nativelsbstr 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun logpath = e.data.getVar('ERR_REPORT_DIR') 53*4882a593Smuzhiyun datafile = os.path.join(logpath, "error-report.txt") 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun if isinstance(e, bb.event.BuildStarted): 56*4882a593Smuzhiyun bb.utils.mkdirhier(logpath) 57*4882a593Smuzhiyun data = {} 58*4882a593Smuzhiyun machine = e.data.getVar("MACHINE") 59*4882a593Smuzhiyun data['machine'] = machine 60*4882a593Smuzhiyun data['build_sys'] = e.data.getVar("BUILD_SYS") 61*4882a593Smuzhiyun data['nativelsb'] = nativelsb() 62*4882a593Smuzhiyun data['distro'] = e.data.getVar("DISTRO") 63*4882a593Smuzhiyun data['target_sys'] = e.data.getVar("TARGET_SYS") 64*4882a593Smuzhiyun data['failures'] = [] 65*4882a593Smuzhiyun data['component'] = " ".join(e.getPkgs()) 66*4882a593Smuzhiyun data['branch_commit'] = str(base_detect_branch(e.data)) + ": " + str(base_detect_revision(e.data)) 67*4882a593Smuzhiyun data['bitbake_version'] = e.data.getVar("BB_VERSION") 68*4882a593Smuzhiyun data['layer_version'] = get_layers_branch_rev(e.data) 69*4882a593Smuzhiyun data['local_conf'] = get_conf_data(e, 'local.conf') 70*4882a593Smuzhiyun data['auto_conf'] = get_conf_data(e, 'auto.conf') 71*4882a593Smuzhiyun lock = bb.utils.lockfile(datafile + '.lock') 72*4882a593Smuzhiyun errorreport_savedata(e, data, "error-report.txt") 73*4882a593Smuzhiyun bb.utils.unlockfile(lock) 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun elif isinstance(e, bb.build.TaskFailed): 76*4882a593Smuzhiyun task = e.task 77*4882a593Smuzhiyun taskdata={} 78*4882a593Smuzhiyun log = e.data.getVar('BB_LOGFILE') 79*4882a593Smuzhiyun taskdata['package'] = e.data.expand("${PF}") 80*4882a593Smuzhiyun taskdata['task'] = task 81*4882a593Smuzhiyun if log: 82*4882a593Smuzhiyun try: 83*4882a593Smuzhiyun with codecs.open(log, encoding='utf-8') as logFile: 84*4882a593Smuzhiyun logdata = logFile.read() 85*4882a593Smuzhiyun # Replace host-specific paths so the logs are cleaner 86*4882a593Smuzhiyun for d in ("TOPDIR", "TMPDIR"): 87*4882a593Smuzhiyun s = e.data.getVar(d) 88*4882a593Smuzhiyun if s: 89*4882a593Smuzhiyun logdata = logdata.replace(s, d) 90*4882a593Smuzhiyun except: 91*4882a593Smuzhiyun logdata = "Unable to read log file" 92*4882a593Smuzhiyun else: 93*4882a593Smuzhiyun logdata = "No Log" 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun # server will refuse failures longer than param specified in project.settings.py 96*4882a593Smuzhiyun # MAX_UPLOAD_SIZE = "5242880" 97*4882a593Smuzhiyun # use lower value, because 650 chars can be spent in task, package, version 98*4882a593Smuzhiyun max_logdata_size = 5242000 99*4882a593Smuzhiyun # upload last max_logdata_size characters 100*4882a593Smuzhiyun if len(logdata) > max_logdata_size: 101*4882a593Smuzhiyun logdata = "..." + logdata[-max_logdata_size:] 102*4882a593Smuzhiyun taskdata['log'] = logdata 103*4882a593Smuzhiyun lock = bb.utils.lockfile(datafile + '.lock') 104*4882a593Smuzhiyun jsondata = json.loads(errorreport_getdata(e)) 105*4882a593Smuzhiyun jsondata['failures'].append(taskdata) 106*4882a593Smuzhiyun errorreport_savedata(e, jsondata, "error-report.txt") 107*4882a593Smuzhiyun bb.utils.unlockfile(lock) 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun elif isinstance(e, bb.event.BuildCompleted): 110*4882a593Smuzhiyun lock = bb.utils.lockfile(datafile + '.lock') 111*4882a593Smuzhiyun jsondata = json.loads(errorreport_getdata(e)) 112*4882a593Smuzhiyun bb.utils.unlockfile(lock) 113*4882a593Smuzhiyun failures = jsondata['failures'] 114*4882a593Smuzhiyun if(len(failures) > 0): 115*4882a593Smuzhiyun filename = "error_report_" + e.data.getVar("BUILDNAME")+".txt" 116*4882a593Smuzhiyun datafile = errorreport_savedata(e, jsondata, filename) 117*4882a593Smuzhiyun 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)) 118*4882a593Smuzhiyun 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.") 119*4882a593Smuzhiyun} 120*4882a593Smuzhiyun 121*4882a593Smuzhiyunaddhandler errorreport_handler 122*4882a593Smuzhiyunerrorreport_handler[eventmask] = "bb.event.BuildStarted bb.event.BuildCompleted bb.build.TaskFailed" 123