xref: /OK3568_Linux_fs/yocto/poky/meta/classes/report-error.bbclass (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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