Skip to content

Commit 0024c8f

Browse files
docs(sdks): Batch Processor
This PR migrates the SpansAggregator RFC to the develop docs. As logs also have to use some aggregation, we renamed the SpansAggregator to BatchProcessor so it can be used with any type of telemetry data.
1 parent 949763e commit 0024c8f

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
title: Batch Processor
3+
---
4+
5+
<Alert level="warning">
6+
🚧 This document is work in progress.
7+
</Alert>
8+
9+
<Alert>
10+
This document uses key words such as "MUST", "SHOULD", and "MAY" as defined in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) to indicate requirement levels.
11+
</Alert>
12+
13+
When an SDK implements span streaming or logs, it MUST batch multiple spans and logs into envelopes to reduce the number of HTTP. SDKs MUST implement a BatchProcessor to achieve this. The BatchProcessor keeps finished spans and logs in memory and batches them together in envelopes. It uses a combination of timeout and [weight](#weight) to decide when to batch its spans and logs into an envelope and send it to Sentry.
14+
The SDK SHOULD use the BatchProcessor in the client because the transport SHOULD NOT be aware of spans or logs. The SDK MAY deviate from this approach. The SDK MUST call filtering and sampling before adding spans or logs to the BatchProcessor. This concept is similar to [OpenTelemetry's Batch Processors](https://github.com/open-telemetry/opentelemetry-collector/blob/main/processor/batchprocessor/README.md).
15+
16+
The BatchProcessor starts a timeout of `x` seconds when the SDK adds the first span or log. When the timeout exceeds, the BatchProcessor sends all spans or logs no matter how many items it contains. The BatchProcessor also sends all items after the SDK captures spans or logs with weight more than `y`. When the BatchProcessor sends all spans or logs, it resets its timeout and removes all spans and logs in the BatchProcessor. When a span and its children have more weight than the max BatchProcessor weight `y`, the BatchProcessor MUST send the spans or logs together in one envelope directly to Sentry.
17+
18+
The specification is written in the [Gherkin syntax](https://cucumber.io/docs/gherkin/reference/) and uses `x = 10` seconds for the timeout and `y = 1024 * 1024` for the maximum batch byte size in the BatchProcessor. SDKs MAY use different values for `x` and `y` depending on their needs. If the timeout is set to `0`, then the SDK sends every span and log immediately. Initially, we don't plan adding options for these variables, but we can make them configurable if required in the future, similar to the option `maxCacheItems`. The specification uses spans as an example, but the same applies to logs or any other future telemetry data.
19+
20+
21+
```Gherkin
22+
Scenario: No spans in BatchProcessor 1 span added
23+
Given no spans in the BatchProcessor
24+
When the SDK adds 1 span
25+
Then the SDK adds this span to the BatchProcessor
26+
And starts a timeout of 10 seconds
27+
And doesn't send the span to Sentry
28+
29+
Scenario: Span added before timeout exceeds
30+
Given 1 span in the BatchProcessor
31+
Given 9.9 seconds pass
32+
When the SDK adds 1 span
33+
Then the SDK adds this span to the BatchProcessor
34+
And doesn't reset the timeout
35+
And doesn't send the spans in the BatchProcessor to Sentry
36+
37+
Scenario: Spans with size of y - 1 added, timeout exceeds
38+
Given spans with size of y - 1 in the BatchProcessor
39+
When the timeout exceeds
40+
Then the SDK adds all the spans to one envelope
41+
And sends them to Sentry
42+
And resets the timeout
43+
And clears the BatchProcessor
44+
45+
Scenario: Spans with size of y added within 9.9 seconds
46+
Given no spans in the BatchProcessor
47+
When the SDK adds spans with a weight of y within 9.9 seconds
48+
Then the SDK puts all spans into one envelope
49+
And sends the envelope to Sentry
50+
And resets the timeout
51+
And clears the BatchProcessor
52+
53+
Scenario: 1 span added app crashes
54+
Given 1 span in the SpansAggregator
55+
When the SDK detects a crash
56+
Then the SDK does nothing with the BatchProcessor
57+
And loses the spans in the BatchProcessor
58+
59+
Scenario: Unfinished spans
60+
Given no span is in the SpansAggregator
61+
When the SDK starts a span but doesn't finish it
62+
Then the SpansAggregator is empty
63+
64+
Scenario: Spans in SpansAggregator, span with children
65+
Given spans with a size of y - 1 in the BatchProcessor
66+
When the SDK finishes a span with one child
67+
Then the SDK puts the spans with a size of y - 1 already in the BatchProcessor into an envelope
68+
And sends the envelope to Sentry.
69+
And stores the span with its child into the BatchProcessor
70+
And resets the timeout
71+
72+
Scenario: Span with more children than max BatchProcessor weight
73+
Given one span A is in the BatchProcessor
74+
When the SDK starts a span B
75+
And starts child spans with a size of y for span B
76+
When the SDK finishes the span B and all it's children
77+
Then the SDK directly puts all spans of span B into one envelope
78+
And sends the envelope to Sentry.
79+
And doesn't store the spans of span B in the BatchProcessor
80+
And keeps the existing span A in the BatchProcessor
81+
And doesn't reset the timeout
82+
83+
Scenario: Timeout set to 0 span without children
84+
Given the timeout is set to 0
85+
When the SDK finishes one span without any children
86+
Then the SDK puts the span into one one envelope
87+
And sends the envelope to Sentry.
88+
89+
Scenario: Timeout set to 0 span with children
90+
Given the timeout is set to 0
91+
When the SDK finishes one span with children of a weight of 100
92+
Then the SDK puts the span with the children into one envelope
93+
And sends the envelope to Sentry.
94+
95+
Scenario: Timeout set to 0 spans without children
96+
Given the timeout is set to 0
97+
When the SDK finishes two spans without any children
98+
Then the SDK puts every span into one envelope
99+
And sends both envelopes to Sentry.
100+
101+
```
102+
103+
## Weight
104+
105+
The SDK MUST implement a way to calculate the weight of a span or a log to manage the BatchProcessor's memory footprint. Depending on the serialization strategy, the SDK MAY either serialize the span or log into bytes and count these or serialize the span or log and recursively count the number of elements in the dictionary. Every key in a dictionary and every element in an array add a weight of one. For a detailed explanation of how to count the weight, see the example below. As serialization is expensive, the BatchProcessor SHOULD keep track of the serialized spans and logs and directly pass them to the envelope item to avoid serializing multiple times.
106+
107+
```JSON
108+
{
109+
// All simple properties count as 1 so in total 12
110+
"timestamp": 1705031078.623853,
111+
"start_timestamp": 1705031078.337715,
112+
"description": "ExtraViewController full display",
113+
"op": "ui.load.full_display",
114+
"span_id": "794d0cba0ac64235",
115+
"parent_span_id": "45054abc6ded413a",
116+
"trace_id": "65880cfc084f4bd5ab3abc7d598b3c14",
117+
"status": "ok",
118+
"origin": "manual.ui.time_to_display",
119+
"hash": "a925395473cfe97d",
120+
"sampled": true,
121+
"type": "trace",
122+
123+
// The data object has 5 simple properties, which count as 5
124+
// and one list with 3 elements counting as 3
125+
"data": {
126+
"frames.frozen": 0,
127+
"frames.slow": 1,
128+
"frames.total": 1,
129+
"thread.id": 259,
130+
"thread.name": "main",
131+
"list" : [1, 2, 3]
132+
},
133+
134+
// Tags count as 2
135+
"sentry_tags": {
136+
"environment": "ui-tests",
137+
"main_thread": "true",
138+
},
139+
140+
// The weight is
141+
// 12 (simple properties)
142+
// 8 (data)
143+
// 2 (tags)
144+
// = 22
145+
}
146+
```

0 commit comments

Comments
 (0)