Skip to content

Commit

Permalink
Wire-up basic apple breadcrumb conversion + migrate bits to Sentry.Ma…
Browse files Browse the repository at this point in the history
…ui project
  • Loading branch information
phunkeler committed Jan 15, 2025
1 parent f7c780e commit c8358f6
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 3 deletions.
174 changes: 172 additions & 2 deletions scripts/generate-cocoa-bindings.ps1
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Reference: https://github.com/xamarin/xamarin-macios/blob/main/docs/website/binding_types_reference_guide.md

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Expand Down Expand Up @@ -172,10 +174,26 @@ internal enum SentryReplayType : long
}
'@

# This enum resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$SentryRRWebEventType = @'
[Native]
internal enum SentryRRWebEventType : long
{
None = 0,
Touch = 3,
Meta = 4,
Custom = 5
}
'@

$Text += "`n$SentryLevel"
$Text += "`n$SentryTransactionNameSource"
$Text += "`n$SentryReplayQuality"
$Text += "`n$SentryReplayType"
$Text += "`n$SentryRRWebEventType"



# Add header and output file
Expand Down Expand Up @@ -262,7 +280,7 @@ $Text = $Text -replace '(DEPRECATED_MSG_ATTRIBUTE\()\n\s*', '$1'
# Remove default IsEqual implementation (already implemented by NSObject)
$Text = $Text -replace '(?ms)\n?^ *// [^\n]*isEqual:.*?$.*?;\n', ''

# Replace obsolete platform avaialbility attributes
# Replace obsolete platform availability attributes
$Text = $Text -replace '([\[,] )MacCatalyst \(', '$1Introduced (PlatformName.MacCatalyst, '
$Text = $Text -replace '([\[,] )Mac \(', '$1Introduced (PlatformName.MacOSX, '
$Text = $Text -replace '([\[,] )iOS \(', '$1Introduced (PlatformName.iOS, '
Expand All @@ -275,7 +293,7 @@ $Text = $Text -replace '(?m)(^\s*\/\/[^\r\n]*$\s*\[Export \("serialize"\)\]$\s*)

$Text = $Text -replace '.*SentryEnvelope .*?[\s\S]*?\n\n', ''
$Text = $Text -replace '.*typedef.*SentryOnAppStartMeasurementAvailable.*?[\s\S]*?\n\n', ''
$Text = $Text -replace '\n.*SentryReplayBreadcrumbConverter.*?[\s\S]*?\);\n', ''
#$Text = $Text -replace '\n.*SentryReplayBreadcrumbConverter.*?[\s\S]*?\);\n', ''

