Skip to content

Commit 5576f89

Browse files
authored
Add ISentryTransactionProcessor (#1862)
1 parent a6101c3 commit 5576f89

19 files changed

+527
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
## Features
66

7+
- Add ISentryTransactionProcessor ([#1862](https://github.com/getsentry/sentry-dotnet/pull/1862))
78
- Move Array option over to use List<T> ([#1866](https://github.com/getsentry/sentry-dotnet/pull/1866))
89
- Added 'integrations' to SdkVersion ([#1820](https://github.com/getsentry/sentry-dotnet/pull/1820))
910
- Updated Sentry Android SDK to version 6.3.0 ([#1826](https://github.com/getsentry/sentry-dotnet/pull/1826))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Sentry.Extensibility
2+
{
3+
/// <summary>
4+
/// Process a <see cref="Transaction"/> during the prepare phase.
5+
/// </summary>
6+
public interface ISentryTransactionProcessor
7+
{
8+
/// <summary>
9+
/// Process the <see cref="Transaction"/>
10+
/// </summary>
11+
/// <param name="transaction">The Transaction to process</param>
12+
/// <remarks>
13+
/// The transaction returned can be the same instance received or a new one.
14+
/// Returning null will stop the processing pipeline.
15+
/// Meaning the transaction should no longer be processed nor send.
16+
/// </remarks>
17+
Transaction? Process(Transaction transaction);
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using Sentry.Extensibility;
3+
4+
namespace Sentry.Internal
5+
{
6+
internal class DelegateTransactionProcessor : ISentryTransactionProcessor
7+
{
8+
private readonly Func<Transaction, Transaction?> _func;
9+
10+
public DelegateTransactionProcessor(Func<Transaction, Transaction?> func)
11+
{
12+
_func = func;
13+
}
14+
15+
public Transaction? Process(Transaction transaction)
16+
{
17+
return _func(transaction);
18+
}
19+
}
20+
}

src/Sentry/Internal/Hub.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,29 @@ public void CaptureTransaction(Transaction transaction)
344344
{
345345
// Apply scope data
346346
var currentScope = ScopeManager.GetCurrent();
347-
currentScope.Key.Evaluate();
348-
currentScope.Key.Apply(transaction);
347+
var scope = currentScope.Key;
348+
scope.Evaluate();
349+
scope.Apply(transaction);
349350

350351
// Apply enricher
351352
_enricher.Apply(transaction);
352353

353-
currentScope.Value.CaptureTransaction(transaction);
354+
var processedTransaction = transaction;
355+
if (transaction.IsSampled != false)
356+
{
357+
foreach (var processor in scope.GetAllTransactionProcessors())
358+
{
359+
processedTransaction = processor.Process(transaction);
360+
if (processedTransaction == null)
361+
{
362+
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, DataCategory.Transaction);
363+
_options.LogInfo("Event dropped by processor {0}", processor.GetType().Name);
364+
return;
365+
}
366+
}
367+
}
368+
369+
currentScope.Value.CaptureTransaction(processedTransaction);
354370
}
355371
catch (Exception e)
356372
{

src/Sentry/Scope.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,19 @@ internal SentryId LastEventId
6262
private readonly Lazy<ConcurrentBag<ISentryEventProcessor>> _lazyEventProcessors =
6363
new(LazyThreadSafetyMode.PublicationOnly);
6464

65+
private readonly Lazy<ConcurrentBag<ISentryTransactionProcessor>> _lazyTransactionProcessors =
66+
new(LazyThreadSafetyMode.PublicationOnly);
67+
6568
/// <summary>
6669
/// A list of event processors.
6770
/// </summary>
6871
internal ConcurrentBag<ISentryEventProcessor> EventProcessors => _lazyEventProcessors.Value;
6972

73+
/// <summary>
74+
/// A list of event processors.
75+
/// </summary>
76+
internal ConcurrentBag<ISentryTransactionProcessor> TransactionProcessors => _lazyTransactionProcessors.Value;
77+
7078
/// <summary>
7179
/// An event that fires when the scope evaluates.
7280
/// </summary>
@@ -425,6 +433,11 @@ public Scope Clone()
425433
clone.EventProcessors.Add(processor);
426434
}
427435

436+
foreach (var processor in TransactionProcessors)
437+
{
438+
clone.TransactionProcessors.Add(processor);
439+
}
440+
428441
foreach (var processor in ExceptionProcessors)
429442
{
430443
clone.ExceptionProcessors.Add(processor);

src/Sentry/ScopeExtensions.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ public static IEnumerable<ISentryEventProcessor> GetAllEventProcessors(this Scop
3232
}
3333
}
3434

35+
/// <summary>
36+
/// Invokes all transaction processor providers available.
37+
/// </summary>
38+
/// <param name="scope">The Scope which holds the processor providers.</param>
39+
public static IEnumerable<ISentryTransactionProcessor> GetAllTransactionProcessors(this Scope scope)
40+
{
41+
foreach (var processor in scope.Options.GetAllTransactionProcessors())
42+
{
43+
yield return processor;
44+
}
45+
46+
foreach (var processor in scope.TransactionProcessors)
47+
{
48+
yield return processor;
49+
}
50+
}
51+
3552
/// <summary>
3653
/// Invokes all exception processor providers available.
3754
/// </summary>
@@ -99,6 +116,35 @@ public static void AddEventProcessors(this Scope scope, IEnumerable<ISentryEvent
99116
}
100117
}
101118

119+
/// <summary>
120+
/// Adds an transaction processor which is invoked when creating a <see cref="Transaction"/>.
121+
/// </summary>
122+
/// <param name="scope">The Scope to hold the processor.</param>
123+
/// <param name="processor">The transaction processor.</param>
124+
public static void AddTransactionProcessor(this Scope scope, ISentryTransactionProcessor processor)
125+
=> scope.TransactionProcessors.Add(processor);
126+
127+
/// <summary>
128+
/// Adds an transaction processor which is invoked when creating a <see cref="Transaction"/>.
129+
/// </summary>
130+
/// <param name="scope">The Scope to hold the processor.</param>
131+
/// <param name="processor">The transaction processor.</param>
132+
public static void AddTransactionProcessor(this Scope scope, Func<Transaction, Transaction?> processor)
133+
=> scope.AddTransactionProcessor(new DelegateTransactionProcessor(processor));
134+
135+
/// <summary>
136+
/// Adds transaction processors which are invoked when creating a <see cref="Transaction"/>.
137+
/// </summary>
138+
/// <param name="scope">The Scope to hold the processor.</param>
139+
/// <param name="processors">The transaction processors.</param>
140+
public static void AddTransactionProcessors(this Scope scope, IEnumerable<ISentryTransactionProcessor> processors)
141+
{
142+
foreach (var processor in processors)
143+
{
144+
scope.TransactionProcessors.Add(processor);
145+
}
146+
}
147+
102148
/// <summary>
103149
/// Adds an attachment.
104150
/// </summary>

src/Sentry/SentryClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,12 @@ public void CaptureTransaction(Transaction transaction)
116116
"to properly finalize the transaction and send it to Sentry.");
117117
}
118118

119+
119120
// Sampling decision MUST have been made at this point
120121
Debug.Assert(transaction.IsSampled != null,
121122
"Attempt to capture transaction without sampling decision.");
122123

124+
123125
if (transaction.IsSampled != true)
124126
{
125127
_options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.SampleRate, DataCategory.Transaction);

src/Sentry/SentryOptions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ public bool IsGlobalModeEnabled
9191
/// </summary>
9292
internal List<ISentryEventExceptionProcessor>? ExceptionProcessors { get; set; }
9393

94+
/// <summary>
95+
/// A list of transaction processors
96+
/// </summary>
97+
internal List<ISentryTransactionProcessor>? TransactionProcessors { get; set; }
98+
9499
/// <summary>
95100
/// A list of event processors
96101
/// </summary>
@@ -101,6 +106,11 @@ public bool IsGlobalModeEnabled
101106
/// </summary>
102107
internal List<Func<IEnumerable<ISentryEventProcessor>>>? EventProcessorsProviders { get; set; }
103108

109+
/// <summary>
110+
/// A list of providers of <see cref="ISentryTransactionProcessor"/>
111+
/// </summary>
112+
internal List<Func<IEnumerable<ISentryTransactionProcessor>>>? TransactionProcessorsProviders { get; set; }
113+
104114
/// <summary>
105115
/// A list of providers of <see cref="ISentryEventExceptionProcessor"/>
106116
/// </summary>
@@ -684,6 +694,10 @@ public SentryOptions()
684694
() => EventProcessors ?? Enumerable.Empty<ISentryEventProcessor>()
685695
};
686696

697+
TransactionProcessorsProviders = new () {
698+
() => TransactionProcessors ?? Enumerable.Empty<ISentryTransactionProcessor>()
699+
};
700+
687701
ExceptionProcessorsProviders = new () {
688702
() => ExceptionProcessors ?? Enumerable.Empty<ISentryEventExceptionProcessor>()
689703
};

src/Sentry/SentryOptionsExtensions.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,50 @@ public static void AddEventProcessorProvider(this SentryOptions options, Func<IE
266266
}
267267
}
268268

269+
/// <summary>
270+
/// Adds an transaction processor which is invoked when creating a <see cref="Transaction"/>.
271+
/// </summary>
272+
/// <param name="options">The SentryOptions to hold the processor.</param>
273+
/// <param name="processor">The transaction processor.</param>
274+
public static void AddTransactionProcessor(this SentryOptions options, ISentryTransactionProcessor processor)
275+
{
276+
if (options.TransactionProcessors == null)
277+
{
278+
options.TransactionProcessors = new() {processor};
279+
}
280+
else
281+
{
282+
options.TransactionProcessors.Add(processor);
283+
}
284+
}
285+
286+
/// <summary>
287+
/// Adds transaction processors which are invoked when creating a <see cref="Transaction"/>.
288+
/// </summary>
289+
/// <param name="options">The SentryOptions to hold the processor.</param>
290+
/// <param name="processors">The transaction processors.</param>
291+
public static void AddTransactionProcessors(this SentryOptions options, IEnumerable<ISentryTransactionProcessor> processors)
292+
{
293+
if (options.TransactionProcessors == null)
294+
{
295+
options.TransactionProcessors = processors.ToList();
296+
}
297+
else
298+
{
299+
options.TransactionProcessors.AddRange(processors);
300+
}
301+
}
302+
303+
/// <summary>
304+
/// Adds an transaction processor provider which is invoked when creating a <see cref="Transaction"/>.
305+
/// </summary>
306+
/// <param name="options">The SentryOptions to hold the processor provider.</param>
307+
/// <param name="processorProvider">The transaction processor provider.</param>
308+
public static void AddTransactionProcessorProvider(this SentryOptions options, Func<IEnumerable<ISentryTransactionProcessor>> processorProvider)
309+
=> options.TransactionProcessorsProviders = options.TransactionProcessorsProviders != null
310+
? options.TransactionProcessorsProviders.Concat(new[] { processorProvider }).ToList()
311+
: new() { processorProvider };
312+
269313
/// <summary>
270314
/// Add the exception processor provider.
271315
/// </summary>
@@ -291,6 +335,13 @@ public static void AddExceptionProcessorProvider(this SentryOptions options,
291335
public static IEnumerable<ISentryEventProcessor> GetAllEventProcessors(this SentryOptions options)
292336
=> options.EventProcessorsProviders?.SelectMany(p => p()) ?? Enumerable.Empty<ISentryEventProcessor>();
293337

338+
/// <summary>
339+
/// Invokes all transaction processor providers available.
340+
/// </summary>
341+
/// <param name="options">The SentryOptions which holds the processor providers.</param>
342+
public static IEnumerable<ISentryTransactionProcessor> GetAllTransactionProcessors(this SentryOptions options)
343+
=> options.TransactionProcessorsProviders?.SelectMany(p => p()) ?? Enumerable.Empty<ISentryTransactionProcessor>();
344+
294345
/// <summary>
295346
/// Invokes all exception processor providers available.
296347
/// </summary>

test/Sentry.Tests/ApiApprovalTests.Run.Core2_1.verified.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[assembly: System.CLSCompliant(true)]
1+
[assembly: System.CLSCompliant(true)]
22
namespace Sentry
33
{
44
[System.Diagnostics.DebuggerDisplay("{FileName}")]
@@ -344,8 +344,12 @@ namespace Sentry
344344
public static void AddEventProcessors(this Sentry.Scope scope, System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventProcessor> processors) { }
345345
public static void AddExceptionProcessor(this Sentry.Scope scope, Sentry.Extensibility.ISentryEventExceptionProcessor processor) { }
346346
public static void AddExceptionProcessors(this Sentry.Scope scope, System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventExceptionProcessor> processors) { }
347+
public static void AddTransactionProcessor(this Sentry.Scope scope, Sentry.Extensibility.ISentryTransactionProcessor processor) { }
348+
public static void AddTransactionProcessor(this Sentry.Scope scope, System.Func<Sentry.Transaction, Sentry.Transaction?> processor) { }
349+
public static void AddTransactionProcessors(this Sentry.Scope scope, System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryTransactionProcessor> processors) { }
347350
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventProcessor> GetAllEventProcessors(this Sentry.Scope scope) { }
348351
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventExceptionProcessor> GetAllExceptionProcessors(this Sentry.Scope scope) { }
352+
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryTransactionProcessor> GetAllTransactionProcessors(this Sentry.Scope scope) { }
349353
}
350354
public sealed class SdkVersion : Sentry.IJsonSerializable
351355
{
@@ -528,13 +532,17 @@ namespace Sentry
528532
public static void AddInAppExclude(this Sentry.SentryOptions options, string prefix) { }
529533
public static void AddInAppInclude(this Sentry.SentryOptions options, string prefix) { }
530534
public static void AddIntegration(this Sentry.SentryOptions options, Sentry.Integrations.ISdkIntegration integration) { }
535+
public static void AddTransactionProcessor(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryTransactionProcessor processor) { }
536+
public static void AddTransactionProcessorProvider(this Sentry.SentryOptions options, System.Func<System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryTransactionProcessor>> processorProvider) { }
537+
public static void AddTransactionProcessors(this Sentry.SentryOptions options, System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryTransactionProcessor> processors) { }
531538
public static void ApplyDefaultTags(this Sentry.SentryOptions options, Sentry.IHasTags hasTags) { }
532539
public static void DisableAppDomainProcessExitFlush(this Sentry.SentryOptions options) { }
533540
public static void DisableAppDomainUnhandledExceptionCapture(this Sentry.SentryOptions options) { }
534541
public static void DisableDuplicateEventDetection(this Sentry.SentryOptions options) { }
535542
public static void DisableTaskUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { }
536543
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventProcessor> GetAllEventProcessors(this Sentry.SentryOptions options) { }
537544
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryEventExceptionProcessor> GetAllExceptionProcessors(this Sentry.SentryOptions options) { }
545+
public static System.Collections.Generic.IEnumerable<Sentry.Extensibility.ISentryTransactionProcessor> GetAllTransactionProcessors(this Sentry.SentryOptions options) { }
538546
public static void RemoveIntegration<TIntegration>(this Sentry.SentryOptions options)
539547
where TIntegration : Sentry.Integrations.ISdkIntegration { }
540548
public static Sentry.SentryOptions UseStackTraceFactory(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { }
@@ -1063,6 +1071,10 @@ namespace Sentry.Extensibility
10631071
{
10641072
Sentry.SentryStackTrace? Create(System.Exception? exception = null);
10651073
}
1074+
public interface ISentryTransactionProcessor
1075+
{
1076+
Sentry.Transaction? Process(Sentry.Transaction transaction);
1077+
}
10661078
public interface ITransport
10671079
{
10681080
System.Threading.Tasks.Task SendEnvelopeAsync(Sentry.Protocol.Envelopes.Envelope envelope, System.Threading.CancellationToken cancellationToken = default);

0 commit comments

Comments
 (0)