Skip to content

Commit 95742b0

Browse files
authored
made meter provider optional in BatchSpanProcessor (#645)
* made meter provider optional in BatchSpanProcessor * re-indented BatchSpanProcessor file.
1 parent 95092cc commit 95742b0

File tree

1 file changed

+131
-139
lines changed

1 file changed

+131
-139
lines changed

Sources/OpenTelemetrySdk/Trace/SpanProcessors/BatchSpanProcessor.swift

Lines changed: 131 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,36 @@ import OpenTelemetryApi
1515
/// exports the spans to wake up and start a new export cycle.
1616
/// This batchSpanProcessor can cause high contention in a very high traffic service.
1717
public struct BatchSpanProcessor: SpanProcessor {
18-
fileprivate static let SPAN_PROCESSOR_TYPE_LABEL: String = "processorType"
19-
fileprivate static let SPAN_PROCESSOR_DROPPED_LABEL: String = "dropped"
20-
fileprivate static let SPAN_PROCESSOR_TYPE_VALUE: String = BatchSpanProcessor.name
21-
22-
fileprivate var worker: BatchWorker
18+
fileprivate static let SPAN_PROCESSOR_TYPE_LABEL: String = "processorType"
19+
fileprivate static let SPAN_PROCESSOR_DROPPED_LABEL: String = "dropped"
20+
fileprivate static let SPAN_PROCESSOR_TYPE_VALUE: String = BatchSpanProcessor.name
2321

24-
public static var name: String {
25-
String(describing: Self.self)
26-
}
27-
28-
public init(
29-
spanExporter: SpanExporter,
30-
meterProvider: StableMeterProvider,
31-
scheduleDelay: TimeInterval = 5,
32-
exportTimeout: TimeInterval = 30,
33-
maxQueueSize: Int = 2048,
34-
maxExportBatchSize: Int = 512,
35-
willExportCallback: ((inout [SpanData]) -> Void)? = nil
36-
) {
37-
worker = BatchWorker(
38-
spanExporter: spanExporter,
39-
meterProvider: meterProvider,
40-
scheduleDelay: scheduleDelay,
41-
exportTimeout: exportTimeout,
42-
maxQueueSize: maxQueueSize,
43-
maxExportBatchSize: maxExportBatchSize,
44-
willExportCallback: willExportCallback
45-
)
46-
worker.start()
47-
}
22+
fileprivate var worker: BatchWorker
23+
24+
public static var name: String {
25+
String(describing: Self.self)
26+
}
27+
28+
public init(
29+
spanExporter: SpanExporter,
30+
meterProvider: StableMeterProvider? = nil,
31+
scheduleDelay: TimeInterval = 5,
32+
exportTimeout: TimeInterval = 30,
33+
maxQueueSize: Int = 2048,
34+
maxExportBatchSize: Int = 512,
35+
willExportCallback: ((inout [SpanData]) -> Void)? = nil
36+
) {
37+
worker = BatchWorker(
38+
spanExporter: spanExporter,
39+
meterProvider: meterProvider,
40+
scheduleDelay: scheduleDelay,
41+
exportTimeout: exportTimeout,
42+
maxQueueSize: maxQueueSize,
43+
maxExportBatchSize: maxExportBatchSize,
44+
willExportCallback: willExportCallback
45+
)
46+
worker.start()
47+
}
4848

4949
public let isStartRequired = false
5050
public let isEndRequired = true
@@ -72,105 +72,95 @@ public struct BatchSpanProcessor: SpanProcessor {
7272
/// the data.
7373
/// The list of batched data is protected by a NSCondition which ensures full concurrency.
7474
private class BatchWorker: Thread {
75-
let spanExporter: SpanExporter
76-
let meterProvider: StableMeterProvider
77-
let scheduleDelay: TimeInterval
78-
let maxQueueSize: Int
79-
let exportTimeout: TimeInterval
80-
let maxExportBatchSize: Int
81-
let willExportCallback: ((inout [SpanData]) -> Void)?
82-
let halfMaxQueueSize: Int
83-
private let cond = NSCondition()
84-
var spanList = [ReadableSpan]()
85-
var queue: OperationQueue
86-
87-
private var queueSizeGauge: ObservableLongGauge?
88-
private var spanGaugeObserver: ObservableLongGauge?
75+
let spanExporter: SpanExporter
76+
let meterProvider: StableMeterProvider?
77+
let scheduleDelay: TimeInterval
78+
let maxQueueSize: Int
79+
let exportTimeout: TimeInterval
80+
let maxExportBatchSize: Int
81+
let willExportCallback: ((inout [SpanData]) -> Void)?
82+
let halfMaxQueueSize: Int
83+
private let cond = NSCondition()
84+
var spanList = [ReadableSpan]()
85+
var queue: OperationQueue
86+
87+
private var queueSizeGauge: ObservableLongGauge?
88+
private var spanGaugeObserver: ObservableLongGauge?
89+
private var processedSpansCounter: LongCounter?
90+
91+
init(
92+
spanExporter: SpanExporter,
93+
meterProvider: StableMeterProvider? = nil,
94+
scheduleDelay: TimeInterval,
95+
exportTimeout: TimeInterval,
96+
maxQueueSize: Int,
97+
maxExportBatchSize: Int,
98+
willExportCallback: ((inout [SpanData]) -> Void)?
99+
) {
100+
self.spanExporter = spanExporter
101+
self.meterProvider = meterProvider
102+
self.scheduleDelay = scheduleDelay
103+
self.exportTimeout = exportTimeout
104+
self.maxQueueSize = maxQueueSize
105+
halfMaxQueueSize = maxQueueSize >> 1
106+
self.maxExportBatchSize = maxExportBatchSize
107+
self.willExportCallback = willExportCallback
108+
queue = OperationQueue()
109+
queue.name = "BatchWorker Queue"
110+
queue.maxConcurrentOperationCount = 1
89111

90-
private var processedSpansCounter: LongCounter?
91-
private let droppedAttrs: [String: AttributeValue]
92-
private let exportedAttrs: [String: AttributeValue]
93-
private let spanGaugeBuilder: LongGaugeBuilder
94-
init(
95-
spanExporter: SpanExporter,
96-
meterProvider: StableMeterProvider,
97-
scheduleDelay: TimeInterval,
98-
exportTimeout: TimeInterval,
99-
maxQueueSize: Int,
100-
maxExportBatchSize: Int,
101-
willExportCallback: ((inout [SpanData]) -> Void)?
102-
) {
103-
self.spanExporter = spanExporter
104-
self.meterProvider = meterProvider
105-
self.scheduleDelay = scheduleDelay
106-
self.exportTimeout = exportTimeout
107-
self.maxQueueSize = maxQueueSize
108-
halfMaxQueueSize = maxQueueSize >> 1
109-
self.maxExportBatchSize = maxExportBatchSize
110-
self.willExportCallback = willExportCallback
111-
queue = OperationQueue()
112-
queue.name = "BatchWorker Queue"
113-
queue.maxConcurrentOperationCount = 1
114-
115-
let meter = meterProvider.meterBuilder(name: "io.opentelemetry.sdk.trace").build()
116-
117-
var longGaugeSdk = meter.gaugeBuilder(name: "queueSize").ofLongs() as? LongGaugeBuilderSdk
118-
longGaugeSdk = longGaugeSdk?.setDescription("The number of items queued")
119-
longGaugeSdk = longGaugeSdk?.setUnit("1")
120-
self.queueSizeGauge = longGaugeSdk?.buildWithCallback { result in
121-
result.record(
122-
value: maxQueueSize,
123-
attributes: [
124-
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE)
125-
]
126-
)
112+
if let meter = meterProvider?.meterBuilder(name: "io.opentelemetry.sdk.trace").build() {
113+
114+
var longGaugeSdk = meter.gaugeBuilder(name: "queueSize").ofLongs() as? LongGaugeBuilderSdk
115+
longGaugeSdk = longGaugeSdk?.setDescription("The number of items queued")
116+
longGaugeSdk = longGaugeSdk?.setUnit("1")
117+
self.queueSizeGauge = longGaugeSdk?.buildWithCallback { result in
118+
result.record(
119+
value: maxQueueSize,
120+
attributes: [
121+
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE)
122+
]
123+
)
124+
}
125+
126+
var longCounterSdk = meter.counterBuilder(name: "processedSpans") as? LongCounterMeterBuilderSdk
127+
longCounterSdk = longCounterSdk?.setUnit("1")
128+
longCounterSdk = longCounterSdk?.setDescription("The number of spans processed by the BatchSpanProcessor. [dropped=true if they were dropped due to high throughput]")
129+
processedSpansCounter = longCounterSdk?.build()
130+
131+
// Subscribe to new gauge observer
132+
self.spanGaugeObserver = meter.gaugeBuilder(name: "spanSize")
133+
.ofLongs()
134+
.buildWithCallback { [count = spanList.count] result in
135+
result.record(
136+
value: count,
137+
attributes: [
138+
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE)
139+
]
140+
)
127141
}
128-
129-
self.spanGaugeBuilder = meter.gaugeBuilder(name: "spanSize")
130-
.ofLongs()
131-
132-
var longCounterSdk = meter.counterBuilder(name: "processedSpans") as? LongCounterMeterBuilderSdk
133-
longCounterSdk = longCounterSdk?.setUnit("1")
134-
longCounterSdk = longCounterSdk?.setDescription("The number of spans processed by the BatchSpanProcessor. [dropped=true if they were dropped due to high throughput]")
135-
processedSpansCounter = longCounterSdk?.build()
136-
137-
droppedAttrs = [
138-
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE),
139-
BatchSpanProcessor.SPAN_PROCESSOR_DROPPED_LABEL: .bool(true)
140-
]
141-
exportedAttrs = [
142-
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE),
143-
BatchSpanProcessor.SPAN_PROCESSOR_DROPPED_LABEL: .bool(false)
144-
]
145-
146-
// Subscribe to new gauge observer
147-
self.spanGaugeObserver = self.spanGaugeBuilder
148-
.buildWithCallback { [count = spanList.count] result in
149-
result.record(
150-
value: count,
151-
attributes: [
152-
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE)
153-
]
154-
)
155-
}
156142
}
143+
}
144+
145+
deinit {
146+
// Cleanup all gauge observer
147+
self.queueSizeGauge?.close()
148+
self.spanGaugeObserver?.close()
149+
}
157150

