Skip to content

Commit b8eae03

Browse files
chore: SDK Truncation Logic (#1347)
* no longer truncate tag value * restore span_set_tag truncation - reason: span tags are a legacy concept so we're not touching it ~dixit ingest * update MAX_ENVELOPE_ITEMS to only apply for sessions * change envelope items to linked list * add attachments MAX_ENVELOPE_ITEMS test - no longer limited to 10; we test for 15, but have tested up to 1000 attachments locally and that works * #define ATTACHMENT_COUNT * update CHANGELOG.md
1 parent b5b9696 commit b8eae03

7 files changed

Lines changed: 158 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
**Fixes**:
6+
7+
- Removed the 10-item limit per envelope for non-session data. Sessions are now limited to 100 per envelope, while other items (e.g., attachments) have no limit in amount. ([#1347](https://github.com/getsentry/sentry-native/pull/1347))
8+
39
## 0.12.2
410

511
**Features**:

src/sentry_database.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
264264
sentry__envelope_add_session(session_envelope, session);
265265

266266
sentry__session_free(session);
267-
if ((++session_num) >= SENTRY_MAX_ENVELOPE_ITEMS) {
267+
if ((++session_num) >= SENTRY_MAX_ENVELOPE_SESSIONS) {
268268
sentry__capture_envelope(
269269
options->transport, session_envelope);
270270
session_envelope = NULL;

src/sentry_envelope.c

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@ struct sentry_envelope_item_s {
1818
sentry_value_t event;
1919
char *payload;
2020
size_t payload_len;
21+
sentry_envelope_item_t *next;
2122
};
2223

2324
struct sentry_envelope_s {
2425
bool is_raw;
2526
union {
2627
struct {
2728
sentry_value_t headers;
28-
sentry_envelope_item_t items[SENTRY_MAX_ENVELOPE_ITEMS];
29+
sentry_envelope_item_t *first_item;
30+
sentry_envelope_item_t *last_item;
2931
size_t item_count;
3032
} items;
3133
struct {
@@ -41,21 +43,34 @@ envelope_add_item(sentry_envelope_t *envelope)
4143
if (envelope->is_raw) {
4244
return NULL;
4345
}
44-
if (envelope->contents.items.item_count >= SENTRY_MAX_ENVELOPE_ITEMS) {
45-
return NULL;
46-
}
46+
4747
// TODO: Envelopes may have at most one event item or one transaction item,
4848
// and not one of both. Some checking should be done here or in
4949
// `sentry__envelope_add_[transaction|event]` to ensure this can't happen.
5050

51-
sentry_envelope_item_t *rv
52-
= &envelope->contents.items
53-
.items[envelope->contents.items.item_count++];
54-
rv->headers = sentry_value_new_object();
55-
rv->event = sentry_value_new_null();
56-
rv->payload = NULL;
57-
rv->payload_len = 0;
58-
return rv;
51+
// Allocate new item
52+
sentry_envelope_item_t *item = SENTRY_MAKE(sentry_envelope_item_t);
53+
if (!item) {
54+
return NULL;
55+
}
56+
57+
// Initialize item
58+
item->headers = sentry_value_new_object();
59+
item->event = sentry_value_new_null();
60+
item->payload = NULL;
61+
item->payload_len = 0;
62+
item->next = NULL;
63+
64+
// Append to linked list
65+
if (envelope->contents.items.last_item) {
66+
envelope->contents.items.last_item->next = item;
67+
} else {
68+
envelope->contents.items.first_item = item;
69+
}
70+
envelope->contents.items.last_item = item;
71+
envelope->contents.items.item_count++;
72+
73+
return item;
5974
}
6075

6176
static void
@@ -141,9 +156,16 @@ sentry_envelope_free(sentry_envelope_t *envelope)
141156
return;
142157
}
143158
sentry_value_decref(envelope->contents.items.headers);
144-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
145-
envelope_item_cleanup(&envelope->contents.items.items[i]);
159+
160+
// Free all items in the linked list
161+
sentry_envelope_item_t *item = envelope->contents.items.first_item;
162+
while (item) {
163+
sentry_envelope_item_t *next = item->next;
164+
envelope_item_cleanup(item);
165+
sentry_free(item);
166+
item = next;
146167
}
168+
147169
sentry_free(envelope);
148170
}
149171

@@ -166,6 +188,8 @@ sentry__envelope_new(void)
166188
}
167189

168190
rv->is_raw = false;
191+
rv->contents.items.first_item = NULL;
192+
rv->contents.items.last_item = NULL;
169193
rv->contents.items.item_count = 0;
170194
rv->contents.items.headers = sentry_value_new_object();
171195

@@ -226,12 +250,13 @@ sentry_envelope_get_event(const sentry_envelope_t *envelope)
226250
if (envelope->is_raw) {
227251
return sentry_value_new_null();
228252
}
229-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
230253

231-
if (!sentry_value_is_null(envelope->contents.items.items[i].event)
232-
&& !sentry__event_is_transaction(
233-
envelope->contents.items.items[i].event)) {
234-
return envelope->contents.items.items[i].event;
254+
for (const sentry_envelope_item_t *item
255+
= envelope->contents.items.first_item;
256+
item; item = item->next) {
257+
if (!sentry_value_is_null(item->event)
258+
&& !sentry__event_is_transaction(item->event)) {
259+
return item->event;
235260
}
236261
}
237262
return sentry_value_new_null();
@@ -243,11 +268,13 @@ sentry_envelope_get_transaction(const sentry_envelope_t *envelope)
243268
if (envelope->is_raw) {
244269
return sentry_value_new_null();
245270
}
246-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
247-
if (!sentry_value_is_null(envelope->contents.items.items[i].event)
248-
&& sentry__event_is_transaction(
249-
envelope->contents.items.items[i].event)) {
250-
return envelope->contents.items.items[i].event;
271+
272+
for (const sentry_envelope_item_t *item
273+
= envelope->contents.items.first_item;
274+
item; item = item->next) {
275+
if (!sentry_value_is_null(item->event)
276+
&& sentry__event_is_transaction(item->event)) {
277+
return item->event;
251278
}
252279
}
253280
return sentry_value_new_null();
@@ -657,8 +684,9 @@ sentry__envelope_serialize_into_stringbuilder(
657684
SENTRY_DEBUG("serializing envelope into buffer");
658685
sentry__envelope_serialize_headers_into_stringbuilder(envelope, sb);
659686

660-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
661-
const sentry_envelope_item_t *item = &envelope->contents.items.items[i];
687+
for (const sentry_envelope_item_t *item
688+
= envelope->contents.items.first_item;
689+
item; item = item->next) {
662690
sentry__envelope_serialize_item_into_stringbuilder(item, sb);
663691
}
664692
}
@@ -679,8 +707,9 @@ sentry_envelope_serialize_ratelimited(const sentry_envelope_t *envelope,
679707
sentry__envelope_serialize_headers_into_stringbuilder(envelope, &sb);
680708

681709
size_t serialized_items = 0;
682-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
683-
const sentry_envelope_item_t *item = &envelope->contents.items.items[i];
710+
for (const sentry_envelope_item_t *item
711+
= envelope->contents.items.first_item;
712+
item; item = item->next) {
684713
if (rl) {
685714
int category = envelope_item_get_ratelimiter_category(item);
686715
if (sentry__rate_limiter_is_disabled(rl, category)) {
@@ -736,9 +765,9 @@ sentry_envelope_write_to_path(
736765
sentry__jsonwriter_write_value(jw, envelope->contents.items.headers);
737766
sentry__jsonwriter_reset(jw);
738767

739-
for (size_t i = 0; i < envelope->contents.items.item_count; i++) {
740-
const sentry_envelope_item_t *item
741-
= &envelope->contents.items.items[i];
768+
for (const sentry_envelope_item_t *item
769+
= envelope->contents.items.first_item;
770+
item; item = item->next) {
742771
const char newline = '\n';
743772
sentry__filewriter_write(fw, &newline, sizeof(char));
744773

@@ -967,9 +996,22 @@ sentry__envelope_get_item_count(const sentry_envelope_t *envelope)
967996
const sentry_envelope_item_t *
968997
sentry__envelope_get_item(const sentry_envelope_t *envelope, size_t idx)
969998
{
970-
return !envelope->is_raw && idx < envelope->contents.items.item_count
971-
? &envelope->contents.items.items[idx]
972-
: NULL;
999+
if (envelope->is_raw) {
1000+
return NULL;
1001+
}
1002+
1003+
// Traverse linked list to find item at index
1004+
size_t current_idx = 0;
1005+
for (const sentry_envelope_item_t *item
1006+
= envelope->contents.items.first_item;
1007+
item; item = item->next) {
1008+
if (current_idx == idx) {
1009+
return item;
1010+
}
1011+
current_idx++;
1012+
}
1013+
1014+
return NULL;
9731015
}
9741016

9751017
sentry_value_t

src/sentry_envelope.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
#include "sentry_session.h"
1111
#include "sentry_string.h"
1212

13-
#define SENTRY_MAX_ENVELOPE_ITEMS 10
13+
// https://develop.sentry.dev/sdk/data-model/envelopes/#size-limits
14+
#define SENTRY_MAX_ENVELOPE_SESSIONS 100
1415

1516
typedef struct sentry_envelope_item_s sentry_envelope_item_t;
1617

tests/test_integration_http.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ def test_abnormal_session(cmake, httpserver):
321321
)
322322
db_dir = tmp_path.joinpath(".sentry-native")
323323
db_dir.mkdir(exist_ok=True)
324-
# 15 exceeds the max envelope items
325-
for i in range(15):
324+
# 101 exceeds the max session items
325+
for i in range(101):
326326
run_dir = db_dir.joinpath(f"foo-{i}.run")
327327
run_dir.mkdir()
328328
with open(run_dir.joinpath("session.json"), "w") as session_file:
@@ -343,7 +343,7 @@ def test_abnormal_session(cmake, httpserver):
343343
for item in itertools.chain(envelope1, envelope2):
344344
if item.headers.get("type") == "session":
345345
session_count += 1
346-
assert session_count == 15
346+
assert session_count == 101
347347

348348
assert_session(envelope1, {"status": "abnormal", "errors": 0, "duration": 10})
349349

tests/unit/test_attachments.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,72 @@ SENTRY_TEST(attachments_bytes)
453453

454454
sentry_close();
455455
}
456+
457+
#define ATTACHMENT_COUNT 15
458+
459+
SENTRY_TEST(attachments_more_than_ten)
460+
{
461+
sentry_attachments_testdata_t testdata;
462+
testdata.called = 0;
463+
sentry__stringbuilder_init(&testdata.serialized_envelope);
464+
465+
SENTRY_TEST_OPTIONS_NEW(options);
466+
sentry_options_set_auto_session_tracking(options, false);
467+
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
468+
sentry_transport_t *transport
469+
= sentry_transport_new(send_envelope_test_attachments);
470+
sentry_transport_set_state(transport, &testdata);
471+
sentry_options_set_transport(options, transport);
472+
473+
sentry_init(options);
474+
475+
// Create 15 unique attachment files (more than the old
476+
// SENTRY_MAX_ENVELOPE_ITEMS of 10) to verify that the limit has been
477+
// removed for attachments
478+
sentry_path_t *attachment_paths[ATTACHMENT_COUNT];
479+
for (int i = 0; i < ATTACHMENT_COUNT; i++) {
480+
char filename[64];
481+
snprintf(filename, sizeof(filename),
482+
SENTRY_TEST_PATH_PREFIX ".attachment%d.txt", i);
483+
attachment_paths[i] = sentry__path_from_str(filename);
484+
sentry__path_write_buffer(attachment_paths[i], "content", 7);
485+
sentry_attach_file(filename);
486+
}
487+
488+
char message[128];
489+
snprintf(message, sizeof(message), "Event with %d attachments",
490+
ATTACHMENT_COUNT);
491+
sentry_capture_event(
492+
sentry_value_new_message_event(SENTRY_LEVEL_INFO, "root", message));
493+
494+
char *serialized
495+
= sentry_stringbuilder_take_string(&testdata.serialized_envelope);
496+
497+
// Count the number of attachment items in the envelope
498+
// Each attachment appears as: {"type":"attachment",...}
499+
int attachment_count = 0;
500+
const char *search_pos = serialized;
501+
const char *pattern = "\"type\":\"attachment\"";
502+
while ((search_pos = strstr(search_pos, pattern)) != NULL) {
503+
attachment_count++;
504+
search_pos += strlen(pattern);
505+
}
506+
507+
// Verify we have all 15 attachments in the envelope
508+
TEST_CHECK_INT_EQUAL(attachment_count, ATTACHMENT_COUNT);
509+
// Verify the envelope also contains the event
510+
TEST_CHECK(strstr(serialized, "\"type\":\"event\"") != NULL);
511+
TEST_CHECK(strstr(serialized, message) != NULL);
512+
513+
sentry_free(serialized);
514+
515+
sentry_close();
516+
517+
// Clean up all attachment files
518+
for (int i = 0; i < ATTACHMENT_COUNT; i++) {
519+
sentry__path_remove(attachment_paths[i]);
520+
sentry__path_free(attachment_paths[i]);
521+
}
522+
523+
TEST_CHECK_INT_EQUAL(testdata.called, 1);
524+
}

tests/unit/tests.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ XX(attachments_add_dedupe)
66
XX(attachments_add_remove)
77
XX(attachments_bytes)
88
XX(attachments_extend)
9+
XX(attachments_more_than_ten)
910
XX(background_worker)
1011
XX(basic_consent_tracking)
1112
XX(basic_function_transport)

0 commit comments

Comments
 (0)