Skip to content

Commit bffc57d

Browse files
authored
feat: implement the new User Feedback API (#1304)
* feat: implement the new User Feedback API https://develop.sentry.dev/sdk/data-model/envelope-items/#user-feedback * Fix heap-use-after-free * Update CHANGELOG.md * remove unused line3_end * what if we reused the old API? * use internal id to fix event association in Sentry Web UI * restore integration test for legacy user report * convert a deprecated "user report" to a new "user feedback" * conversion: note in docs & log info message * let sentry__envelope_add_user_feedback take ownership * revert back to option 1 * deprecate sentry_value_new_user_feedback() & sentry_capture_user_feedback() * fix remaining deprecation warnings * msvc
1 parent 9ed9a70 commit bffc57d

File tree

15 files changed

+335
-53
lines changed

15 files changed

+335
-53
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- Add `sentry_clear_attachments()` to allow clearing all previously added attachments in the global scope. ([#1290](https://github.com/getsentry/sentry-native/pull/1290))
88
- Compiles also on Xbox One ([#1294](https://github.com/getsentry/sentry-native/pull/1294))
99
- Provide `sentry_regenerate_trace()` to allow users to set manual trace boundaries. ([#1293](https://github.com/getsentry/sentry-native/pull/1293))
10+
- Add `sentry_value_new_feedback` and `sentry_capture_feedback` to allow capturing [User Feedback](https://develop.sentry.dev/sdk/data-model/envelope-items/#user-feedback). ([#1304](https://github.com/getsentry/sentry-native/pull/1304))
11+
- Deprecate `sentry_value_new_user_feedback` and `sentry_capture_user_feedback` in favor of the new API.
1012

1113
**Fixes**:
1214

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ The example currently supports the following commands:
189189
- `capture-with-scope`: Captures an event with a local scope.
190190
- `attach-to-scope`: Same as `attachment` but attaches the file to the local scope.
191191
- `clear-attachments`: Clears all attachments from the global scope.
192+
- `capture-user-feedback`: Captures a user feedback event.
192193

193194
Only on Linux using crashpad:
194195
- `crashpad-wait-for-upload`: Couples application shutdown to complete the upload in the `crashpad_handler`.

examples/example.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,14 +556,22 @@ main(int argc, char **argv)
556556
sentry_capture_event(event);
557557
}
558558
if (has_arg(argc, argv, "capture-user-feedback")) {
559+
sentry_value_t user_feedback = sentry_value_new_feedback(
560+
"some-message", "some-email", "some-name", NULL);
561+
562+
sentry_capture_feedback(user_feedback);
563+
}
564+
if (has_arg(argc, argv, "capture-user-report")) {
559565
sentry_value_t event = sentry_value_new_message_event(
560566
SENTRY_LEVEL_INFO, "my-logger", "Hello user feedback!");
561567
sentry_uuid_t event_id = sentry_capture_event(event);
562568

569+
SENTRY_SUPPRESS_DEPRECATED
563570
sentry_value_t user_feedback = sentry_value_new_user_feedback(
564571
&event_id, "some-name", "some-email", "some-comment");
565572

566573
sentry_capture_user_feedback(user_feedback);
574+
SENTRY_RESTORE_DEPRECATED
567575
}
568576

569577
if (has_arg(argc, argv, "capture-transaction")) {

include/sentry.h

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,21 @@ extern "C" {
119119
# endif
120120
#endif
121121

122+
#if defined(__GNUC__) || defined(__clang__)
123+
# define SENTRY_SUPPRESS_DEPRECATED \
124+
_Pragma("GCC diagnostic push"); \
125+
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
126+
# define SENTRY_RESTORE_DEPRECATED _Pragma("GCC diagnostic pop")
127+
#elif defined(_MSC_VER)
128+
# define SENTRY_SUPPRESS_DEPRECATED \
129+
__pragma(warning(push)); \
130+
__pragma(warning(disable : 4996))
131+
# define SENTRY_RESTORE_DEPRECATED __pragma(warning(pop))
132+
#else
133+
# define SENTRY_SUPPRESS_DEPRECATED
134+
# define SENTRY_RESTORE_DEPRECATED
135+
#endif
136+
122137
/* marks a function as experimental api */
123138
#ifndef SENTRY_EXPERIMENTAL_API
124139
# define SENTRY_EXPERIMENTAL_API SENTRY_API
@@ -2434,25 +2449,48 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_name_n(
24342449
sentry_transaction_t *transaction, const char *name, size_t name_len);
24352450

24362451
/**
2437-
* Creates a new User Feedback with a specific name, email and comments.
2438-
*
2439-
* See https://develop.sentry.dev/sdk/envelopes/#user-feedback
2452+
* Creates a deprecated User Report with a specific name, email and comments.
24402453
*
2441-
* User Feedback has to be associated with a specific event that has been
2442-
* sent to Sentry earlier.
2454+
* See
2455+
* https://develop.sentry.dev/sdk/data-model/envelope-items/#user-report---deprecated
24432456
*/
2457+
SENTRY_DEPRECATED("Use `sentry_value_new_feedback` instead")
24442458
SENTRY_API sentry_value_t sentry_value_new_user_feedback(
24452459
const sentry_uuid_t *uuid, const char *name, const char *email,
24462460
const char *comments);
2461+
SENTRY_DEPRECATED("Use `sentry_value_new_feedback_n` instead")
24472462
SENTRY_API sentry_value_t sentry_value_new_user_feedback_n(
24482463
const sentry_uuid_t *uuid, const char *name, size_t name_len,
24492464
const char *email, size_t email_len, const char *comments,
24502465
size_t comments_len);
24512466

2467+
/**
2468+
* Captures a deprecated User Report and sends it to Sentry.
2469+
*/
2470+
SENTRY_DEPRECATED("Use `sentry_capture_feedback` instead")
2471+
SENTRY_API void sentry_capture_user_feedback(sentry_value_t user_report);
2472+
2473+
/**
2474+
* Creates a new User Feedback with a specific message (required), and optional
2475+
* contact_email, name, message, and associated_event_id.
2476+
*
2477+
* See https://develop.sentry.dev/sdk/data-model/envelope-items/#user-feedback
2478+
*
2479+
* User Feedback can be associated with a specific event that has been
2480+
* sent to Sentry earlier.
2481+
*/
2482+
SENTRY_API sentry_value_t sentry_value_new_feedback(const char *message,
2483+
const char *contact_email, const char *name,
2484+
const sentry_uuid_t *associated_event_id);
2485+
SENTRY_API sentry_value_t sentry_value_new_feedback_n(const char *message,
2486+
size_t message_len, const char *contact_email, size_t contact_email_len,
2487+
const char *name, size_t name_len,
2488+
const sentry_uuid_t *associated_event_id);
2489+
24522490
/**
24532491
* Captures a manually created User Feedback and sends it to Sentry.
24542492
*/
2455-
SENTRY_API void sentry_capture_user_feedback(sentry_value_t user_feedback);
2493+
SENTRY_API void sentry_capture_feedback(sentry_value_t user_feedback);
24562494

24572495
/**
24582496
* The status of a Span or Transaction.

src/sentry_core.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,25 @@ sentry__prepare_transaction(const sentry_options_t *options,
658658
return NULL;
659659
}
660660

661+
static sentry_envelope_t *
662+
prepare_user_report(sentry_value_t user_report)
663+
{
664+
sentry_envelope_t *envelope = NULL;
665+
666+
envelope = sentry__envelope_new();
667+
if (!envelope || !sentry__envelope_add_user_report(envelope, user_report)) {
668+
goto fail;
669+
}
670+
671+
return envelope;
672+
673+
fail:
674+
SENTRY_WARN("dropping user report");
675+
sentry_envelope_free(envelope);
676+
sentry_value_decref(user_report);
677+
return NULL;
678+
}
679+
661680
static sentry_envelope_t *
662681
prepare_user_feedback(sentry_value_t user_feedback)
663682
{
@@ -1335,17 +1354,32 @@ sentry_span_finish_ts(sentry_span_t *opaque_span, uint64_t timestamp)
13351354
}
13361355

13371356
void
1338-
sentry_capture_user_feedback(sentry_value_t user_feedback)
1357+
sentry_capture_user_feedback(sentry_value_t user_report)
1358+
{
1359+
sentry_envelope_t *envelope = NULL;
1360+
1361+
SENTRY_WITH_OPTIONS (options) {
1362+
envelope = prepare_user_report(user_report);
1363+
if (envelope) {
1364+
sentry__capture_envelope(options->transport, envelope);
1365+
}
1366+
}
1367+
sentry_value_decref(user_report);
1368+
}
1369+
1370+
void
1371+
sentry_capture_feedback(sentry_value_t user_feedback)
13391372
{
13401373
sentry_envelope_t *envelope = NULL;
13411374

13421375
SENTRY_WITH_OPTIONS (options) {
13431376
envelope = prepare_user_feedback(user_feedback);
13441377
if (envelope) {
13451378
sentry__capture_envelope(options->transport, envelope);
1379+
} else {
1380+
sentry_value_decref(user_feedback);
13461381
}
13471382
}
1348-
sentry_value_decref(user_feedback);
13491383
}
13501384

13511385
int

src/sentry_envelope.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ sentry__envelope_add_transaction(
297297
}
298298

299299
sentry_envelope_item_t *
300-
sentry__envelope_add_user_feedback(
301-
sentry_envelope_t *envelope, sentry_value_t user_feedback)
300+
sentry__envelope_add_user_report(
301+
sentry_envelope_t *envelope, sentry_value_t user_report)
302302
{
303303
sentry_envelope_item_t *item = envelope_add_item(envelope);
304304
if (!item) {
@@ -310,9 +310,9 @@ sentry__envelope_add_user_feedback(
310310
return NULL;
311311
}
312312

313-
sentry_value_t event_id = sentry__ensure_event_id(user_feedback, NULL);
313+
sentry_value_t event_id = sentry__ensure_event_id(user_report, NULL);
314314

315-
sentry__jsonwriter_write_value(jw, user_feedback);
315+
sentry__jsonwriter_write_value(jw, user_report);
316316
item->payload = sentry__jsonwriter_into_string(jw, &item->payload_len);
317317

318318
sentry__envelope_item_set_header(
@@ -326,6 +326,30 @@ sentry__envelope_add_user_feedback(
326326
return item;
327327
}
328328

329+
sentry_envelope_item_t *
330+
sentry__envelope_add_user_feedback(
331+
sentry_envelope_t *envelope, sentry_value_t user_feedback)
332+
{
333+
sentry_value_t event = sentry_value_new_event();
334+
sentry_value_t contexts = sentry_value_get_by_key(event, "contexts");
335+
if (sentry_value_is_null(contexts)) {
336+
contexts = sentry_value_new_object();
337+
}
338+
sentry_value_set_by_key(contexts, "feedback", user_feedback);
339+
sentry_value_set_by_key(event, "contexts", contexts);
340+
341+
sentry_envelope_item_t *item = sentry__envelope_add_event(envelope, event);
342+
if (!item) {
343+
sentry_value_decref(event);
344+
return NULL;
345+
}
346+
347+
sentry__envelope_item_set_header(
348+
item, "type", sentry_value_new_string("feedback"));
349+
350+
return item;
351+
}
352+
329353
sentry_envelope_item_t *
330354
sentry__envelope_add_session(
331355
sentry_envelope_t *envelope, const sentry_session_t *session)

src/sentry_envelope.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ sentry_envelope_item_t *sentry__envelope_add_event(
4343
sentry_envelope_item_t *sentry__envelope_add_transaction(
4444
sentry_envelope_t *envelope, sentry_value_t transaction);
4545

46+
/**
47+
* Add a deprecated user report to this envelope.
48+
*/
49+
sentry_envelope_item_t *sentry__envelope_add_user_report(
50+
sentry_envelope_t *envelope, sentry_value_t user_report);
51+
4652
/**
4753
* Add a user feedback to this envelope.
4854
*/

src/sentry_value.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,9 +1350,11 @@ sentry_value_t
13501350
sentry_value_new_user_feedback(const sentry_uuid_t *uuid, const char *name,
13511351
const char *email, const char *comments)
13521352
{
1353+
SENTRY_SUPPRESS_DEPRECATED
13531354
return sentry_value_new_user_feedback_n(uuid, name,
13541355
sentry__guarded_strlen(name), email, sentry__guarded_strlen(email),
13551356
comments, sentry__guarded_strlen(comments));
1357+
SENTRY_RESTORE_DEPRECATED
13561358
}
13571359

13581360
sentry_value_t
@@ -1380,6 +1382,42 @@ sentry_value_new_user_feedback_n(const sentry_uuid_t *uuid, const char *name,
13801382
return rv;
13811383
}
13821384

1385+
sentry_value_t
1386+
sentry_value_new_feedback(const char *message, const char *contact_email,
1387+
const char *name, const sentry_uuid_t *associated_event_id)
1388+
{
1389+
return sentry_value_new_feedback_n(message, sentry__guarded_strlen(message),
1390+
contact_email, sentry__guarded_strlen(contact_email), name,
1391+
sentry__guarded_strlen(name), associated_event_id);
1392+
}
1393+
1394+
sentry_value_t
1395+
sentry_value_new_feedback_n(const char *message, size_t message_len,
1396+
const char *contact_email, size_t contact_email_len, const char *name,
1397+
size_t name_len, const sentry_uuid_t *associated_event_id)
1398+
{
1399+
sentry_value_t rv = sentry_value_new_object();
1400+
1401+
if (message) {
1402+
sentry_value_set_by_key(
1403+
rv, "message", sentry_value_new_string_n(message, message_len));
1404+
}
1405+
if (contact_email) {
1406+
sentry_value_set_by_key(rv, "contact_email",
1407+
sentry_value_new_string_n(contact_email, contact_email_len));
1408+
}
1409+
if (name) {
1410+
sentry_value_set_by_key(
1411+
rv, "name", sentry_value_new_string_n(name, name_len));
1412+
}
1413+
if (associated_event_id) {
1414+
sentry_value_set_by_key(rv, "associated_event_id",
1415+
sentry__value_new_internal_uuid(associated_event_id));
1416+
}
1417+
1418+
return rv;
1419+
}
1420+
13831421
static sentry_value_t
13841422
sentry__get_or_insert_values_list(sentry_value_t parent, const char *key)
13851423
{

tests/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,13 @@ def deserialize_from(
278278
headers = json.loads(line)
279279
length = headers["length"]
280280
payload = f.read(length)
281-
if headers.get("type") in ["event", "session", "transaction", "user_report"]:
281+
if headers.get("type") in [
282+
"event",
283+
"feedback",
284+
"session",
285+
"transaction",
286+
"user_report",
287+
]:
282288
rv = cls(headers=headers, payload=PayloadRef(json=json.loads(payload)))
283289
else:
284290
rv = cls(headers=headers, payload=payload)

tests/assertions.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,25 @@ def assert_session(envelope, extra_assertion=None):
4242
def assert_user_feedback(envelope):
4343
user_feedback = None
4444
for item in envelope:
45-
if item.headers.get("type") == "user_report" and item.payload.json is not None:
46-
user_feedback = item.payload.json
45+
if item.headers.get("type") == "feedback" and item.payload.json is not None:
46+
user_feedback = item.payload.json["contexts"]["feedback"]
4747

4848
assert user_feedback is not None
4949
assert user_feedback["name"] == "some-name"
50-
assert user_feedback["email"] == "some-email"
51-
assert user_feedback["comments"] == "some-comment"
50+
assert user_feedback["contact_email"] == "some-email"
51+
assert user_feedback["message"] == "some-message"
52+
53+
54+
def assert_user_report(envelope):
55+
user_report = None
56+
for item in envelope:
57+
if item.headers.get("type") == "user_report" and item.payload.json is not None:
58+
user_report = item.payload.json
59+
60+
assert user_report is not None
61+
assert user_report["name"] == "some-name"
62+
assert user_report["email"] == "some-email"
63+
assert user_report["comments"] == "some-comment"
5264

5365

5466
def assert_meta(

0 commit comments

Comments
 (0)