Skip to content
Closed
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
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` 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`.

## 0.4.4

**Features**:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,12 @@ Other important configuration options include:

## Known Limitations

- The crashpad backend currently has no support for notifying the crashing
- The crashpad backend on macOS currently has no support for notifying the crashing
process, and can thus not properly terminate sessions or call the registered
`before_send` hook. It will also lose any events that have been queued for
sending at time of crash.
- When using the crashpad backend, the list of attachments that will be sent
along with crashes is frozen at the time of `sentry_init`.

## Development

Expand Down
46 changes: 46 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, 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 @@ -821,6 +832,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 @@ -1050,6 +1063,39 @@ SENTRY_API void sentry_remove_transaction(void);
*/
SENTRY_API void sentry_set_level(sentry_level_t level);

/**
* 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.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to explicitly say something about the ownership of *path? (same for remove attachment)

SENTRY_API void sentry_add_attachment(const char *path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we always want this to be void? Does a status return make any sense now or in the future?


/**
* 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While an idempotent API is good, would a return from which you can tell whether anything happened or not be useful?


#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char version of `sentry_add_attachment`.
*/
SENTRY_API void sentry_add_attachmentw(const wchar_t *path);

/**
* Wide char version of `sentry_remove_attachment`.
*/
SENTRY_API void sentry_remove_attachmentw(const wchar_t *path);
#endif

/**
* Starts a new session.
*/
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
1 change: 1 addition & 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
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
105 changes: 105 additions & 0 deletions src/sentry_attachment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "sentry_attachment.h"
#include "sentry_alloc.h"
#include "sentry_envelope.h"
#include "sentry_options.h"
#include "sentry_path.h"
#include "sentry_value.h"

static void
sentry__attachment_free(sentry_attachment_t *attachment)
{
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)
{
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;

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_TRACE("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;
}
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)));
}
}
43 changes: 43 additions & 0 deletions src/sentry_attachment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef SENTRY_ATTACHMENT_H_INCLUDED
#define SENTRY_ATTACHMENT_H_INCLUDED

#include "sentry_boot.h"

typedef struct sentry_path_s sentry_path_t;
typedef struct sentry_options_s sentry_options_t;
typedef struct sentry_envelope_s sentry_envelope_t;

/**
* This is a linked list of all the attachments registered via
* `sentry_options_add_attachment`.
*/
typedef struct sentry_attachment_s sentry_attachment_t;
struct sentry_attachment_s {
sentry_path_t *path;
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`.
*/
void sentry__attachment_add(
sentry_attachment_t **attachments_ptr, sentry_path_t *path);

/**
* Removes an attachment from the attachments list at `attachments_ptr`.
*/
void sentry__attachment_remove(
sentry_attachment_t **attachments_ptr, sentry_path_t *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);

#endif
59 changes: 43 additions & 16 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.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 @@ -144,7 +145,8 @@ sentry_init(sentry_options_t *options)
// the only way to get a reference to the scope is by locking it, the macro
// does all that at once, including invoking the backends scope flush hook
SENTRY_WITH_SCOPE_MUT (scope) {
(void)scope;
scope->attachments = options->attachments;
options->attachments = NULL;
}
if (backend && backend->user_consent_changed_func) {
backend->user_consent_changed_func(backend);
Expand Down Expand Up @@ -360,21 +362,8 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event,
goto fail;
}

SENTRY_TRACE("adding attachments to envelope");
for (sentry_attachment_t *attachment = options->attachments; attachment;
attachment = attachment->next) {
sentry_envelope_item_t *item = sentry__envelope_add_from_path(
envelope, attachment->path, "attachment");
if (!item) {
continue;
}
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)));
SENTRY_WITH_SCOPE (scope) {
sentry__apply_attachments_to_envelope(envelope, scope->attachments);
}

return envelope;
Expand Down Expand Up @@ -560,3 +549,41 @@ sentry_set_level(sentry_level_t level)
scope->level = level;
}
}

void
sentry_add_attachment(const char *path)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry__attachment_add(
&scope->attachments, sentry__path_from_str(path));
}
}

void
sentry_remove_attachment(const char *path)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry__attachment_remove(
&scope->attachments, sentry__path_from_str(path));
}
}

#ifdef SENTRY_PLATFORM_WINDOWS
void
sentry_add_attachmentw(const wchar_t *path)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry__attachment_add(
&scope->attachments, sentry__path_from_wstr(path));
}
}

void
sentry_remove_attachmentw(const wchar_t *path)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry__attachment_remove(
&scope->attachments, sentry__path_from_wstr(path));
}
}
#endif
4 changes: 3 additions & 1 deletion src/sentry_envelope.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,9 @@ sentry_envelope_serialize(const sentry_envelope_t *envelope, size_t *size_out)

sentry__envelope_serialize_into_stringbuilder(envelope, &sb);

*size_out = sentry__stringbuilder_len(&sb);
if (size_out) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice 😄

*size_out = sentry__stringbuilder_len(&sb);
}
return sentry__stringbuilder_into_string(&sb);
}

Expand Down
Loading