Skip to content

Commit 4012768

Browse files
krayc425bryce-b
andauthored
Safeguard parameters in BatchSpanProcessor init (#810)
* Safeguard parameters in BatchSpanProcessor init * add unit tests * apply changes to BatchLogRecordProcessor * Update BatchLogRecordProcessor.swift * fix a typo --------- Co-authored-by: Bryce Buchanan <[email protected]>
1 parent 3f5dceb commit 4012768

File tree

5 files changed

+158
-8
lines changed

5 files changed

+158
-8
lines changed

Sources/OpenTelemetrySdk/Logs/Processors/BatchLogRecordProcessor.swift

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,48 @@ import OpenTelemetryApi
99
public class BatchLogRecordProcessor: LogRecordProcessor {
1010
fileprivate var worker: BatchWorker
1111

12-
public init(logRecordExporter: LogRecordExporter, scheduleDelay: TimeInterval = 5, exportTimeout: TimeInterval = 30, maxQueueSize: Int = 2048, maxExportBatchSize: Int = 512, willExportCallback: ((inout [ReadableLogRecord]) -> Void)? = nil) {
13-
worker = BatchWorker(logRecordExporter: logRecordExporter, scheduleDelay: scheduleDelay, exportTimeout: exportTimeout, maxQueueSize: maxQueueSize, maxExportBatchSize: maxExportBatchSize, willExportCallback: willExportCallback)
12+
let safeScheduleDelay: TimeInterval
13+
let safeExportTimeout: TimeInterval
14+
let safeMaxQueueSize: Int
15+
let safeMaxExportBatchSize: Int
16+
17+
public init(logRecordExporter: LogRecordExporter,
18+
scheduleDelay: TimeInterval = 5,
19+
exportTimeout: TimeInterval = 30,
20+
maxQueueSize: Int = 2048,
21+
maxExportBatchSize: Int = 512,
22+
willExportCallback: ((inout [ReadableLogRecord]) -> Void)? = nil) {
23+
if scheduleDelay >= 0 {
24+
safeScheduleDelay = scheduleDelay
25+
} else {
26+
print("scheduleDelay (\(scheduleDelay)) < 0, fallback to default 5.")
27+
safeScheduleDelay = 5
28+
}
29+
if exportTimeout >= 0 {
30+
safeExportTimeout = exportTimeout
31+
} else {
32+
print("exportTimeout (\(exportTimeout)) < 0, fallback to default 30.")
33+
safeExportTimeout = 30
34+
}
35+
if maxQueueSize > 0 {
36+
safeMaxQueueSize = maxQueueSize
37+
} else {
38+
print("maxQueueSize (\(maxQueueSize)) <= 0, fallback to default 2048.")
39+
safeMaxQueueSize = 2048
40+
}
41+
if maxExportBatchSize > 0 {
42+
safeMaxExportBatchSize = maxExportBatchSize
43+
} else {
44+
print("maxExportBatchSize (\(maxExportBatchSize)) <= 0, fallback to default 512.")
45+
safeMaxExportBatchSize = 512
46+
}
47+
48+
worker = BatchWorker(logRecordExporter: logRecordExporter,
49+
scheduleDelay: safeScheduleDelay,
50+
exportTimeout: safeExportTimeout,
51+
maxQueueSize: safeMaxQueueSize,
52+
maxExportBatchSize: safeMaxExportBatchSize,
53+
willExportCallback: willExportCallback)
1454

1555
worker.start()
1656
}

Sources/OpenTelemetrySdk/Trace/SpanProcessors/BatchSpanProcessor.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,49 @@ public struct BatchSpanProcessor: SpanProcessor {
2525
String(describing: Self.self)
2626
}
2727

28+
let safeScheduleDelay: TimeInterval
29+
let safeExportTimeout: TimeInterval
30+
let safeMaxQueueSize: Int
31+
let safeMaxExportBatchSize: Int
32+
2833
public init(spanExporter: SpanExporter,
2934
meterProvider: (any StableMeterProvider)? = nil,
3035
scheduleDelay: TimeInterval = 5,
3136
exportTimeout: TimeInterval = 30,
3237
maxQueueSize: Int = 2048,
3338
maxExportBatchSize: Int = 512,
3439
willExportCallback: ((inout [SpanData]) -> Void)? = nil) {
40+
if scheduleDelay >= 0 {
41+
safeScheduleDelay = scheduleDelay
42+
} else {
43+
print("scheduleDelay (\(scheduleDelay)) < 0, fallback to default 5.")
44+
safeScheduleDelay = 5
45+
}
46+
if exportTimeout >= 0 {
47+
safeExportTimeout = exportTimeout
48+
} else {
49+
print("exportTimeout (\(exportTimeout)) < 0, fallback to default 30.")
50+
safeExportTimeout = 30
51+
}
52+
if maxQueueSize > 0 {
53+
safeMaxQueueSize = maxQueueSize
54+
} else {
55+
print("maxQueueSize (\(maxQueueSize)) <= 0, fallback to default 2048.")
56+
safeMaxQueueSize = 2048
57+
}
58+
if maxExportBatchSize > 0 {
59+
safeMaxExportBatchSize = maxExportBatchSize
60+
} else {
61+
print("maxExportBatchSize (\(maxExportBatchSize)) <= 0, fallback to default 512.")
62+
safeMaxExportBatchSize = 512
63+
}
64+
3565
worker = BatchWorker(spanExporter: spanExporter,
3666
meterProvider: meterProvider,
37-
scheduleDelay: scheduleDelay,
38-
exportTimeout: exportTimeout,
39-
maxQueueSize: maxQueueSize,
40-
maxExportBatchSize: maxExportBatchSize,
67+
scheduleDelay: safeScheduleDelay,
68+
exportTimeout: safeExportTimeout,
69+
maxQueueSize: safeMaxQueueSize,
70+
maxExportBatchSize: safeMaxExportBatchSize,
4171
willExportCallback: willExportCallback)
4272
worker.start()
4373
}

Tests/ExportersTests/OpenTelemetryProtocol/SpanAdapterTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class SpanAdapterTests: XCTestCase {
2323
spanContext = SpanContext.create(traceId: traceId, spanId: spanId, traceFlags: TraceFlags(), traceState: tracestate)
2424
}
2525

26-
func testToPRotoResourceSpans() {
26+
func testToProtoResourceSpans() {
2727
let libInfo = InstrumentationScopeInfo(name: "testScope", version: "semver:0.0.1")
2828

2929
let event = RecordEventsReadableSpan.startSpan(context: spanContext, name: "GET /api/endpoint", instrumentationScopeInfo: libInfo, kind: SpanKind.server, parentContext: nil, hasRemoteParent: false, spanLimits: SpanLimits(), spanProcessor: NoopSpanProcessor(), clock: MillisClock(), resource: Resource(), attributes: AttributesDictionary(capacity: 0), links: [], totalRecordedLinks: 0, startTime: Date())

Tests/OpenTelemetrySdkTests/Logs/BatchLogRecordProcessorTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,43 @@ class BatchLogRecordProcessorTests: XCTestCase {
121121
// Interestingly, this will always succeed on macOS even if you intentionally create a strong reference cycle between the BatchWorker and the Thread's closure. I assume either calling cancel or the thread exiting releases the closure which breaks the cycle. This is not the case on Linux where the test will fail as expected.
122122
XCTAssertNil(exporter)
123123
}
124+
125+
func testInitializeWithDefaultParameters() {
126+
let processor = BatchLogRecordProcessor(logRecordExporter: WaitingLogRecordExporter(numberToWaitFor: 0))
127+
XCTAssertEqual(processor.safeScheduleDelay, 5)
128+
XCTAssertEqual(processor.safeExportTimeout, 30)
129+
XCTAssertEqual(processor.safeMaxQueueSize, 2048)
130+
XCTAssertEqual(processor.safeMaxExportBatchSize, 512)
131+
}
132+
133+
func testInitializeWithValidParameters() {
134+
let processor = BatchLogRecordProcessor(
135+
logRecordExporter: WaitingLogRecordExporter(numberToWaitFor: 0),
136+
scheduleDelay: 99,
137+
exportTimeout: 99,
138+
maxQueueSize: 99,
139+
maxExportBatchSize: 99
140+
)
141+
XCTAssertEqual(processor.safeScheduleDelay, 99)
142+
XCTAssertEqual(processor.safeExportTimeout, 99)
143+
XCTAssertEqual(processor.safeMaxQueueSize, 99)
144+
XCTAssertEqual(processor.safeMaxExportBatchSize, 99)
145+
}
146+
147+
func testInitializeWithInvalidParameters() {
148+
let processor = BatchLogRecordProcessor(
149+
logRecordExporter: WaitingLogRecordExporter(numberToWaitFor: 0),
150+
scheduleDelay: -99,
151+
exportTimeout: -99,
152+
maxQueueSize: 0,
153+
maxExportBatchSize: 0
154+
)
155+
// Fallback to default parameters
156+
XCTAssertEqual(processor.safeScheduleDelay, 5)
157+
XCTAssertEqual(processor.safeExportTimeout, 30)
158+
XCTAssertEqual(processor.safeMaxQueueSize, 2048)
159+
XCTAssertEqual(processor.safeMaxExportBatchSize, 512)
160+
}
124161
}
125162

126163
class BlockingLogRecordExporter: LogRecordExporter {

Tests/OpenTelemetrySdkTests/Trace/Export/BatchSpansProcessorTests.swift

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class BatchSpansProcessorTests: XCTestCase {
7070
tracerSdkFactory.addSpanProcessor(BatchSpanProcessor(spanExporter: waitingSpanExporter,
7171
meterProvider: DefaultStableMeterProvider.instance,
7272
scheduleDelay: maxScheduleDelay,
73-
maxQueueSize: 6, maxExportBatchSize: 2)
73+
maxQueueSize: 6,
74+
maxExportBatchSize: 2)
7475
)
7576

7677
let span1 = createSampledEndedSpan(spanName: spanName1)
@@ -247,6 +248,48 @@ class BatchSpansProcessorTests: XCTestCase {
247248
// Interestingly, this will always succeed on macOS even if you intentionally create a strong reference cycle between the BatchWorker and the Thread's closure. I assume either calling cancel or the thread exiting releases the closure which breaks the cycle. This is not the case on Linux where the test will fail as expected.
248249
XCTAssertNil(exporter)
249250
}
251+
252+
func testInitializeWithDefaultParameters() {
253+
let processor = BatchSpanProcessor(
254+
spanExporter: WaitingSpanExporter(numberToWaitFor: 0),
255+
meterProvider: DefaultStableMeterProvider.instance
256+
)
257+
XCTAssertEqual(processor.safeScheduleDelay, 5)
258+
XCTAssertEqual(processor.safeExportTimeout, 30)
259+
XCTAssertEqual(processor.safeMaxQueueSize, 2048)
260+
XCTAssertEqual(processor.safeMaxExportBatchSize, 512)
261+
}
262+
263+
func testInitializeWithValidParameters() {
264+
let processor = BatchSpanProcessor(
265+
spanExporter: WaitingSpanExporter(numberToWaitFor: 0),
266+
meterProvider: DefaultStableMeterProvider.instance,
267+
scheduleDelay: 99,
268+
exportTimeout: 99,
269+
maxQueueSize: 99,
270+
maxExportBatchSize: 99
271+
)
272+
XCTAssertEqual(processor.safeScheduleDelay, 99)
273+
XCTAssertEqual(processor.safeExportTimeout, 99)
274+
XCTAssertEqual(processor.safeMaxQueueSize, 99)
275+
XCTAssertEqual(processor.safeMaxExportBatchSize, 99)
276+
}
277+
278+
func testInitializeWithInvalidParameters() {
279+
let processor = BatchSpanProcessor(
280+
spanExporter: WaitingSpanExporter(numberToWaitFor: 0),
281+
meterProvider: DefaultStableMeterProvider.instance,
282+
scheduleDelay: -99,
283+
exportTimeout: -99,
284+
maxQueueSize: 0,
285+
maxExportBatchSize: 0
286+
)
287+
// Fallback to default parameters
288+
XCTAssertEqual(processor.safeScheduleDelay, 5)
289+
XCTAssertEqual(processor.safeExportTimeout, 30)
290+
XCTAssertEqual(processor.safeMaxQueueSize, 2048)
291+
XCTAssertEqual(processor.safeMaxExportBatchSize, 512)
292+
}
250293
}
251294

252295
class BlockingSpanExporter: SpanExporter {

0 commit comments

Comments
 (0)