Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey 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)
commit3af98641a4471468caa61705f0fba1205247ec29 (patch)
tree1854536d8a5e1044bb4ff1014cf6f6a98d39b5bc
parent4a96592ea1879a21caf4dd07bc62791e07d88395 (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.am1
-rw-r--r--src/sugar/activity/activityfactory.py10
-rw-r--r--src/sugar/activity/main.py4
-rw-r--r--src/sugar/feedback.py103
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