-
-
Notifications
You must be signed in to change notification settings - Fork 230
Expand file tree
/
Copy pathSamplingTransactionProfilerFactory.cs
More file actions
88 lines (72 loc) · 3 KB
/
SamplingTransactionProfilerFactory.cs
File metadata and controls
88 lines (72 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using Sentry.Extensibility;
using Sentry.Internal;
namespace Sentry.Profiling;
internal class SamplingTransactionProfilerFactory : IDisposable, ITransactionProfilerFactory
{
// We only allow a single profile so let's keep track of the current status.
internal InterlockedBoolean _inProgress = false;
// Whether the session startup took longer than the given timeout.
internal bool StartupTimedOut { get; }
// Stop profiling after the given number of milliseconds.
private const int TIME_LIMIT_MS = 30_000;
private readonly SentryOptions _options;
internal Task<SampleProfilerSession> _sessionTask;
private bool _errorLogged = false;
public SamplingTransactionProfilerFactory(SentryOptions options, TimeSpan startupTimeout)
{
_options = options;
_sessionTask = Task.Run(async () =>
{
// This can block up to 30 seconds. The timeout is out of our hands.
var session = SampleProfilerSession.StartNew(options.DiagnosticLogger);
// This can block indefinitely.
await session.WaitForFirstEventAsync().ConfigureAwait(false);
return session;
});
Debug.Assert(TimeSpan.FromSeconds(0) == TimeSpan.Zero);
if (startupTimeout != TimeSpan.Zero && !_sessionTask.Wait(startupTimeout))
{
options.LogWarning("Profiler session startup took longer then the given timeout {0:c}. Profiling will start once the first event is received.", startupTimeout);
StartupTimedOut = true;
}
}
/// <inheritdoc />
public ITransactionProfiler? Start(ITransactionTracer _, CancellationToken cancellationToken)
{
// Start a profiler if one wasn't running yet.
if (!_errorLogged && !_inProgress.Exchange(true))
{
if (!_sessionTask.IsCompleted)
{
_options.LogWarning("Cannot start a sampling profiler, the session hasn't started yet.");
_inProgress = false;
return null;
}
if (!_sessionTask.IsCompletedSuccessfully)
{
_options.LogWarning("Cannot start a sampling profiler because the session startup has failed. This is a permanent error and no future transactions will be sampled.");
_errorLogged = true;
_inProgress = false;
return null;
}
_options.LogDebug("Starting a sampling profiler.");
try
{
return new SamplingTransactionProfiler(_options, _sessionTask.Result, TIME_LIMIT_MS, cancellationToken)
{
OnFinish = () => _inProgress = false
};
}
catch (Exception e)
{
_options.LogError(e, "Failed to start a profiler session.");
_inProgress = false;
}
}
return null;
}
public void Dispose()
{
_sessionTask.ContinueWith(session => session.Dispose());
}
}