1 #include <opentracing/mocktracer/json.h>
2 #include <opentracing/mocktracer/recorder.h>
3 #include <opentracing/string_view.h>
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
) {
37 if ('\x00' <= c && c <= '\x1f') {
39 writer << std::hex << std::setw(4) << std::setfill('0')
40 << static_cast<int>(c);
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
;
53 writer
.setstate(std::ios::failbit
);
56 writer
<< '"' << oss
.str() << '"';
59 static void ToJson(std::ostream
& writer
,
60 const SpanContextData
& span_context_data
) {
62 writer
<< R
"("trace_id
":)";
63 WriteId(writer
, span_context_data
.trace_id
);
66 writer
<< R
"("span_id
":)";
67 WriteId(writer
, span_context_data
.span_id
);
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
);
76 WriteEscapedString(writer
, baggage_item
.second
);
77 if (++baggage_index
< num_baggage
) {
85 static void ToJson(std::ostream
& writer
,
86 const SpanReferenceData
& span_reference_data
) {
88 writer
<< R
"("reference_type
":)";
89 if (span_reference_data
.reference_type
== SpanReferenceType::ChildOfRef
) {
90 writer
<< R
"("CHILD_OF
")";
92 writer
<< R
"("FOLLOWS_FROM
")";
96 writer
<< R
"("trace_id
":)";
97 WriteId(writer
, span_reference_data
.trace_id
);
99 writer
<< R
"("span_id
":)";
100 WriteId(writer
, span_reference_data
.span_id
);
105 static void ToJson(std::ostream
& writer
, const Value
& value
);
108 struct ValueVisitor
{
109 std::ostream
& writer
;
111 void operator()(bool value
) {
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
")";
126 writer
<< R
"("+Inf
")";
133 void operator()(int64_t value
) { writer
<< value
; }
135 void operator()(uint64_t value
) { writer
<< value
; }
137 void operator()(const std::string
& s
) { WriteEscapedString(writer
, s
); }
139 void operator()(std::nullptr_t
) { writer
<< "null"; }
141 void operator()(const char* s
) { WriteEscapedString(writer
, s
); }
143 void operator()(const Values
& values
) {
146 for (const auto& value
: values
) {
147 ToJson(writer
, value
);
148 if (++i
< values
.size()) {
155 void operator()(const Dictionary
& dictionary
) {
158 for (const auto& key_value
: dictionary
) {
159 WriteEscapedString(writer
, key_value
.first
);
161 ToJson(writer
, key_value
.second
);
162 if (++i
< dictionary
.size()) {
169 } // anonymous namespace
171 void ToJson(std::ostream
& writer
, const Value
& value
) {
172 ValueVisitor value_visitor
{writer
};
173 apply_visitor(value_visitor
, value
);
176 template <class Rep
, class Period
>
177 static void ToJson(std::ostream
& writer
,
178 const std::chrono::duration
<Rep
, Period
>& duration
) {
180 std::chrono::duration_cast
<std::chrono::microseconds
>(duration
).count();
184 static void ToJson(std::ostream
& writer
, const LogRecord
& log_record
) {
186 writer
<< R
"("timestamp
":)";
187 ToJson(writer
, log_record
.timestamp
.time_since_epoch());
189 writer
<< R
"("fields
":)";
191 auto num_fields
= log_record
.fields
.size();
192 size_t field_index
= 0;
193 for (auto& field
: log_record
.fields
) {
195 writer
<< R
"("key
":)";
196 WriteEscapedString(writer
, field
.first
);
198 writer
<< R
"("value
":)";
199 ToJson(writer
, field
.second
);
201 if (++field_index
< num_fields
) {
209 static void ToJson(std::ostream
& writer
, const SpanData
& span_data
) {
212 writer
<< R
"("span_context
":)";
213 ToJson(writer
, span_data
.span_context
);
216 writer
<< R
"("references
":)";
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
) {
229 writer
<< R
"("operation_name
":)";
230 WriteEscapedString(writer
, span_data
.operation_name
);
233 writer
<< R
"("start_timestamp
":)";
234 ToJson(writer
, span_data
.start_timestamp
.time_since_epoch());
237 writer
<< R
"("duration
":)";
238 ToJson(writer
, span_data
.duration
);
241 writer
<< R
"("tags
":)";
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
);
248 ToJson(writer
, tag
.second
);
249 if (++tag_index
< num_tags
) {
256 writer
<< R
"("logs
":)";
258 auto num_logs
= span_data
.logs
.size();
259 size_t log_index
= 0;
260 for (auto& log
: span_data
.logs
) {
262 if (++log_index
< num_logs
) {
271 void ToJson(std::ostream
& writer
, const std::vector
<SpanData
>& spans
) {
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
) {
283 } // namespace mocktracer
284 END_OPENTRACING_ABI_NAMESPACE
285 } // namespace opentracing