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

## Unreleased

**Features**:

- The `sentry_add_attachment`, `sentry_scope_add_attachment`, and `sentry_remove_attachment` (and their wide-string variants) 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))

## 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_add_attachment("./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_add_attachment(scope, "./CMakeCache.txt");
}

sentry_capture_event_with_scope(event, scope);
}

Expand Down
59 changes: 59 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` 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,52 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy(

#endif // SENTRY_PLATFORM_LINUX

/**
* 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_add_attachmentw` instead.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API void sentry_add_attachment(const char *path);
SENTRY_API void sentry_add_attachment_n(const char *path, size_t path_len);
SENTRY_API void sentry_scope_add_attachment(
sentry_scope_t *scope, const char *path);
SENTRY_API void sentry_scope_add_attachment_n(
sentry_scope_t *scope, const char *path, size_t path_len);

/**
* Removes a previously added attachment.
*
* `path` is assumed to be in platform-specific filesystem path encoding.
* API Users on windows are encouraged to use `sentry_remove_attachmentw`
* instead.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API void sentry_remove_attachment(const char *path);
SENTRY_API void sentry_remove_attachment_n(const char *path, size_t path_len);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char version of `sentry_add_attachment`.
*/
SENTRY_API void sentry_add_attachmentw(const wchar_t *path);
SENTRY_API void sentry_add_attachmentw_n(const wchar_t *path, size_t path_len);
SENTRY_API void sentry_scope_add_attachmentw(
sentry_scope_t *scope, const wchar_t *path);
SENTRY_API void sentry_scope_add_attachmentw_n(
sentry_scope_t *scope, const wchar_t *path, size_t path_len);

/**
* Wide char version of `sentry_remove_attachment`.
*/
SENTRY_API void sentry_remove_attachmentw(const wchar_t *path);
SENTRY_API void sentry_remove_attachmentw_n(
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
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->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->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
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
155 changes: 155 additions & 0 deletions src/sentry_attachment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include "sentry_attachment.h"
#include "sentry_alloc.h"
#include "sentry_envelope.h"
#include "sentry_options.h"
#include "sentry_path.h"
#include "sentry_utils.h"
#include "sentry_value.h"

#include <assert.h>

static const char *
str_from_attachment_type(sentry_attachment_type_t attachment_type)
{
switch (attachment_type) {
case ATTACHMENT:
return "event.attachment";
case MINIDUMP:
return "event.minidump";
case VIEW_HIERARCHY:
return "event.view_hierarchy";
default:
UNREACHABLE("Unknown attachment type");
return "event.attachment";
}
}

static void
sentry__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 *next_attachment = attachments;
while (next_attachment) {
sentry_attachment_t *attachment = next_attachment;
next_attachment = attachment->next;

sentry__attachment_free(attachment);
}
}

void
sentry__attachment_add(sentry_attachment_t **attachments_ptr,
sentry_path_t *path, sentry_attachment_type_t attachment_type,
const char *content_type)
{
if (!path) {
return;
}
sentry_attachment_t *attachment = SENTRY_MAKE(sentry_attachment_t);
if (!attachment) {
sentry__path_free(path);
return;
}
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 *last_attachment = *attachments_ptr;
last_attachment; last_attachment = last_attachment->next) {
if (sentry__path_eq(last_attachment->path, path)) {
sentry__attachment_free(attachment);
return;
}

next_ptr = &last_attachment->next;
}

*next_ptr = attachment;
}

void
sentry__attachment_remove(
sentry_attachment_t **attachments_ptr, sentry_path_t *path)
{
sentry_attachment_t **next_ptr = attachments_ptr;

for (sentry_attachment_t *attachment = *attachments_ptr; attachment;
attachment = attachment->next) {
if (sentry__path_eq(attachment->path, path)) {
*next_ptr = attachment->next;
sentry__attachment_free(attachment);
goto out;
}

next_ptr = &attachment->next;
}

out:
sentry__path_free(path);
}

/**
* Reads the attachments from disk and adds them to the `envelope`.
*/
void
sentry__apply_attachments_to_envelope(
sentry_envelope_t *envelope, const sentry_attachment_t *attachments)
{
if (!attachments) {
return;
}

SENTRY_DEBUG("adding attachments to envelope");
for (const sentry_attachment_t *attachment = attachments; attachment;
attachment = attachment->next) {
sentry_envelope_item_t *item = sentry__envelope_add_from_path(
envelope, attachment->path, "attachment");
if (!item) {
continue;
}
if (attachment->type != ATTACHMENT) { // don't need to set the default
sentry__envelope_item_set_header(item, "attachment_type",
sentry_value_new_string(
str_from_attachment_type(attachment->type)));
}
if (attachment->content_type) {
sentry__envelope_item_set_header(item, "content_type",
sentry_value_new_string(attachment->content_type));
}
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(attachment->path)));
}
}

void
sentry__attachments_extend(
sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments)
{
if (!attachments) {
return;
}

for (sentry_attachment_t *attachment = attachments; attachment;
attachment = attachment->next) {
sentry__attachment_add(attachments_ptr,
sentry__path_clone(attachment->path), attachment->type,
attachment->content_type);
}
}
Loading
Loading