158-
deinit {
159-
// Cleanup all gauge observer
160-
self.queueSizeGauge?.close()
161-
self.spanGaugeObserver?.close()
162-
}
163-
164151
func addSpan(span: ReadableSpan) {
165152
cond.lock()
166153
defer { cond.unlock() }
167154

168155
if spanList.count == maxQueueSize {
169-
processedSpansCounter?.add(value: 1, attribute: droppedAttrs)
156+
processedSpansCounter?.add(value: 1, attribute: [
157+
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE),
158+
BatchSpanProcessor.SPAN_PROCESSOR_DROPPED_LABEL: .bool(true)
159+
])
170160
return
171161
}
172162
spanList.append(span)
173-
163+
174164
// Notify the worker thread that at half of the queue is available. It will take
175165
// time anyway for the thread to wake up.
176166
if spanList.count >= halfMaxQueueSize {
@@ -180,18 +170,18 @@ private class BatchWorker: Thread {
180170

181171
override func main() {
182172
repeat {
183-
autoreleasepool {
184-
var spansCopy: [ReadableSpan]
185-
cond.lock()
186-
if spanList.count < maxExportBatchSize {
187-
repeat {
188-
cond.wait(until: Date().addingTimeInterval(scheduleDelay))
189-
} while spanList.isEmpty && !self.isCancelled
190-
}
191-
spansCopy = spanList
192-
spanList.removeAll()
193-
cond.unlock()
194-
self.exportBatch(spanList: spansCopy, explicitTimeout: self.exportTimeout)
173+
autoreleasepool {
174+
var spansCopy: [ReadableSpan]
175+
cond.lock()
176+
if spanList.count < maxExportBatchSize {
177+
repeat {
178+
cond.wait(until: Date().addingTimeInterval(scheduleDelay))
179+
} while spanList.isEmpty && !self.isCancelled
180+
}
181+
spansCopy = spanList
182+
spanList.removeAll()
183+
cond.unlock()
184+
self.exportBatch(spanList: spansCopy, explicitTimeout: self.exportTimeout)
195185
}
196186
} while !self.isCancelled
197187
}
@@ -228,16 +218,18 @@ private class BatchWorker: Thread {
228218
timeoutTimer.cancel()
229219
}
230220

231-
private func exportAction(spanList: [ReadableSpan], explicitTimeout: TimeInterval? = nil) {
232-
stride(from: 0, to: spanList.endIndex, by: maxExportBatchSize).forEach {
233-
var spansToExport = spanList[$0 ..< min($0 + maxExportBatchSize, spanList.count)].map { $0.toSpanData() }
234-
willExportCallback?(&spansToExport)
235-
let result = spanExporter.export(spans: spansToExport, explicitTimeout: explicitTimeout)
236-
if result == .success {
237-
cond.lock()
238-
processedSpansCounter?.add(value: spanList.count, attribute: exportedAttrs)
239-
cond.unlock()
240-
}
241-
}
221+
private func exportAction(spanList: [ReadableSpan], explicitTimeout: TimeInterval? = nil) {
222+
stride(from: 0, to: spanList.endIndex, by: maxExportBatchSize).forEach {
223+
var spansToExport = spanList[$0 ..< min($0 + maxExportBatchSize, spanList.count)].map { $0.toSpanData() }
224+
willExportCallback?(&spansToExport)
225+
let result = spanExporter.export(spans: spansToExport, explicitTimeout: explicitTimeout)
226+
if result == .success {
227+
cond.lock()
228+
processedSpansCounter?.add(value: spanList.count, attribute: [
229+
BatchSpanProcessor.SPAN_PROCESSOR_TYPE_LABEL: .string(BatchSpanProcessor.SPAN_PROCESSOR_TYPE_VALUE),
230+
BatchSpanProcessor.SPAN_PROCESSOR_DROPPED_LABEL: .bool(false)])
231+
cond.unlock();
232+
}
242233
}
234+
}
243235
}

0 commit comments

Comments
 (0)