Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- The SDK now also syncs breadcrumb data to the native layer so they are available on events coming from the native SDKs ([#2720](https://github.com/getsentry/sentry-unity/pull/2720))
- Removed `Lumin` and `Stadia` platforms from the package's assembly definition to resolve compilation errors. ([#2716](https://github.com/getsentry/sentry-unity/pull/2716))

### Features
Expand Down
16 changes: 14 additions & 2 deletions package-dev/Plugins/iOS/SentryNativeBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ void SentryNativeBridgeSetSdkName()

void SentryNativeBridgeClose() { [SentrySDK close]; }

void SentryNativeBridgeAddBreadcrumb(
const char *timestamp, const char *message, const char *type, const char *category, int level)
void SentryNativeBridgeAddBreadcrumb(const char *timestamp, const char *message, const char *type,
const char *category, int level, const char **dataKeys, const char **dataValues, int dataCount)
{
if (timestamp == NULL && message == NULL && type == NULL && category == NULL) {
return;
Expand Down Expand Up @@ -139,6 +139,18 @@ void SentryNativeBridgeAddBreadcrumb(
breadcrumb.type = typeString;
}

if (dataCount > 0 && dataKeys != NULL && dataValues != NULL) {
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:dataCount];
for (int i = 0; i < dataCount; i++) {
NSString *key = _NSStringOrNil(dataKeys[i]);
NSString *value = _NSStringOrNil(dataValues[i]);
if (key != nil && value != nil) {
data[key] = value;
}
}
breadcrumb.data = data;
}

[scope addBreadcrumb:breadcrumb];
}];
}
Expand Down
4 changes: 2 additions & 2 deletions package-dev/Plugins/iOS/SentryNativeBridgeNoOp.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ void SentryNativeBridgeSetSdkName() { }

void SentryNativeBridgeClose() { }

void SentryNativeBridgeAddBreadcrumb(
const char *timestamp, const char *message, const char *type, const char *category, int level) { }
void SentryNativeBridgeAddBreadcrumb(const char *timestamp, const char *message, const char *type,
const char *category, int level, const char **dataKeys, const char **dataValues, int dataCount) { }

void SentryNativeBridgeSetExtra(const char *key, const char *value) { }

Expand Down
16 changes: 14 additions & 2 deletions package-dev/Plugins/macOS/SentryNativeBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ void SentryNativeBridgeClose()
}
}

void SentryNativeBridgeAddBreadcrumb(
const char *timestamp, const char *message, const char *type, const char *category, int level)
void SentryNativeBridgeAddBreadcrumb(const char *timestamp, const char *message, const char *type,
const char *category, int level, const char **dataKeys, const char **dataValues, int dataCount)
{
if (timestamp == NULL && message == NULL && type == NULL && category == NULL) {
return;
Expand Down Expand Up @@ -244,6 +244,18 @@ void SentryNativeBridgeAddBreadcrumb(

[breadcrumb setValue:[NSNumber numberWithInt:level] forKey:@"level"];

if (dataCount > 0 && dataKeys != NULL && dataValues != NULL) {
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:dataCount];
for (int i = 0; i < dataCount; i++) {
NSString *key = _NSStringOrNil(dataKeys[i]);
NSString *value = _NSStringOrNil(dataValues[i]);
if (key != nil && value != nil) {
data[key] = value;
}
}
[breadcrumb setValue:data forKey:@"data"];
}

[scope performSelector:@selector(addBreadcrumb:) withObject:breadcrumb];
});
}
Expand Down
7 changes: 7 additions & 0 deletions src/Sentry.Unity.Android/SentryJava.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,13 @@ public void AddBreadcrumb(Breadcrumb breadcrumb)
javaBreadcrumb.Set("category", breadcrumb.Category);
using var javaLevel = breadcrumb.Level.ToJavaSentryLevel();
javaBreadcrumb.Set("level", javaLevel);
if (breadcrumb.Data is { Count: > 0 })
{
foreach (var kvp in breadcrumb.Data)
{
javaBreadcrumb.Call("setData", kvp.Key, kvp.Value);
}
}
sentry.CallStatic("addBreadcrumb", javaBreadcrumb, null);
});
}
Expand Down
9 changes: 9 additions & 0 deletions src/Sentry.Unity.Native/NativeScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public override void AddBreadcrumbImpl(Breadcrumb breadcrumb)
C.sentry_value_set_by_key(crumb, "level", C.sentry_value_new_string(breadcrumb.Level.ToString().ToLower()));
C.sentry_value_set_by_key(crumb, "timestamp", C.sentry_value_new_string(GetTimestamp(breadcrumb.Timestamp)));
C.SetValueIfNotNull(crumb, "category", breadcrumb.Category);
if (breadcrumb.Data is { Count: > 0 })
{
var data = C.sentry_value_new_object();
foreach (var kvp in breadcrumb.Data)
{
C.SetValueIfNotNull(data, kvp.Key, kvp.Value);
}
_ = C.sentry_value_set_by_key(crumb, "data", data);
}
C.sentry_add_breadcrumb(crumb);
}

