Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-Plattform Crash Reporting #4455

Merged
merged 28 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ constexpr const char* SENTRY_DER =
constexpr const char* SENTRY_ENVELOPE_INGESTION =
"https://o1396220.ingest.sentry.io/api/6719480/envelope/";


constexpr const char* API_PRODUCTION_URL = "https://vpn.mozilla.org";
constexpr const char* API_STAGING_URL =
"https://stage-vpn.guardian.nonprod.cloudops.mozgcp.net";
Expand Down
8 changes: 8 additions & 0 deletions src/featureslist.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,11 @@ FEATURE_SIMPLE(gleanRust, // Feature ID
FeatureCallback_true, // Can be flipped off
QStringList(), // feature dependencies
FeatureCallback_false)

FEATURE_SIMPLE(sentry, // Feature ID
"Sentry Crash Report SDK", // Feature name
"2.13.0", // released
FeatureCallback_false, // Can be flipped on
FeatureCallback_false, // Can be flipped off
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not allow flipping it on and off?

QStringList(), // feature dependencies
FeatureCallback_inStaging)
brizental marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 0 additions & 2 deletions src/qmake/sources.pri
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ SOURCES += \
rfc/rfc4193.cpp \
rfc/rfc4291.cpp \
rfc/rfc5735.cpp \
sentry/dummysentryadapter.cpp \
serveri18n.cpp \
serverlatency.cpp \
settingsholder.cpp \
Expand Down Expand Up @@ -306,7 +305,6 @@ HEADERS += \
rfc/rfc4193.h \
rfc/rfc4291.h \
rfc/rfc5735.h \
sentry/sentryadapter.h \
serveri18n.h \
serverlatency.h \
settingsholder.h \
Expand Down
38 changes: 13 additions & 25 deletions src/sentry/sentryadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QDir>

#include "constants.h"
#include "models/feature.h"
#include "leakdetector.h"
#include "loghandler.h"
#include "logger.h"
Expand All @@ -33,11 +34,9 @@ SentryAdapter::SentryAdapter() { MVPN_COUNT_CTOR(SentryAdapter); }
SentryAdapter::~SentryAdapter() { MVPN_COUNT_DTOR(SentryAdapter); }