$propertiesToRemove = @(
'SentryAppStartMeasurement',
Expand Down Expand Up @@ -403,6 +421,158 @@ interface SentryReplayOptions //: ISentryRedactOptions

$Text += "`n$SentryReplayOptions"

# This interface resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$SentryRRWebEvent = @'
// @interface SentryRRWebEvent : NSObject <SentryRRWebEvent>
[BaseType (typeof(NSObject), Name = "_TtC6Sentry16SentryRRWebEvent")]
[Protocol]
[Model]
[DisableDefaultCtor]
[Internal]
interface SentryRRWebEvent : SentrySerializable
{
// @property (readonly, nonatomic) enum SentryRRWebEventType type;
[Export ("type")]
SentryRRWebEventType Type { get; }
// @property (readonly, copy, nonatomic) NSDate * _Nonnull timestamp;
[Export ("timestamp", ArgumentSemantic.Copy)]
NSDate Timestamp { get; }
// @property (readonly, copy, nonatomic) NSDictionary<NSString *,id> * _Nullable data;
[NullAllowed, Export ("data", ArgumentSemantic.Copy)]
NSDictionary<NSString, NSObject> Data { get; }
// -(instancetype _Nonnull)initWithType:(enum SentryRRWebEventType)type timestamp:(NSDate * _Nonnull)timestamp data:(NSDictionary<NSString *,id> * _Nullable)data __attribute__((objc_designated_initializer));
[Export ("initWithType:timestamp:data:")]
[DesignatedInitializer]
NativeHandle Constructor (SentryRRWebEventType type, NSDate timestamp, [NullAllowed] NSDictionary<NSString, NSObject> data);
// -(NSDictionary<NSString *,id> * _Nonnull)serialize __attribute__((warn_unused_result("")));
[Export ("serialize")]
new NSDictionary<NSString, NSObject> Serialize();
}
'@

$Text += "`n$SentryRRWebEvent"

# This interface resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$SentryReplayBreadcrumbConverter = @'
// @protocol SentryReplayBreadcrumbConverter <NSObject>
[Protocol (Name = "_TtP6Sentry31SentryReplayBreadcrumbConverter_")]
[BaseType (typeof(NSObject), Name = "_TtP6Sentry31SentryReplayBreadcrumbConverter_")]
[Model]
[Internal]
interface SentryReplayBreadcrumbConverter
{
// @required -(id<SentryRRWebEvent> _Nullable)convertFrom:(SentryBreadcrumb * _Nonnull)breadcrumb __attribute__((warn_unused_result("")));
[Abstract]
[Export ("convertFrom:")]
[return: NullAllowed]
SentryRRWebEvent ConvertFrom (SentryBreadcrumb breadcrumb);
}
'@

$Text += "`n$SentryReplayBreadcrumbConverter"

# This interface resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$SentryViewScreenshotProvider = @'
// @protocol SentryViewScreenshotProvider <NSObject>
[Protocol (Name = "_TtP6Sentry28SentryViewScreenshotProvider_")]
[Model]
[BaseType (typeof(NSObject), Name = "_TtP6Sentry28SentryViewScreenshotProvider_")]
[Internal]
interface SentryViewScreenshotProvider
{
// @required -(void)imageWithView:(UIView * _Nonnull)view onComplete:(void (^ _Nonnull)(UIImage * _Nonnull))onComplete;
[Abstract]
[Export ("imageWithView:onComplete:")]
void OnComplete (UIView view, Action<UIImage> onComplete);
}
'@

$Text += "`n$SentryViewScreenshotProvider"

# This interface resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$defaultReplayBreadcrumbConverter = @'
// @interface SentrySRDefaultBreadcrumbConverter : NSObject <SentryReplayBreadcrumbConverter>
[BaseType (typeof(NSObject), Name = "_TtC6Sentry34SentrySRDefaultBreadcrumbConverter")]
[Internal]
interface SentrySRDefaultBreadcrumbConverter
{
// -(id<SentryRRWebEvent> _Nullable)convertFrom:(SentryBreadcrumb * _Nonnull)breadcrumb __attribute__((warn_unused_result("")));
[Export ("convertFrom:")]
[return: NullAllowed]
SentryRRWebEvent ConvertFrom (SentryBreadcrumb breadcrumb);
}
'@

$Text += "`n$defaultReplayBreadcrumbConverter"

# This interface resides in the Sentry-Swift.h
# Appending it here so we don't need to import and create bindings for the entire header
$sentrySessionReplayIntegration = @'
// @interface SentrySessionReplayIntegration : SentryBaseIntegration
[BaseType (typeof(NSObject))]
[Internal]
interface SentrySessionReplayIntegration
{
// -(instancetype _Nonnull)initForManualUse:(SentryOptions * _Nonnull)options;
[Export ("initForManualUse:")]
NativeHandle Constructor (SentryOptions options);
// -(BOOL)captureReplay;
[Export ("captureReplay")]
bool CaptureReplay();
// -(void)configureReplayWith:(id<SentryReplayBreadcrumbConverter> _Nullable)breadcrumbConverter screenshotProvider:(id<SentryViewScreenshotProvider> _Nullable)screenshotProvider;
[Export ("configureReplayWith:screenshotProvider:")]
void ConfigureReplayWith ([NullAllowed] SentryReplayBreadcrumbConverter breadcrumbConverter, [NullAllowed] SentryViewScreenshotProvider screenshotProvider);
// -(void)pause;
[Export ("pause")]
void Pause ();
// -(void)resume;
[Export ("resume")]
void Resume ();
// -(void)stop;
[Export ("stop")]
void Stop ();
// -(void)start;
[Export ("start")]
void Start ();
// +(id<SentryRRWebEvent> _Nonnull)createBreadcrumbwithTimestamp:(NSDate * _Nonnull)timestamp category:(NSString * _Nonnull)category message:(NSString * _Nullable)message level:(enum SentryLevel)level data:(NSDictionary<NSString *,id> * _Nullable)data;
[Static]
[Export ("createBreadcrumbwithTimestamp:category:message:level:data:")]
SentryRRWebEvent CreateBreadcrumbwithTimestamp (NSDate timestamp, string category, [NullAllowed] string message, SentryLevel level, [NullAllowed] NSDictionary<NSString, NSObject> data);
// +(id<SentryRRWebEvent> _Nonnull)createNetworkBreadcrumbWithTimestamp:(NSDate * _Nonnull)timestamp endTimestamp:(NSDate * _Nonnull)endTimestamp operation:(NSString * _Nonnull)operation description:(NSString * _Nonnull)description data:(NSDictionary<NSString *,id> * _Nonnull)data;
[Static]
[Export ("createNetworkBreadcrumbWithTimestamp:endTimestamp:operation:description:data:")]
SentryRRWebEvent CreateNetworkBreadcrumbWithTimestamp (NSDate timestamp, NSDate endTimestamp, string operation, string description, NSDictionary<NSString, NSObject> data);
// +(id<SentryReplayBreadcrumbConverter> _Nonnull)createDefaultBreadcrumbConverter;
[Static]
[Export ("createDefaultBreadcrumbConverter")]
SentryReplayBreadcrumbConverter CreateDefaultBreadcrumbConverter();
}
'@

$Text += "`n$sentrySessionReplayIntegration"

# Add header and output file
$Text = "$Header`n`n$Text"
$Text | Out-File "$BindingsPath/$File"
1 change: 1 addition & 0 deletions src/Sentry.Bindings.Android/Sentry.Bindings.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<InternalsVisibleTo Include="Sentry.Testing" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Tests" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Extensions.Logging.Tests" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Maui" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Maui.Tests" PublicKey="$(SentryPublicKey)" />
</ItemGroup>

Expand Down
122 changes: 122 additions & 0 deletions src/Sentry.Bindings.Cocoa/ApiDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2424,6 +2424,11 @@ interface PrivateSentrySDKOnly
[Export ("setCurrentScreen:")]
void SetCurrentScreen (string screenName);

// +(void)configureSessionReplayWith:(id<SentryReplayBreadcrumbConverter> _Nullable)breadcrumbConverter screenshotProvider:(id<SentryViewScreenshotProvider> _Nullable)screenshotProvider;
[Static]
[Export ("configureSessionReplayWith:screenshotProvider:")]
void ConfigureSessionReplayWith ([NullAllowed] SentryReplayBreadcrumbConverter breadcrumbConverter, [NullAllowed] SentryViewScreenshotProvider screenshotProvider);

// +(void)captureReplay;
[Static]
[Export ("captureReplay")]
Expand Down Expand Up @@ -2568,3 +2573,120 @@ interface SentryReplayOptions //: ISentryRedactOptions
NativeHandle Constructor (NSDictionary<NSString, NSObject> dictionary);
*/
}

