mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-07 01:15:33 +00:00
Ubuntu 20.04 comes with Python 3.8 which doesn't have `platform.freedesktop_os_release()`. This change catches the exception if this happens, as well as other exceptions we might get so that the initialization of Sentry will succeed. Fixes #9773.
177 lines
7 KiB
Python
177 lines
7 KiB
Python
#!/usr/bin/python3
|
|
import getpass
|
|
import hashlib
|
|
import importlib
|
|
import logging
|
|
import os
|
|
import platform
|
|
import sys
|
|
import traceback
|
|
from keyman_config.version import (
|
|
__version__,
|
|
__versionwithtag__,
|
|
__versiongittag__,
|
|
__majorversion__,
|
|
__releaseversion__,
|
|
__tier__,
|
|
__pkgversion__,
|
|
__environment__,
|
|
__uploadsentry__
|
|
)
|
|
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gio, Gtk
|
|
|
|
|
|
class SentryErrorHandling:
|
|
def __init__(self) -> None:
|
|
self.settings = Gio.Settings.new('com.keyman.options')
|
|
|
|
def initialize_sentry(self):
|
|
(enabled, reason) = self.is_sentry_enabled()
|
|
if not enabled:
|
|
print(reason, file=sys.stderr)
|
|
logging.info(reason)
|
|
return (enabled, reason)
|
|
else:
|
|
try:
|
|
self._sentry_sdk_initialize()
|
|
except ImportError:
|
|
try:
|
|
self._raven_initialize()
|
|
except ImportError:
|
|
# even raven is not available. This is the case on Ubuntu 16.04. Just ignore.
|
|
print(_('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'),
|
|
file=sys.stderr)
|
|
logging.info('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.')
|
|
return (False, _('Neither sentry-sdk nor raven is available. Not enabling Sentry error reporting.'))
|
|
return (True, '')
|
|
|
|
def is_sentry_enabled(self):
|
|
if self._is_unit_test():
|
|
return (False, 'Running unit tests, not reporting to Sentry')
|
|
elif self._get_environ_nosentry():
|
|
return (False, 'Not reporting to Sentry because KEYMAN_NOSENTRY environment variable set')
|
|
elif not __uploadsentry__:
|
|
return (False, f'Not reporting to Sentry because UPLOAD_SENTRY is false ({__environment__})')
|
|
elif not self._get_setting():
|
|
return (False, 'Not reporting to Sentry because disabled in GSettings')
|
|
return (True, 'Reporting to Sentry')
|
|
|
|
def is_sentry_disabled_by_variable(self):
|
|
return self._get_environ_nosentry() or not __uploadsentry__
|
|
|
|
def bind_checkbutton(self, button: Gtk.CheckButton):
|
|
self.settings.bind("error-reporting", button, "active", Gio.SettingsBindFlags.NO_SENSITIVITY)
|
|
self.settings.connect("changed::error-reporting", self._on_sentry_reporting_toggled)
|
|
|
|
def set_enabled(self, enabled):
|
|
assert not self.is_sentry_disabled_by_variable()
|
|
was_enabled = self.is_sentry_enabled()
|
|
self._save_setting(enabled)
|
|
if enabled != was_enabled:
|
|
self._handle_enabled(enabled)
|
|
|
|
def _get_environ_nosentry(self):
|
|
keyman_nosentry = os.environ.get('KEYMAN_NOSENTRY')
|
|
return keyman_nosentry and (int(keyman_nosentry) == 1)
|
|
|
|
def _is_unit_test(self): # sourcery skip: use-any, use-next
|
|
# The suggested refactorings (using any() or next()) don't work
|
|
# when testing on Ubuntu 20.04
|
|
for line in traceback.format_stack():
|
|
if '/unittest/' in line:
|
|
return True
|
|
return False
|
|
|
|
def _handle_enabled(self, enabled):
|
|
if enabled:
|
|
self.initialize_sentry()
|
|
else:
|
|
self._close_sentry()
|
|
|
|
def _save_setting(self, enabled: bool):
|
|
self.settings.set_boolean('error-reporting', enabled)
|
|
|
|
def _get_setting(self) -> bool:
|
|
return self.settings.get_boolean('error-reporting')
|
|
|
|
def _on_sentry_reporting_toggled(self, settings, key):
|
|
self._handle_enabled(self.settings.get_boolean('error-reporting'))
|
|
|
|
def _close_sentry(self):
|
|
from sentry_sdk import Hub
|
|
logging.info("Shutting down Sentry error reporting")
|
|
client = Hub.current.client
|
|
if client is not None:
|
|
client.close(timeout=2.0)
|
|
|
|
def _sentry_sdk_initialize(self):
|
|
# Try new sentry-sdk first
|
|
sentry_sdk = importlib.import_module('sentry_sdk')
|
|
from sentry_sdk import configure_scope, set_user
|
|
from sentry_sdk.integrations.logging import LoggingIntegration
|
|
|
|
sentry_logging = LoggingIntegration(
|
|
level=logging.INFO, # Capture info and above as breadcrumbs
|
|
event_level=logging.CRITICAL # Send critical errors as events
|
|
)
|
|
SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357@o1005580.ingest.sentry.io/5983525"
|
|
sentry_sdk.init(
|
|
dsn=SentryUrl,
|
|
environment=__environment__,
|
|
release=__versiongittag__,
|
|
integrations=[sentry_logging],
|
|
before_send=self._before_send
|
|
)
|
|
hash = hashlib.md5()
|
|
hash.update(getpass.getuser().encode())
|
|
set_user({'id': hash.hexdigest()})
|
|
with configure_scope() as scope:
|
|
scope.set_tag("app", os.path.basename(sys.argv[0]))
|
|
scope.set_tag("pkgversion", __pkgversion__)
|
|
scope.set_tag("platform", platform.platform())
|
|
scope.set_tag("system", platform.system())
|
|
scope.set_tag("tier", __tier__)
|
|
scope.set_tag("device", platform.node())
|
|
try:
|
|
os_release = platform.freedesktop_os_release()
|
|
scope.set_tag('os', os_release['PRETTY_NAME'])
|
|
scope.set_tag('os.name', os_release['NAME'])
|
|
if 'VERSION' in os_release:
|
|
scope.set_tag('os.version', os_release['VERSION'])
|
|
except OSError as e:
|
|
logging.debug(f'System does not have os_release file: {e.strerror}')
|
|
except AttributeError:
|
|
logging.debug('System does not have platform.freedesktop_os_release() method')
|
|
except:
|
|
logging.debug(
|
|
'Got exception trying to access platform.freedesktop_os_release() method or os_release information')
|
|
logging.info("Initialized Sentry error reporting")
|
|
|
|
def _raven_initialize(self):
|
|
# sentry-sdk is not available, so use older raven
|
|
raven = importlib.import_module('raven')
|
|
from raven import Client
|
|
|
|
# Note, legacy raven API requires secret (https://github.com/keymanapp/keyman/pull/5787#discussion_r721457909)
|
|
SentryUrl = "https://1d0edbf2d0dc411b87119b6e92e2c357:e6d5a81ee6944fc79bd9f0cbb1f2c2a4@o1005580.ingest.sentry.io/5983525"
|
|
client = Client(SentryUrl, environment=__environment__, release=__versiongittag__)
|
|
client.user_context({'id': hash(getpass.getuser())})
|
|
client.tags_context({
|
|
'app': os.path.basename(sys.argv[0]),
|
|
'pkgversion': __pkgversion__,
|
|
'platform': platform.platform(),
|
|
'system': platform.system(),
|
|
'tier': __tier__,
|
|
})
|
|
logging.info("Initialized Sentry error reporting (raven)")
|
|
|
|
def _before_send(self, event, hint):
|
|
if 'exc_info' in hint:
|
|
exc_type, exc_value, tb = hint['exc_info']
|
|
if isinstance(exc_value, KeyboardInterrupt):
|
|
# Ignore KeyboardInterrupt exception
|
|
return None
|
|
return event
|