kicad/thirdparty/sentry-native/src/sentry_session.c

318 lines
8.7 KiB
C

#include "sentry_session.h"
#include "sentry_alloc.h"
#include "sentry_database.h"
#include "sentry_envelope.h"
#include "sentry_json.h"
#include "sentry_options.h"
#include "sentry_scope.h"
#include "sentry_string.h"
#include "sentry_utils.h"
#include "sentry_value.h"
#include <assert.h>
#include <string.h>
static const char *
status_as_string(sentry_session_status_t status)
{
switch (status) {
case SENTRY_SESSION_STATUS_OK:
return "ok";
case SENTRY_SESSION_STATUS_CRASHED:
return "crashed";
case SENTRY_SESSION_STATUS_ABNORMAL:
return "abnormal";
case SENTRY_SESSION_STATUS_EXITED:
return "exited";
default:
assert(!"invalid session status");
return "invalid";
}
}
static sentry_session_status_t
status_from_string(const char *status)
{
if (sentry__string_eq(status, "ok")) {
return SENTRY_SESSION_STATUS_OK;
} else if (sentry__string_eq(status, "exited")) {
return SENTRY_SESSION_STATUS_EXITED;
} else if (sentry__string_eq(status, "crashed")) {
return SENTRY_SESSION_STATUS_CRASHED;
} else if (sentry__string_eq(status, "abnormal")) {
return SENTRY_SESSION_STATUS_ABNORMAL;
} else {
return SENTRY_SESSION_STATUS_OK;
}
}
sentry_session_t *
sentry__session_new(void)
{
char *release = NULL;
char *environment = NULL;
SENTRY_WITH_OPTIONS (options) {
release = sentry__string_clone(sentry_options_get_release(options));
environment
= sentry__string_clone(sentry_options_get_environment(options));
}
if (!release) {
sentry_free(environment);
return NULL;
}
sentry_session_t *rv = SENTRY_MAKE(sentry_session_t);
if (!rv) {
sentry_free(release);
sentry_free(environment);
return NULL;
}
rv->release = release;
rv->environment = environment;
rv->session_id = sentry_uuid_new_v4();
rv->distinct_id = sentry_value_new_null();
rv->status = SENTRY_SESSION_STATUS_OK;
rv->init = true;
rv->errors = 0;
rv->started_ms = sentry__msec_time();
rv->duration_ms = (uint64_t)-1;
return rv;
}
void
sentry__session_free(sentry_session_t *session)
{
if (!session) {
return;
}
sentry_value_decref(session->distinct_id);
sentry_free(session->release);
sentry_free(session->environment);
sentry_free(session);
}
void
sentry__session_to_json(
const sentry_session_t *session, sentry_jsonwriter_t *jw)
{
sentry__jsonwriter_write_object_start(jw);
if (session->init) {
sentry__jsonwriter_write_key(jw, "init");
sentry__jsonwriter_write_bool(jw, true);
}
sentry__jsonwriter_write_key(jw, "sid");
sentry__jsonwriter_write_uuid(jw, &session->session_id);
sentry__jsonwriter_write_key(jw, "status");
sentry__jsonwriter_write_str(jw, status_as_string(session->status));
if (!sentry_value_is_null(session->distinct_id)) {
char *did = sentry__value_stringify(session->distinct_id);
if (did) {
sentry__jsonwriter_write_key(jw, "did");
sentry__jsonwriter_write_str(jw, did);
sentry_free(did);
}
}
sentry__jsonwriter_write_key(jw, "errors");
sentry__jsonwriter_write_int32(jw, (int32_t)session->errors);
sentry__jsonwriter_write_key(jw, "started");
sentry__jsonwriter_write_msec_timestamp(jw, session->started_ms);
// if there is a duration stored on the struct (that happens after
// reading back from disk) we use that, otherwise we calculate the
// difference to the start time.
sentry__jsonwriter_write_key(jw, "duration");
double duration;
if (session->duration_ms != (uint64_t)-1) {
duration = (double)session->duration_ms / 1000.0;
} else {
duration = (double)(sentry__msec_time() - session->started_ms) / 1000.0;
}
sentry__jsonwriter_write_double(jw, duration);
sentry__jsonwriter_write_key(jw, "attrs");
sentry__jsonwriter_write_object_start(jw);
sentry__jsonwriter_write_key(jw, "release");
sentry__jsonwriter_write_str(jw, session->release);
sentry__jsonwriter_write_key(jw, "environment");
sentry__jsonwriter_write_str(jw, session->environment);
sentry__jsonwriter_write_object_end(jw);
sentry__jsonwriter_write_object_end(jw);
}
sentry_session_t *
sentry__session_from_json(const char *buf, size_t buflen)
{
sentry_value_t value = sentry__value_from_json(buf, buflen);
if (sentry_value_is_null(value)) {
return NULL;
}
sentry_value_t attrs = sentry_value_get_by_key(value, "attrs");
if (sentry_value_is_null(attrs)) {
return NULL;
}
char *release = sentry__string_clone(
sentry_value_as_string(sentry_value_get_by_key(attrs, "release")));
if (!release) {
return NULL;
}
sentry_session_t *rv = SENTRY_MAKE(sentry_session_t);
if (!rv) {
sentry_free(release);
return NULL;
}
rv->session_id
= sentry__value_as_uuid(sentry_value_get_by_key(value, "sid"));
rv->distinct_id = sentry_value_get_by_key_owned(value, "did");
rv->release = release;
rv->environment = sentry__string_clone(
sentry_value_as_string(sentry_value_get_by_key(attrs, "environment")));
const char *status
= sentry_value_as_string(sentry_value_get_by_key(value, "status"));
rv->status = status_from_string(status);
rv->init = sentry_value_is_true(sentry_value_get_by_key(value, "init"));
rv->errors = (int64_t)sentry_value_as_int32(
sentry_value_get_by_key(value, "errors"));
rv->started_ms = sentry__iso8601_to_msec(
sentry_value_as_string(sentry_value_get_by_key(value, "started")));
double duration
= sentry_value_as_double(sentry_value_get_by_key(value, "duration"));
rv->duration_ms = (uint64_t)(duration * 1000);
sentry_value_decref(value);
return rv;
}
sentry_session_t *
sentry__session_from_path(const sentry_path_t *path)
{
size_t buf_len;
char *buf = sentry__path_read_to_buffer(path, &buf_len);
if (!buf) {
return NULL;
}
sentry_session_t *rv = sentry__session_from_json(buf, buf_len);
sentry_free(buf);
return rv;
}
void
sentry_start_session(void)
{
sentry_end_session();
SENTRY_WITH_SCOPE (scope) {
sentry_options_t *options = sentry__options_lock();
if (options) {
options->session = sentry__session_new();
if (options->session) {
sentry__session_sync_user(options->session, scope->user);
sentry__run_write_session(options->run, options->session);
}
}
sentry__options_unlock();
}
}
void
sentry__record_errors_on_current_session(uint32_t error_count)
{
sentry_options_t *options = sentry__options_lock();
if (options && options->session) {
options->session->errors += error_count;
}
sentry__options_unlock();
}
static sentry_session_t *
sentry__end_session_internal(void)
{
sentry_session_t *session = NULL;
sentry_options_t *options = sentry__options_lock();
if (options) {
session = options->session;
options->session = NULL;
sentry__run_clear_session(options->run);
}
sentry__options_unlock();
if (session && session->status == SENTRY_SESSION_STATUS_OK) {
session->status = SENTRY_SESSION_STATUS_EXITED;
}
return session;
}
sentry_session_t *
sentry__end_current_session_with_status(sentry_session_status_t status)
{
sentry_session_t *session = sentry__end_session_internal();
if (session) {
session->status = status;
}
return session;
}
static void
sentry__capture_session(sentry_session_t *session)
{
sentry_envelope_t *envelope = sentry__envelope_new();
sentry__envelope_add_session(envelope, session);
SENTRY_WITH_OPTIONS (options) {
sentry__capture_envelope(options->transport, envelope);
}
}
void
sentry_end_session(void)
{
sentry_session_t *session = sentry__end_session_internal();
if (!session) {
return;
}
sentry__capture_session(session);
sentry__session_free(session);
}
void
sentry_end_session_with_status(sentry_session_status_t status)
{
sentry_session_t *session = sentry__end_current_session_with_status(status);
if (!session) {
return;
}
sentry__capture_session(session);
sentry__session_free(session);
}
void
sentry__session_sync_user(sentry_session_t *session, sentry_value_t user)
{
sentry_value_t did = sentry_value_get_by_key(user, "id");
if (sentry_value_is_null(did)) {
did = sentry_value_get_by_key(user, "email");
}
if (sentry_value_is_null(did)) {
did = sentry_value_get_by_key(user, "username");
}
sentry_value_decref(session->distinct_id);
sentry_value_incref(did);
session->distinct_id = did;
}