Skip to content

Commit f22c2d4

Browse files
authored
revert: Tracing for SentryHttpMessageHandler with no active transaction (#3367)
1 parent acbbdd3 commit f22c2d4

11 files changed

+90
-128
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- Reverted changes to the SentryHttpMessageHandler and SentryGraphQLHttpMessageHandler to automatically create transactions for each request as this could negatively affect users' quota ([#3367](https://github.com/getsentry/sentry-dotnet/pull/3367))
8+
39
## 4.6.1
410

511
### Fixes

src/Sentry/HubExtensions.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,4 @@ internal static ITransactionTracer StartTransaction(
244244
var transaction = hub.GetTransaction();
245245
return transaction?.IsSampled == true ? transaction : null;
246246
}
247-
248-
internal static ISpan StartSpan(this IHub hub, string operation, string description)
249-
{
250-
ITransactionTracer? currentTransaction = null;
251-
hub.ConfigureScope(s => currentTransaction = s.Transaction);
252-
return currentTransaction is { } transaction
253-
? transaction.StartChild(operation, description)
254-
: hub.StartTransaction(description, operation, description);
255-
}
256247
}
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using Sentry.Protocol.Metrics;
22

3-
namespace Sentry.Internal;
3+
namespace Sentry;
44

5-
/// <summary>
6-
/// Specifies various internal methods required on the Hub for metrics to work.
7-
/// </summary>
8-
internal interface IMetricHub : IHub
5+
internal interface IMetricHub
96
{
107
/// <summary>
118
/// Captures one or more metrics to be sent to Sentry.
@@ -16,4 +13,12 @@ internal interface IMetricHub : IHub
1613
/// Captures one or more <see cref="CodeLocations"/> to be sent to Sentry.
1714
/// </summary>
1815
void CaptureCodeLocations(CodeLocations codeLocations);
16+
17+
/// <summary>
18+
/// Starts a child span for the current transaction or, if there is no active transaction, starts a new transaction.
19+
/// </summary>
20+
ISpan StartSpan(string operation, string description);
21+
22+
/// <inheritdoc cref="IHub.GetSpan"/>
23+
ISpan? GetSpan();
1924
}

src/Sentry/Internal/Hub.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,16 @@ public void CaptureCodeLocations(CodeLocations codeLocations)
530530
}
531531
}
532532

