Skip to content

Commit 3c3182d

Browse files
Merged IHasMeasurements into ISpanData (#2659)
1 parent 0aed969 commit 3c3182d

9 files changed

+117
-86
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ without native/platform specific bindings and SDKs. See [this ticket for more de
1515
- Drop .NET 6 Mobile in favor of .NET 7 ([#2624](https://github.com/getsentry/sentry-dotnet/pull/2604))
1616

1717
API Changes:
18+
19+
- IHasMeasurements was removed. Use ISpanData instead. ([#2659](https://github.com/getsentry/sentry-dotnet/pull/2659))
1820
- If `null` has been supplied as DSN when initializing Sentry, and ArgumentNullException is now thrown ([#2655](https://github.com/getsentry/sentry-dotnet/pull/2655))
1921
- IHasBreadcrumbs was removed. Use IEventLike instead. ([#2670](https://github.com/getsentry/sentry-dotnet/pull/2670))
2022
- ISpanContext was removed. Use ITraceContext instead. ([#2668](https://github.com/getsentry/sentry-dotnet/pull/2668))

src/Sentry/IHasMeasurements.cs

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/Sentry/ISpanData.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,53 @@ public interface ISpanData : ITraceContext, IHasTags, IHasExtra
2626
/// Get Sentry trace header.
2727
/// </summary>
2828
SentryTraceHeader GetTraceHeader();
29+
30+
/// <summary>
31+
/// The measurements that have been set on the transaction.
32+
/// </summary>
33+
IReadOnlyDictionary<string, Measurement> Measurements { get; }
34+
35+
/// <summary>
36+
/// Sets a measurement on the transaction.
37+
/// </summary>
38+
/// <param name="name">The name of the measurement.</param>
39+
/// <param name="measurement">The measurement.</param>
40+
void SetMeasurement(string name, Measurement measurement);
41+
}
42+
43+
/// <summary>
44+
/// Extensions for <see cref="ISpanData"/>
45+
/// </summary>
46+
[EditorBrowsable(EditorBrowsableState.Never)]
47+
public static class SpanDataExtensions
48+
{
49+
/// <summary>
50+
/// Sets a measurement on the transaction.
51+
/// </summary>
52+
/// <param name="spanData">The transaction.</param>
53+
/// <param name="name">The name of the measurement.</param>
54+
/// <param name="value">The value of the measurement.</param>
55+
/// <param name="unit">The optional unit of the measurement.</param>
56+
public static void SetMeasurement(this ISpanData spanData, string name, int value,
57+
MeasurementUnit unit = default) =>
58+
spanData.SetMeasurement(name, new Measurement(value, unit));
59+
60+
/// <inheritdoc cref="SetMeasurement(Sentry.ISpanData,string,int,Sentry.MeasurementUnit)" />
61+
public static void SetMeasurement(this ISpanData spanData, string name, long value,
62+
MeasurementUnit unit = default) =>
63+
spanData.SetMeasurement(name, new Measurement(value, unit));
64+
65+
/// <inheritdoc cref="SetMeasurement(Sentry.ISpanData,string,int,Sentry.MeasurementUnit)" />
66+
#if !__MOBILE__
67+
// ulong parameter is not CLS compliant
68+
[CLSCompliant(false)]
69+
#endif
70+
public static void SetMeasurement(this ISpanData spanData, string name, ulong value,
71+
MeasurementUnit unit = default) =>
72+
spanData.SetMeasurement(name, new Measurement(value, unit));
73+
74+
/// <inheritdoc cref="SetMeasurement(Sentry.ISpanData,string,int,Sentry.MeasurementUnit)" />
75+
public static void SetMeasurement(this ISpanData spanData, string name, double value,
76+
MeasurementUnit unit = default) =>
77+
spanData.SetMeasurement(name, new Measurement(value, unit));
2978
}

src/Sentry/Internal/NoOpSpan.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Sentry.Protocol;
2+
13
namespace Sentry.Internal;
24

35
/// <summary>
@@ -70,4 +72,10 @@ public void SetExtra(string key, object? value)
7072
}
7173

7274
public SentryTraceHeader GetTraceHeader() => SentryTraceHeader.Empty;
75+
76+
public IReadOnlyDictionary<string, Measurement> Measurements => ImmutableDictionary<string, Measurement>.Empty;
77+
78+
public void SetMeasurement(string name, Measurement measurement)
79+
{
80+
}
7381
}

src/Sentry/Internal/NoOpTransaction.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Sentry.Protocol;
2+
13
namespace Sentry.Internal;
24

35
/// <summary>
@@ -86,8 +88,10 @@ public IReadOnlyList<string> Fingerprint
8688
}
8789

8890
public IReadOnlyCollection<ISpan> Spans => ImmutableList<ISpan>.Empty;
91+
8992
public IReadOnlyCollection<Breadcrumb> Breadcrumbs => ImmutableList<Breadcrumb>.Empty;
9093

9194
public ISpan? GetLastActiveSpan() => default;
95+
9296
public void AddBreadcrumb(Breadcrumb breadcrumb) { }
9397
}

src/Sentry/Span.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Sentry.Extensibility;
22
using Sentry.Internal;
33
using Sentry.Internal.Extensions;
4+
using Sentry.Protocol;
45

56
namespace Sentry;
67

@@ -28,6 +29,16 @@ public class Span : ISpanData, IJsonSerializable
2829
/// <inheritdoc />
2930
public bool IsFinished => EndTimestamp is not null;
3031

32+
// Not readonly because of deserialization
33+
private Dictionary<string, Measurement>? _measurements;
34+
35+
/// <inheritdoc />
36+
public IReadOnlyDictionary<string, Measurement> Measurements => _measurements ??= new Dictionary<string, Measurement>();
37+
38+
/// <inheritdoc />
39+
public void SetMeasurement(string name, Measurement measurement) =>
40+
(_measurements ??= new Dictionary<string, Measurement>())[name] = measurement;
41+
3142
/// <inheritdoc />
3243
public string Operation { get; set; }
3344

@@ -88,7 +99,17 @@ public Span(ISpan tracer)
8899
Status = tracer.Status;
89100
IsSampled = tracer.IsSampled;
90101
_extra = tracer.Extra.ToDictionary();
91-
_tags = tracer is SpanTracer s ? s.InternalTags?.ToDictionary() : tracer.Tags.ToDictionary();
102+
103+
if (tracer is SpanTracer spanTracer)
104+
{
105+
_measurements = spanTracer.InternalMeasurements?.ToDictionary();
106+
_tags = spanTracer.InternalTags?.ToDictionary();
107+
}
108+
else
109+
{
110+
_measurements = tracer.Measurements.ToDictionary();
111+
_tags = tracer.Tags.ToDictionary();
112+
}
92113
}
93114

94115
/// <inheritdoc />
@@ -112,6 +133,7 @@ public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger)
112133
writer.WriteStringIfNotNull("timestamp", EndTimestamp);
113134
writer.WriteStringDictionaryIfNotEmpty("tags", _tags!);
114135
writer.WriteDictionaryIfNotEmpty("data", _extra!, logger);
136+
writer.WriteDictionaryIfNotEmpty("measurements", _measurements, logger);
115137

116138
writer.WriteEndObject();
117139
}
@@ -131,6 +153,7 @@ public static Span FromJson(JsonElement json)
131153
var status = json.GetPropertyOrNull("status")?.GetString()?.Replace("_", "").ParseEnum<SpanStatus>();
132154
var isSampled = json.GetPropertyOrNull("sampled")?.GetBoolean();
133155
var tags = json.GetPropertyOrNull("tags")?.GetStringDictionaryOrNull()?.ToDictionary();
156+
var measurements = json.GetPropertyOrNull("measurements")?.GetDictionaryOrNull(Measurement.FromJson);
134157
var data = json.GetPropertyOrNull("data")?.GetDictionaryOrNull()?.ToDictionary();
135158

136159
return new Span(parentSpanId, operation)
@@ -143,7 +166,8 @@ public static Span FromJson(JsonElement json)
143166
Status = status,
144167
IsSampled = isSampled,
145168
_tags = tags!,
146-
_extra = data!
169+
_extra = data!,
170+
_measurements = measurements,
147171
};
148172
}
149173

src/Sentry/SpanTracer.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Sentry.Internal;
2+
using Sentry.Protocol;
23

34
namespace Sentry;
45

@@ -30,6 +31,16 @@ public class SpanTracer : ISpan
3031
/// <inheritdoc />
3132
public bool IsFinished => EndTimestamp is not null;
3233

34+
// Not readonly because of deserialization
35+
internal Dictionary<string, Measurement>? InternalMeasurements { get; private set; }
36+
37+
/// <inheritdoc />
38+
public IReadOnlyDictionary<string, Measurement> Measurements => InternalMeasurements ??= new Dictionary<string, Measurement>();
39+
40+
/// <inheritdoc />
41+
public void SetMeasurement(string name, Measurement measurement) =>
42+
(InternalMeasurements ??= new Dictionary<string, Measurement>())[name] = measurement;
43+
3344
/// <inheritdoc cref="ISpan.Operation" />
3445
public string Operation { get; set; }
3546

@@ -50,20 +61,18 @@ public class SpanTracer : ISpan
5061
/// <inheritdoc />
5162
public bool? IsSampled { get; internal set; }
5263

53-
private ConcurrentDictionary<string, string>? _tags;
54-
55-
internal ConcurrentDictionary<string, string>? InternalTags => _tags;
64+
internal ConcurrentDictionary<string, string>? InternalTags { get; private set; }
5665

5766
/// <inheritdoc />
58-
public IReadOnlyDictionary<string, string> Tags => _tags ??= new ConcurrentDictionary<string, string>();
67+
public IReadOnlyDictionary<string, string> Tags => InternalTags ??= new ConcurrentDictionary<string, string>();
5968

6069
/// <inheritdoc />
6170
public void SetTag(string key, string value) =>
62-
(_tags ??= new ConcurrentDictionary<string, string>())[key] = value;
71+
(InternalTags ??= new ConcurrentDictionary<string, string>())[key] = value;
6372

6473
/// <inheritdoc />
6574
public void UnsetTag(string key) =>
66-
(_tags ??= new ConcurrentDictionary<string, string>()).TryRemove(key, out _);
75+
(InternalTags ??= new ConcurrentDictionary<string, string>()).TryRemove(key, out _);
6776

6877
private readonly ConcurrentDictionary<string, object?> _data = new();
6978

src/Sentry/Transaction.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Sentry;
99
/// <summary>
1010
/// Sentry performance transaction.
1111
/// </summary>
12-
public class Transaction : ITransactionData, IJsonSerializable, IHasMeasurements
12+
public class Transaction : ITransactionData, IJsonSerializable
1313
{
1414
/// <summary>
1515
/// Transaction's event ID.
@@ -68,6 +68,16 @@ public SentryId TraceId
6868
/// <inheritdoc />
6969
public DateTimeOffset? EndTimestamp { get; internal set; } // internal for testing
7070

71+
// Not readonly because of deserialization
72+
private Dictionary<string, Measurement>? _measurements;
73+
74+
/// <inheritdoc />
75+
public IReadOnlyDictionary<string, Measurement> Measurements => _measurements ??= new Dictionary<string, Measurement>();
76+
77+
/// <inheritdoc />
78+
public void SetMeasurement(string name, Measurement measurement) =>
79+
(_measurements ??= new Dictionary<string, Measurement>())[name] = measurement;
80+
7181
/// <inheritdoc />
7282
public string Operation
7383
{
@@ -181,12 +191,6 @@ public IReadOnlyList<string> Fingerprint
181191
/// </summary>
182192
public IReadOnlyCollection<Span> Spans => _spans;
183193

184-
// Not readonly because of deserialization
185-
private Dictionary<string, Measurement> _measurements = new();
186-
187-
/// <inheritdoc />
188-
public IReadOnlyDictionary<string, Measurement> Measurements => _measurements;
189-
190194
/// <inheritdoc />
191195
public bool IsFinished => EndTimestamp is not null;
192196

@@ -262,14 +266,14 @@ public Transaction(ITransaction tracer)
262266
_spans = tracer.Spans
263267
.Where(s => s is not SpanTracer { IsSentryRequest: true }) // Filter sentry requests created by Sentry.OpenTelemetry.SentrySpanProcessor
264268
.Select(s => new Span(s)).ToArray();
269+
_measurements = tracer.Measurements.ToDictionary();
265270

266271
// Some items are not on the interface, but we only ever pass in a TransactionTracer anyway.
267272
if (tracer is TransactionTracer transactionTracer)
268273
{
269274
SampleRate = transactionTracer.SampleRate;
270275
DynamicSamplingContext = transactionTracer.DynamicSamplingContext;
271276
TransactionProfiler = transactionTracer.TransactionProfiler;
272-
_measurements = transactionTracer.Measurements.ToDictionary();
273277
}
274278
}
275279

@@ -289,11 +293,6 @@ public void SetTag(string key, string value) =>
289293
public void UnsetTag(string key) =>
290294
_tags.Remove(key);
291295

292-
/// <inheritdoc />
293-
[EditorBrowsable(EditorBrowsableState.Never)]
294-
public void SetMeasurement(string name, Measurement measurement) =>
295-
_measurements[name] = measurement;
296-
297296
/// <inheritdoc />
298297
public SentryTraceHeader GetTraceHeader() => new(
299298
TraceId,

src/Sentry/TransactionTracer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Sentry;
77
/// <summary>
88
/// Transaction tracer.
99
/// </summary>
10-
public class TransactionTracer : ITransaction, IHasMeasurements
10+
public class TransactionTracer : ITransaction
1111
{
1212
private readonly IHub _hub;
1313
private readonly SentryOptions? _options;
@@ -277,7 +277,6 @@ internal TransactionTracer(IHub hub, ITransactionContext context, TimeSpan? idle
277277
public void UnsetTag(string key) => _tags.TryRemove(key, out _);
278278

279279
/// <inheritdoc />
280-
[EditorBrowsable(EditorBrowsableState.Never)]
281280
public void SetMeasurement(string name, Measurement measurement) => _measurements[name] = measurement;
282281

283282
/// <inheritdoc />

0 commit comments

Comments
 (0)