~diwic/apport/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Apport per-package hooks
========================

In addition to the generic information apport collects, arbitrary
package-specific data can be included in the report by adding package hooks.
For example:

 - Relevant log files
 - Configuration files
 - Current system state 

Hooks can also ask interactive questions, cause a crash to be ignored, or the
problem can be marked as "not reportable" with an explanation. 

This happens by placing a Python code snippet into

  /usr/share/apport/package-hooks/<packagename>.py

or

  /usr/share/apport/package-hooks/source_<sourcepackagename>.py

Apport will import this and call a function

  add_info(report, ui)

and pass two arguments:

 - The currently processed problem report. This is an instance of
   apport.Report, and should mainly be used as a dictionary (keys have to be
   alphanumeric and may contain dots, dashes, or underscores). Please see the
   Python help of this class for details:
   
     python -c 'import apport; help(apport.Report)'

 - An instance of apport.ui.HookUI which can be used to interactively get more
   information from the user, such as asking for doing a particular action,
   yes/no question, multiple choices, or a file selector. Please see the Python
   help for available functions:

     python -c 'import apport.ui; help(apport.ui.HookUI)'

Hook behaviour
==============

If you just add information in hooks, Apport will always proceed with filing
a report. You can influence this in various ways:

 * The hook detects a situation which should not be reported as a problem,
   because they happen on known-bad hardware, from a third-party repository, or
   other situations. This can be achieved by adding a field

      report['UnreportableReason'] = _('explanation')

   Such reports are displayed by the apport frontends as unreportable with the
   given explanation. Please ensure proper i18n for the texts.

 * The user cancelled an interactive question for which the hook requires an
   answer. Then you should call

     raise StopIteration

   to cancel the problem report submission.

Package independent hooks
=========================

Similarly to per-package hooks, you can also have additional
information collected for any crash or bug. For example, you might
want to include violation logs from SELinux or AppArmor for every
crash. The interface and file format is identical to the per-package
hooks, except that they need to be put into

  /usr/share/apport/general-hooks/<hookname>.py

The <hookname> can be arbitrary and should describe the functionality.

Tags
====
Some bug tracking systems support tags to further categorize bug reports and
make searching/duplication easier. Hooks can set tags with

  report['Tags'] = 'tag1 tag2'

i. e. a space separated list of tag names.

Customize the crash DB to use
=============================

To use another crash database than the default one, you should create
an hook that adds a 'CrashDB' field with the name of the database to
use. See /etc/apport/crashdb.conf and
/etc/apport/crashdb.conf.d/*.conf for available databases.

Standard hook functions
=======================

If you write hooks, please have a look at the apport.hookutils
module first: 

 python -c 'import apport.hookutils; help(apport.hookutils)'

It provides readymade and safe functions many standard situations, 
such as getting a command's output, attaching a file's contents, 
attaching hardware related information, etc.

Examples
========

Trivial example: To attach a log file /var/log/foo.log for crashes in
binary package foo, put this into /usr/share/apport/package-hooks/foo.py:

------------ 8< ----------------
import os.path

def add_info(report, ui):
    if os.path.exists('/var/log/foo.log'):
        report['FooLog'] = open('/var/log/foo.log').read()
------------ 8< ----------------


Example with an interactive question and attaching sound hardware information:

------------ 8< ----------------
import apport.hookutils

def add_info(report, ui):
    apport.hookutils.attach_alsa(report)

    ui.information('Now playing test sound...')

    report['AplayOut'] = apport.hookutils.command_output(['aplay',
	    '/usr/share/sounds/question.wav'])

    response = ui.yesno('Did you hear the sound?')
    if response == None: # user cancelled
        raise StopIteration
    report['SoundAudible'] = str(response)
------------ 8< ----------------

Apport itself ships a source package hook, see
/usr/share/apport/package-hooks/source_apport.py.