Merge lp:~ycheng-twn/apport/bug-1841157 into lp:~apport-hackers/apport/trunk

Proposed by Yuan-Chen Cheng
Status: Merged
Merge reported by: Brian Murray
Merged at revision: not available
Proposed branch: lp:~ycheng-twn/apport/bug-1841157
Merge into: lp:~apport-hackers/apport/trunk
Diff against target: 261 lines (+239/-0)
2 files modified
apport/hookutils.py (+4/-0)
bin/oem-getlogs (+235/-0)
To merge this branch: bzr merge lp:~ycheng-twn/apport/bug-1841157
Reviewer Review Type Date Requested Status
Yuan-Chen Cheng (community) Needs Resubmitting
Apport upstream developers Pending
Review via email: mp+373802@code.launchpad.net

Description of the change

add bin/oem-getlogs to collect all-in-one HWE log that will be very helpful for interacting with OEM vendor.

To post a comment you must log in.
Revision history for this message
Brian Murray (brian-murray) wrote :

I apologize for the delay in reviewing this. I approve of the new direction but there are some changes I'd like to see made and my comments can be found inline.

lp:~ycheng-twn/apport/bug-1841157 updated
3259. By Yuan-Chen Cheng

polish by better command line option, more checking, etc.

3260. By Yuan-Chen Cheng

comment out debug flag

Revision history for this message
Yuan-Chen Cheng (ycheng-twn) wrote :

modify accordingly. tested on both platforms with/without nv debug script.

for change output file owner, there seems no reliable way to get the
user/group, not sure how we should properly doing it.

review: Needs Resubmitting
Revision history for this message
Brian Murray (brian-murray) wrote :

One thing that might reduce code duplication in add_info() is calling attach_command_output() in a for loop. For example something like this:

stuff = {
         'UbuntuReport': ['ubuntu-report', 'show'],
         'lspci-xx': ['lspci', '-x'],
         'dmidecode': ['dmidecode', '']
        }
for name in stuff:
    attach_command_output(report, [stuff[name][0], stuff[name][1]], name)
    dot()

You could still include comments indicating the grouping (audio related) in the dictionary definition which would mostly keep the logical groupings you have.

lp:~ycheng-twn/apport/bug-1841157 updated
3261. By Yuan-Chen Cheng

refactor commands into loop, add lsusb -v and -t

Revision history for this message
Yuan-Chen Cheng (ycheng-twn) wrote :

modify accordingly and tested.

Just found the existing lsusb does not have -v / -t.
"lsusb -v" will the minimal requirement.

So I add lsusb -v and -t to hookutils.py.

review: Needs Resubmitting
Revision history for this message
Brian Murray (brian-murray) wrote :

Sorry, one more thing needs addressing.

lp:~ycheng-twn/apport/bug-1841157 updated
3262. By Yuan-Chen Cheng

refine error and notice message, and add acpitables

Revision history for this message
Yuan-Chen Cheng (ycheng-twn) wrote :

no worry, I also made lots of small mistakes.

Fix accordingly, refine notice message and add acpitables.

review: Needs Resubmitting
Revision history for this message
Brian Murray (brian-murray) wrote :

