Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Unreleased

**Features**:

- The `sentry_attach_file`, `sentry_scope_attach_file` (and their wide-string variants), and `sentry_remove_attachment` have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266))
- NOTE: When using the `crashpad` backend on macOS, the list of attachments that will be added at the time of a hard crash will be frozen at the time of `sentry_init`, and later modifications will not be reflected.

## 0.9.0

**Breaking changes**:
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ The example currently supports the following commands:
instead of a hardcoded value.
- `attachment`: Adds an attachment, which is currently defined as the
`CMakeCache.txt` file, which is part of the CMake build folder.
- `attach-after-init`: Same as `attachment` but after the SDK has been initialized.
- `stdout`: Uses a custom transport which dumps all envelopes to `stdout`.
- `no-setup`: Skips all scope and breadcrumb initialization code.
- `start-session`: Starts a new release-health session.
Expand Down Expand Up @@ -185,6 +186,7 @@ The example currently supports the following commands:
This file can be found in `./tests/fixtures/view-hierachy.json`.
- `set-trace`: Sets the scope `propagation_context`'s trace data to the given `trace_id="aaaabbbbccccddddeeeeffff00001111"` and `parent_span_id=""f0f0f0f0f0f0f0f0"`.
- `capture-with-scope`: Captures an event with a local scope.
- `attach-to-scope`: Same as `attachment` but attaches the file to the local scope.

Only on Linux using crashpad:
- `crashpad-wait-for-upload`: Couples application shutdown to complete the upload in the `crashpad_handler`.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ Other important configuration options include:
But since this process bypasses SEH, the application local exception handler is no longer invoked, which
also means that for these kinds of crashes, `before_send` and `on_crash` will not be invoked before
sending the minidump and thus have no effect.
- When using the crashpad backend on macOS, the list of attachments that will be sent
along with crashes is frozen at the time of `sentry_init`.

## Benchmarks

Expand Down
12 changes: 12 additions & 0 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ main(int argc, char **argv)
sentry_set_trace(direct_trace_id, direct_parent_span_id);
}

if (has_arg(argc, argv, "attach-after-init")) {
// assuming the example / test is run directly from the cmake build
// directory
sentry_attach_file("./CMakeCache.txt");
}

if (has_arg(argc, argv, "start-session")) {
sentry_start_session();
}
Expand All @@ -424,6 +430,12 @@ main(int argc, char **argv)
sentry_value_t debug_crumb = create_debug_crumb("scoped crumb");
sentry_scope_add_breadcrumb(scope, debug_crumb);

if (has_arg(argc, argv, "attach-to-scope")) {
// assuming the example / test is run directly from the cmake build
// directory
sentry_scope_attach_file(scope, "./CMakeCache.txt");
}

sentry_capture_event_with_scope(event, scope);
}

Expand Down
62 changes: 62 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@
* encoding, typically ANSI on Windows, UTF-8 macOS, and the locale encoding on
* Linux; and they provide wchar-compatible alternatives on Windows which are
* preferred.
*
* NOTE on attachments:
*
* Attachments are read lazily at the time of `sentry_capture_event`,
* `sentry_capture_event_with_scope`, or at time of a hard crash. Relative
* attachment paths will be resolved according to the current working directory
* at the time of envelope creation. When adding and removing attachments, they
* are matched according to their given `path`. No normalization is performed.
* When using the `crashpad` backend on macOS, the list of attachments that will
* be added at the time of a hard crash will be frozen at the time of
* `sentry_init`, and later modifications will not be reflected.
*/