// @interface SentryRRWebEvent : NSObject <SentryRRWebEvent>
[BaseType (typeof(NSObject), Name = "_TtC6Sentry16SentryRRWebEvent")]
[Protocol]
[Model]
[DisableDefaultCtor]
[Internal]
interface SentryRRWebEvent : SentrySerializable
{
// @property (readonly, nonatomic) enum SentryRRWebEventType type;
[Export ("type")]
SentryRRWebEventType Type { get; }

// @property (readonly, copy, nonatomic) NSDate * _Nonnull timestamp;
[Export ("timestamp", ArgumentSemantic.Copy)]
NSDate Timestamp { get; }

// @property (readonly, copy, nonatomic) NSDictionary<NSString *,id> * _Nullable data;
[NullAllowed, Export ("data", ArgumentSemantic.Copy)]
NSDictionary<NSString, NSObject> Data { get; }

// -(instancetype _Nonnull)initWithType:(enum SentryRRWebEventType)type timestamp:(NSDate * _Nonnull)timestamp data:(NSDictionary<NSString *,id> * _Nullable)data __attribute__((objc_designated_initializer));
[Export ("initWithType:timestamp:data:")]
[DesignatedInitializer]
NativeHandle Constructor (SentryRRWebEventType type, NSDate timestamp, [NullAllowed] NSDictionary<NSString, NSObject> data);

// -(NSDictionary<NSString *,id> * _Nonnull)serialize __attribute__((warn_unused_result("")));
[Export ("serialize")]
new NSDictionary<NSString, NSObject> Serialize();
}

