]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/docs/cpp-ostream-exporter-design.md
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / docs / cpp-ostream-exporter-design.md
CommitLineData
1e59de90
TL
1# OStreamExporter Design
2
3In strongly typed languages typically there will be 2 separate `Exporter`
4interfaces, one that accepts spans from a tracer (SpanExporter) and one that
5accepts metrics (MetricsExporter)
6
7The exporter SHOULD be called with a checkpoint of finished (possibly
8dimensionally reduced) export records. Most configuration decisions have been
9made before the exporter is invoked, including which instruments are enabled,
10which concrete aggregator types to use, and which dimensions to aggregate by.
11
12## Use Cases
13
14Monitoring and alerting systems commonly use the data provided through metric
15events or tracers, after applying various aggregations and converting into
16various exposition format. After getting the data, the systems need to be able
17to see the data. The OStreamExporter will be used here to print data through an
18ostream, this is seen as a simple exporter where the user doesn’t have the
19burden of implementing or setting up a protocol dependent exporter.
20
21The OStreamExporter will also be used as a debugging tool for the Metrics
22API/SDK and Tracing API/SDK which are currently work in progress projects. This
23exporter will allow contributors to easily diagnose problems when working on the
24project.
25
26## Push vs Pull Exporter
27
28There are two different versions of exporters: Push and Pull. A Push Exporter
29pushes the data outwards towards a system, in the case of the OStreamExporter it
30sends its data into an ostream. A Pull Exporter exposes data to some endpoint
31for another system to grab the data.
32
33The OStreamExporter will only be implementing a Push Exporter framework.
34
35## Design Tenets
36
37* Reliability
38 * The Exporter should be reliable; data exported should always be accounted
39 for. The data will either all be successfully exported to the destination
40 server, or in the case of failure, the data is dropped. `Export` will always
41 return failure or success to notify the user of the result.
42 * Thread Safety
43 * The OStreamExporter can be called simultaneously, however we do not handle
44 this in the Exporter. Synchronization should be done at a lower level.
45* Scalability
46 * The Exporter must be able to operate on sizeable systems with predictable
47 overhead growth. A key requirement of this is that the library does not
48 consume unbounded memory resource.
49* Security
50 * OStreamExporter should only be used for development and testing purpose,
51 where security and privacy is less a concern as it doesn't communicate to
52 external systems.
53
54## SpanExporter
55
56`Span Exporter` defines the interface that protocol-specific exporters must
57implement so that they can be plugged into OpenTelemetry SDK and support sending
58of telemetry data.
59
60The goal of the interface is to minimize burden of implementation for
61protocol-dependent telemetry exporters. The protocol exporter is expected to be
62primarily a simple telemetry data encoder and transmitter.
63
64The SpanExporter is called through the SpanProcessor, which passes finished
65spans to the configured SpanExporter, as soon as they are finished. The
66SpanProcessor also shutdown the exporter by the Shutdown function within the
67SpanProcessor.
68
69<!-- [//]: # ![SDK Data Path](./images/SpanDataPath.png) -->
70
71The specification states: exporter must support two functions: Export and
72Shutdown.
73
74### SpanExporter.Export(span of recordables)
75
76Exports a batch of telemetry data. Protocol exporters that will implement this
77function are typically expected to serialize and transmit the data to the
78destination.
79
80Export() must not block indefinitely. We can rely on printing to an ostream is
81reasonably performant and doesn't block.
82
83The specification states: Any retry logic that is required by the exporter is
84the responsibility of the exporter. The default SDK SHOULD NOT implement retry
85logic, as the required logic is likely to depend heavily on the specific
86protocol and backend the spans are being sent to.
87
88### SpanExporter.Shutdown()
89
90Shuts down the exporter. Called when SDK is shut down. This is an opportunity
91for exporter to do any cleanup required.
92
93`Shutdown` should be called only once for each `Exporter` instance. After the
94call to `Shutdown` subsequent calls to `Export` are not allowed and should
95return a `Failure` result.
96
97`Shutdown` should not block indefinitely (e.g. if it attempts to flush the data
98and the destination is unavailable). Language library authors can decide if they
99want to make the shutdown timeout configurable.
100
101In the OStreamExporter there is no cleanup to be done, so there is no need to
102use the timeout within the `Shutdown` function as it will never be blocking.
103
104```cpp
105class StreamSpanExporter final : public sdktrace::SpanExporter
106{
107
108private:
109 bool isShutdown = false;
110
111public:
112 /*
113 This function should never be called concurrently.
114 */
115 sdktrace::ExportResult Export(
116 const nostd::span<std::unique_ptr<sdktrace::Recordable>> &spans) noexcept
117 {
118
119 if(isShutdown)
120 {
121 return sdktrace::ExportResult::kFailure;
122 }
123
124 for (auto &recordable : spans)
125 {
126 auto span = std::unique_ptr<sdktrace::SpanData>(
127 static_cast<sdktrace::SpanData *>(recordable.release()));
128
129 if (span != nullptr)
130 {
131 char trace_id[32] = {0};
132 char span_id[16] = {0};
133 char parent_span_id[16] = {0};
134
135 span->GetTraceId().ToLowerBase16(trace_id);
136 span->GetSpanId().ToLowerBase16(span_id);
137 span->GetParentSpanId().ToLowerBase16(parent_span_id);
138
139 std::cout << "{"
140 << "\n name : " << span->GetName()
141 << "\n trace_id : " << std::string(trace_id, 32)
142 << "\n span_id : " << std::string(span_id, 16)
143 << "\n parent_span_id: " << std::string(parent_span_id, 16)
144 << "\n start : " << span->GetStartTime().time_since_epoch().count()
145 << "\n duration : " << span->GetDuration().count()
146 << "\n description : " << span->GetDescription()
147 << "\n status : " << span->GetStatus()
148 << "\n attributes : " << span->GetAttributes() << "\n}"
149 << "\n";
150 }
151
152 }
153
154 return sdktrace::ExportResult::kSuccess;
155 }
156
157 bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept
158 {
159 isShutdown = true;
160 return true;
161 }
162};
163```
164
165## MetricsExporter
166
167The MetricsExporter has the same requirements as the SpanExporter. The exporter
168will go through the different metric instruments and send the value stored in
169their aggregators to an ostream, for simplicity only Counter is shown here, but
170all aggregators will be implemented. Counter, Gauge, MinMaxSumCount, Sketch,
171Histogram and Exact Aggregators will be supported.
172
173Exports a batch of telemetry data. Protocol exporters that will implement this
174function are typically expected to serialize and transmit the data to the
175destination.
176
177<!-- [//]: # ![SDK Data Path](./images/DataPath.png) -->
178
179### MetricsExporter.Export(batch of Records)
180
181Export() must not block indefinitely. We can rely on printing to an ostream is
182reasonably performant and doesn't block.
183
184The specification states: Any retry logic that is required by the exporter is
185the responsibility of the exporter. The default SDK SHOULD NOT implement retry
186logic, as the required logic is likely to depend heavily on the specific
187protocol and backend the spans are being sent to.
188
189The MetricsExporter is called through the Controller in the SDK data path. The
190exporter will either be called on a regular interval in the case of a push
191controller or through manual calls in the case of a pull controller.
192
193### MetricsExporter.Shutdown()
194
195Shutdown() is currently not required for the OStreamMetricsExporter.
196
197```cpp
198class StreamMetricsExporter final : public sdkmeter::MetricsExporter
199{
200
201private:
202 bool isShutdown = false;
203
204public:
205 sdkmeter::ExportResult Export(
206 const Collection<Record> batch) noexcept
207 {
208
209 for (auto &metric : batch)
210 {
211
212 if (metric != nullptr)
213 {
214
215 if(metric.AggregationType == CounterAggregator) {
216 std::cout << "{"
217 << "\n name : " << metric->GetName()
218 << "\n labels : " << metric->GetLabels()
219 << "\n sum : " << metric->Value[0] << "\n}"
220 }
221 else if(metric.AggregationType == SketchAggregator) {
222 // Similarly print data
223 }
224 // Other Aggreagators will also be handeled,
225 // Counter, Gauge, MinMaxSumCount, Sketch, Histogram,
226 // and Exact Aggreagtors
227 }
228
229 }
230
231 return sdkmeter::ExportResult::kSuccess;
232 }
233
234};
235```
236
237## Test Strategy / Plan
238
239In this project, we will follow the TDD rules, and write enough functional unit
240tests before implementing production code. We will design exhaustive test cases
241for normal and abnormal inputs, and tests for edge cases.
242
243In terms of test framework, as is described in the [Metrics API/SDK design
244document](https://quip-amazon.com/UBXyAuqRzkIj/Metrics-APISDK-C-Design-Document-External),
245the OStreamExporter will use [Googletest](https://github.com/google/googletest)
246framework because it provides test coverage reports, and it also integrate code
247coverage tools such as [codecov.io](http://codecov.io/) in the project. There
248are already many reference tests such as MockExporter tests written in
249GoogleTest, making it a clear choice to stick with it as the testing framework.
250A required coverage target of 90% will help to ensure that our code is fully
251tested.
252
253## Future Features
254
255* Serialize data to another format (json)
256
257## Contributors
258
259* Hudson Humphries