#ifndef SENTRY_H_INCLUDED
Expand Down Expand Up @@ -1215,6 +1226,8 @@ SENTRY_API int sentry_options_get_symbolize_stacktraces(
* `path` is assumed to be in platform-specific filesystem path encoding.
* API Users on windows are encouraged to use `sentry_options_add_attachmentw`
* instead.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API void sentry_options_add_attachment(
sentry_options_t *opts, const char *path);
Expand Down Expand Up @@ -1771,6 +1784,55 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy(

#endif // SENTRY_PLATFORM_LINUX

/**
* A sentry Attachment.
*
* See https://develop.sentry.dev/sdk/data-model/envelope-items/#attachment
*/
struct sentry_attachment_s;
typedef struct sentry_attachment_s sentry_attachment_t;

/**
* Adds a new attachment to be sent along.
*
* `path` is assumed to be in platform-specific filesystem path encoding.
* API Users on windows are encouraged to use `sentry_attach_filew` or
* `sentry_scope_attach_filew` instead.
*
* The returned `sentry_attachment_t` is owned by the SDK and will remain valid
* until the attachment is removed with `sentry_remove_attachment` or
* `sentry_close` is called
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API sentry_attachment_t *sentry_attach_file(const char *path);
SENTRY_API sentry_attachment_t *sentry_attach_file_n(
const char *path, size_t path_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_file(
sentry_scope_t *scope, const char *path);
SENTRY_API sentry_attachment_t *sentry_scope_attach_file_n(
sentry_scope_t *scope, const char *path, size_t path_len);

/**
* Removes and frees a previously added attachment.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API void sentry_remove_attachment(sentry_attachment_t *attachment);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char versions of `sentry_attach_file` and `sentry_scope_attach_file`.
*/
SENTRY_API sentry_attachment_t *sentry_attach_filew(const wchar_t *path);
SENTRY_API sentry_attachment_t *sentry_attach_filew_n(
const wchar_t *path, size_t path_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_filew(
sentry_scope_t *scope, const wchar_t *path);
SENTRY_API sentry_attachment_t *sentry_scope_attach_filew_n(
sentry_scope_t *scope, const wchar_t *path, size_t path_len);
#endif

/* -- Session APIs -- */

typedef enum {
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
sentry_target_sources_cwd(sentry
sentry_alloc.c
sentry_alloc.h
sentry_attachment.c
sentry_attachment.h
sentry_backend.c
sentry_backend.h
sentry_boot.h
Expand Down
2 changes: 1 addition & 1 deletion src/backends/sentry_backend_breakpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor,
= sentry__screenshot_get_path(options);
if (sentry__screenshot_capture(screenshot_path)) {
sentry__envelope_add_attachment(
envelope, screenshot_path, nullptr);
envelope, screenshot_path, ATTACHMENT, nullptr);
}
sentry__path_free(screenshot_path);
}
Expand Down
29 changes: 29 additions & 0 deletions src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern "C" {
#include "sentry_boot.h"

#include "sentry_alloc.h"
#include "sentry_attachment.h"
#include "sentry_backend.h"
#include "sentry_core.h"
#include "sentry_database.h"
Expand Down Expand Up @@ -660,6 +661,30 @@ crashpad_backend_prune_database(sentry_backend_t *backend)
crashpad::PruneCrashReportDatabase(data->db, &condition);
}

#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX)
static void
crashpad_backend_add_attachment(
sentry_backend_t *backend, const sentry_path_t *attachment)
{
auto *data = static_cast<crashpad_state_t *>(backend->data);
if (!data || !data->client) {
return;
}
data->client->AddAttachment(base::FilePath(attachment->path));
}

static void
crashpad_backend_remove_attachment(
sentry_backend_t *backend, const sentry_path_t *attachment)
{
auto *data = static_cast<crashpad_state_t *>(backend->data);
if (!data || !data->client) {
return;
}
data->client->RemoveAttachment(base::FilePath(attachment->path));
}
#endif

sentry_backend_t *
sentry__backend_new(void)
{
Expand Down Expand Up @@ -687,6 +712,10 @@ sentry__backend_new(void)
backend->user_consent_changed_func = crashpad_backend_user_consent_changed;
backend->get_last_crash_func = crashpad_backend_last_crash;
backend->prune_database_func = crashpad_backend_prune_database;
#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX)
backend->add_attachment_func = crashpad_backend_add_attachment;
backend->remove_attachment_func = crashpad_backend_remove_attachment;
#endif
backend->data = data;
backend->can_capture_after_shutdown = true;

Expand Down
2 changes: 1 addition & 1 deletion src/backends/sentry_backend_inproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ handle_ucontext(const sentry_ucontext_t *uctx)
= sentry__screenshot_get_path(options);
if (sentry__screenshot_capture(screenshot_path)) {
sentry__envelope_add_attachment(
envelope, screenshot_path, NULL);
envelope, screenshot_path, ATTACHMENT, NULL);
}
sentry__path_free(screenshot_path);
}
Expand Down
13 changes: 13 additions & 0 deletions src/path/sentry_path.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ sentry__path_free(sentry_path_t *path)
sentry_free(path);
}

bool
sentry__path_eq(const sentry_path_t *path_a, const sentry_path_t *path_b)
{
size_t i = 0;
while (path_a->path[i] == path_b->path[i]) {
if (path_a->path[i] == (sentry_pathchar_t)0) {
return true;
}
i++;
}
return false;
}

int
sentry__path_remove_all(const sentry_path_t *path)
{
Expand Down
89 changes: 89 additions & 0 deletions src/sentry_attachment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "sentry_attachment.h"
#include "sentry_alloc.h"
#include "sentry_path.h"

static void
attachment_free(sentry_attachment_t *attachment)
{
if (!attachment) {
return;
}
sentry__path_free(attachment->path);
sentry_free(attachment);
}

void
sentry__attachments_free(sentry_attachment_t *attachments)
{
sentry_attachment_t *it = attachments;
while (it) {
sentry_attachment_t *attachment = it;
it = attachment->next;

attachment_free(attachment);
}
}

sentry_attachment_t *
sentry__attachments_add(sentry_attachment_t **attachments_ptr,
sentry_path_t *path, sentry_attachment_type_t attachment_type,
const char *content_type)
{
if (!path) {
return NULL;
}
sentry_attachment_t *attachment = SENTRY_MAKE(sentry_attachment_t);
if (!attachment) {
sentry__path_free(path);
return NULL;
}
attachment->path = path;
attachment->next = NULL;
attachment->type = attachment_type;
attachment->content_type = content_type;

sentry_attachment_t **next_ptr = attachments_ptr;

for (sentry_attachment_t *it = *attachments_ptr; it; it = it->next) {
if (sentry__path_eq(it->path, path)) {
attachment_free(attachment);
return it;
}

next_ptr = &it->next;
}

*next_ptr = attachment;
return attachment;
}

void
sentry__attachments_remove(
sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachment)
{
if (!attachment) {
return;
}

sentry_attachment_t **next_ptr = attachments_ptr;

for (sentry_attachment_t *it = *attachments_ptr; it; it = it->next) {
if (it == attachment || sentry__path_eq(it->path, attachment->path)) {
*next_ptr = it->next;
attachment_free(it);
return;
}

next_ptr = &it->next;
}
}

void
sentry__attachments_extend(
sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments)
{
for (sentry_attachment_t *it = attachments; it; it = it->next) {
sentry__attachments_add(attachments_ptr, sentry__path_clone(it->path),
it->type, it->content_type);
}
}
53 changes: 53 additions & 0 deletions src/sentry_attachment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef SENTRY_ATTACHMENT_H_INCLUDED
#define SENTRY_ATTACHMENT_H_INCLUDED

#include "sentry_boot.h"

#include "sentry_path.h"

/**
* The attachment_type.
*/
typedef enum {
ATTACHMENT,
MINIDUMP,
VIEW_HIERARCHY,
} sentry_attachment_type_t;

/**
* This is a linked list of all the attachments registered via
* `sentry_options_add_attachment`.
*/
struct sentry_attachment_s {
sentry_path_t *path;
sentry_attachment_type_t type;
const char *content_type;
sentry_attachment_t *next;
};

/**
* Frees the linked list of `attachments`.
*/
void sentry__attachments_free(sentry_attachment_t *attachments);

/**
* Adds an attachment to the attachments list at `attachments_ptr`.
*/
sentry_attachment_t *sentry__attachments_add(
sentry_attachment_t **attachments_ptr, sentry_path_t *path,
sentry_attachment_type_t attachment_type, const char *content_type);

/**
* Removes an attachment from the attachments list at `attachments_ptr`.
*/
void sentry__attachments_remove(
sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachment);

/**
* Extends the linked list of attachments at `attachments_ptr` with all
* attachments in `attachments`.
*/
void sentry__attachments_extend(
sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments);

#endif
2 changes: 2 additions & 0 deletions src/sentry_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ struct sentry_backend_s {
void (*user_consent_changed_func)(sentry_backend_t *);
uint64_t (*get_last_crash_func)(sentry_backend_t *);
void (*prune_database_func)(sentry_backend_t *);
void (*add_attachment_func)(sentry_backend_t *, const sentry_path_t *);
void (*remove_attachment_func)(sentry_backend_t *, const sentry_path_t *);
void *data;
// Whether this backend still runs after shutdown_func was called.
bool can_capture_after_shutdown;
Expand Down
Loading
Loading