// @protocol SentryReplayBreadcrumbConverter <NSObject>
[Protocol (Name = "_TtP6Sentry31SentryReplayBreadcrumbConverter_")]
[BaseType (typeof(NSObject), Name = "_TtP6Sentry31SentryReplayBreadcrumbConverter_")]
[Model]
[Internal]
interface SentryReplayBreadcrumbConverter
{
// @required -(id<SentryRRWebEvent> _Nullable)convertFrom:(SentryBreadcrumb * _Nonnull)breadcrumb __attribute__((warn_unused_result("")));
[Abstract]
[Export ("convertFrom:")]
[return: NullAllowed]
SentryRRWebEvent ConvertFrom (SentryBreadcrumb breadcrumb);
}

// @protocol SentryViewScreenshotProvider <NSObject>
[Protocol (Name = "_TtP6Sentry28SentryViewScreenshotProvider_")]
[Model]
[BaseType (typeof(NSObject), Name = "_TtP6Sentry28SentryViewScreenshotProvider_")]
[Internal]
interface SentryViewScreenshotProvider
{
// @required -(void)imageWithView:(UIView * _Nonnull)view onComplete:(void (^ _Nonnull)(UIImage * _Nonnull))onComplete;
[Abstract]
[Export ("imageWithView:onComplete:")]
void OnComplete (UIView view, Action<UIImage> onComplete);
}

// @interface SentrySRDefaultBreadcrumbConverter : NSObject <SentryReplayBreadcrumbConverter>
[BaseType (typeof(NSObject), Name = "_TtC6Sentry34SentrySRDefaultBreadcrumbConverter")]
[Internal]
interface SentrySRDefaultBreadcrumbConverter
{
// -(id<SentryRRWebEvent> _Nullable)convertFrom:(SentryBreadcrumb * _Nonnull)breadcrumb __attribute__((warn_unused_result("")));
[Export ("convertFrom:")]
[return: NullAllowed]
SentryRRWebEvent ConvertFrom (SentryBreadcrumb breadcrumb);
}

