Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
5 changes: 5 additions & 0 deletions src/Sentry/IScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ public interface IScopeObserver
/// Sets the user information.
/// </summary>
public void SetUser(SentryUser? user);

/// <summary>
/// Sets the current trace
/// </summary>
public void SetTrace(SentryId traceId, SpanId parentSpanId);
}
2 changes: 1 addition & 1 deletion src/Sentry/Internal/Hub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public TransactionContext ContinueTrace(
string? operation = null)
{
var propagationContext = SentryPropagationContext.CreateFromHeaders(_options.DiagnosticLogger, traceHeader, baggageHeader);
ConfigureScope(scope => scope.PropagationContext = propagationContext);
ConfigureScope(scope => scope.SetPropagationContext(propagationContext));

return new TransactionContext(
name: name ?? string.Empty,
Expand Down
10 changes: 10 additions & 0 deletions src/Sentry/Internal/ScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,14 @@ public void SetUser(SentryUser? user)
public abstract void SetUserImpl(SentryUser user);

public abstract void UnsetUserImpl();

public void SetTrace(SentryId traceId, SpanId parentSpanId)
{
_options.DiagnosticLogger?.Log(
SentryLevel.Debug,"{0} Scope Sync - Setting Trace traceId:{1} parentSpanId:{2}", null,
_name, traceId, parentSpanId);
SetTraceImpl(traceId, parentSpanId);
}

public abstract void SetTraceImpl(SentryId traceId, SpanId parentSpanId);
}
14 changes: 14 additions & 0 deletions src/Sentry/InternalSentrySdk.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Sentry;

/// <summary>
/// Sentry SDK internal API methods meant for being used by the Sentry Unity SDK
/// </summary>
public static class InternalSentrySdk
{
/// <summary>
/// Allows to set the trace
/// </summary>
public static void SetTrace(SentryId traceId, SpanId parentSpanId) =>
SentrySdk.CurrentHub.ConfigureScope(scope =>
scope.SetPropagationContext(new SentryPropagationContext(traceId, parentSpanId)));
}
5 changes: 5 additions & 0 deletions src/Sentry/Platforms/Android/AndroidScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,9 @@ public void SetUser(SentryUser? user)
_innerObserver?.SetUser(user);
}
}

public void SetTrace(SentryId traceId, SpanId parentSpanId)
{
// TODO: This requires sentry-java 8.4.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to follow up later with this once this is added to the Java and Apple SDKs?
If so ideally we create a ticket so folks here can add it later

Copy link
Contributor Author

@bitsandfoxes bitsandfoxes Apr 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking in #4074

}
}
5 changes: 5 additions & 0 deletions src/Sentry/Platforms/Cocoa/CocoaScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,9 @@ public void SetUser(SentryUser? user)
_innerObserver?.SetUser(user);
}
}

public void SetTrace(SentryId traceId, SpanId parentSpanId)
{
// TODO: Missing corresponding functionality on the Cocoa SDK
}
}
3 changes: 3 additions & 0 deletions src/Sentry/Platforms/Native/CFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ internal static string GetCacheDirectory(SentryOptions options)
[DllImport("sentry-native")]
internal static extern void sentry_remove_extra(string key);

[DllImport("sentry-native")]
internal static extern void sentry_set_trace(string traceId, string parentSpanId);

internal static Dictionary<long, DebugImage> LoadDebugImages(IDiagnosticLogger? logger)
{
// It only makes sense to load them once because they're cached on the native side anyway. We could force
Expand Down
3 changes: 3 additions & 0 deletions src/Sentry/Platforms/Native/NativeScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public override void SetUserImpl(SentryUser user)

public override void UnsetUserImpl() => C.sentry_remove_user();

public override void SetTraceImpl(SentryId traceId, SpanId parentSpanId) =>
C.sentry_set_trace(traceId.ToString(), parentSpanId.ToString());

private static string GetTimestamp(DateTimeOffset timestamp) =>
// "o": Using ISO 8601 to make sure the timestamp makes it to the bridge correctly.
// https://docs.microsoft.com/en-gb/dotnet/standard/base-types/standard-date-and-time-format-strings#Roundtrip
Expand Down
11 changes: 10 additions & 1 deletion src/Sentry/Scope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public ITransactionTracer? Transaction
}
}

