Skip to content

Commit 3ef1422

Browse files
Associate replays with errors and traces on Android
Part of #2136 Associate Errors and Traces with the active Session Replay (if one exists) on Android.
1 parent e72ca08 commit 3ef1422

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/Sentry/Platforms/Android/AndroidEventProcessor.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Java.Lang;
2+
using Kotlin;
13
using Sentry.Android.Extensions;
24
using Sentry.Extensibility;
35
using Sentry.JavaSdk.Android.Core;
@@ -33,6 +35,14 @@ public SentryEvent Process(SentryEvent @event)
3335
// Copy more information from the Android SDK
3436
if (_androidProcessor is { } androidProcessor)
3537
{
38+
// TODO: We should really do this when creating the DSC, so that it gets propagated correctly
39+
// Check to see if a Replay ID is available
40+
var activeReplayId = Sentry.JavaSdk.ScopesAdapter.Instance?.Options?.ReplayController?.ReplayId?.ToSentryId();
41+
if (activeReplayId is {} replayId && replayId != SentryId.Empty)
42+
{
43+
@event.Contexts.Replay.ReplayId = replayId;
44+
}
45+
3646
// TODO: Can we gather more data directly and remove this?
3747

3848
// Run a fake event through the Android processor, so we can get context info from the Android SDK.

src/Sentry/Protocol/Replay.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using Sentry.Extensibility;
2+
using Sentry.Internal;
3+
using Sentry.Internal.Extensions;
4+
5+
namespace Sentry.Protocol;
6+
7+
/// <summary>
8+
/// Sentry Replay context interface.
9+
/// </summary>
10+
/// <example>
11+
/// {
12+
/// "contexts": {
13+
/// "replay": {
14+
/// "replay_id": "12312012123120121231201212312012"
15+
/// }
16+
/// }
17+
/// }
18+
/// </example>
19+
/// <see href="https://develop.sentry.dev/sdk/data-model/event-payloads/contexts/#replay-context"/>
20+
public sealed class Replay : ISentryJsonSerializable, ICloneable<Replay>, IUpdatable<Replay>
21+
{
22+
/// <summary>
23+
/// Tells Sentry which type of context this is.
24+
/// </summary>
25+
public const string Type = "replay";
26+
27+
/// <summary>
28+
/// The name of the runtime.
29+
/// </summary>
30+
public SentryId? ReplayId { get; set; }
31+
32+
/// <summary>
33+
/// Clones this instance.
34+
/// </summary>
35+
public Replay Clone()
36+
{
37+
var response = new Replay();
38+
39+
response.UpdateFrom(this);
40+
41+
return response;
42+
}
43+
44+
/// <summary>
45+
/// Updates this instance with data from the properties in the <paramref name="source"/>,
46+
/// unless there is already a value in the existing property.
47+
/// </summary>
48+
public void UpdateFrom(Replay source)
49+
{
50+
ReplayId ??= source.ReplayId;
51+
}
52+
53+
/// <summary>
54+
/// Updates this instance with data from the properties in the <paramref name="source"/>,
55+
/// unless there is already a value in the existing property.
56+
/// </summary>
57+
public void UpdateFrom(object source)
58+
{
59+
if (source is Replay response)
60+
{
61+
UpdateFrom(response);
62+
}
63+
}
64+
65+
/// <inheritdoc />
66+
public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger)
67+
{
68+
writer.WriteStartObject();
69+
70+
writer.WriteString("type", Type);
71+
writer.WriteSerializableIfNotNull("replay_id", ReplayId, logger);
72+
73+
writer.WriteEndObject();
74+
}
75+
76+
/// <summary>
77+
/// Parses from JSON.
78+
/// </summary>
79+
public static Replay FromJson(JsonElement json)
80+
{
81+
var replayId = json.GetPropertyOrNull("replay_id")?.Pipe(SentryId.FromJson);
82+
83+
return new Replay
84+
{
85+
ReplayId = replayId
86+
};
87+
}
88+
}

src/Sentry/SentryContexts.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public SentryFeedback? Feedback
5555
/// </remarks>
5656
public OperatingSystem OperatingSystem => _innerDictionary.GetOrCreate<OperatingSystem>(OperatingSystem.Type);
5757

58+
/// <summary>
59+
/// Replay interface that contains information about the Session Replay (if any) related to the event.
60+
/// </summary>
61+
public Replay Replay => _innerDictionary.GetOrCreate<Replay>(Replay.Type);
62+
5863
/// <summary>
5964
/// Response interface that contains information on any HTTP response related to the event.
6065
/// </summary>
@@ -172,6 +177,10 @@ public static SentryContexts FromJson(JsonElement json)
172177
{
173178
result[name] = OperatingSystem.FromJson(value);
174179
}
180+
else if (string.Equals(type, Replay.Type, StringComparison.OrdinalIgnoreCase))
181+
{
182+
result[name] = Replay.FromJson(value);
183+
}
175184
else if (string.Equals(type, Response.Type, StringComparison.OrdinalIgnoreCase))
176185
{
177186
result[name] = Response.FromJson(value);

0 commit comments

Comments
 (0)