// @interface SentrySessionReplayIntegration : SentryBaseIntegration
[BaseType (typeof(NSObject))]
[Internal]
interface SentrySessionReplayIntegration
{
// -(instancetype _Nonnull)initForManualUse:(SentryOptions * _Nonnull)options;
[Export ("initForManualUse:")]
NativeHandle Constructor (SentryOptions options);

// -(BOOL)captureReplay;
[Export ("captureReplay")]
bool CaptureReplay();

// -(void)configureReplayWith:(id<SentryReplayBreadcrumbConverter> _Nullable)breadcrumbConverter screenshotProvider:(id<SentryViewScreenshotProvider> _Nullable)screenshotProvider;
[Export ("configureReplayWith:screenshotProvider:")]
void ConfigureReplayWith ([NullAllowed] SentryReplayBreadcrumbConverter breadcrumbConverter, [NullAllowed] SentryViewScreenshotProvider screenshotProvider);

// -(void)pause;
[Export ("pause")]
void Pause ();

// -(void)resume;
[Export ("resume")]
void Resume ();

// -(void)stop;
[Export ("stop")]
void Stop ();

// -(void)start;
[Export ("start")]
void Start ();

// +(id<SentryRRWebEvent> _Nonnull)createBreadcrumbwithTimestamp:(NSDate * _Nonnull)timestamp category:(NSString * _Nonnull)category message:(NSString * _Nullable)message level:(enum SentryLevel)level data:(NSDictionary<NSString *,id> * _Nullable)data;
[Static]
[Export ("createBreadcrumbwithTimestamp:category:message:level:data:")]
SentryRRWebEvent CreateBreadcrumbwithTimestamp (NSDate timestamp, string category, [NullAllowed] string message, SentryLevel level, [NullAllowed] NSDictionary<NSString, NSObject> data);

// +(id<SentryRRWebEvent> _Nonnull)createNetworkBreadcrumbWithTimestamp:(NSDate * _Nonnull)timestamp endTimestamp:(NSDate * _Nonnull)endTimestamp operation:(NSString * _Nonnull)operation description:(NSString * _Nonnull)description data:(NSDictionary<NSString *,id> * _Nonnull)data;
[Static]
[Export ("createNetworkBreadcrumbWithTimestamp:endTimestamp:operation:description:data:")]
SentryRRWebEvent CreateNetworkBreadcrumbWithTimestamp (NSDate timestamp, NSDate endTimestamp, string operation, string description, NSDictionary<NSString, NSObject> data);

// +(id<SentryReplayBreadcrumbConverter> _Nonnull)createDefaultBreadcrumbConverter;
[Static]
[Export ("createDefaultBreadcrumbConverter")]
SentryReplayBreadcrumbConverter CreateDefaultBreadcrumbConverter();
}
1 change: 1 addition & 0 deletions src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<InternalsVisibleTo Include="Sentry.Testing" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Tests" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Extensions.Logging.Tests" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Maui" PublicKey="$(SentryPublicKey)" />
<InternalsVisibleTo Include="Sentry.Maui.Tests" PublicKey="$(SentryPublicKey)" />
</ItemGroup>

Expand Down
9 changes: 9 additions & 0 deletions src/Sentry.Bindings.Cocoa/StructsAndEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,12 @@ internal enum SentryReplayType : long
Session = 0,
Buffer = 1
}

[Native]
internal enum SentryRRWebEventType : long
{
None = 0,
Touch = 3,
Meta = 4,
Custom = 5
}
25 changes: 25 additions & 0 deletions src/Sentry.Maui/Internal/ReplayBreadcrumbConverter.macios.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Sentry;

internal class ReplayBreadcrumbConverter : Sentry.CocoaSdk.SentryReplayBreadcrumbConverter
{
public override Sentry.CocoaSdk.SentryRRWebEvent? ConvertFrom(Sentry.CocoaSdk.SentryBreadcrumb breadcrumb)
{
if (breadcrumb.Timestamp is null)
{
return null;
}

if (string.Equals(breadcrumb.Category, "touch", StringComparison.OrdinalIgnoreCase))
{
return Sentry.CocoaSdk.SentrySessionReplayIntegration.CreateBreadcrumbwithTimestamp(
breadcrumb.Timestamp,
breadcrumb.Category,
breadcrumb.Message,
breadcrumb.Level,
breadcrumb.Data
);
}

return null;
}
}
Loading

0 comments on commit c8358f6

Please sign in to comment.