Skip to content

Commit

Permalink
feat: expose function to send minidumps (#1067)
Browse files Browse the repository at this point in the history
* feat: programmatic minidump capture

This provides a new function that will allow for independently created minidumps to be captured by sentry

Resolves: #1050

* fixed compile errors

* Rework of programmatic minidumps based on feedback

* Remove unused parameters

* Address Lint errors

* Address more review feedback

* Address Lint errors

* Address more lint errors

* changed from bool to int due to undefined errors

* Address review feedback

* Work on addressing feedback, example and test

* Fixes to lint errors

* Apply comment suggestion

* Add empty line to file end

* use parameter directly

* chore: fix changelog

* add capture_minidump_n

* feat: capture minidump from path

* chore: update changelog

* cleanup

* linter issues

* cleanup, review changes, docs

* chore: fixup doc

* Update CHANGELOG.md

---------

Co-authored-by: PlasmaDev5 <[email protected]>
Co-authored-by: PlasmaDev5 <[email protected]>
  • Loading branch information
3 people authored Nov 4, 2024
1 parent ffdf6ed commit d61acdd
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

**Features**:

- Add `sentry_capture_minidump()` to capture independently created minidumps ([#1067](https://github.com/getsentry/sentry-native/pull/1067))

**Fixes**:

Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,9 @@ if(SENTRY_BUILD_EXAMPLES)
set_target_properties(sentry_example PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()

add_custom_command(TARGET sentry_example POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/minidump.dmp" "$<TARGET_FILE_DIR:sentry_example>/minidump.dmp")

add_test(NAME sentry_example COMMAND sentry_example)
endif()

Expand Down
4 changes: 4 additions & 0 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ main(int argc, char **argv)
sentry_transaction_finish(tx);
}

if (has_arg(argc, argv, "capture-minidump")) {
sentry_capture_minidump("minidump.dmp");
}

// make sure everything flushes
sentry_close();

Expand Down
10 changes: 10 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,16 @@ SENTRY_API sentry_user_consent_t sentry_user_consent_get(void);
*/
SENTRY_API sentry_uuid_t sentry_capture_event(sentry_value_t event);

/**
* Allows capturing independently created minidumps.
*
* This generates a fatal error event, includes the scope and attachments.
* If the event isn't dropped by a before-send hook, the minidump is attached
* and the event is sent.
*/
SENTRY_API void sentry_capture_minidump(const char *path);
SENTRY_API void sentry_capture_minidump_n(const char *path, size_t path_len);

/**
* Captures an exception to be handled by the backend.
*
Expand Down
57 changes: 57 additions & 0 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1174,3 +1174,60 @@ sentry_clear_crashed_last_run(void)
sentry__options_unlock();
return success ? 0 : 1;
}

void
sentry_capture_minidump(const char *path)
{
sentry_capture_minidump_n(path, sentry__guarded_strlen(path));
}

void
sentry_capture_minidump_n(const char *path, size_t path_len)
{
sentry_path_t *dump_path = sentry__path_from_str_n(path, path_len);

if (!dump_path) {
SENTRY_WARN(
"sentry_capture_minidump() failed due to null path to minidump");
return;
}

SENTRY_DEBUGF(
"Capturing minidump \"%" SENTRY_PATH_PRI "\"", dump_path->path);

sentry_value_t event = sentry_value_new_event();
sentry_value_set_by_key(
event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL));

SENTRY_WITH_OPTIONS (options) {
sentry_envelope_t *envelope
= sentry__prepare_event(options, event, NULL, true);

if (envelope) {
// the minidump is added as an attachment, with type
// `event.minidump`
sentry_envelope_item_t *item = sentry__envelope_add_from_path(
envelope, dump_path, "attachment");
if (item) {
sentry__envelope_item_set_header(item, "attachment_type",
sentry_value_new_string("event.minidump"));

sentry__envelope_item_set_header(item, "filename",
#ifdef SENTRY_PLATFORM_WINDOWS
sentry__value_new_string_from_wstr(
#else
sentry_value_new_string(
#endif
sentry__path_filename(dump_path)));
}

sentry__capture_envelope(options->transport, envelope);

SENTRY_DEBUGF("Minidump has been captured: \"%" SENTRY_PATH_PRI
"\"",
dump_path->path);
}
}

sentry__path_free(dump_path);
}
Binary file added tests/fixtures/minidump.dmp
Binary file not shown.
33 changes: 33 additions & 0 deletions tests/test_integration_http.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import itertools
import json
import os
import shutil
import time
import uuid

Expand Down Expand Up @@ -573,3 +574,35 @@ def test_transaction_only(cmake, httpserver, build_args):
assert start_timestamp
timestamp = time.strptime(payload["timestamp"], RFC3339_FORMAT)
assert timestamp >= start_timestamp


def test_capture_minidump(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "none"})

# make sure we are isolated from previous runs
shutil.rmtree(tmp_path / ".sentry-native", ignore_errors=True)

httpserver.expect_oneshot_request(
"/api/123456/envelope/",
headers={"x-sentry-auth": auth_header},
).respond_with_data("OK")

run(
tmp_path,
"sentry_example",
["log", "attachment", "capture-minidump"],
check=True,
env=dict(os.environ, SENTRY_DSN=make_dsn(httpserver)),
)

assert len(httpserver.log) == 1

req = httpserver.log[0][0]
body = req.get_data()

envelope = Envelope.deserialize(body)

assert_breadcrumb(envelope)
assert_attachment(envelope)

assert_minidump(envelope)

0 comments on commit d61acdd

Please sign in to comment.