]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentracing-cpp/mocktracer/src/json.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / opentracing-cpp / mocktracer / src / json.cpp
1 #include <opentracing/mocktracer/json.h>
2 #include <opentracing/mocktracer/recorder.h>
3 #include <opentracing/string_view.h>
4 #include <cmath>
5 #include <iomanip>
6 #include <sstream>
7
8 namespace opentracing {
9 BEGIN_OPENTRACING_ABI_NAMESPACE
10 namespace mocktracer {
11 // The implementation is based off of this answer from StackOverflow:
12 // https://stackoverflow.com/a/33799784
13 static void WriteEscapedString(std::ostream& writer,
14 opentracing::string_view s) {
15 writer << '"';
16 for (char c : s) {
17 switch (c) {
18 case '"':
19 writer << R"(\")";
20 break;
21 case '\\':
22 writer << R"(\\)";
23 break;
24 case '\b':
25 writer << R"(\b)";
26 break;
27 case '\n':
28 writer << R"(\n)";
29 break;
30 case '\r':
31 writer << R"(\r)";
32 break;
33 case '\t':
34 writer << R"(\t)";
35 break;
36 default:
37 if ('\x00' <= c && c <= '\x1f') {
38 writer << R"(\u)";
39 writer << std::hex << std::setw(4) << std::setfill('0')
40 << static_cast<int>(c);
41 } else {
42 writer << c;
43 }
44 }
45 }
46 writer << '"';
47 }
48
49 static void WriteId(std::ostream& writer, uint64_t id) {
50 std::ostringstream oss;
51 oss << std::setfill('0') << std::setw(16) << std::hex << id;
52 if (!oss.good()) {
53 writer.setstate(std::ios::failbit);
54 return;
55 }
56 writer << '"' << oss.str() << '"';
57 }
58
59 static void ToJson(std::ostream& writer,
60 const SpanContextData& span_context_data) {
61 writer << '{';
62 writer << R"("trace_id":)";
63 WriteId(writer, span_context_data.trace_id);
64 writer << ',';
65
66 writer << R"("span_id":)";
67 WriteId(writer, span_context_data.span_id);
68 writer << ',';
69
70 writer << R"("baggage":{)";
71 auto num_baggage = span_context_data.baggage.size();
72 size_t baggage_index = 0;
73 for (auto& baggage_item : span_context_data.baggage) {
74 WriteEscapedString(writer, baggage_item.first);
75 writer << ':';
76 WriteEscapedString(writer, baggage_item.second);
77 if (++baggage_index < num_baggage) {
78 writer << ',';
79 }
80 }
81 writer << '}';
82 writer << '}';
83 }
84
85 static void ToJson(std::ostream& writer,
86 const SpanReferenceData& span_reference_data) {
87 writer << '{';
88 writer << R"("reference_type":)";
89 if (span_reference_data.reference_type == SpanReferenceType::ChildOfRef) {
90 writer << R"("CHILD_OF")";
91 } else {
92 writer << R"("FOLLOWS_FROM")";
93 }
94 writer << ',';
95
96 writer << R"("trace_id":)";
97 WriteId(writer, span_reference_data.trace_id);
98 writer << ',';
99 writer << R"("span_id":)";
100 WriteId(writer, span_reference_data.span_id);
101
102 writer << '}';
103 }
104
105 static void ToJson(std::ostream& writer, const Value& value);
106
107 namespace {
108 struct ValueVisitor {
109 std::ostream& writer;
110
111 void operator()(bool value) {
112 if (value) {
113 writer << "true";
114 } else {
115 writer << "false";
116 }
117 }
118
119 void operator()(double value) {
120 if (std::isnan(value)) {
121 writer << R"("NaN")";
122 } else if (std::isinf(value)) {
123 if (std::signbit(value)) {
124 writer << R"("-Inf")";
125 } else {
126 writer << R"("+Inf")";
127 }
128 } else {
129 writer << value;
130 }
131 }
132
133 void operator()(int64_t value) { writer << value; }
134
135 void operator()(uint64_t value) { writer << value; }
136
137 void operator()(const std::string& s) { WriteEscapedString(writer, s); }
138
139 void operator()(std::nullptr_t) { writer << "null"; }
140
141 void operator()(const char* s) { WriteEscapedString(writer, s); }
142
143 void operator()(const Values& values) {
144 writer << '[';
145 size_t i = 0;
146 for (const auto& value : values) {
147 ToJson(writer, value);
148 if (++i < values.size()) {
149 writer << ',';
150 }
151 }
152 writer << ']';
153 }
154
155 void operator()(const Dictionary& dictionary) {
156 writer << '{';
157 size_t i = 0;
158 for (const auto& key_value : dictionary) {
159 WriteEscapedString(writer, key_value.first);
160 writer << ':';
161 ToJson(writer, key_value.second);
162 if (++i < dictionary.size()) {
163 writer << ',';
164 }
165 }
166 writer << '}';
167 }
168 };
169 } // anonymous namespace
170
171 void ToJson(std::ostream& writer, const Value& value) {
172 ValueVisitor value_visitor{writer};
173 apply_visitor(value_visitor, value);
174 }
175
176 template <class Rep, class Period>
177 static void ToJson(std::ostream& writer,
178 const std::chrono::duration<Rep, Period>& duration) {
179 auto count =
180 std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
181 writer << count;
182 }
183
184 static void ToJson(std::ostream& writer, const LogRecord& log_record) {
185 writer << '{';
186 writer << R"("timestamp":)";
187 ToJson(writer, log_record.timestamp.time_since_epoch());
188 writer << ',';
189 writer << R"("fields":)";
190 writer << '[';
191 auto num_fields = log_record.fields.size();
192 size_t field_index = 0;
193 for (auto& field : log_record.fields) {
194 writer << '{';
195 writer << R"("key":)";
196 WriteEscapedString(writer, field.first);
197 writer << ',';
198 writer << R"("value":)";
199 ToJson(writer, field.second);
200 writer << '}';
201 if (++field_index < num_fields) {
202 writer << ',';
203 }
204 }
205 writer << ']';
206 writer << '}';
207 }
208
209 static void ToJson(std::ostream& writer, const SpanData& span_data) {
210 writer << '{';
211
212 writer << R"("span_context":)";
213 ToJson(writer, span_data.span_context);
214 writer << ',';
215
216 writer << R"("references":)";
217 writer << '[';
218 auto num_references = span_data.references.size();
219 size_t reference_index = 0;
220 for (auto& reference : span_data.references) {
221 ToJson(writer, reference);
222 if (++reference_index < num_references) {
223 writer << ',';
224 }
225 }
226 writer << ']';
227 writer << ',';
228
229 writer << R"("operation_name":)";
230 WriteEscapedString(writer, span_data.operation_name);
231 writer << ',';
232
233 writer << R"("start_timestamp":)";
234 ToJson(writer, span_data.start_timestamp.time_since_epoch());
235 writer << ',';
236
237 writer << R"("duration":)";
238 ToJson(writer, span_data.duration);
239 writer << ',';
240
241 writer << R"("tags":)";
242 writer << '{';
243 auto num_tags = span_data.tags.size();
244 size_t tag_index = 0;
245 for (auto& tag : span_data.tags) {
246 WriteEscapedString(writer, tag.first);
247 writer << ':';
248 ToJson(writer, tag.second);
249 if (++tag_index < num_tags) {
250 writer << ',';
251 }
252 }
253 writer << '}';
254 writer << ',';
255
256 writer << R"("logs":)";
257 writer << '[';
258 auto num_logs = span_data.logs.size();
259 size_t log_index = 0;
260 for (auto& log : span_data.logs) {
261 ToJson(writer, log);
262 if (++log_index < num_logs) {
263 writer << ',';
264 }
265 }
266 writer << ']';
267
268 writer << '}';
269 }
270
271 void ToJson(std::ostream& writer, const std::vector<SpanData>& spans) {
272 writer << '[';
273 auto num_spans = spans.size();
274 size_t span_index = 0;
275 for (auto& span_data : spans) {
276 ToJson(writer, span_data);
277 if (++span_index < num_spans) {
278 writer << ',';
279 }
280 }
281 writer << ']';
282 }
283 } // namespace mocktracer
284 END_OPENTRACING_ABI_NAMESPACE
285 } // namespace opentracing