Skip to content

Commit

Permalink
chore(debug): setup sentry for error tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
sassanh committed Mar 27, 2024
1 parent 79cd0b0 commit fbea428
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 43 deletions.
46 changes: 39 additions & 7 deletions .github/workflows/integration_delivery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,16 @@ jobs:
run: |
poetry run poe test --make-screenshots --cov-report=xml --cov-report=html -n auto
- name: Collect Screenshots
- name: Collect Window Screenshots
uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
path: tests/**/results/**/*.png
continue-on-error: true

- name: Collect Store Snapshots
uses: actions/upload-artifact@v4
if: always()
with:
name: snapshots
path: tests/**/results/**/*.jsonc
Expand All @@ -160,8 +161,8 @@ jobs:
- dependencies
runs-on: ubuntu-latest
outputs:
version: ${{ steps.extract_version.outputs.version }}
name: ${{ steps.extract_version.outputs.name }}
version: ${{ steps.extract_version.outputs.VERSION }}
name: ${{ steps.extract_version.outputs.NAME }}
steps:
- uses: actions/checkout@v4
name: Checkout
Expand All @@ -183,14 +184,45 @@ jobs:
~/.local
key: poetry-${{ hashFiles('poetry.lock') }}

- name: Add SENTRY_DSN to .env
run: |
echo "SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
- name: Build
run: poetry build

- name: Extract Version
id: extract_version
run: |
echo "version=$(poetry version --short)" >> "$GITHUB_OUTPUT"
echo "name=$(poetry version | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
echo "VERSION=$(poetry version --short)" >> "$GITHUB_OUTPUT"
echo "NAME=$(poetry version | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
echo "VERSION=$(poetry version --short)"
echo "NAME=$(poetry version | cut -d' ' -f1)"
- name: Extract Version from CHANGELOG.md
id: extract_changelog_version
run: |
VERSION_CHANGELOG=$(sed -n '3 s/## Version //p' CHANGELOG.md)
echo "VERSION_CHANGELOG=$VERSION_CHANGELOG"
if [ "${{ steps.extract_version.outputs.VERSION }}" != "$VERSION_CHANGELOG" ]; then
echo "Error: Version extracted from CHANGELOG.md does not match the version in pyproject.toml"
exit 1
else
echo "Versions are consistent."
fi
- name: Extract Version from Tag
if: startsWith(github.ref, 'refs/tags/v')
id: extract_tag_version
run: |
VERSION_TAG=$(sed 's/^v//' <<< ${{ github.ref_name }})
echo "VERSION_TAG=$VERSION_TAG"
if [ "${{ steps.extract_version.outputs.VERSION }}" != "$VERSION_TAG" ]; then
echo "Error: Version extracted from tag does not match the version in pyproject.toml"
exit 1
else
echo "Versions are consistent."
fi
- name: Upload wheel
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -329,6 +361,7 @@ jobs:
if-no-files-found: error

release:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
name: Release
needs:
- type-check
Expand All @@ -343,7 +376,6 @@ jobs:
url: https://pypi.org/p/${{ needs.build.outputs.name }}
permissions:
contents: write
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- name: Procure Lite Image
uses: actions/download-artifact@v4
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Version 0.11.6

- chore(debug): setup sentry for error tracking

## Version 0.11.4

- feat(docker): add ngrok service (currently serves port 22 with no auth token)
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
Ubo App is a Python application for managing Raspberry Pi utilities and UBo-specific
features.

## 🚧 Disclaimer

Be aware that at the moment, Ubo app sends crash reports to Sentry. Soon we will
limit this to beta versions only.

## ⚙️ Features

[To be written]
Expand Down
49 changes: 48 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ubo-app"
version = "0.11.5"
version = "0.11.6"
description = "Ubo main app, running on device initialization. A platform for running other apps."
authors = ["Sassan Haradji <[email protected]>"]
license = "Apache-2.0"
Expand Down Expand Up @@ -38,6 +38,7 @@ adafruit-circuitpython-pct2075 = "^1.1.21"
adafruit-circuitpython-veml7700 = "^1.1.22"
docker = "^7.0.0"
python-dotenv = "^1.0.1"
sentry-sdk = "^1.43.0"

[tool.poetry.group.dev]
optional = true
Expand Down
2 changes: 2 additions & 0 deletions ubo_app/.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ UBO_DEBUG_DOCKER=False
UBO_LOG_LEVEL=INFO
UBO_GUI_LOG_LEVEL=INFO
UBO_SERVICES_PATH=

SENTRY_DSN=
2 changes: 2 additions & 0 deletions ubo_app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@
DEBUG_MODE_DOCKER = strtobool(os.environ.get('UBO_DEBUG_DOCKER', 'False')) == 1
DOCKER_PREFIX = os.environ.get('UBO_DOCKER_PREFIX', '')
DOCKER_INSTALLATION_LOCK_FILE = Path('/var/run/ubo/docker_installation.lock')

