Skip to content

Commit 969bda1

Browse files
committed
Merge branch 'main' into feat/breadcrumb-hook
2 parents 8838745 + e262da5 commit 969bda1

File tree

10 files changed

+102
-15
lines changed

10 files changed

+102
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Features
1010

1111
- In-editor class reference documentation ([#104](https://github.com/getsentry/sentry-godot/pull/104))
12+
- Capture screenshots when enabled via `attach_screenshot` option ([#128](https://github.com/getsentry/sentry-godot/pull/128))
1213

1314
### Fixes
1415

SConstruct

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ env.Append(CPPPATH=["src/"])
222222
# Source files to compile.
223223
sources = Glob("src/*.cpp")
224224
sources += Glob("src/sentry/*.cpp")
225+
sources += Glob("src/sentry/util/*.cpp")
225226
# Compile sentry-native code only on respective platforms.
226227
if env["platform"] in ["linux", "windows", "macos"]:
227228
sources += Glob("src/sentry/native/*.cpp")

doc_classes/SentryConfiguration.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
options.before_send = _process_event
1919
options.on_crash = _process_event
2020

21-
func _process_event(event: SentryEvent) -> SentryEvent:
21+
func _process_event(event: SentryEvent) -> SentryEvent:
2222
if event.environment == "debug":
2323
# Discard event if running in a debug build.
2424
return null

doc_classes/SentryOptions.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<member name="attach_log" type="bool" setter="set_attach_log" getter="is_attach_log_enabled" default="true">
1414
If [code]true[/code], the SDK will attach the Godot log file to the event.
1515
</member>
16+
<member name="attach_screenshot" type="bool" setter="set_attach_screenshot" getter="is_attach_screenshot_enabled" default="false">
17+
If [code]true[/code], the SDK will try to capture and attach a screenshot to the event.
18+
</member>
1619
<member name="before_send" type="Callable" setter="set_before_send" getter="get_before_send" default="Callable()">
1720
If assigned, this callback runs before a message or error event is sent to Sentry. It takes [SentryEvent] as a parameter and return either the same event object, with or without modifications, or [code]null[/code] to skip reporting the event. You can assign it in a [SentryConfiguration] script.
1821
[codeblock]

project/project.godot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ ui/toolbar/run_overall=true
3737
[sentry]
3838

3939
options/dsn="https://[email protected]/6680910"
40+
options/attach_screenshot=true
4041
options/configuration_script="res://example_configuration.gd"

src/sentry/native/native_sdk.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
#include "sentry/native/native_event.h"
88
#include "sentry/native/native_util.h"
99
#include "sentry/util.h"
10+
#include "sentry/util/screenshot.h"
1011
#include "sentry_options.h"
1112

1213
#include <chrono>
14+
#include <godot_cpp/classes/dir_access.hpp>
15+
#include <godot_cpp/classes/display_server.hpp>
1316
#include <godot_cpp/classes/file_access.hpp>
1417
#include <godot_cpp/classes/os.hpp>
1518
#include <godot_cpp/classes/project_settings.hpp>
1619

20+
#define _SCREENSHOT_FN "screenshot.png"
21+
1722
namespace {
1823

1924
void sentry_event_set_context(sentry_value_t p_event, const char *p_context_name, const Dictionary &p_context) {
@@ -45,7 +50,21 @@ void sentry_event_set_context(sentry_value_t p_event, const char *p_context_name
4550
}
4651
}
4752

48-
inline void inject_contexts(sentry_value_t p_event) {
53+
inline void _save_screenshot() {
54+
String screenshot_path = "user://" _SCREENSHOT_FN;
55+
DirAccess::remove_absolute(screenshot_path);
56+
57+
if (!DisplayServer::get_singleton() || DisplayServer::get_singleton()->get_name() == "headless") {
58+
return;
59+
}
60+
61+
PackedByteArray buffer = sentry::util::take_screenshot();
62+
Ref<FileAccess> f = FileAccess::open(screenshot_path, FileAccess::WRITE);
63+
f->store_buffer(buffer);
64+
f->close();
65+
}
66+
67+
inline void _inject_contexts(sentry_value_t p_event) {
4968
ERR_FAIL_COND(sentry_value_get_type(p_event) != SENTRY_VALUE_TYPE_OBJECT);
5069

5170
HashMap<String, Dictionary> contexts = sentry::contexts::make_event_contexts();
@@ -66,9 +85,10 @@ void test_performance(sentry_value_t ev) {
6685
sentry::util::print_debug(context_dic);
6786
}
6887

69-
sentry_value_t handle_before_send(sentry_value_t event, void *hint, void *closure) {
88+
sentry_value_t _handle_before_send(sentry_value_t event, void *hint, void *closure) {
7089
sentry::util::print_debug("handling before_send");
71-
inject_contexts(event);
90+
_save_screenshot();
91+
_inject_contexts(event);
7292
test_performance(event);
7393
if (const Callable &before_send = SentryOptions::get_singleton()->get_before_send(); before_send.is_valid()) {
7494
Ref<NativeEvent> event_obj = memnew(NativeEvent(event));
@@ -85,8 +105,10 @@ sentry_value_t handle_before_send(sentry_value_t event, void *hint, void *closur
85105
return event;
86106
}
87107

88-
sentry_value_t handle_on_crash(const sentry_ucontext_t *uctx, sentry_value_t event, void *closure) {
89-
inject_contexts(event);
108+
sentry_value_t _handle_on_crash(const sentry_ucontext_t *uctx, sentry_value_t event, void *closure) {
109+
sentry::util::print_debug("handling on_crash");
110+
_save_screenshot();
111+
_inject_contexts(event);
90112
if (const Callable &on_crash = SentryOptions::get_singleton()->get_on_crash(); on_crash.is_valid()) {
91113
Ref<NativeEvent> event_obj = memnew(NativeEvent(event));
92114
Ref<NativeEvent> processed = on_crash.call(event_obj);
@@ -295,9 +317,15 @@ void NativeSDK::initialize() {
295317
}
296318
}
297319

320+
// Attach screenshot.
321+
if (SentryOptions::get_singleton()->is_attach_screenshot_enabled()) {
322+
String screenshot_path = OS::get_singleton()->get_user_data_dir().path_join(_SCREENSHOT_FN);
323+
sentry_options_add_attachment(options, screenshot_path.utf8());
324+
}
325+
298326
// Hooks.
299-
sentry_options_set_before_send(options, handle_before_send, NULL);
300-
sentry_options_set_on_crash(options, handle_on_crash, NULL);
327+
sentry_options_set_before_send(options, _handle_before_send, NULL);
328+
sentry_options_set_on_crash(options, _handle_on_crash, NULL);
301329

302330
int err = sentry_init(options);
303331
initialized = (err == 0);

src/sentry/util/screenshot.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "screenshot.h"
2+
3+
#include <godot_cpp/classes/engine.hpp>
4+
#include <godot_cpp/classes/rendering_server.hpp>
5+
#include <godot_cpp/classes/scene_tree.hpp>
6+
#include <godot_cpp/classes/viewport_texture.hpp>
7+
#include <godot_cpp/classes/window.hpp>
8+
9+
using namespace godot;
10+
11+
namespace sentry::util {
12+
13+
PackedByteArray take_screenshot() {
14+
SceneTree *sml = Object::cast_to<SceneTree>(Engine::get_singleton()->get_main_loop());
15+
ERR_FAIL_NULL_V_MSG(sml, PackedByteArray(), "Sentry: Failed to capture screenshot - couldn't get scene tree.");
16+
17+
Window *main_window = sml->get_root();
18+
ERR_FAIL_NULL_V_MSG(main_window, PackedByteArray(), "Sentry: Failed to capture screenshot - couldn't get main window.");
19+
20+
Ref<ViewportTexture> tex = main_window->get_texture();
21+
Ref<Image> img = tex->get_image();
22+
PackedByteArray bytes = img->save_png_to_buffer();
23+
return bytes;
24+
}
25+
26+
} //namespace sentry::util

src/sentry/util/screenshot.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef SCREENSHOT_H
2+
#define SCREENSHOT_H
3+
4+
namespace godot {
5+
6+
class PackedByteArray;
7+
8+
}
9+
10+
namespace sentry::util {
11+
12+
godot::PackedByteArray take_screenshot();
13+
14+
}
15+
16+
#endif // SCREENSHOT_H

src/sentry_options.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ void SentryOptions::_define_project_settings(const Ref<SentryOptions> &p_options
5757
_define_setting("sentry/options/dist", p_options->dist);
5858
_define_setting(PropertyInfo(Variant::INT, "sentry/options/debug_printing", PROPERTY_HINT_ENUM, "Off,On,Auto"), (int)SentryOptions::DEBUG_DEFAULT);
5959
_define_setting(PropertyInfo(Variant::FLOAT, "sentry/options/sample_rate", PROPERTY_HINT_RANGE, "0.0,1.0"), p_options->sample_rate);
60-
_define_setting("sentry/options/attach_log", p_options->attach_log);
6160
_define_setting(PropertyInfo(Variant::INT, "sentry/options/max_breadcrumbs", PROPERTY_HINT_RANGE, "0, 500"), p_options->max_breadcrumbs);
6261
_define_setting("sentry/options/send_default_pii", p_options->send_default_pii);
6362

63+
_define_setting("sentry/options/attach_log", p_options->attach_log);
64+
_define_setting("sentry/options/attach_screenshot", p_options->attach_screenshot);
65+
6466
_define_setting("sentry/options/error_logger/enabled", p_options->error_logger_enabled);
6567
_define_setting("sentry/options/error_logger/include_source", p_options->error_logger_include_source);
6668
_define_setting(PropertyInfo(Variant::INT, "sentry/options/error_logger/events", PROPERTY_HINT_FLAGS, sentry::GODOT_ERROR_MASK_EXPORT_STRING()), p_options->error_logger_event_mask);
@@ -98,10 +100,12 @@ void SentryOptions::_load_project_settings(const Ref<SentryOptions> &p_options)
98100
p_options->_init_debug_option(mode);
99101

100102
p_options->sample_rate = ProjectSettings::get_singleton()->get_setting("sentry/options/sample_rate", p_options->sample_rate);
101-
p_options->attach_log = ProjectSettings::get_singleton()->get_setting("sentry/options/attach_log", p_options->attach_log);
102103
p_options->max_breadcrumbs = ProjectSettings::get_singleton()->get_setting("sentry/options/max_breadcrumbs", p_options->max_breadcrumbs);
103104
p_options->send_default_pii = ProjectSettings::get_singleton()->get_setting("sentry/options/send_default_pii", p_options->send_default_pii);
104105

106+
p_options->attach_log = ProjectSettings::get_singleton()->get_setting("sentry/options/attach_log", p_options->attach_log);
107+
p_options->attach_screenshot = ProjectSettings::get_singleton()->get_setting("sentry/options/attach_screenshot", p_options->attach_screenshot);
108+
105109
p_options->error_logger_enabled = ProjectSettings::get_singleton()->get_setting("sentry/options/error_logger/enabled", p_options->error_logger_enabled);
106110
p_options->error_logger_include_source = ProjectSettings::get_singleton()->get_setting("sentry/options/error_logger/include_source", p_options->error_logger_include_source);
107111
p_options->error_logger_event_mask = (int)ProjectSettings::get_singleton()->get_setting("sentry/options/error_logger/events", p_options->error_logger_event_mask);
@@ -154,10 +158,12 @@ void SentryOptions::_bind_methods() {
154158
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "debug"), set_debug_enabled, is_debug_enabled);
155159
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::STRING, "environment"), set_environment, get_environment);
156160
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::FLOAT, "sample_rate"), set_sample_rate, get_sample_rate);
157-
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "attach_log"), set_attach_log, is_attach_log_enabled);
158161
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::INT, "max_breadcrumbs"), set_max_breadcrumbs, get_max_breadcrumbs);
159162
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "send_default_pii"), set_send_default_pii, is_send_default_pii_enabled);
160163

164+
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "attach_log"), set_attach_log, is_attach_log_enabled);
165+
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "attach_screenshot"), set_attach_screenshot, is_attach_screenshot_enabled);
166+
161167
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "error_logger_enabled"), set_error_logger_enabled, is_error_logger_enabled);
162168
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::BOOL, "error_logger_include_source"), set_error_logger_include_source, is_error_logger_include_source_enabled);
163169
BIND_PROPERTY(SentryOptions, PropertyInfo(Variant::INT, "error_logger_event_mask"), set_error_logger_event_mask, get_error_logger_event_mask);

