From 499794ddd1814cbc6042720bacac87eec85a0875 Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Fri, 7 Jun 2024 05:43:16 -0700 Subject: [PATCH] FrogPilot features - openpilot crashed alert --- selfdrive/controls/controlsd.py | 10 ++++++ selfdrive/controls/lib/events.py | 8 +++++ selfdrive/ui/qt/offroad/software_settings.cc | 2 +- system/manager/manager.py | 5 +++ system/sentry.py | 35 ++++++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index ff250e114..85c9006ab 100644 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -6,6 +6,7 @@ import threading from typing import SupportsFloat import cereal.messaging as messaging +import openpilot.system.sentry as sentry from cereal import car, custom, log from msgq.visionipc import VisionIpcClient, VisionStreamType @@ -180,6 +181,7 @@ class Controls: # FrogPilot variables self.frogpilot_toggles = FrogPilotVariables.toggles + self.openpilot_crashed_triggered = False self.update_toggles = False self.display_timer = 0 @@ -398,6 +400,9 @@ class Controls: if self.sm['modelV2'].frameDropPerc > 20: self.events.add(EventName.modeldLagging) + # Update FrogPilot events + self.update_frogpilot_events(CS) + def data_sample(self): """Receive data from sockets""" @@ -871,6 +876,11 @@ class Controls: e.set() t.join() + def update_frogpilot_events(self, CS): + if not self.openpilot_crashed_triggered and os.path.isfile(os.path.join(sentry.CRASHES_DIR, 'error.txt')): + self.events.add(EventName.openpilotCrashed) + self.openpilot_crashed_triggered = True + def update_frogpilot_variables(self, CS): FPCC = custom.FrogPilotCarControl.new_message() diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 8ba56d005..045038dca 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -961,6 +961,14 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { ET.NO_ENTRY: NoEntryAlert("Please don't use the 'Development' branch!"), }, + EventName.openpilotCrashed: { + ET.PERMANENT: Alert( + "openpilot crashed", + "Please post the 'Error Log' in the FrogPilot Discord!", + AlertStatus.normal, AlertSize.mid, + Priority.HIGH, VisualAlert.none, AudibleAlert.none, 10.), + }, + EventName.pedalInterceptorNoBrake: { ET.WARNING: Alert( "Braking Unavailable", diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 8dfb68483..6483e14fa 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -97,7 +97,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { // error log button auto errorLogBtn = new ButtonControl(tr("Error Log"), tr("VIEW"), tr("View the error log for openpilot crashes.")); connect(errorLogBtn, &ButtonControl::clicked, [=]() { - const std::string txt = util::read_file("/data/community/crashes/error.txt"); + const std::string txt = util::read_file("/data/crashes/error.txt"); ConfirmationDialog::rich(QString::fromStdString(txt), this); }); addItem(errorLogBtn); diff --git a/system/manager/manager.py b/system/manager/manager.py index 59424cbf4..f9d65e0da 100644 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -450,6 +450,11 @@ def manager_thread() -> None: if started and not started_prev: params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) + + error_log = os.path.join(sentry.CRASHES_DIR, 'error.txt') + if os.path.isfile(error_log): + os.remove(error_log) + elif not started and started_prev: params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params_memory.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) diff --git a/system/sentry.py b/system/sentry.py index 71cd4dfad..91f7a5692 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -1,7 +1,10 @@ """Install exception handler for process crash.""" +import os import sentry_sdk import time +import traceback +from datetime import datetime from enum import Enum from sentry_sdk.integrations.threading import ThreadingIntegration @@ -13,6 +16,8 @@ from openpilot.system.version import get_build_metadata, get_version from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import is_url_pingable +CRASHES_DIR = "/data/crashes/" + class SentryProject(Enum): # python project SELFDRIVE = "https://5ad1714d27324c74a30f9c538bff3b8d@o4505034923769856.ingest.sentry.io/4505034930651136" @@ -111,6 +116,16 @@ def capture_fingerprint(candidate, params, blocked=False): def capture_exception(*args, **kwargs) -> None: + exc_text = traceback.format_exc() + + phrases_to_check = [ + "To overwrite it, set 'overwrite' to True.", + ] + + if any(phrase in exc_text for phrase in phrases_to_check): + return + + save_exception(exc_text) cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) FrogPilot = "frogai" in get_build_metadata().openpilot.git_origin.lower() @@ -125,6 +140,26 @@ def capture_exception(*args, **kwargs) -> None: cloudlog.exception("sentry exception") +def save_exception(exc_text: str) -> None: + if not os.path.exists(CRASHES_DIR): + os.makedirs(CRASHES_DIR) + + files = [ + os.path.join(CRASHES_DIR, datetime.now().strftime('%Y-%m-%d--%H-%M-%S.log')), + os.path.join(CRASHES_DIR, 'error.txt') + ] + + for file in files: + with open(file, 'w') as f: + if file.endswith("error.txt"): + lines = exc_text.splitlines()[-10:] + f.write("\n".join(lines)) + else: + f.write(exc_text) + + print('Logged current crash to {}'.format(files)) + + def set_tag(key: str, value: str) -> None: sentry_sdk.set_tag(key, value)