internal SentryPropagationContext PropagationContext { get; set; }
internal SentryPropagationContext PropagationContext { get; private set; }

internal SessionUpdate? SessionUpdate { get; set; }

Expand Down Expand Up @@ -376,6 +376,15 @@ public void UnsetTag(string key)
/// </summary>
public void AddAttachment(SentryAttachment attachment) => _attachments.Add(attachment);

internal void SetPropagationContext(SentryPropagationContext propagationContext)
{
PropagationContext = propagationContext;
if (Options.EnableScopeSync)
{
Options.ScopeObserver?.SetTrace(propagationContext.TraceId, propagationContext.SpanId);
}
}

/// <summary>
/// Resets all the properties and collections within the scope to their default values.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions test/Sentry.Tests/HubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ public void GetTraceHeader_NoSpanActive_ReturnsHeaderFromPropagationContext()
var propagationContext = new SentryPropagationContext(
SentryId.Parse("75302ac48a024bde9a3b3734a82e36c8"),
SpanId.Parse("2000000000000000"));
hub.ConfigureScope(scope => scope.PropagationContext = propagationContext);
hub.ConfigureScope(scope => scope.SetPropagationContext(propagationContext));

// Act
var header = hub.GetTraceHeader();
Expand Down Expand Up @@ -1052,7 +1052,7 @@ public void GetBaggage_NoSpanActive_ReturnsBaggageFromPropagationContext()
var hub = _fixture.GetSut();
var propagationContext = new SentryPropagationContext(
SentryId.Parse("43365712692146d08ee11a729dfbcaca"), SpanId.Parse("1000000000000000"));
hub.ConfigureScope(scope => scope.PropagationContext = propagationContext);
hub.ConfigureScope(scope => scope.SetPropagationContext(propagationContext));

// Act
var baggage = hub.GetBaggage();
Expand All @@ -1069,7 +1069,7 @@ public void ContinueTrace_SetsPropagationContextAndReturnsTransactionContext()
var hub = _fixture.GetSut();
var propagationContext = new SentryPropagationContext(
SentryId.Parse("43365712692146d08ee11a729dfbcaca"), SpanId.Parse("1000000000000000"));
hub.ConfigureScope(scope => scope.PropagationContext = propagationContext);
hub.ConfigureScope(scope => scope.SetPropagationContext(propagationContext));

var traceHeader = new SentryTraceHeader(SentryId.Parse("5bd5f6d346b442dd9177dce9302fd737"),
SpanId.Parse("2000000000000000"), null);
Expand Down Expand Up @@ -1104,7 +1104,7 @@ public void ContinueTrace_ReceivesHeadersAsStrings_SetsPropagationContextAndRetu
var hub = _fixture.GetSut();
var propagationContext = new SentryPropagationContext(
SentryId.Parse("43365712692146d08ee11a729dfbcaca"), SpanId.Parse("1000000000000000"));
hub.ConfigureScope(scope => scope.PropagationContext = propagationContext);
hub.ConfigureScope(scope => scope.SetPropagationContext(propagationContext));
var traceHeader = "5bd5f6d346b442dd9177dce9302fd737-2000000000000000";
var baggageHeader = "sentry-trace_id=5bd5f6d346b442dd9177dce9302fd737, sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=1.0";

Expand Down
25 changes: 25 additions & 0 deletions test/Sentry.Tests/ScopeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,31 @@ public void SetTag_NullValue_DoesNotThrowArgumentNullException()

Assert.Null(exception);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void SetPropagationContext_ObserverExist_ObserverSetsTraceIfEnabled(bool enableScopeSync)
{
// Arrange
var observer = Substitute.For<IScopeObserver>();
var scope = new Scope(new SentryOptions
{
ScopeObserver = observer,
EnableScopeSync = enableScopeSync
});
var propagationContext = new SentryPropagationContext();
var expectedTraceId = propagationContext.TraceId;
var expectedSpanId = propagationContext.SpanId;
var expectedCount = enableScopeSync ? 1 : 0;

// Act
scope.SetPropagationContext(propagationContext);

// Assert
scope.PropagationContext.Should().Be(propagationContext);
observer.Received(expectedCount).SetTrace(Arg.Is(expectedTraceId), Arg.Is(expectedSpanId));
}
}

public static class ScopeTestExtensions
Expand Down
Loading