diff --git a/CHANGELOG.md b/CHANGELOG.md index bed0332..2ba07b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ -# Changelog - +# Changelog + +## Unreleased + +### Features + +- Create or modify events using `SentryEvent` objects and new SDK methods: `SentrySDK.create_event()`, `SentrySDK.capture_event(event)` ([#51](https://github.com/getsentry/sentry-godot/pull/51)) + ## 0.0.3 ### Various fixes & improvements @@ -8,10 +14,10 @@ ## 0.0.2 -### Dependencies - +### Dependencies + - Bump sentry-native to 0.7.17 ([#53](https://github.com/getsentry/sentry-godot/pull/53)) -## 0.0.1 - -Initial release +## 0.0.1 + +Initial release diff --git a/project/test/test_event.gd b/project/test/test_event.gd new file mode 100644 index 0000000..9d92273 --- /dev/null +++ b/project/test/test_event.gd @@ -0,0 +1,81 @@ +class_name TestEvent +extends GdUnitTestSuite + + +## SentryEvent.id should not be empty on event creation. +func test_event_id() -> void: + var event := SentrySDK.create_event() + assert_str(event.id).is_not_empty() + + +## SentryEvent.message should be set to the specified value, and should be empty on event creation. +func test_event_message() -> void: + var event := SentrySDK.create_event() + assert_str(event.message).is_empty() + event.message = "Hello, World!" + assert_str(event.message).is_equal("Hello, World!") + + +## SentryEvent.level should be set to the specified value. +func test_event_level() -> void: + var event := SentrySDK.create_event() + for l in [SentrySDK.LEVEL_DEBUG, SentrySDK.LEVEL_INFO, SentrySDK.LEVEL_WARNING, SentrySDK.LEVEL_ERROR, SentrySDK.LEVEL_FATAL]: + event.level = l + assert_int(event.level).is_equal(l) + + +## SentryEvent.timestamp should not be empty on event creation, and setter should update it. +func test_event_timestamp() -> void: + var event := SentrySDK.create_event() + assert_str(event.timestamp).is_not_empty() + var ts = Time.get_datetime_string_from_system() + event.timestamp = ts + assert_str(event.timestamp).is_equal(ts) + + +## SentryEvent.platform should not be empty. +func test_event_platform() -> void: + var event := SentrySDK.create_event() + assert_str(event.platform).is_not_empty() + + +## SentryEvent.logger should be set to the specified value, and empty on event creation. +func test_event_logger() -> void: + var event := SentrySDK.create_event() + assert_str(event.logger).is_empty() + event.logger = "custom-logger" + assert_str(event.logger).is_equal("custom-logger") + + +## SentryEvent.release should be set to the specified value, and empty on event creation. +func test_event_release() -> void: + var event := SentrySDK.create_event() + assert_str(event.release).is_empty() + event.release = "custom-release" + assert_str(event.release).is_equal("custom-release") + + +## SentryEvent.dist should be set to the specified value, and empty on event creation. +func test_event_dist() -> void: + var event := SentrySDK.create_event() + assert_str(event.dist).is_empty() + event.dist = "custom-dist" + assert_str(event.dist).is_equal("custom-dist") + + +## SentryEvent.environment should be set to the specified value, and empty on event creation. +func test_event_environment() -> void: + var event := SentrySDK.create_event() + assert_str(event.environment).is_empty() + event.environment = "custom-environment" + assert_str(event.environment).is_equal("custom-environment") + + +## SentrySDK.capture_event() should return a non-empty event ID, which must match the ID returned by the get_last_event_id() call. +func test_capture_event() -> void: + var event := SentrySDK.create_event() + var event_id := SentrySDK.capture_event(event) + assert_str(event_id).is_not_empty() + assert_str(event_id).is_equal(event.id) + assert_str(SentrySDK.get_last_event_id()).is_not_empty() + assert_str(event_id).is_equal(SentrySDK.get_last_event_id()) diff --git a/src/register_types.cpp b/src/register_types.cpp index 2cebcb5..6708b3d 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -1,4 +1,7 @@ #include "runtime_config.h" +#include "sentry/disabled_event.h" +#include "sentry/native/native_event.h" +#include "sentry_event.h" #include "sentry_logger.h" #include "sentry_options.h" #include "sentry_sdk.h" @@ -38,6 +41,9 @@ void initialize_module(ModuleInitializationLevel p_level) { GDREGISTER_INTERNAL_CLASS(RuntimeConfig); GDREGISTER_CLASS(SentryUser); GDREGISTER_CLASS(SentrySDK); + GDREGISTER_ABSTRACT_CLASS(SentryEvent); + GDREGISTER_INTERNAL_CLASS(NativeEvent); + GDREGISTER_INTERNAL_CLASS(DisabledEvent); SentrySDK *sentry_singleton = memnew(SentrySDK); Engine::get_singleton()->register_singleton("SentrySDK", SentrySDK::get_singleton()); diff --git a/src/sentry/disabled_event.h b/src/sentry/disabled_event.h new file mode 100644 index 0000000..423f059 --- /dev/null +++ b/src/sentry/disabled_event.h @@ -0,0 +1,49 @@ +#ifndef DISABLED_EVENT_H +#define DISABLED_EVENT_H + +#include "sentry_event.h" + +// Event class that is used when the SDK is disabled. +class DisabledEvent : public SentryEvent { + GDCLASS(DisabledEvent, SentryEvent); + +private: + String message; + String timestamp; + String logger; + sentry::Level level = sentry::Level::LEVEL_INFO; + String release; + String dist; + String environment; + +protected: + static void _bind_methods() {} + +public: + virtual String get_id() const override { return ""; } + + virtual void set_message(const String &p_message) override { message = p_message; } + virtual String get_message() const override { return message; } + + virtual void set_timestamp(const String &p_timestamp) override { timestamp = p_timestamp; } + virtual String get_timestamp() const override { return timestamp; } + + virtual String get_platform() const override { return ""; } + + virtual void set_level(sentry::Level p_level) override { level = p_level; } + virtual sentry::Level get_level() const override { return level; } + + virtual void set_logger(const String &p_logger) override { logger = p_logger; } + virtual String get_logger() const override { return logger; } + + virtual void set_release(const String &p_release) override { release = p_release; } + virtual String get_release() const override { return release; } + + virtual void set_dist(const String &p_dist) override { dist = p_dist; } + virtual String get_dist() const override { return dist; } + + virtual void set_environment(const String &p_environment) override { environment = p_environment; } + virtual String get_environment() const override { return environment; } +}; + +#endif // DISABLED_EVENT_H diff --git a/src/sentry/disabled_sdk.h b/src/sentry/disabled_sdk.h index ced0625..239e8ae 100644 --- a/src/sentry/disabled_sdk.h +++ b/src/sentry/disabled_sdk.h @@ -1,6 +1,7 @@ #ifndef DISABLED_SDK_H #define DISABLED_SDK_H +#include "sentry/disabled_event.h" #include "sentry/internal_sdk.h" namespace sentry { @@ -18,13 +19,14 @@ class DisabledSDK : public InternalSDK { virtual void add_breadcrumb(const String &p_message, const String &p_category, Level p_level, const String &p_type = "default", const Dictionary &p_data = Dictionary()) override {} - // TODO: Consider adding the following function. - // virtual void clear_breadcrumbs() = 0; - virtual String capture_message(const String &p_message, Level p_level, const String &p_logger = "") override { return ""; } + virtual String capture_message(const String &p_message, Level p_level = sentry::LEVEL_INFO, const String &p_logger = "") override { return ""; } virtual String get_last_event_id() override { return ""; } virtual String capture_error(const String &p_type, const String &p_value, Level p_level, const Vector &p_frames) override { return ""; } + virtual Ref create_event() override { return memnew(DisabledEvent); } + virtual String capture_event(const Ref &p_event) override { return ""; } + virtual void initialize() override {} }; diff --git a/src/sentry/internal_sdk.h b/src/sentry/internal_sdk.h index 88e0320..17e0122 100644 --- a/src/sentry/internal_sdk.h +++ b/src/sentry/internal_sdk.h @@ -2,6 +2,7 @@ #define INTERNAL_SDK_H #include "sentry/level.h" +#include "sentry_event.h" #include "sentry_user.h" #include @@ -44,6 +45,9 @@ class InternalSDK { virtual String get_last_event_id() = 0; virtual String capture_error(const String &p_type, const String &p_value, Level p_level, const Vector &p_frames) = 0; + virtual Ref create_event() = 0; + virtual String capture_event(const Ref &p_event) = 0; + virtual void initialize() = 0; virtual ~InternalSDK() = default; }; diff --git a/src/sentry/level.cpp b/src/sentry/level.cpp index fdd28b2..4dec1d1 100644 --- a/src/sentry/level.cpp +++ b/src/sentry/level.cpp @@ -2,7 +2,7 @@ namespace sentry { -CharString level_as_cstring(Level level) { +godot::CharString level_as_cstring(Level level) { switch (level) { case Level::LEVEL_DEBUG: return "debug"; @@ -19,4 +19,8 @@ CharString level_as_cstring(Level level) { } } +godot::PropertyInfo make_level_enum_property(const godot::String &p_name) { + return godot::PropertyInfo(godot::Variant::INT, p_name, godot::PROPERTY_HINT_ENUM, "Debug,Info,Warning,Error,Fatal"); +} + } // namespace sentry diff --git a/src/sentry/level.h b/src/sentry/level.h index ca1bb77..c2aa7ac 100644 --- a/src/sentry/level.h +++ b/src/sentry/level.h @@ -1,12 +1,14 @@ #ifndef SENTRY_LEVEL_H #define SENTRY_LEVEL_H -#include - -using namespace godot; +#include +#include namespace sentry { +// Represents the severity of events or breadcrumbs. +// In the public API, it is exposed as SentrySDK.Level enum. +// And as such, VariantCaster is defined in sentry_sdk.h. enum Level { LEVEL_DEBUG = 0, LEVEL_INFO = 1, @@ -15,7 +17,8 @@ enum Level { LEVEL_FATAL = 4 }; -CharString level_as_cstring(Level level); +godot::CharString level_as_cstring(Level level); +godot::PropertyInfo make_level_enum_property(const godot::String &p_name); } // namespace sentry diff --git a/src/sentry/native/native_event.cpp b/src/sentry/native/native_event.cpp new file mode 100644 index 0000000..45b3628 --- /dev/null +++ b/src/sentry/native/native_event.cpp @@ -0,0 +1,114 @@ +#include "native_event.h" + +#include "sentry/level.h" +#include "sentry/native/native_util.h" + +#include + +namespace { + +inline void _sentry_value_set_or_remove_string_by_key(sentry_value_t value, const char *k, const String &v) { + if (v.is_empty()) { + sentry_value_remove_by_key(value, k); + } else { + sentry_value_set_by_key(value, k, sentry_value_new_string(v.utf8())); + } +} + +} // unnamed namespace + +String NativeEvent::get_id() const { + sentry_value_t id = sentry_value_get_by_key(native_event, "event_id"); + return sentry_value_as_string(id); +} + +void NativeEvent::set_message(const String &p_message) { + if (p_message.is_empty()) { + sentry_value_remove_by_key(native_event, "message"); + } else { + sentry_value_t message = sentry_value_get_by_key(native_event, "message"); + if (sentry_value_is_null(message)) { + message = sentry_value_new_object(); + sentry_value_set_by_key(native_event, "message", message); + } + sentry_value_set_by_key(message, "formatted", sentry_value_new_string(p_message.utf8())); + } +} + +String NativeEvent::get_message() const { + sentry_value_t message = sentry_value_get_by_key(native_event, "message"); + sentry_value_t formatted = sentry_value_get_by_key(message, "formatted"); + return sentry_value_as_string(formatted); +} + +void NativeEvent::set_timestamp(const String &p_timestamp) { + _sentry_value_set_or_remove_string_by_key(native_event, "timestamp", p_timestamp); +} + +String NativeEvent::get_timestamp() const { + sentry_value_t timestamp = sentry_value_get_by_key(native_event, "timestamp"); + return sentry_value_as_string(timestamp); +} + +String NativeEvent::get_platform() const { + sentry_value_t platform = sentry_value_get_by_key(native_event, "platform"); + return sentry_value_as_string(platform); +} + +void NativeEvent::set_level(sentry::Level p_level) { + sentry_value_set_by_key(native_event, "level", + sentry_value_new_string(sentry::native::level_to_cstring(p_level))); +} + +sentry::Level NativeEvent::get_level() const { + sentry_value_t value = sentry_value_get_by_key(native_event, "level"); + return sentry::native::cstring_to_level(sentry_value_as_string(value)); +} + +void NativeEvent::set_logger(const String &p_logger) { + _sentry_value_set_or_remove_string_by_key(native_event, "logger", p_logger); +} + +String NativeEvent::get_logger() const { + sentry_value_t logger = sentry_value_get_by_key(native_event, "logger"); + return sentry_value_as_string(logger); +} + +void NativeEvent::set_release(const String &p_release) { + _sentry_value_set_or_remove_string_by_key(native_event, "release", p_release); +} + +String NativeEvent::get_release() const { + sentry_value_t release = sentry_value_get_by_key(native_event, "release"); + return sentry_value_as_string(release); +} + +void NativeEvent::set_dist(const String &p_dist) { + _sentry_value_set_or_remove_string_by_key(native_event, "dist", p_dist); +} + +String NativeEvent::get_dist() const { + sentry_value_t dist = sentry_value_get_by_key(native_event, "dist"); + return sentry_value_as_string(dist); +} + +void NativeEvent::set_environment(const String &p_environment) { + _sentry_value_set_or_remove_string_by_key(native_event, "environment", p_environment); +} + +String NativeEvent::get_environment() const { + sentry_value_t environment = sentry_value_get_by_key(native_event, "environment"); + return sentry_value_as_string(environment); +} + +NativeEvent::NativeEvent(sentry_value_t p_native_event) { + native_event = p_native_event; +} + +NativeEvent::NativeEvent() : + NativeEvent(sentry_value_new_event()) { +} + +NativeEvent::~NativeEvent() { + sentry_value_decref(native_event); +} diff --git a/src/sentry/native/native_event.h b/src/sentry/native/native_event.h new file mode 100644 index 0000000..a8ad0a6 --- /dev/null +++ b/src/sentry/native/native_event.h @@ -0,0 +1,51 @@ +#ifndef NATIVE_EVENT_H +#define NATIVE_EVENT_H + +#include "sentry_event.h" + +#include + +// Event class that is used with the NativeSDK. +class NativeEvent : public SentryEvent { + GDCLASS(NativeEvent, SentryEvent); + +private: + sentry_value_t native_event; + +protected: + static void _bind_methods() {} + +public: + sentry_value_t get_native_value() const { return native_event; } + + virtual String get_id() const override; + + virtual void set_message(const String &p_message) override; + virtual String get_message() const override; + + virtual void set_timestamp(const String &p_timestamp) override; + virtual String get_timestamp() const override; + + virtual String get_platform() const override; + + virtual void set_level(sentry::Level p_level) override; + virtual sentry::Level get_level() const override; + + virtual void set_logger(const String &p_logger) override; + virtual String get_logger() const override; + + virtual void set_release(const String &p_release) override; + virtual String get_release() const override; + + virtual void set_dist(const String &p_dist) override; + virtual String get_dist() const override; + + virtual void set_environment(const String &p_environment) override; + virtual String get_environment() const override; + + NativeEvent(sentry_value_t p_event); + NativeEvent(); + virtual ~NativeEvent() override; +}; + +#endif // NATIVE_EVENT_H diff --git a/src/sentry/native/native_sdk.cpp b/src/sentry/native/native_sdk.cpp index b71d659..1d916c0 100644 --- a/src/sentry/native/native_sdk.cpp +++ b/src/sentry/native/native_sdk.cpp @@ -1,10 +1,10 @@ #include "native_sdk.h" -#include "godot_cpp/core/error_macros.hpp" #include "sentry.h" #include "sentry/contexts.h" #include "sentry/environment.h" #include "sentry/level.h" +#include "sentry/native/native_event.h" #include "sentry/native/native_util.h" #include "sentry_options.h" @@ -68,23 +68,6 @@ inline String _uuid_as_string(sentry_uuid_t p_uuid) { return str; } -sentry_level_t _level_as_native(sentry::Level p_level) { - switch (p_level) { - case sentry::Level::LEVEL_DEBUG: - return SENTRY_LEVEL_DEBUG; - case sentry::Level::LEVEL_INFO: - return SENTRY_LEVEL_INFO; - case sentry::Level::LEVEL_WARNING: - return SENTRY_LEVEL_WARNING; - case sentry::Level::LEVEL_ERROR: - return SENTRY_LEVEL_ERROR; - case sentry::Level::LEVEL_FATAL: - return SENTRY_LEVEL_FATAL; - default: - ERR_FAIL_V_MSG(SENTRY_LEVEL_ERROR, "SentrySDK: Internal error - unexpected level value. Please open an issue."); - } -} - } // unnamed namespace namespace sentry { @@ -148,7 +131,7 @@ void NativeSDK::add_breadcrumb(const String &p_message, const String &p_category String NativeSDK::capture_message(const String &p_message, Level p_level, const String &p_logger) { sentry_value_t event = sentry_value_new_message_event( - _level_as_native(p_level), + native::level_to_native(p_level), p_logger.utf8().get_data(), p_message.utf8().get_data()); last_uuid = sentry_capture_event(event); @@ -188,6 +171,23 @@ String NativeSDK::capture_error(const String &p_type, const String &p_value, Lev return _uuid_as_string(last_uuid); } +Ref NativeSDK::create_event() { + sentry_value_t event_value = sentry_value_new_event(); + Ref event = memnew(NativeEvent(event_value)); + return event; +} + +String NativeSDK::capture_event(const Ref &p_event) { + last_uuid = sentry_uuid_nil(); + ERR_FAIL_COND_V_MSG(p_event.is_null(), _uuid_as_string(last_uuid), "Sentry: Can't capture event - event object is null."); + NativeEvent *native_event = Object::cast_to(p_event.ptr()); + ERR_FAIL_NULL_V(native_event, _uuid_as_string(last_uuid)); // Sanity check - this should never happen. + sentry_value_t event = native_event->get_native_value(); + sentry_value_incref(event); // Keep ownership. + last_uuid = sentry_capture_event(event); + return _uuid_as_string(last_uuid); +} + void NativeSDK::initialize() { ERR_FAIL_NULL(OS::get_singleton()); ERR_FAIL_NULL(ProjectSettings::get_singleton()); diff --git a/src/sentry/native/native_sdk.h b/src/sentry/native/native_sdk.h index e128bff..28b5334 100644 --- a/src/sentry/native/native_sdk.h +++ b/src/sentry/native/native_sdk.h @@ -25,10 +25,13 @@ class NativeSDK : public InternalSDK { virtual void add_breadcrumb(const String &p_message, const String &p_category, Level p_level, const String &p_type = "default", const Dictionary &p_data = Dictionary()) override; - virtual String capture_message(const String &p_message, Level p_level, const String &p_logger = "") override; + virtual String capture_message(const String &p_message, Level p_level = sentry::LEVEL_INFO, const String &p_logger = "") override; virtual String get_last_event_id() override; virtual String capture_error(const String &p_type, const String &p_value, Level p_level, const Vector &p_frames) override; + virtual Ref create_event() override; + virtual String capture_event(const Ref &p_event) override; + virtual void initialize() override; virtual ~NativeSDK() override; diff --git a/src/sentry/native/native_util.cpp b/src/sentry/native/native_util.cpp index a6966ac..481eb3f 100644 --- a/src/sentry/native/native_util.cpp +++ b/src/sentry/native/native_util.cpp @@ -73,4 +73,71 @@ String make_uuid() { return String(cstr); } +sentry_level_t level_to_native(sentry::Level p_level) { + switch (p_level) { + case sentry::Level::LEVEL_DEBUG: + return SENTRY_LEVEL_DEBUG; + case sentry::Level::LEVEL_INFO: + return SENTRY_LEVEL_INFO; + case sentry::Level::LEVEL_WARNING: + return SENTRY_LEVEL_WARNING; + case sentry::Level::LEVEL_ERROR: + return SENTRY_LEVEL_ERROR; + case sentry::Level::LEVEL_FATAL: + return SENTRY_LEVEL_FATAL; + default: + ERR_FAIL_V_MSG(SENTRY_LEVEL_ERROR, "SentrySDK: Internal error - unexpected level value. Please open an issue."); + } +} + +sentry::Level native_to_level(sentry_level_t p_native_level) { + switch (p_native_level) { + case SENTRY_LEVEL_DEBUG: + return sentry::Level::LEVEL_DEBUG; + case SENTRY_LEVEL_INFO: + return sentry::Level::LEVEL_INFO; + case SENTRY_LEVEL_WARNING: + return sentry::Level::LEVEL_WARNING; + case SENTRY_LEVEL_ERROR: + return sentry::Level::LEVEL_ERROR; + case SENTRY_LEVEL_FATAL: + return sentry::Level::LEVEL_FATAL; + default: + ERR_FAIL_V_MSG(sentry::Level::LEVEL_ERROR, "SentrySDK: Internal error - unexpected level value. Please open an issue."); + } +} + +CharString level_to_cstring(Level level) { + switch (level) { + case Level::LEVEL_DEBUG: + return "debug"; + case Level::LEVEL_INFO: + return "info"; + case Level::LEVEL_WARNING: + return "warning"; + case Level::LEVEL_ERROR: + return "error"; + case Level::LEVEL_FATAL: + return "fatal"; + default: + ERR_FAIL_V_MSG("error", "SentrySDK: Internal error - unexpected level value. Please open an issue."); + } +} + +Level cstring_to_level(const CharString &p_cstring) { + if (strcmp(p_cstring, "debug") == 0) { + return Level::LEVEL_DEBUG; + } else if (strcmp(p_cstring, "info") == 0) { + return Level::LEVEL_INFO; + } else if (strcmp(p_cstring, "warning") == 0) { + return Level::LEVEL_WARNING; + } else if (strcmp(p_cstring, "error") == 0) { + return Level::LEVEL_ERROR; + } else if (strcmp(p_cstring, "fatal") == 0) { + return Level::LEVEL_FATAL; + } else { + ERR_FAIL_V_MSG(Level::LEVEL_ERROR, "SentrySDK: Internal error - unexpected level value. Please open an issue."); + } +} + } // namespace sentry::native diff --git a/src/sentry/native/native_util.h b/src/sentry/native/native_util.h index 98bc4b1..51fac3c 100644 --- a/src/sentry/native/native_util.h +++ b/src/sentry/native/native_util.h @@ -1,7 +1,10 @@ #ifndef NATIVE_UTIL_H #define NATIVE_UTIL_H +#include "sentry/level.h" + #include +#include #include #include @@ -19,6 +22,12 @@ sentry_value_t strings_to_sentry_list(const PackedStringArray &p_strings); // Used by sentry::uuid::make_uuid(). String make_uuid(); +sentry_level_t level_to_native(Level p_level); +Level native_to_level(sentry_level_t p_native_level); + +CharString level_to_cstring(Level p_level); +Level cstring_to_level(const CharString &p_cstring); + } //namespace sentry::native #endif // NATIVE_UTIL_H diff --git a/src/sentry_event.cpp b/src/sentry_event.cpp new file mode 100644 index 0000000..0e5289d --- /dev/null +++ b/src/sentry_event.cpp @@ -0,0 +1,34 @@ +#include "sentry_event.h" + +#include "sentry_sdk.h" // Needed for VariantCaster + +#include + +void SentryEvent::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_id"), &SentryEvent::get_id); + ClassDB::bind_method(D_METHOD("set_message", "message"), &SentryEvent::set_message); + ClassDB::bind_method(D_METHOD("get_message"), &SentryEvent::get_message); + ClassDB::bind_method(D_METHOD("set_timestamp", "timestamp"), &SentryEvent::set_timestamp); + ClassDB::bind_method(D_METHOD("get_timestamp"), &SentryEvent::get_timestamp); + ClassDB::bind_method(D_METHOD("get_platform"), &SentryEvent::get_platform); + ClassDB::bind_method(D_METHOD("set_level", "level"), &SentryEvent::set_level); + ClassDB::bind_method(D_METHOD("get_level"), &SentryEvent::get_level); + ClassDB::bind_method(D_METHOD("set_logger", "logger"), &SentryEvent::set_logger); + ClassDB::bind_method(D_METHOD("get_logger"), &SentryEvent::get_logger); + ClassDB::bind_method(D_METHOD("set_release", "release"), &SentryEvent::set_release); + ClassDB::bind_method(D_METHOD("get_release"), &SentryEvent::get_release); + ClassDB::bind_method(D_METHOD("set_dist", "dist"), &SentryEvent::set_dist); + ClassDB::bind_method(D_METHOD("get_dist"), &SentryEvent::get_dist); + ClassDB::bind_method(D_METHOD("set_environment", "environment"), &SentryEvent::set_environment); + ClassDB::bind_method(D_METHOD("get_environment"), &SentryEvent::get_environment); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "", "get_id"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "message"), "set_message", "get_message"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "timestamp"), "set_timestamp", "get_timestamp"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "platform"), "", "get_platform"); + ADD_PROPERTY(sentry::make_level_enum_property("level"), "set_level", "get_level"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "logger"), "set_logger", "get_logger"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "release"), "set_release", "get_release"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "dist"), "set_dist", "get_dist"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "environment"), "set_environment", "get_environment"); +} diff --git a/src/sentry_event.h b/src/sentry_event.h new file mode 100644 index 0000000..f0492b1 --- /dev/null +++ b/src/sentry_event.h @@ -0,0 +1,47 @@ +#ifndef SENTRY_EVENT_H +#define SENTRY_EVENT_H + +#include "sentry/level.h" + +#include +#include + +using namespace godot; + +// Base class for event objects in the public API. +class SentryEvent : public RefCounted { + GDCLASS(SentryEvent, RefCounted); + +protected: + static void _bind_methods(); + +public: + virtual String get_id() const = 0; + + virtual void set_message(const String &p_message) = 0; + virtual String get_message() const = 0; + + virtual void set_timestamp(const String &p_timestamp) = 0; + virtual String get_timestamp() const = 0; + + virtual String get_platform() const = 0; + + virtual void set_level(sentry::Level p_level) = 0; + virtual sentry::Level get_level() const = 0; + + virtual void set_logger(const String &p_logger) = 0; + virtual String get_logger() const = 0; + + virtual void set_release(const String &p_release) = 0; + virtual String get_release() const = 0; + + virtual void set_dist(const String &p_dist) = 0; + virtual String get_dist() const = 0; + + virtual void set_environment(const String &p_environment) = 0; + virtual String get_environment() const = 0; + + virtual ~SentryEvent() = default; +}; + +#endif // SENTRY_EVENT_H diff --git a/src/sentry_sdk.cpp b/src/sentry_sdk.cpp index f290bfc..cc75062 100644 --- a/src/sentry_sdk.cpp +++ b/src/sentry_sdk.cpp @@ -20,8 +20,6 @@ using namespace sentry; SentrySDK *SentrySDK::singleton = nullptr; -VARIANT_ENUM_CAST(Level); - String SentrySDK::capture_message(const String &p_message, Level p_level, const String &p_logger) { return internal_sdk->capture_message(p_message, p_level, p_logger); } @@ -35,6 +33,15 @@ String SentrySDK::get_last_event_id() const { return internal_sdk->get_last_event_id(); } +Ref SentrySDK::create_event() const { + return internal_sdk->create_event(); +} + +String SentrySDK::capture_event(const Ref &p_event) { + ERR_FAIL_COND_V_MSG(p_event.is_null(), "", "Sentry: Can't capture event - event object is null."); + return internal_sdk->capture_event(p_event); +} + void SentrySDK::set_tag(const String &p_key, const String &p_value) { ERR_FAIL_COND_MSG(p_key.is_empty(), "Sentry: Can't set tag with an empty key."); internal_sdk->set_tag(p_key, p_value); @@ -100,6 +107,8 @@ void SentrySDK::_bind_methods() { ClassDB::bind_method(D_METHOD("set_user", "user"), &SentrySDK::set_user); ClassDB::bind_method(D_METHOD("get_user"), &SentrySDK::get_user); ClassDB::bind_method(D_METHOD("remove_user"), &SentrySDK::remove_user); + ClassDB::bind_method(D_METHOD("create_event"), &SentrySDK::create_event); + ClassDB::bind_method(D_METHOD("capture_event", "event"), &SentrySDK::capture_event); } SentrySDK::SentrySDK() { diff --git a/src/sentry_sdk.h b/src/sentry_sdk.h index b0e7168..b63325a 100644 --- a/src/sentry_sdk.h +++ b/src/sentry_sdk.h @@ -4,6 +4,7 @@ #include "runtime_config.h" #include "sentry/internal_sdk.h" #include "sentry/level.h" +#include "sentry_event.h" #include #include @@ -15,6 +16,12 @@ using namespace godot; class SentrySDK : public Object { GDCLASS(SentrySDK, Object); +public: + // SentrySDK.Level is actually defined in sentry/level.h. + // In Godot API, extensions can't expose global enums - it must belong to a class. + // This structure is needed to avoid circular dependencies between this and other headers that use Level enum. + using Level = sentry::Level; + private: static SentrySDK *singleton; @@ -47,11 +54,16 @@ class SentrySDK : public Object { Ref get_user() const { return runtime_config->get_user(); } void remove_user(); - String capture_message(const String &p_message, sentry::Level p_level, const String &p_logger = ""); + String capture_message(const String &p_message, sentry::Level p_level = sentry::LEVEL_INFO, const String &p_logger = ""); String get_last_event_id() const; + Ref create_event() const; + String capture_event(const Ref &p_event); + SentrySDK(); ~SentrySDK(); }; +VARIANT_ENUM_CAST(SentrySDK::Level); + #endif // SENTRY_SINGLETON_H