53#define DT_SENTRY_ENABLED_KEY "sentry/enabled"
54#define DT_SENTRY_ASKED_KEY "sentry/consent_asked"
55#define DT_SENTRY_CLEAN_SESSIONS_KEY "sentry/clean_sessions"
56#define DT_SENTRY_LAST_SESSION_KEY "sentry/last_session_seconds"
57#define DT_SENTRY_TOTAL_SESSION_KEY "sentry/total_session_seconds"
59static gboolean _sentry_inited =
FALSE;
63static volatile sig_atomic_t _sentry_backtrace_captured = 0;
68static GHashTable *_module_usage = NULL;
72static GMutex _processed_image_lock;
73static int32_t _processed_imgid = -1;
74static char _processed_pipeline[32] = { 0 };
78static double _sentry_session_seconds(
void)
81 return (dur > 0.0) ? dur : 0.0;
86static void _sentry_stamp_session_length(sentry_value_t event)
88 const double dur = _sentry_session_seconds();
91 sentry_value_t extra = sentry_value_get_by_key(event,
"extra");
92 if(sentry_value_is_null(extra))
94 extra = sentry_value_new_object();
95 sentry_value_set_by_key(extra,
"session_seconds", sentry_value_new_double(dur));
96 sentry_value_set_by_key(event,
"extra", extra);
100 sentry_value_set_by_key(extra,
"session_seconds", sentry_value_new_double(dur));
105 snprintf(buf,
sizeof(buf),
"%.0f", dur);
106 sentry_value_t tags = sentry_value_get_by_key(event,
"tags");
107 if(sentry_value_is_null(tags))
109 tags = sentry_value_new_object();
110 sentry_value_set_by_key(tags,
"session_seconds", sentry_value_new_string(buf));
111 sentry_value_set_by_key(event,
"tags", tags);
115 sentry_value_set_by_key(tags,
"session_seconds", sentry_value_new_string(buf));
121static sentry_value_t _sentry_before_send(sentry_value_t event,
void *hint,
void *user_data)
123 _sentry_stamp_session_length(event);
127#if defined(__linux__)
132static char *_sentry_capture_gdb_backtrace(gsize *len)
135 const int fd = g_file_open_tmp(
"ansel_sentry_bt_XXXXXX.txt", &
name, NULL);
136 if(fd == -1)
return NULL;
139 gchar *pid_arg = g_strdup_printf(
"%d", (
int)getpid());
140 gchar *exe_arg = g_strdup_printf(
"/proc/%s/exe", pid_arg);
141 gchar *log_file_arg = g_strdup_printf(
"set logging file %s",
name);
143 char *contents = NULL;
144 const pid_t pid = fork();
148 execlp(
"gdb",
"gdb", exe_arg, pid_arg,
"-batch",
149 "-ex",
"set pagination off",
150 "-ex",
"set confirm off",
152 "-ex",
"set logging overwrite on",
153 "-ex",
"set logging redirect on",
154 "-ex",
"set logging enabled on",
155 "-ex",
"thread apply all bt full",
161 prctl(PR_SET_PTRACER, pid, 0, 0, 0);
162 waitpid(pid, NULL, 0);
165 if(g_file_get_contents(
name, &contents, &
n, NULL))
179 g_free(log_file_arg);
187static sentry_value_t _sentry_on_crash(
const sentry_ucontext_t *uctx, sentry_value_t event,
void *user_data)
189 _sentry_stamp_session_length(event);
191#if defined(__linux__)
193 char *bt = _sentry_capture_gdb_backtrace(&bt_len);
198 sentry_attach_bytes(bt, bt_len,
"gdb-backtrace.txt");
202 _sentry_backtrace_captured = 1;
212 return _sentry_backtrace_captured != 0;
217 if(!_sentry_inited || !category || !
name || !*
name)
return;
220 _module_usage = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
224 char *
key = g_strdup_printf(
"%s/%s", category,
name);
225 const int count = GPOINTER_TO_INT(g_hash_table_lookup(_module_usage,
key)) + 1;
226 g_hash_table_insert(_module_usage,
key, GINT_TO_POINTER(count));
230 sentry_value_t obj = sentry_value_new_object();
233 g_hash_table_iter_init(&iter, _module_usage);
234 while(g_hash_table_iter_next(&iter, &
k, &
v))
235 sentry_value_set_by_key(obj, (
const char *)
k, sentry_value_new_int32(GPOINTER_TO_INT(
v)));
236 sentry_set_context(
"module_usage", obj);
241 if(!_sentry_inited || !img)
return;
242 const char *pl = pipeline ? pipeline :
"";
246 g_mutex_lock(&_processed_image_lock);
247 if(img->
id == _processed_imgid && !strcmp(pl, _processed_pipeline))
249 g_mutex_unlock(&_processed_image_lock);
252 _processed_imgid = img->
id;
253 g_strlcpy(_processed_pipeline, pl,
sizeof(_processed_pipeline));
254 g_mutex_unlock(&_processed_image_lock);
257 const char *dot = strrchr(img->
filename,
'.');
259 sentry_value_t o = sentry_value_new_object();
260 sentry_value_set_by_key(o,
"extension", sentry_value_new_string(dot ? dot + 1 :
""));
261 sentry_value_set_by_key(o,
"pipeline", sentry_value_new_string(pl));
262 sentry_value_set_by_key(o,
"raw", sentry_value_new_bool(
dt_image_is_raw(img)));
263 sentry_value_set_by_key(o,
"ldr", sentry_value_new_bool(
dt_image_is_ldr(img)));
264 sentry_value_set_by_key(o,
"hdr", sentry_value_new_bool(
dt_image_is_hdr(img)));
268 sentry_value_set_by_key(o,
"needs_demosaic", sentry_value_new_bool(img->
dsc.
filters != 0));
269 sentry_value_set_by_key(o,
"width", sentry_value_new_int32(img->
width));
270 sentry_value_set_by_key(o,
"height", sentry_value_new_int32(img->
height));
271 sentry_set_context(
"processed_image", o);
276static void _sentry_set_context(
void)
279 sentry_value_t device = sentry_value_new_object();
280 sentry_value_set_by_key(device,
"cpu_logical_cores", sentry_value_new_int32(g_get_num_processors()));
286 sentry_value_set_by_key(device,
"memory_gb", sentry_value_new_double(mem_gb));
290 sentry_value_set_by_key(device,
"opencl_enabled", sentry_value_new_bool(cl_enabled));
296 sentry_value_t gpus = sentry_value_new_list();
300 if(
name) sentry_value_append(gpus, sentry_value_new_string(
name));
302 sentry_value_set_by_key(device,
"opencl_devices", gpus);
308 sentry_set_context(
"device", device);
310#if !defined(_WIN32) && !defined(__APPLE__)
313 const char *session_type = g_getenv(
"XDG_SESSION_TYPE");
314 if(!session_type || !*session_type)
317 if(g_getenv(
"WAYLAND_DISPLAY"))
318 session_type =
"wayland";
319 else if(g_getenv(
"DISPLAY"))
320 session_type =
"x11";
322 if(session_type && *session_type) sentry_set_tag(
"display_server", session_type);
324 const char *desktop = g_getenv(
"XDG_CURRENT_DESKTOP");
325 if(!desktop || !*desktop) desktop = g_getenv(
"DESKTOP_SESSION");
326 if(desktop && *desktop) sentry_set_tag(
"desktop_environment", desktop);
331 GdkDisplay *display = gdk_display_get_default();
332 if(display) sentry_set_tag(
"gdk_backend", G_OBJECT_TYPE_NAME(display));
341 sentry_value_t scr = sentry_value_new_object();
342 sentry_value_set_by_key(scr,
"dpi", sentry_value_new_double(
darktable.
gui->
dpi));
344 sentry_value_set_by_key(scr,
"ppd", sentry_value_new_double(
darktable.
gui->
ppd));
348 if(win_w > 0 && win_h > 0)
350 sentry_value_set_by_key(scr,
"window_width", sentry_value_new_int32(win_w));
351 sentry_value_set_by_key(scr,
"window_height", sentry_value_new_int32(win_h));
355 snprintf(wbuf,
sizeof(wbuf),
"%dx%d", win_w, win_h);
356 sentry_set_tag(
"window_size", wbuf);
360 GdkDisplay *gdkdisp = gdk_display_get_default();
361 GdkMonitor *
mon = gdkdisp ? gdk_display_get_primary_monitor(gdkdisp) : NULL;
362 if(!
mon && gdkdisp && gdk_display_get_n_monitors(gdkdisp) > 0)
363 mon = gdk_display_get_monitor(gdkdisp, 0);
367 gdk_monitor_get_geometry(
mon, &geo);
368 sentry_value_set_by_key(scr,
"screen_width", sentry_value_new_int32(geo.width));
369 sentry_value_set_by_key(scr,
"screen_height", sentry_value_new_int32(geo.height));
370 sentry_value_set_by_key(scr,
"monitor_scale_factor",
371 sentry_value_new_int32(gdk_monitor_get_scale_factor(
mon)));
374 snprintf(sbuf,
sizeof(sbuf),
"%dx%d", geo.width, geo.height);
375 sentry_set_tag(
"screen_size", sbuf);
377 sentry_set_context(
"display", scr);
381 sentry_set_extra(
"build_type", sentry_value_new_string(
DT_BUILD_TYPE));
382 sentry_set_tag(
"opencl", cl_enabled ?
"yes" :
"no");
386 sentry_set_extra(
"clean_sessions_local",
387 sentry_value_new_int32(
dt_conf_get_int(DT_SENTRY_CLEAN_SESSIONS_KEY)));
392 sentry_set_extra(
"previous_session_seconds",
394 sentry_set_extra(
"total_session_seconds",
405 if(SENTRY_DSN[0] ==
'\0')
411 sentry_options_t *
options = sentry_options_new();
412 sentry_options_set_dsn(
options, SENTRY_DSN);
417 char *db_path = g_build_filename(cachedir,
"sentry-native", NULL);
418 sentry_options_set_database_path(
options, db_path);
422 sentry_options_set_release(
options, release);
429 sentry_options_set_before_send(
options, _sentry_before_send, NULL);
432 sentry_options_set_on_crash(
options, _sentry_on_crash, NULL);
437 sentry_options_set_auto_session_tracking(
options, 1);
441 _sentry_inited =
TRUE;
442 _sentry_set_context();
453 if(!_sentry_inited)
return;
462 const int dur = (int)_sentry_session_seconds();
468 _sentry_inited =
FALSE;
472 g_hash_table_destroy(_module_usage);
473 _module_usage = NULL;
gboolean dt_image_is_raw(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
gboolean dt_image_is_monochrome(const dt_image_t *img)
gboolean dt_image_is_ldr(const dt_image_t *img)
const char darktable_package_version[]
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
void dt_conf_set_int64(const char *name, int64_t val)
int dt_conf_get_int(const char *name)
int64_t dt_conf_get_int64(const char *name)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static double dt_get_wtime(void)
void dt_loc_get_user_cache_dir(char *cachedir, size_t bufsize)
float *const restrict const size_t k
int dt_opencl_is_enabled(void)
gboolean dt_sentry_backtrace_captured(void)
void dt_sentry_record_module_usage(const char *category, const char *name)
void dt_sentry_shutdown(void)
void dt_sentry_init(const gboolean have_gui)
void dt_sentry_set_processed_image(const struct dt_image_t *img, const char *pipeline)
static const char *const mon[12]
int32_t num_openmp_threads
struct dt_gui_gtk_t * gui
struct dt_sys_resources_t dtresources
struct dt_opencl_t * opencl
char filename[DT_MAX_FILENAME_LEN]
typedef double((*spd)(unsigned long int wavelength, double TempK))