Expand Down
28 changes: 27 additions & 1 deletion src/Sentry.Unity.iOS/NativeScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,33 @@ public override void AddBreadcrumbImpl(Breadcrumb breadcrumb)
var level = GetBreadcrumbLevel(breadcrumb.Level);
var timestamp = GetTimestamp(breadcrumb.Timestamp);

SentryCocoaBridgeProxy.AddBreadcrumb(timestamp, breadcrumb.Message, breadcrumb.Type, breadcrumb.Category, level);
// Pass breadcrumb.Data as two parallel key/value arrays for the __Internal P/Invoke boundary.
var dataCount = GetBreadcrumbData(breadcrumb, out var dataKeys, out var dataValues);

SentryCocoaBridgeProxy.AddBreadcrumb(timestamp, breadcrumb.Message, breadcrumb.Type, breadcrumb.Category, level,
dataKeys, dataValues, dataCount);
}

internal static int GetBreadcrumbData(Breadcrumb breadcrumb, out string[]? keys, out string[]? values)
{
if (breadcrumb.Data is not { Count: > 0 } data)
{
keys = null;
values = null;
return 0;
}

keys = new string[data.Count];
values = new string[data.Count];
var i = 0;
foreach (var kvp in data)
{
keys[i] = kvp.Key;
values[i] = kvp.Value;
i++;
}

return data.Count;
}

public override void SetExtraImpl(string key, string? value) =>
Expand Down
3 changes: 2 additions & 1 deletion src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ public static bool Init(SentryUnityOptions options)
public static extern void Close();

[DllImport("__Internal", EntryPoint = "SentryNativeBridgeAddBreadcrumb")]
public static extern void AddBreadcrumb(string timestamp, string? message, string? type, string? category, int level);
public static extern void AddBreadcrumb(string timestamp, string? message, string? type, string? category, int level,
string[]? dataKeys, string[]? dataValues, int dataCount);
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
bitsandfoxes marked this conversation as resolved.

[DllImport("__Internal", EntryPoint = "SentryNativeBridgeSetExtra")]
public static extern void SetExtra(string key, string? value);
Expand Down
4 changes: 4 additions & 0 deletions test/IntegrationTest/CommonTestCases.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ $CommonTestCases = @(
$SentryEvent.breadcrumbs.values | Should -Not -BeNullOrEmpty
$SentryEvent.breadcrumbs.values | Where-Object { $_.message -eq "Integration test started" } | Should -Not -BeNullOrEmpty
$SentryEvent.breadcrumbs.values | Where-Object { $_.message -eq "Context configuration finished" } | Should -Not -BeNullOrEmpty

$dataCrumb = $SentryEvent.breadcrumbs.values | Where-Object { $_.message -eq "Context configuration finished" }
$dataCrumb | Should -Not -BeNullOrEmpty
$dataCrumb.data.integration_test_key | Should -Be "integration_test_value"
}
}
@{ Name = "Contains SDK information"; TestBlock = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ private void AddIntegrationTestContext(string testType)
};
});

SentrySdk.AddBreadcrumb("Context configuration finished");
SentrySdk.AddBreadcrumb("Context configuration finished", data: new Dictionary<string, string>
{
{ "integration_test_key", "integration_test_value" }
});
}

private IEnumerator MessageCapture()
Expand Down
33 changes: 33 additions & 0 deletions test/Sentry.Unity.iOS.Tests/NativeScopeObserverTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using NUnit.Framework;

Expand Down Expand Up @@ -29,4 +30,36 @@ public void GetBreadcrumbLevel_TestCases(BreadcrumbLevel level, int expectedNati

Assert.AreEqual(actualLevel, expectedNativeLevel);
}

[Test]
public void GetBreadcrumbData_WithData_BuildsParallelArrays()
{
var breadcrumb = new Breadcrumb("message", "type", new Dictionary<string, string>
{
{ "key1", "value1" },
{ "key2", "value2" },
});

var count = NativeScopeObserver.GetBreadcrumbData(breadcrumb, out var keys, out var values);

Assert.AreEqual(2, count);
Assert.IsNotNull(keys);
Assert.IsNotNull(values);
Assert.AreEqual("key1", keys![0]);
Assert.AreEqual("value1", values![0]);
Assert.AreEqual("key2", keys[1]);
Assert.AreEqual("value2", values[1]);
}

[Test]
public void GetBreadcrumbData_WithoutData_ReturnsZeroAndNullArrays()
{
var breadcrumb = new Breadcrumb("message", "type");

var count = NativeScopeObserver.GetBreadcrumbData(breadcrumb, out var keys, out var values);

Assert.AreEqual(0, count);
Assert.IsNull(keys);
Assert.IsNull(values);
}
}
Loading