-
Notifications
You must be signed in to change notification settings - Fork 893
Expand file tree
/
Copy pathBatchExportProcessor.cs
More file actions
168 lines (139 loc) · 5.95 KB
/
Copy pathBatchExportProcessor.cs
File metadata and controls
168 lines (139 loc) · 5.95 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using System.Runtime.CompilerServices;
using OpenTelemetry.Internal;
namespace OpenTelemetry;
/// <summary>
/// Implements processor that batches telemetry objects before calling exporter.
/// </summary>
/// <typeparam name="T">The type of telemetry object to be exported.</typeparam>
public abstract class BatchExportProcessor<T> : BaseExportProcessor<T>
where T : class
{
internal const int DefaultMaxQueueSize = 2048;
internal const int DefaultScheduledDelayMilliseconds = 5000;
internal const int DefaultExporterTimeoutMilliseconds = 30000;
internal const int DefaultMaxExportBatchSize = 512;
internal readonly int MaxExportBatchSize;
internal readonly int ScheduledDelayMilliseconds;
internal readonly int ExporterTimeoutMilliseconds;
private readonly CircularBuffer<T> circularBuffer;
private readonly BatchExportWorker<T> worker;
private bool disposed;
/// <summary>
/// Initializes a new instance of the <see cref="BatchExportProcessor{T}"/> class.
/// </summary>
/// <param name="exporter">Exporter instance.</param>
/// <param name="maxQueueSize">The maximum queue size. After the size is reached data are dropped. The default value is 2048.</param>
/// <param name="scheduledDelayMilliseconds">The delay interval in milliseconds between two consecutive exports. The default value is 5000.</param>
/// <param name="exporterTimeoutMilliseconds">How long the export can run before it is cancelled. The default value is 30000.</param>
/// <param name="maxExportBatchSize">The maximum batch size of every export. It must be smaller or equal to maxQueueSize. The default value is 512.</param>
protected BatchExportProcessor(
BaseExporter<T> exporter,
int maxQueueSize = DefaultMaxQueueSize,
int scheduledDelayMilliseconds = DefaultScheduledDelayMilliseconds,
int exporterTimeoutMilliseconds = DefaultExporterTimeoutMilliseconds,
int maxExportBatchSize = DefaultMaxExportBatchSize)
: base(exporter)
{
Guard.ThrowIfOutOfRange(maxQueueSize, min: 1);
Guard.ThrowIfOutOfRange(maxExportBatchSize, min: 1, max: maxQueueSize, maxName: nameof(maxQueueSize));
Guard.ThrowIfOutOfRange(scheduledDelayMilliseconds, min: 1);
Guard.ThrowIfOutOfRange(exporterTimeoutMilliseconds, min: 0);
this.circularBuffer = new CircularBuffer<T>(maxQueueSize);
this.ScheduledDelayMilliseconds = scheduledDelayMilliseconds;
this.ExporterTimeoutMilliseconds = exporterTimeoutMilliseconds;
this.MaxExportBatchSize = maxExportBatchSize;
this.worker = this.CreateWorker();
this.worker.Start();
}
/// <summary>
/// Gets the number of telemetry objects dropped by the processor.
/// </summary>
internal long DroppedCount => this.worker.DroppedCount;
/// <summary>
/// Gets the number of telemetry objects received by the processor.
/// </summary>
internal long ReceivedCount => this.circularBuffer.AddedCount + this.DroppedCount;
/// <summary>
/// Gets the number of telemetry objects processed by the underlying exporter.
/// </summary>
internal long ProcessedCount => this.circularBuffer.RemovedCount;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool TryExport(T data)
{
if (this.circularBuffer.TryAdd(data, maxSpinCount: 50000))
{
if (this.circularBuffer.Count >= this.MaxExportBatchSize)
{
this.worker.TriggerExport();
}
return true; // enqueue succeeded
}
// either the queue is full or exceeded the spin limit, drop the item on the floor
this.worker.IncrementDroppedCount();
return false;
}
/// <inheritdoc/>
protected override void OnExport(T data)
=> this.TryExport(data);
/// <inheritdoc/>
protected override bool OnForceFlush(int timeoutMilliseconds)
=> this.worker.WaitForExport(timeoutMilliseconds);
/// <inheritdoc/>
protected override bool OnShutdown(int timeoutMilliseconds)
{
long? timestamp = timeoutMilliseconds == Timeout.Infinite ? null : Stopwatch.GetTimestamp();
var result = this.worker.Shutdown(timeoutMilliseconds);
OpenTelemetrySdkEventSource.Log.DroppedExportProcessorItems(this.GetType().Name, this.exporter.GetType().Name, this.DroppedCount);
if (timeoutMilliseconds == Timeout.Infinite)
{
return this.exporter.Shutdown() && result;
}
if (timeoutMilliseconds == 0)
{
return this.exporter.Shutdown(0) && result;
}
if (timestamp is { } startedAt)
{
timeoutMilliseconds = Stopwatch.Remaining(timeoutMilliseconds, startedAt);
}
return this.exporter.Shutdown(timeoutMilliseconds) && result;
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
this.worker?.Dispose();
}
this.disposed = true;
}
base.Dispose(disposing);
}
private BatchExportWorker<T> CreateWorker()
{
#if NET
// Use task-based worker for browser platform where threading may be limited
if (ThreadingHelper.IsThreadingDisabled())
{
return new BatchExportTaskWorker<T>(
this.circularBuffer,
this.exporter,
this.MaxExportBatchSize,
this.ScheduledDelayMilliseconds,
this.ExporterTimeoutMilliseconds);
}
#endif
// Use thread-based worker for all other platforms
return new BatchExportThreadWorker<T>(
this.circularBuffer,
this.exporter,
this.MaxExportBatchSize,
this.ScheduledDelayMilliseconds,
this.ExporterTimeoutMilliseconds);
}
}