Processes
The main administration tool is the sabayon process: it runs as root, and it is the little window that shows you the list of user profiles. It uses two helper processes. The first helper is sabayon-session, which runs as a temporary user and shows the live Xnest session. The second helper is sabayon-apply, which is used to apply the settings from the user profile being edited into a temporary home directory.
sabayon - main tool used by admins
sabayon-session - helper to run the nested session in a window
sabayon-apply - system tool and helper to make a home directory obtain a certain user profile
Error logging
The helper processes must be able to keep detailed logs of their operation to aid debugging. These logs must be accessible from the main "sabayon" tool which admins use: when the tool encounters an error in itself or in any of its helpers, it must be able to give the admin useful information for debugging (either by the admin himself or by a Sabayon hacker).
While each helper process could maintain its own log, this would be cumbersome for admins to gather and send to a developer. So, Sabayon automatically aggregates all the logs into a single one which can be sent "as-is" to someone for debugging purposes.
Turning on logging
By default, all user actions are logged. That is, Sabayon and its helpers keep logs of the actions which the admin does while directly using them. Sabayon will automatically present these logs to the admin when an error occurs.
Additionally, the admin can enable more detailed logging. To do this, create a file called sabayon-debug-log.conf in root's home directory. This file has a syntax similar to Samba's smb.conf or to Windows .ini files. Put the following text in the ~root/sabayon-debug-log.conf file:
[debug log] max lines = 1000 enable domains = <list of domain names separated by ";">
For example, to enable logs from the storage and files-source modules, you would use a line like this:
enable domains = storage;files-source
These are the available domain names. Note that by default they are not logged unless you list them in the sabayon-debug-log.conf file:
user-profile - Main module to handle user profiles.
storage - Module to save user profiles to a .zip bundle.
panel-delegate - Understands changes which affect the GNOME Panel and its applets.
gconf-source - Monitoring changes in GConf data and logging/saving/restoring them.
files-source - Monitoring of changes in the temporary home directory and logging/saving/restoring them.
mozilla-source - Understands changes in the configuration of Mozilla Firefox.
proto-session - Low-level setup of the nested session (X authority, X displays, etc.).
usermod - Low-level utilities to create a temporary home directory.
dir-monitor - Low-level monitoring of the file system.
user-db - Maintains an association between users and profiles.
cache - Retrieves and caches the contents of remote URIs.
admin-tool - Toplevel operations in the sabayon program (not normally needed).
sabayon-apply - Toplevel operations in the sabayon-apply helper program (not normally needed).
sabayon-session - Toplevel operations in the sabayon-session helper program (not normally needed).
deprecated - Turns on warnings about using deprecated Python or pygtk features (not normally needed).
Exceptions in callbacks
Often, the code flow in Sabayon looks like this:
python code: (1)
gtk_main (): (2)
python code inside a callback: (3)
... (4)If the code inside the callback (3) throws an exception in (4), then Python will go to (2) and the main loop will keep spinning happily. That is, (1) will never know about that exception! It will seem as if the program kept running normally.
If a callback gets an exception due to a bug, we want the toplevel program to notice that as soon as possible so that it can log the appropriate message to the debug log, and terminate the program. So, we use the errors.checked_callback decorator. This decorator catches all unhandled exceptions in a callback, logs the exception to the debug log, and calls gtk.main_quit(). You must use the decorator in all GObject or GSource callbacks (this includes idle handlers, GIO watches, etc.):
import errors
@errors.checked_callback
def my_callback (...):
... body ...And finally, the toplevel program (or whatever calls gtk.main()) should look like this:
import errors
gtk.main ()
if errors.errors_have_fatal_error ():
debuglog.debug_log (True, "domain", "a fatal error occurred; exiting the program")
debuglog.debug_log_dump_to_dated_file (...)
sys.exit (1)