533+
/// <inheritdoc cref="IMetricHub.StartSpan"/>
534+
public ISpan StartSpan(string operation, string description)
535+
{
536+
ITransactionTracer? currentTransaction = null;
537+
ConfigureScope(s => currentTransaction = s.Transaction);
538+
return currentTransaction is { } transaction
539+
? transaction.StartChild(operation, description)
540+
: this.StartTransaction(operation, description);
541+
}
542+
533543
public void CaptureSession(SessionUpdate sessionUpdate)
534544
{
535545
if (!IsEnabled)

src/Sentry/SentryGraphQLHttpMessageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal SentryGraphQLHttpMessageHandler(IHub? hub, SentryOptions? options,
5050

5151
// Start a span that tracks this request
5252
// (may be null if transaction is not set on the scope)
53-
var span = _hub.StartSpan(
53+
var span = _hub.GetSpan()?.StartChild(
5454
"http.client",
5555
$"{method} {url}" // e.g. "GET https://example.com"
5656
);

src/Sentry/SentryHttpMessageHandler.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Sentry.Extensibility;
2-
using Sentry.Internal;
32
using Sentry.Internal.OpenTelemetry;
43

54
namespace Sentry;
@@ -64,7 +63,7 @@ internal SentryHttpMessageHandler(IHub? hub, SentryOptions? options, HttpMessage
6463
{
6564
// Start a span that tracks this request
6665
// (may be null if transaction is not set on the scope)
67-
var span = _hub.StartSpan(
66+
var span = _hub.GetSpan()?.StartChild(
6867
"http.client",
6968
$"{method} {url}" // e.g. "GET https://example.com"
7069
);

src/Sentry/Timing.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Sentry.Extensibility;
2-
using Sentry.Internal;
32
using Sentry.Protocol.Metrics;
43

54
namespace Sentry;

test/Sentry.Tests/SentryGraphQlHttpMessageHandlerTests.cs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Sentry.Tests;
77
* TODO: Find a way to consolidate these tests cleanly.
88
*/
99

10-
public class SentryGraphQlHttpMessageHandlerTests : SentryMessageHandlerTests
10+
public class SentryGraphQlHttpMessageHandlerTests
1111
{
1212
private const string ValidQuery = "query getAllNotes { notes { id } }";
1313
private const string ValidResponse = @"{
@@ -47,7 +47,13 @@ public void ProcessRequest_ExtractsGraphQlRequestContent()
4747
public void ProcessRequest_SetsSpanData()
4848
{
4949
// Arrange
50-
var hub = _fixture.GetHub();
50+
var hub = Substitute.For<IHub>();
51+
var parentSpan = Substitute.For<ISpan>();
52+
hub.GetSpan().Returns(parentSpan);
53+
var childSpan = Substitute.For<ISpan>();
54+
parentSpan.When(p => p.StartChild(Arg.Any<string>()))
55+
.Do(op => childSpan.Operation = op.Arg<string>());
56+
parentSpan.StartChild(Arg.Any<string>()).Returns(childSpan);
5157
var sut = new SentryGraphQLHttpMessageHandler(hub, null);
5258

5359
var method = "POST";
@@ -61,19 +67,9 @@ public void ProcessRequest_SetsSpanData()
6167

6268
// Assert
6369
returnedSpan.Should().NotBeNull();
64-
using (new AssertionScope())
65-
{
66-
returnedSpan!.Operation.Should().Be("http.client");
67-
returnedSpan.Description.Should().Be($"{method} {url}");
68-
returnedSpan.Extra.Should().Contain(kvp =>
69-
kvp.Key == OtelSemanticConventions.AttributeHttpRequestMethod &&
70-
kvp.Value.ToString() == method
71-
);
72-
returnedSpan.Extra.Should().Contain(kvp =>
73-
kvp.Key == OtelSemanticConventions.AttributeServerAddress &&
74-
kvp.Value.ToString() == host
75-
);
76-
}
70+
returnedSpan!.Operation.Should().Be("http.client");
71+
returnedSpan.Description.Should().Be($"{method} {url}");
72+
returnedSpan.Received(1).SetExtra(OtelSemanticConventions.AttributeHttpRequestMethod, method);
7773
}
7874

7975
// [Theory]
@@ -123,13 +119,14 @@ public void HandleResponse_AddsBreadcrumb()
123119
public void HandleResponse_SetsSpanData()
124120
{
125121
// Arrange
126-
var hub = _fixture.GetHub();
122+
var hub = Substitute.For<IHub>();
127123
var status = HttpStatusCode.OK;
128124
var response = new HttpResponseMessage(status);
129125
var method = "POST";
130126
var url = "http://example.com/graphql";
131127
var request = SentryGraphQlTestHelpers.GetRequestQuery(ValidQuery, url);
132128
response.RequestMessage = request;
129+
hub.GetSpan().Returns(new TransactionTracer(hub, "test", "test"));
133130
var sut = new SentryGraphQLHttpMessageHandler(hub, null);
134131

135132
// Act

test/Sentry.Tests/SentryHttpMessageHandlerTests.cs

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Sentry.Tests;
77
* TODO: Find a way to consolidate these tests cleanly.
88
*/
99

10-
public class SentryHttpMessageHandlerTests : SentryMessageHandlerTests
10+
public class SentryHttpMessageHandlerTests
1111
{
1212
[Fact]
1313
public async Task SendAsync_SentryTraceHeaderNotSet_SetsHeader_ByDefault()
@@ -122,12 +122,17 @@ public async Task SendAsync_SentryTraceHeaderAlreadySet_NotOverwritten()
122122
}
123123

124124
[Fact]
125-
public async Task SendAsync_TransactionOnScope_StartsChildSpan()
125+
public async Task SendAsync_TransactionOnScope_StartsNewSpan()
126126
{
127127
// Arrange
128-
var hub = _fixture.GetHub();
129-
var transaction = hub.StartTransaction("foo", "bar");
130-
hub.ConfigureScope(scope => scope.Transaction = transaction);
128+
var hub = Substitute.For<IHub>();
129+
130+
var transaction = new TransactionTracer(
131+
hub,
132+
"foo",
133+
"bar");
134+
135+
hub.GetSpan().ReturnsForAnyArgs(transaction);
131136

132137
using var innerHandler = new FakeHttpMessageHandler();
133138
using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
@@ -144,40 +149,17 @@ public async Task SendAsync_TransactionOnScope_StartsChildSpan()
144149
}
145150

146151
[Fact]
147-
public async Task SendAsync_NoTransactionOnScope_StartsTransaction()
152+
public async Task SendAsync_ExceptionThrown_ExceptionLinkedToSpan()
148153
{
149154
// Arrange
150-
SentryTransaction received = null;
151-
_fixture.Client.CaptureTransaction(
152-
Arg.Do<SentryTransaction>(t => received = t),
153-
Arg.Any<Scope>(),
154-
Arg.Any<SentryHint>()
155-
);
156-
var hub = _fixture.GetHub();
157-
158-
using var innerHandler = new FakeHttpMessageHandler();
159-
using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
160-
using var client = new HttpClient(sentryHandler);
155+
var hub = Substitute.For<IHub>();
161156

162-
// Act
163-
await client.GetAsync("https://localhost/");
157+
var transaction = new TransactionTracer(
158+
hub,
159+
"foo",
160+
"bar");
164161

165-
// Assert
166-
received.Should().NotBeNull();
167-
using (new AssertionScope())
168-
{
169-
received.Name.Should().Be("GET https://localhost/");
170-
received.Operation.Should().Be("http.client");
171-
received.Description.Should().Be("GET https://localhost/");
172-
received.IsFinished.Should().BeTrue();
173-
}
174-
}
175-
176-
[Fact]
177-
public async Task SendAsync_ExceptionThrown_ExceptionLinkedToSpan()
178-
{
179-
// Arrange
180-
var hub = _fixture.GetHub();
162+
hub.GetSpan().ReturnsForAnyArgs(transaction);
181163

182164
var exception = new Exception();
183165

@@ -189,8 +171,7 @@ public async Task SendAsync_ExceptionThrown_ExceptionLinkedToSpan()
189171
await Assert.ThrowsAsync<Exception>(() => client.GetAsync("https://localhost/"));
190172

191173
// Assert
192-
hub.ExceptionToSpanMap.TryGetValue(exception, out var span).Should().BeTrue();
193-
span.Should().NotBeNull();
174+
hub.Received(1).BindException(exception, Arg.Any<ISpan>()); // second argument is an implicitly created span
194175
}
195176

196177
[Fact]
@@ -262,15 +243,18 @@ public async Task SendAsync_Executed_FailedRequestsCaptured()
262243
public void ProcessRequest_SetsSpanData()
263244
{
264245
// Arrange
265-
var hub = _fixture.GetHub();
266-
using var innerHandler = new FakeHttpMessageHandler();
267-
var sut = new SentryHttpMessageHandler(hub, _fixture.Options, innerHandler);
246+
var hub = Substitute.For<IHub>();
247+
var parentSpan = Substitute.For<ISpan>();
248+
hub.GetSpan().Returns(parentSpan);
249+
var childSpan = Substitute.For<ISpan>();
250+
parentSpan.When(p => p.StartChild(Arg.Any<string>()))
251+
.Do(op => childSpan.Operation = op.Arg<string>());
252+
parentSpan.StartChild(Arg.Any<string>()).Returns(childSpan);
253+
var sut = new SentryHttpMessageHandler(hub, null);
268254

269255
var method = "GET";
270-
var host = "example.com";
271-
var url = $"https://{host}/graphql";
272-
var uri = new Uri(url);
273-
var request = new HttpRequestMessage(HttpMethod.Get, uri);
256+
var url = "http://example.com/graphql";
257+
var request = new HttpRequestMessage(HttpMethod.Get, url);
274258

275259
// Act
276260
var returnedSpan = sut.ProcessRequest(request, method, url);
@@ -279,14 +263,7 @@ public void ProcessRequest_SetsSpanData()
279263
returnedSpan.Should().NotBeNull();
280264
returnedSpan!.Operation.Should().Be("http.client");
281265
returnedSpan.Description.Should().Be($"{method} {url}");
282-
returnedSpan.Extra.Should().Contain(kvp =>
283-
kvp.Key == OtelSemanticConventions.AttributeHttpRequestMethod &&
284-
Equals(kvp.Value, method)
285-
);
286-
returnedSpan.Extra.Should().Contain(kvp =>
287-
kvp.Key == OtelSemanticConventions.AttributeServerAddress &&
288-
Equals(kvp.Value, host)
289-
);
266+
returnedSpan.Received(1).SetExtra(OtelSemanticConventions.AttributeHttpRequestMethod, method);
290267
}
291268

292269
[Fact]
@@ -430,9 +407,14 @@ public void Send_SentryTraceHeaderAlreadySet_NotOverwritten()
430407
public void Send_TransactionOnScope_StartsNewSpan()
431408
{
432409
// Arrange
433-
var hub = _fixture.GetHub();
434-
var transaction = hub.StartTransaction("foo", "bar");
435-
hub.ConfigureScope(scope => scope.Transaction = transaction);
410+
var hub = Substitute.For<IHub>();
411+
412+
var transaction = new TransactionTracer(
413+
hub,
414+
"foo",
415+
"bar");
416+
417+
hub.GetSpan().ReturnsForAnyArgs(transaction);
436418

437419
using var innerHandler = new FakeHttpMessageHandler();
438420
using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
@@ -452,7 +434,14 @@ public void Send_TransactionOnScope_StartsNewSpan()
452434
public void Send_ExceptionThrown_ExceptionLinkedToSpan()
453435
{
454436
// Arrange
455-
var hub = _fixture.GetHub();
437+
var hub = Substitute.For<IHub>();
438+
439+
var transaction = new TransactionTracer(
440+
hub,
441+
"foo",
442+
"bar");
443+
444+
hub.GetSpan().ReturnsForAnyArgs(transaction);
456445

457446
var exception = new Exception();
458447

@@ -464,8 +453,7 @@ public void Send_ExceptionThrown_ExceptionLinkedToSpan()
464453
Assert.Throws<Exception>(() => client.Get("https://localhost/"));
465454

466455
// Assert
467-
hub.ExceptionToSpanMap.TryGetValue(exception, out var span).Should().BeTrue();
468-
span.Should().NotBeNull();
456+
hub.Received(1).BindException(exception, Arg.Any<ISpan>()); // second argument is an implicitly created span
469457
}
470458

471459
[Fact]

test/Sentry.Tests/SentryMessageHandlerTests.cs

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

0 commit comments

Comments
 (0)