I've gone ahead and merged this but I actually used the focal branch of apport as the target. I did this as I don't think oem-getlogs belongs in the upstream code as it is Ubuntu specific.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'apport/hookutils.py'
2--- apport/hookutils.py 2019-05-16 18:48:29 +0000
3+++ apport/hookutils.py 2019-12-13 07:53:16 +0000
4@@ -235,6 +235,8 @@
5 - /proc/modules
6 - lspci -vvnn
7 - lsusb
8+ - lsusb -v
9+ - lsusb -t
10 - devices from udev
11 - DMI information from /sys
12 - prtconf (sparc)
13@@ -249,6 +251,8 @@
14 if os.path.exists('/sys/bus/pci'):
15 report['Lspci'] = command_output(['lspci', '-vvnn'])
16 report['Lsusb'] = command_output(['lsusb'])
17+ report['Lsusb-v'] = command_output(['lsusb', '-v'])
18+ report['Lsusb-t'] = command_output(['lsusb', '-t'])
19 report['ProcModules'] = command_output(['sort', '/proc/modules'])
20 report['UdevDb'] = command_output(['udevadm', 'info', '--export-db'])
21
22
23=== added file 'bin/oem-getlogs'
24--- bin/oem-getlogs 1970-01-01 00:00:00 +0000
25+++ bin/oem-getlogs 2019-12-13 07:53:16 +0000
26@@ -0,0 +1,235 @@
27+#! /usr/bin/python3
28+
29+from apport.hookutils import *
30+
31+from glob import glob
32+from io import BytesIO
33+import zipfile
34+from problem_report import CompressedValue
35+import os, sys, tempfile, shutil, re
36+import time, subprocess
37+
38+opt_debug = False
39+
40+# Apport helper routines
41+def debug(text):
42+ if opt_debug:
43+ print("%s\n" %(text))
44+
45+def attach_command_output(report, command_list, key):
46+ debug("%s" %(' '.join(command_list)))
47+ log = command_output(command_list) # from hookutils
48+ if not log or log[:5] == "Error":
49+ return
50+ report[key] = log
51+
52+def attach_pathglob_as_zip(report, pathglob, key, data_filter=None, type="b"):
53+ """Use zip file here because tarfile module in linux can't
54+ properly handle file size 0 with content in /sys directory like
55+ edid file. zipfile module works fine here. So we use it.
56+
57+ type:
58+ a: for ascii type of data
59+ b: for binary type of data
60+ """
61+ if data_filter is None:
62+ data_filter = lambda x: x
63+ filelist = []
64+ for pg in pathglob:
65+ for file in glob(pg):
66+ filelist.append(file)
67+
68+ zipf = BytesIO()
69+ with zipfile.ZipFile(zipf, mode='w', compression=zipfile.ZIP_DEFLATED) as zipobj:
70+ for f in filelist:
71+ if opt_debug:
72+ print(key, f)
73+ if not os.path.isfile(f):
74+ if opt_debug:
75+ print(f, "is not a file")
76+ continue
77+ if type == "a":
78+ with open(f) as f_fd:
79+ data = f_fd.read()
80+ zipobj.writestr(f, data_filter(data))
81+ else:
82+ zipobj.write(f)
83+ cvalue = CompressedValue()
84+ cvalue.set_value(zipf.getbuffer())
85+ report[key + ".zip"] = cvalue
86+
87+def attach_nvidia_debug_logs(report, keep_locale=False):
88+ # check if nvidia-bug-report.sh exists
89+ nv_debug_command = 'nvidia-bug-report.sh'
90+
91+ if shutil.which(nv_debug_command) is None:
92+ if opt_debug:
93+ print(nv_debug_command, "does not exists.")
94+ return
95+
96+ env = os.environ.copy()
97+ if not keep_locale:
98+ env['LC_MESSAGES'] = 'C'
99+
100+ # output result to temp directory
101+ nv_tempdir = tempfile.mkdtemp()
102+ nv_debug_file = 'nvidia-bug-report'
103+ nv_debug_fullfile = os.path.join(nv_tempdir, nv_debug_file)
104+ nv_debug_cmd = [nv_debug_command, '--output-file', nv_debug_fullfile]
105+ try:
106+ with open(os.devnull, 'w') as devnull:
107+ subprocess.run(nv_debug_cmd, env=env, stdout=devnull, stderr=devnull)
108+ nv_debug_fullfile_gz = nv_debug_fullfile + ".gz"
109+ attach_file_if_exists(report, nv_debug_fullfile_gz, 'nvidia-bug-report.gz')
110+ os.unlink(nv_debug_fullfile_gz)
111+ os.rmdir(nv_tempdir)
112+ except OSError as e:
113+ print("Error:", str(e))
114+ print("Fail on cleanup", nv_tempdir, ". Please fire a bug for it.")
115+
116+def dot():
117+ print(".", end="", flush=True)
118+
119+def build_packages():
120+ # related packages
121+ packages = ['apt', 'grub2']
122+
123+ # display
124+ packages.append('xorg')
125+ packages.append('gnome-shell')
126+
127+ # audio
128+ packages.append('alsa-base')
129+
130+ # hotkey and hotplugs
131+ packages.append('udev')
132+
133+ # networking issues
134+ packages.append('network-manager')
135+
136+ return packages
137+
138+
139+def helper_url_credential_filter(string_with_urls):
140+ return re.sub(r"://\w+?:\w+?@", "://USER:SECRET@", string_with_urls)
141+
142+def add_info(report):
143+ # Check if the DCD file is exist in the installer.
144+ attach_command_output(report, ['ubuntu-report', 'show'], 'UbuntuReport'); dot()
145+ attach_file_if_exists(report, '/etc/buildstamp', 'BuildStamp'); dot()
146+
147+ # Basic hardare information
148+ attach_hardware(report); dot()
149+ attach_wifi(report); dot()
150+
151+ hwe_system_commands = {
152+ 'lspci--xxxx': ['lspci', '-xxxx'],
153+ 'lshw.json': ['lshw', '-json', '-numeric'],
154+ 'dmidecode': ['dmidecode'],
155+ 'acpidump': ['acpidump'],
156+ 'fwupdmgr_get-devices': ['fwupdmgr', 'get-devices', '--show-all-devices', '--no-unreported-check'],
157+ 'boltctl-list': ['boltctl', 'list'],
158+ 'mokutil---sb-state': ['mokutil', '--sb-state'],
159+ 'tlp-stat': ['tlp-stat']
160+ }
161+ for name in hwe_system_commands:
162+ attach_command_output(report, hwe_system_commands[name], name); dot()
163+ attach_pathglob_as_zip(report, [
164+ '/sys/firmware/acpi/tables/*',
165+ '/sys/firmware/acpi/tables/*/*'
166+ ], "acpitables"); dot()
167+
168+ # More audio related
169+ attach_alsa(report); dot()
170+ audio_system_commands = {
171+ 'pactl-list': ['pactl', 'list'],
172+ 'aplay-l': ['aplay', '-l'],
173+ 'aplay-L': ['aplay', '-L'],
174+ 'arecord-l': ['arecord', '-l'],
175+ 'arecord-L': ['arecord', '-L']
176+ }
177+ for name in audio_system_commands:
178+ attach_command_output(report, audio_system_commands[name], name); dot()
179+ attach_pathglob_as_zip(report, ['/usr/share/alsa/ucm/*/*'], "ALSA-UCM"); dot()
180+
181+ # FIXME: should be included in xorg in the future
182+ gfx_system_commands = {
183+ 'glxinfo': ['glxinfo'],
184+ 'xrandr': ['xrandr'],
185+ 'xinput': ['xinput']
186+ }
187+ for name in gfx_system_commands:
188+ attach_command_output(report, gfx_system_commands[name], name); dot()
189+ attach_pathglob_as_zip(report, ['/sys/devices/*/*/drm/card?/*/edid'], "EDID"); dot()
190+
191+ # nvidia-bug-reports.sh
192+ attach_nvidia_debug_logs(report); dot()
193+
194+ # FIXME: should be included in thermald in the future
195+ attach_pathglob_as_zip(report, [
196+ "/etc/thermald/*",
197+ "/sys/devices/virtual/thermal/*",
198+ "/sys/class/thermal/*"
199+ ], "THERMALD"); dot()
200+
201+ # all kernel and system messages
202+ attach_pathglob_as_zip(report, ["/var/log/*", "/var/log/*/*"], "VAR_LOG"); dot()
203+
204+ # apt configs
205+ attach_pathglob_as_zip(report, [
206+ "/etc/apt/apt.conf.d/*",
207+ "/etc/apt/sources.list",
208+ "/etc/apt/sources.list.d/*.list",
209+ "/etc/apt/preferences.d/*"], "APT_CONFIGS",
210+ type="a", data_filter=helper_url_credential_filter); dot()
211+
212+ # TODO: debug information for suspend or hibernate
213+
214+ # packages installed.
215+ attach_command_output(report, ['dpkg', '-l'], 'dpkg-l'); dot()
216+
217+ # FIXME: should be included in bluez in the future
218+ attach_command_output(report, ['hciconfig', '-a'], 'hciconfig-a'); dot()
219+
220+ # FIXME: should be included in dkms in the future
221+ attach_command_output(report, ['dkms', 'status'], 'dkms_status'); dot()
222+
223+ # enable when the feature to include data from package hooks exists.
224+ # packages = build_packages()
225+ # attach_related_packages(report, packages)
226+
227+if __name__ == '__main__':
228+ from argparse import ArgumentParser
229+ import gzip
230+
231+ parser = ArgumentParser(prog="oem-getlogs",
232+ usage="Useage: sudo oem-getlogs [-c CASE_ID]",
233+ description="Get Hardware Enablement related logs")
234+ parser.add_argument("-c", "--case-id", help="optional CASE_ID", dest="cid", default="")
235+ args = parser.parse_args()
236+
237+ # check if we got root permission
238+ if os.geteuid() != 0:
239+ print("Error: you need to run this program as root")
240+ parser.print_help()
241+ sys.exit(1)
242+
243+ print("Start to collect logs: ", end="", flush=True)
244+ # create report
245+ report = apport.Report()
246+ add_info(report)
247+
248+ # generate filename
249+ hostname = os.uname()[1]
250+ date_time = time.strftime("%Y%m%d%H%M%S%z", time.localtime())
251+ filename_lst = ["oemlogs", hostname]
252+ if (len(args.cid) > 0):
253+ filename_lst.append(args.cid)
254+ filename_lst.append(date_time + ".apport.gz")
255+ filename = "-".join(filename_lst)
256+
257+ with gzip.open(filename, 'wb') as f:
258+ report.write(f)
259+ print("\nSaved log to", filename)
260+ print("The ower of the file is root. You might want to")
261+ print(" chown [user].[group]", filename)

Subscribers

People subscribed via source and target branches