void SentryAdapter::init() {
if (Constants::inProduction()) {
// If we're not in Production let's just not enable this :)
if (!Feature::get(Feature::Feature_sentry)->isSupported()) {
return;
}
// Okay so Lets INIT
auto vpn = MozillaVPN::instance();
auto log = LogHandler::instance();

Expand Down Expand Up @@ -67,15 +66,16 @@ void SentryAdapter::init() {
sentry_options_set_transport(options, transport);
#endif

// Leaving this for convinence, be warned, it's spammy to stdout.
// Uncomment the following line for debugging purposes.
// Be warned, it's spammy to stdout.
// sentry_options_set_debug(options, 1);

if (sentry_init(options) == -1) {
strseb marked this conversation as resolved.
Show resolved Hide resolved
logger.error() << "Sentry failed to init!";
return;
};
m_initialized = true;
logger.info() << "Sentry initialised";
logger.info() << "Sentry initialized";
}

void SentryAdapter::report(const QString& errorType, const QString& message,
Expand All @@ -94,35 +94,31 @@ void SentryAdapter::report(const QString& errorType, const QString& message,
sentry_capture_event(event);
}

void SentryAdapter::onBeforeShutdown() {
// Flush everything,
sentry_close();
}
void SentryAdapter::onBeforeShutdown() { sentry_close(); }

void SentryAdapter::onLoglineAdded(const QByteArray& line) {
if (!m_initialized) {
return;
}
// Todo: we could certainly catch this more early and format the data ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this worth filing a ticket so we don't forget about it?

// (VPN-3276)
sentry_value_t crumb =
sentry_value_new_breadcrumb("Logger", line.constData());
sentry_add_breadcrumb(crumb);
}

sentry_value_t SentryAdapter::onCrash(
const sentry_ucontext_t*
uctx, // provides the user-space context of the crash
sentry_value_t event, // used the same way as in `before_send`
void* closure // user-data that you can provide at configuration time
) {
sentry_value_t SentryAdapter::onCrash(const sentry_ucontext_t* uctx,
sentry_value_t event, void* closure) {
logger.info() << "Sentry ON CRASH";
// Do contextual clean-up before the crash is sent to sentry's backend
// infrastructure
bool shouldSend = true;
// Todo: We can use this callback to make sure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticket?

// we only send data with user consent.
// Tracked in: VPN-3158
// We could:
// -> Maybe start a new Process for the Crash-Report UI ask for consent
// (VPN-2823)
// -> Check if a setting "upload crashes" is present.
// If we should not send it, we can discard the crash data here :)
if (shouldSend) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check with legal if we can use the telemetry policy flag.

Expand All @@ -135,24 +131,16 @@ sentry_value_t SentryAdapter::onCrash(
// static
void SentryAdapter::transportEnvelope(sentry_envelope_t* envelope,
void* state) {
/*
* Send the event here. If the transport requires state, such as an HTTP
* client object or request queue, it can be specified in the `state`
* parameter when configuring the transport. It will be passed as second
* argument to this function.
* The transport takes ownership of the `envelope`, and must free it once it
* is done.
*/
Q_UNUSED(state);
size_t sentry_buf_size = 0;
char* sentry_buf = sentry_envelope_serialize(envelope, &sentry_buf_size);

// Qt Will copy this.
auto qt_owned_buffer = QByteArray(sentry_buf, sentry_buf_size);
// We can now free the stuff.
// We can now free the envelope.
sentry_envelope_free(envelope);
sentry_free(sentry_buf);

auto t = new TaskSentry(qt_owned_buffer);
TaskScheduler::scheduleTask(t);
}
}
70 changes: 59 additions & 11 deletions src/sentry/sentryadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,78 @@ class SentryAdapter final : public QObject {
~SentryAdapter();
static SentryAdapter* instance();

// Inits Sentry.
// In case Telemetry is disabled this is a no-op.
/**
* @brief Inits Sentry.
*
* This is a no-op if the client is in production mode.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "This is a no-op if the "sentry" feature is turned off".

This way if we change the feature we don't need to update this again :)

*/
void init();

// Reports an Error - can attach extra data and a stack trace if needed.
/**
* @brief Sends an "Issue" report to Sentry
*
* @param category - "Category" of the error, any String is valid.
* @param message - Additional message content.
* @param attachStackTrace - If true a stacktrace for later debugging will be
* attached.
*/
void report(const QString& category, const QString& message,
bool attachStackTrace = false);

// Called when a Line is added, will add this as a breadcrumb
/**
* @brief Event Slot for when a log-line is added.
*
* The logline will be added as a Sentry-Breadrumb, so that
* the next "report" or crash will have the last few
* loglines available
*
* @param line - UTF-8 encoded bytes of the logline.
*/
Q_SLOT void onLoglineAdded(const QByteArray& line);
// Called before shutdown, will flush pending events.

/**
* @brief Event Slot for when the client is about to Shut down
*
* This will call sentry to wrap up - this might cause new network requests
* or drisk writes.
* After calling this, any call to sentry is UB.
*/
Q_SLOT void onBeforeShutdown();

// Only define Sentry related callbacks if we have the typedefs :)
// Called before Sentry will send a crash report
/**
* @brief Callback for when sentry's backend recieved a crash.
*
* In this function we can decide to either send, discard the crash
* and additonally "scrub" the minidump of data, if wanted.
*
* @param uctx provides the user-space context of the crash
* @param event used the same way as in `before_send`
* @param closure user-data that you can provide at configuration time
* (we'dont.)
* @return either the @param event or null_sentry_value , if the crash event
* should not be recorded.
*/
static sentry_value_t onCrash(const sentry_ucontext_t* uctx,
sentry_value_t event, void* closure);

// Will be used if NONE_TRANSPORT is enabled
// in that case this will be called if the client has a
// report to send to Sentry.
/**
* @brief Send's a Sentry Event "envelope" to the Sentry endpoint.
*
* Will be used if NONE_TRANSPORT is enabled in cmake.
* Will create a Task in the TaskSheudler to send that.
*
* @param envelope Envelope to be sent to sentry.
* The transport takes ownership of the `envelope`, and must free it once it
* is done.
* @param state
* If the transport requires state, such as an HTTP
* client object or request queue, it can be specified in the `state`
* parameter when configuring the transport. It will be passed as second
* argument to this function. We are not using that.
*
*/
static void transportEnvelope(sentry_envelope_t* envelope, void* state);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the comment adding on this file. In mozilla-central docstrings are added to the header files too, right? I've been adding them to the .cpp file, maybe we should reach an agreement about this, happy to swich from .cpp to .h. On another note, I believe ideally we should use doxygen format comments, just because if we ever decide to auto generate docs based on these doc-comments it will be easier that way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mc has most in the header; Which i kind of like because I can easily can get a glimpse of what everything in the class is happening. :D
Totally with you about the standard comment, I already forgot that we agreed on a standard format :D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL, well me and you agreed. We should probably broadcast that. I agree with having it in the header. I'll do that from now on and also change the stuff that is not in the header!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File looks beautiful now with all the comments 💯



private:
bool m_initialized = false;
SentryAdapter();
Expand Down