src/sentry_options.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ class SentryOptions : public RefCounted {
5555
bool debug = false;
5656
String environment;
5757
double sample_rate = 1.0;
58-
bool attach_log = true;
5958
int max_breadcrumbs = 100;
6059
bool send_default_pii = false;
6160

61+
bool attach_log = true;
62+
bool attach_screenshot = false;
63+
6264
bool error_logger_enabled = true;
6365
bool error_logger_include_source = true;
6466
BitField<GodotErrorMask> error_logger_event_mask = int(GodotErrorMask::MASK_ALL_EXCEPT_WARNING);
@@ -107,15 +109,18 @@ class SentryOptions : public RefCounted {
107109
_FORCE_INLINE_ double get_sample_rate() const { return sample_rate; }
108110
_FORCE_INLINE_ void set_sample_rate(double p_sample_rate) { sample_rate = p_sample_rate; }
109111

110-
_FORCE_INLINE_ bool is_attach_log_enabled() const { return attach_log; }
111-
_FORCE_INLINE_ void set_attach_log(bool p_enabled) { attach_log = p_enabled; }
112-
113112
_FORCE_INLINE_ int get_max_breadcrumbs() const { return max_breadcrumbs; }
114113
_FORCE_INLINE_ void set_max_breadcrumbs(int p_max_breadcrumbs) { max_breadcrumbs = p_max_breadcrumbs; }
115114

116115
_FORCE_INLINE_ bool is_send_default_pii_enabled() const { return send_default_pii; }
117116
_FORCE_INLINE_ void set_send_default_pii(bool p_enabled) { send_default_pii = p_enabled; }
118117

118+
_FORCE_INLINE_ bool is_attach_log_enabled() const { return attach_log; }
119+
_FORCE_INLINE_ void set_attach_log(bool p_enabled) { attach_log = p_enabled; }
120+
121+
_FORCE_INLINE_ bool is_attach_screenshot_enabled() const { return attach_screenshot; }
122+
_FORCE_INLINE_ void set_attach_screenshot(bool p_attach_screenshot) { attach_screenshot = p_attach_screenshot; }
123+
119124
_FORCE_INLINE_ bool is_error_logger_enabled() const { return error_logger_enabled; }
120125
_FORCE_INLINE_ void set_error_logger_enabled(bool p_enabled) { error_logger_enabled = p_enabled; }
121126

0 commit comments

Comments
 (0)