SENTRY_DSN = os.environ.get('SENTRY_DSN', '')
90 changes: 60 additions & 30 deletions ubo_app/main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107
from __future__ import annotations

import os
import sys
import threading
import traceback
from pathlib import Path
from types import TracebackType
from typing import TYPE_CHECKING

import dotenv
import sentry_sdk
from redux import FinishAction

if TYPE_CHECKING:
from types import TracebackType

dotenv.load_dotenv(Path(__file__).parent / '.dev.env')


Expand Down Expand Up @@ -45,47 +51,71 @@ def setup_logging() -> None:
ubo_gui.logger.add_stdout_handler(level)


def main() -> None:
"""Instantiate the `MenuApp` and run it."""
setup_logging()

if len(sys.argv) > 1 and sys.argv[1] == 'bootstrap':
from ubo_app.system.bootstrap import bootstrap
def setup_sentry() -> None: # pragma: no cover
from ubo_app.constants import SENTRY_DSN

bootstrap(
with_docker='--with-docker' in sys.argv,
for_packer='--for-packer' in sys.argv,
if SENTRY_DSN:
sentry_sdk.init(
dsn=SENTRY_DSN,
traces_sample_rate=1.0,
profiles_sample_rate=1.0,
)
sys.exit(0)

def global_exception_handler(
exception_type: type,
value: int,
tb: TracebackType,
) -> None:
from ubo_app.logging import logger

logger.error(f'Uncaught exception: {exception_type}: {value}')
logger.error(''.join(traceback.format_tb(tb)))
def get_all_thread_stacks() -> dict[str, list[str]]:
id_to_name = {th.ident: th.name for th in threading.enumerate()}
thread_stacks = {}
for thread_id, frame in sys._current_frames().items(): # noqa: SLF001
thread_stacks[id_to_name.get(thread_id, f'unknown-{thread_id}')] = (
traceback.format_stack(frame)
)
return thread_stacks

# Set the global exception handler
sys.excepthook = global_exception_handler

def thread_exception_handler(args: threading.ExceptHookArgs) -> None:
import traceback
def global_exception_handler(
exception_type: type[BaseException],
exception_value: BaseException,
exception_traceback: TracebackType,
) -> None:
from ubo_app.logging import logger

from ubo_app.logging import logger
error_message = ''.join(
traceback.format_exception(
exception_type,
exception_value,
exception_traceback,
),
)
threads_info = get_all_thread_stacks()

logger.error(
f"""Exception in thread {args.thread.name if args.thread else "-"}: {
args.exc_type} {args.exc_value}""",
)
logger.error(''.join(traceback.format_tb(args.exc_traceback)))
logger.debug(
f'Uncaught exception: {exception_type}: {exception_value}\n{error_message}',
extra={'threads': threads_info},
)

threading.excepthook = thread_exception_handler

def main() -> None:
"""Instantiate the `MenuApp` and run it."""
os.environ['KIVY_NO_CONFIG'] = '1'
os.environ['KIVY_NO_FILELOG'] = '1'
os.environ['KIVY_NO_CONSOLELOG'] = '1'
os.environ['KCFG_KIVY_EXIT_ON_ESCAPE'] = '0'

setup_sentry()
setup_logging()

# Set the global exception handler
sys.excepthook = global_exception_handler
threading.excepthook = global_exception_handler

if len(sys.argv) > 1 and sys.argv[1] == 'bootstrap':
from ubo_app.system.bootstrap import bootstrap

bootstrap(
with_docker='--with-docker' in sys.argv,
for_packer='--for-packer' in sys.argv,
)
sys.exit(0)

import headless_kivy_pi.config

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/020-keyboard/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def on_keyboard(
dispatch(KeypadKeyPressAction(key=Key.L2))
elif key == Keyboard.keycodes['3']:
dispatch(KeypadKeyPressAction(key=Key.L3))
elif key == Keyboard.keycodes['left']:
elif key == Keyboard.keycodes['esc']:
dispatch(KeypadKeyPressAction(key=Key.BACK))
elif key == Keyboard.keycodes['m']:
from ubo_app.store import dispatch
Expand Down
4 changes: 1 addition & 3 deletions ubo_app/services/080-docker/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,7 @@ def act() -> None:


@autorun(lambda state: state.docker)
def _run_container_generator(
docker_state: DockerState,
) -> Callable[[ImageState], None]:
def _run_container_generator(docker_state: DockerState) -> Callable[[ImageState], None]:
def run_container(image: ImageState) -> None:
def act() -> None:
docker_client = docker.from_env()
Expand Down

0 comments on commit fbea428

Please sign in to comment.