diff options
author | Aleksey Lim <alsroot@member.fsf.org> | 2011-01-18 08:00:27 (GMT) |
---|---|---|
committer | Anish Mangal <anish@activitycentral.com> | 2012-04-27 10:04:45 (GMT) |
commit | 3af98641a4471468caa61705f0fba1205247ec29 (patch) | |
tree | 1854536d8a5e1044bb4ff1014cf6f6a98d39b5bc | |
parent | 4a96592ea1879a21caf4dd07bc62791e07d88395 (diff) |
Report to the shell on errors
m 72f0694200feccd88646e21aadb1c5bde36e7ca3 Mon Sep 17 00:00:00 2001
From: Aleksey Lim <alsroot@member.fsf.org>
Date: Wed, 19 Jan 2011 18:47:58 +0000
Subject: [PATCH sugar-toolkit] Report to the shell on errors
-rw-r--r-- | src/sugar/Makefile.am | 1 | ||||
-rw-r--r-- | src/sugar/activity/activityfactory.py | 10 | ||||
-rw-r--r-- | src/sugar/activity/main.py | 4 | ||||
-rw-r--r-- | src/sugar/feedback.py | 103 |
4 files changed, 115 insertions, 3 deletions
diff --git a/src/sugar/Makefile.am b/src/sugar/Makefile.am index c1ff933..eb4590e 100644 --- a/src/sugar/Makefile.am +++ b/src/sugar/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = activity bundle graphics presence datastore sugardir = $(pythondir)/sugar sugar_PYTHON = \ + feedback.py \ env.py \ network.py \ profile.py \ diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py index a206d15..0da997e 100644 --- a/src/sugar/activity/activityfactory.py +++ b/src/sugar/activity/activityfactory.py @@ -25,6 +25,7 @@ the moment there is no reason to stabilize this API. import logging import uuid +import cjson import dbus import gobject @@ -260,7 +261,7 @@ class ActivityCreationHandler(gobject.GObject): gobject.child_watch_add(child.pid, _child_watch_cb, - (environment_dir, log_file, + (environment_dir, log_file, log_path, self._handle.activity_id)) def _no_reply_handler(self, *args): @@ -324,7 +325,7 @@ def create_with_object_id(bundle, object_id): def _child_watch_cb(pid, condition, user_data): # FIXME we use standalone method here instead of ActivityCreationHandler's # member to have workaround code, see #1123 - environment_dir, log_file, activity_id = user_data + environment_dir, log_file, log_path, activity_id = user_data if environment_dir is not None: subprocess.call(['/bin/rm', '-rf', environment_dir]) @@ -367,6 +368,11 @@ def _child_watch_cb(pid, condition, user_data): def error_handler_cb(error): logging.error('Cannot send NotifyLaunchFailure to the shell') + report = cjson.encode({'failed_exit': 1}) + shell.Feedback(activity_id, report, log_path, + reply_handler=reply_handler_cb, + error_handler=error_handler_cb) + # TODO send launching failure but activity could already show # main window, see http://bugs.sugarlabs.org/ticket/1447#comment:19 shell.NotifyLaunchFailure(activity_id, diff --git a/src/sugar/activity/main.py b/src/sugar/activity/main.py index d2a9302..d513085 100644 --- a/src/sugar/activity/main.py +++ b/src/sugar/activity/main.py @@ -30,7 +30,7 @@ from sugar.activity import activityhandle from sugar.activity import i18n from sugar.bundle.activitybundle import ActivityBundle from sugar.graphics import style -from sugar import logger +from sugar import logger, feedback def create_activity_instance(constructor, handle): @@ -114,6 +114,8 @@ def main(): gettext.bindtextdomain('sugar-toolkit', sugar.locale_path) gettext.textdomain(bundle.get_bundle_id()) + feedback.start(options.activity_id) + splitted_module = args[0].rsplit('.', 1) module_name = splitted_module[0] class_name = splitted_module[1] diff --git a/src/sugar/feedback.py b/src/sugar/feedback.py new file mode 100644 index 0000000..56dacab --- /dev/null +++ b/src/sugar/feedback.py @@ -0,0 +1,103 @@ +# Copyright (C) 2011, Aleksey Lim +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import atexit +import logging + +import dbus +import cjson + + +_SHELL_SERVICE = "org.laptop.Shell" +_SHELL_PATH = "/org/laptop/Shell" +_SHELL_IFACE = "org.laptop.Shell" + +_report = {} +_need_log = False +_log_formatter = None + + +def start(activity_id, log_path=None): + if log_path is None: + # TODO more portable solution + stdout_file = os.readlink('/proc/self/fd/%s' % sys.stdout.fileno()) + if os.path.isfile(stdout_file): + log_path = stdout_file + else: + log_path = '' + + atexit.register(_send, activity_id, log_path) + + +def trigger(key, need_log=False): + global _need_log + + if key not in _report: + _report[key] = 0 + _report[key] += 1 + _need_log = _need_log or need_log + + logging.debug('Feedback[%s] == %s', key, _report[key]) + + +def flush(): + global _report + global _need_log + + report = _report + need_log = _need_log + _report = {} + _need_log = False + + return report, need_log + + +def _send(activity_id, log_path): + if not _report: + return + + report, need_log = flush() + + bus = dbus.SessionBus() + bus_object = bus.get_object(_SHELL_SERVICE, _SHELL_PATH) + shell = dbus.Interface(bus_object, _SHELL_IFACE) + shell.Feedback(activity_id, cjson.encode(report), + log_path if need_log else '') + + +def _excepthook(exctype, value, tb): + global _log_formatter + + if _log_formatter is None: + try: + # Attempt to provide verbose IPython tracebacks. + # Importing IPython is slow, so we import it lazily. + from IPython.ultraTB import AutoFormattedTB + formatter = AutoFormattedTB(mode='Verbose', color_scheme='NoColor') + _log_formatter = formatter.text + except ImportError: + import traceback + _log_formatter = \ + lambda * args: ''.join(traceback.format_exception(*args)) + + message = _log_formatter(exctype, value, tb) + logging.error(message) + + trigger('unhandled_exception', need_log=True) + + +sys.excepthook = _excepthook |