Skip to content

Commit

Permalink
Add debug info to the About dialog
Browse files Browse the repository at this point in the history
To provide a single source of information about the app, this commit
adds debug info to the About dialog in the form of a JSON object dump.
It includes the version of the application itself, the versions of
essential Python modules, and runtime information about the Kolibri
daemon service.

Helps: #69
  • Loading branch information
dylanmccall committed Oct 23, 2023
1 parent ac3c16c commit 112fbbd
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 4 deletions.
6 changes: 4 additions & 2 deletions data/metainfo/org.endlessos.Key.metainfo.xml.in.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@
</screenshot>
</screenshots>
<releases>
<release version="0.8" date="2023-09-26" type="stable">
<release version="0.8" date="2023-10-23" type="development">
<description>
<ul>
<li>Fix Spanish content pack download and fix font rendering.</li>
<li>Font rendering has been improved.</li>
<li>An error involving the Spanish content pack has been resolved.</li>
<li>Debugging information can now be viewed from the About dialog.</li>
</ul>
</description>
</release>
Expand Down
38 changes: 38 additions & 0 deletions src/kolibri_app/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
from __future__ import annotations

import os
import typing


_APP_MODULES_LIST = [
"kolibri",
"kolibri_app_desktop_xdg_plugin",
"kolibri_desktop_auth_plugin",
"kolibri_explore_plugin",
"kolibri_zim_plugin",
]


def getenv_as_bool(key: str, default: bool = False) -> bool:
Expand All @@ -22,3 +32,31 @@ def getenv_as_bool(key: str, default: bool = False) -> bool:
return False

return default


def get_app_modules_debug_info() -> dict:
debug_info = {}

for module_name in _APP_MODULES_LIST:
debug_info[module_name] = _get_module_debug_info(module_name)

return debug_info


def _get_module_debug_info(module_name: str) -> typing.Optional[dict]:
from importlib.metadata import PackageNotFoundError
from importlib.util import find_spec
from importlib.metadata import version

module_spec = find_spec(module_name)

if module_spec is None:
return None

try:
return {
"version": version(module_name),
"origin": module_spec.origin,
}
except PackageNotFoundError:
return None
9 changes: 9 additions & 0 deletions src/kolibri_gnome/application.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
import logging
import typing
from functools import partial
Expand Down Expand Up @@ -124,9 +125,17 @@ def __on_about(self, action, *args):
license_type=Gtk.License.MIT_X11,
website="https://learningequality.org",
issue_url="https://community.learningequality.org/",
debug_info=self.__format_debug_info(),
debug_info_filename="endless-key-debug-info.json",
)
about_window.present()

def __format_debug_info(self):
return json.dumps(
self.__context.get_debug_info(),
indent=4,
)

def __on_quit(self, action, *args):
self.quit()

Expand Down
17 changes: 17 additions & 0 deletions src/kolibri_gnome/kolibri_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import WebKit
from kolibri_app.config import BUILD_PROFILE
from kolibri_app.config import ENDLESS_KEY_DATA_DIR
from kolibri_app.config import FRONTEND_APPLICATION_ID
from kolibri_app.config import PROJECT_VERSION
from kolibri_app.utils import get_app_modules_debug_info

from .kolibri_daemon_manager import KolibriDaemonManager
from .utils import await_properties
Expand Down Expand Up @@ -145,6 +148,20 @@ def default_is_url_in_scope(self, url: str) -> bool:
def is_url_in_scope(self, url: str) -> bool:
return self.default_is_url_in_scope(url)

def get_debug_info(self) -> dict:
# FIXME: It would be better to call `get_app_modules_debug_info()` from`
# the kolibri_daemon service and include the output here. In some
# rare cases, its Python environment may differ.
return {
"app": {
"project_version": PROJECT_VERSION,
"build_profile": BUILD_PROFILE,
"do_automatic_login": self.__kolibri_daemon.do_automatic_login,
},
"kolibri_daemon": self.__kolibri_daemon.get_debug_info(),
"python_modules": get_app_modules_debug_info(),
}

def get_loader_url(self, state: str) -> str:
if state == "error":
return f"{self.__loader_url}#/loading/error"
Expand Down
16 changes: 14 additions & 2 deletions src/kolibri_gnome/kolibri_daemon_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from kolibri_app.config import DAEMON_APPLICATION_ID
from kolibri_app.config import DAEMON_MAIN_OBJECT_PATH
from kolibri_app.globals import APP_AUTOMATIC_LOGIN
from kolibri_app.globals import APP_AUTOMATIC_PROVISION

from .utils import GioInputStreamIO

Expand All @@ -30,6 +31,7 @@ class KolibriDaemonManager(GObject.GObject):
stops Kolibri, and provides some helpers to access Kolibri's HTTP API.
"""

__bus_type: Gio.BusType
__dbus_proxy: KolibriDaemonDBus.MainProxy

__did_init: bool = False
Expand All @@ -47,10 +49,10 @@ class KolibriDaemonManager(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)

g_bus_type = KolibriDaemonDBus.get_default_bus_type()
self.__bus_type = KolibriDaemonDBus.get_default_bus_type()

self.__dbus_proxy = KolibriDaemonDBus.MainProxy(
g_bus_type=g_bus_type,
g_bus_type=self.__bus_type,
g_name=DAEMON_APPLICATION_ID,
g_object_path=DAEMON_MAIN_OBJECT_PATH,
g_interface_name=KolibriDaemonDBus.main_interface_info().name,
Expand Down Expand Up @@ -107,6 +109,16 @@ def get_absolute_url(self, url: str = "") -> typing.Optional[str]:
else:
return None

def get_debug_info(self) -> dict:
return {
"g_bus_type": self.__bus_type.value_name,
"status": self.__dbus_proxy.props.status,
"base_url": self.__dbus_proxy.props.base_url,
"kolibri_home": self.__dbus_proxy.props.kolibri_home,
"kolbri_version": self.__dbus_proxy.props.kolibri_version,
"do_automatic_provision": APP_AUTOMATIC_PROVISION,
}

def kolibri_api_get(self, path: str) -> typing.Any:
url = self.get_absolute_url(path)

Expand Down

0 comments on commit 112fbbd

Please sign in to comment.