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