Clean-up: sessiond: use empty() instead of comparing size to 0
[lttng-tools.git] / src / bin / lttng-sessiond / ctf2-trace-class-visitor.cpp
CommitLineData
da9dd521
JG
1/*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2022 Simon Marchi <simon.marchi@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
da9dd521 9#include "clock-class.hpp"
28ab034a 10#include "ctf2-trace-class-visitor.hpp"
da9dd521
JG
11
12#include <common/exception.hpp>
13#include <common/format.hpp>
14
15#include <vendor/nlohmann/json.hpp>
16
17#include <algorithm>
cd9adb8b 18#include <utility>
da9dd521
JG
19
20namespace lsc = lttng::sessiond::ctf2;
21namespace lst = lttng::sessiond::trace;
22
23namespace json = nlohmann;
24
25namespace {
26const unsigned int spaces_per_indent = 2;
27const std::string record_separator = "\x1e";
28
29json::json make_json_fragment(const char *type)
30{
28ab034a 31 return { { "type", type } };
da9dd521
JG
32}
33
28ab034a 34json::json to_json(const lst::field_location& location)
da9dd521
JG
35{
36 json::json location_array;
37
38 switch (location.root_) {
39 case lst::field_location::root::PACKET_HEADER:
40 location_array.push_back("packet-header");
41 break;
42 case lst::field_location::root::PACKET_CONTEXT:
43 location_array.push_back("packet-context");
44 break;
45 case lst::field_location::root::EVENT_RECORD_HEADER:
46 location_array.push_back("event-record-header");
47 break;
48 case lst::field_location::root::EVENT_RECORD_COMMON_CONTEXT:
49 location_array.push_back("event-record-common-context");
50 break;
51 case lst::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT:
52 location_array.push_back("event-record-specific-context");
53 break;
54 case lst::field_location::root::EVENT_RECORD_PAYLOAD:
55 location_array.push_back("event-record-payload");
56 break;
57 }
58
28ab034a
JG
59 std::copy(location.elements_.begin(),
60 location.elements_.end(),
61 std::back_inserter(location_array));
da9dd521
JG
62 return location_array;
63}
64
65const char *get_role_name(lst::integer_type::role role)
66{
67 switch (role) {
68 case lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP:
69 return "default-clock-timestamp";
70 case lst::integer_type::role::DATA_STREAM_CLASS_ID:
71 return "data-stream-class-id";
72 case lst::integer_type::role::DATA_STREAM_ID:
73 return "data-stream-id";
74 case lst::integer_type::role::PACKET_MAGIC_NUMBER:
75 return "packet-magic-number";
76 case lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT:
77 return "discarded-event-record-counter-snapshot";
78 case lst::integer_type::role::PACKET_CONTENT_LENGTH:
79 return "packet-content-length";
80 case lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP:
81 return "packet-end-default-clock-timestamp";
82 case lst::integer_type::role::PACKET_SEQUENCE_NUMBER:
83 return "packet-sequence-number";
84 case lst::integer_type::role::PACKET_TOTAL_LENGTH:
85 return "packet-total-length";
86 case lst::integer_type::role::EVENT_RECORD_CLASS_ID:
87 return "event-record-class-id";
88 default:
89 abort();
90 }
91}
92
93const char *get_role_name(lst::static_length_blob_type::role role)
94{
95 switch (role) {
96 case lst::static_length_blob_type::role::METADATA_STREAM_UUID:
97 return "metadata-stream-uuid";
98 default:
99 abort();
100 }
101}
102
103namespace ctf2 {
104class trace_environment_visitor : public lst::trace_class_environment_visitor {
105public:
5c7248cd
JG
106 trace_environment_visitor() = default; /* NOLINT clang-tidy 14 identifies this as a move
107 constructor. */
da9dd521 108
cd9adb8b 109 void visit(const lst::environment_field<int64_t>& field) override
da9dd521
JG
110 {
111 _visit(field);
112 }
113
cd9adb8b 114 void visit(const lst::environment_field<const char *>& field) override
da9dd521
JG
115 {
116 _visit(field);
117 }
118
119 /* Only call once. */
c22ded12 120 json::json move_fragment()
da9dd521
JG
121 {
122 return std::move(_environment);
123 }
124
125private:
126 template <class FieldType>
127 void _visit(const FieldType& field)
128 {
129 _environment[field.name] = field.value;
130 }
131
132 json::json _environment;
133};
134
135class field_visitor : public lttng::sessiond::trace::field_visitor,
136 public lttng::sessiond::trace::type_visitor {
137public:
5c7248cd 138 field_visitor() = default; /* NOLINT clang-tidy 14 identifies this as a move constructor. */
da9dd521
JG
139
140 /* Only call once. */
c22ded12 141 json::json move_fragment()
da9dd521
JG
142 {
143 return std::move(_fragment);
144 }
145
146private:
cd9adb8b 147 void visit(const lst::field& field) final
da9dd521
JG
148 {
149 field_visitor field_type_visitor;
150 field.get_type().accept(field_type_visitor);
151
152 _fragment["name"] = field.name;
c22ded12 153 _fragment["field-class"] = field_type_visitor.move_fragment();
da9dd521
JG
154 }
155
cd9adb8b 156 void visit(const lst::integer_type& type) final
da9dd521
JG
157 {
158 _fragment["type"] = type.signedness_ == lst::integer_type::signedness::SIGNED ?
28ab034a
JG
159 "fixed-length-signed-integer" :
160 "fixed-length-unsigned-integer";
da9dd521
JG
161 _fragment["length"] = type.size;
162 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
163 "big-endian" :
164 "little-endian";
da9dd521
JG
165 _fragment["alignment"] = type.alignment;
166 _fragment["preferred-display-base"] = (unsigned int) type.base_;
167
20c4b46a 168 if (!type.roles_.empty()) {
da9dd521
JG
169 json::json role_array = json::json::array();
170
171 for (const auto role : type.roles_) {
172 role_array.push_back(get_role_name(role));
173 }
174
175 _fragment["roles"] = std::move(role_array);
176 }
177 }
178
cd9adb8b 179 void visit(const lst::floating_point_type& type) final
da9dd521
JG
180 {
181 _fragment["type"] = "fixed-length-floating-point-number";
182 _fragment["length"] = type.exponent_digits + type.mantissa_digits;
183 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
184 "big-endian" :
185 "little-endian";
da9dd521
JG
186 _fragment["alignment"] = type.alignment;
187 }
188
189 template <class EnumerationType>
190 void visit_enumeration(const EnumerationType& type)
191 {
28ab034a
JG
192 _fragment["type"] =
193 std::is_signed<
194 typename EnumerationType::mapping::range_t::range_integer_t>::value ?
195 "fixed-length-signed-enumeration" :
196 "fixed-length-unsigned-enumeration";
da9dd521
JG
197 _fragment["length"] = type.size;
198 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
199 "big-endian" :
200 "little-endian";
da9dd521
JG
201 _fragment["alignment"] = type.alignment;
202 _fragment["preferred-display-base"] = (unsigned int) type.base_;
203
20c4b46a 204 if (!type.roles_.empty()) {
da9dd521 205 if (std::is_signed<typename EnumerationType::mapping::range_t::
28ab034a
JG
206 range_integer_t>::value) {
207 LTTNG_THROW_ERROR(
f9a41357
JG
208 lttng::format("Failed to serialize {}: unexpected role",
209 _fragment["type"]));
da9dd521
JG
210 }
211
212 auto role_array = json::json::array();
213
214 for (const auto role : type.roles_) {
215 role_array.push_back(get_role_name(role));
216 }
217
218 _fragment["roles"] = std::move(role_array);
219 }
220
221 if (type.mappings_->size() < 1) {
f9a41357 222 LTTNG_THROW_ERROR(lttng::format(
28ab034a
JG
223 "Failed to serialize {}: enumeration must have at least one mapping",
224 _fragment["type"]));
da9dd521
JG
225 }
226
227 json::json mappings_value;
28ab034a
JG
228 for (const auto& mapping : *type.mappings_) {
229 mappings_value[mapping.name] = { { mapping.range.begin,
230 mapping.range.end } };
da9dd521
JG
231 }
232
233 _fragment["mappings"] = std::move(mappings_value);
234 }
235
cd9adb8b 236 void visit(const lst::signed_enumeration_type& type) final
da9dd521
JG
237 {
238 visit_enumeration(type);
239 }
240
cd9adb8b 241 void visit(const lst::unsigned_enumeration_type& type) final
da9dd521
JG
242 {
243 visit_enumeration(type);
244 }
245
cd9adb8b 246 void visit(const lst::static_length_array_type& type) final
da9dd521
JG
247 {
248 _fragment["type"] = "static-length-array";
249
250 ::ctf2::field_visitor element_visitor;
251 type.element_type->accept(element_visitor);
c22ded12 252 _fragment["element-field-class"] = element_visitor.move_fragment();
da9dd521
JG
253
254 if (type.alignment != 0) {
255 _fragment["minimum-alignment"] = type.alignment;
256 }
257
258 _fragment["length"] = type.length;
259 }
260
cd9adb8b 261 void visit(const lst::dynamic_length_array_type& type) final
da9dd521
JG
262 {
263 _fragment["type"] = "dynamic-length-array";
264
265 ::ctf2::field_visitor element_visitor;
266 type.element_type->accept(element_visitor);
c22ded12 267 _fragment["element-field-class"] = element_visitor.move_fragment();
da9dd521
JG
268
269 if (type.alignment != 0) {
270 _fragment["minimum-alignment"] = type.alignment;
271 }
272
273 _fragment["length-field-location"] = to_json(type.length_field_location);
274 }
275
cd9adb8b 276 void visit(const lst::static_length_blob_type& type) final
da9dd521
JG
277 {
278 _fragment["type"] = "static-length-blob";
279 _fragment["length"] = type.length_bytes;
280
20c4b46a 281 if (!type.roles_.empty()) {
da9dd521
JG
282 auto role_array = json::json::array();
283
284 for (const auto role : type.roles_) {
285 role_array.push_back(get_role_name(role));
286 }
287
288 _fragment["roles"] = std::move(role_array);
289 }
290 }
291
cd9adb8b 292 void visit(const lst::dynamic_length_blob_type& type) final
da9dd521
JG
293 {
294 _fragment["type"] = "dynamic-length-blob";
295 _fragment["length-field-location"] = to_json(type.length_field_location);
296 }
297
cd9adb8b 298 void visit(const lst::null_terminated_string_type& type __attribute__((unused))) final
da9dd521
JG
299 {
300 _fragment["type"] = "null-terminated-string";
301 }
302
cd9adb8b 303 void visit(const lst::structure_type& type) final
da9dd521
JG
304 {
305 _fragment["type"] = "structure";
306
307 if (type.alignment != 0) {
308 _fragment["minimum-alignment"] = type.alignment;
309 }
310
311 auto member_classes_value = json::json::array();
28ab034a 312 for (const auto& field : type.fields_) {
da9dd521
JG
313 ::ctf2::field_visitor member_visitor;
314 json::json member_class;
315
316 field->accept(member_visitor);
c22ded12 317 member_classes_value.emplace_back(member_visitor.move_fragment());
da9dd521
JG
318 }
319
320 _fragment["member-classes"] = std::move(member_classes_value);
321 }
322
323 template <class MappingIntegerType>
324 void visit_variant(const lst::variant_type<MappingIntegerType>& type)
325 {
326 _fragment["type"] = "variant";
327 _fragment["selector-field-location"] = to_json(type.selector_field_location);
328
329 auto options_value = json::json::array();
330 for (const auto& option : type.choices_) {
331 ::ctf2::field_visitor option_visitor;
332 json::json member_class;
333
334 /* TODO missing selector-field-range. */
28ab034a
JG
335 member_class["selector-field-ranges"] = { { option.first.range.begin,
336 option.first.range.end } };
da9dd521 337 option.second->accept(option_visitor);
c22ded12 338 member_class["field-class"] = option_visitor.move_fragment();
da9dd521
JG
339 options_value.emplace_back(std::move(member_class));
340 }
341
342 _fragment["options"] = std::move(options_value);
343 }
344
cd9adb8b 345 void visit(const lst::variant_type<int64_t>& type) final
da9dd521
JG
346 {
347 visit_variant(type);
348 }
349
cd9adb8b 350 void visit(const lst::variant_type<uint64_t>& type) final
da9dd521
JG
351 {
352 visit_variant(type);
353 }
354
cd9adb8b 355 void visit(const lst::static_length_string_type& type) final
da9dd521
JG
356 {
357 _fragment["type"] = "static-length-string";
358 _fragment["length"] = type.length;
359 }
360
cd9adb8b 361 void visit(const lst::dynamic_length_string_type& type) final
da9dd521
JG
362 {
363 _fragment["type"] = "dynamic-length-string";
364 _fragment["length-field-location"] = to_json(type.length_field_location);
365 }
366
367 json::json _fragment;
368};
369} /* namespace ctf2 */
370
371}; /* namespace */
372
4f2da8b8 373lsc::trace_class_visitor::trace_class_visitor(
28ab034a 374 lsc::append_metadata_fragment_function append_metadata_fragment) :
cd9adb8b 375 _append_metadata_fragment(std::move(append_metadata_fragment))
da9dd521
JG
376{
377}
378
379void lsc::trace_class_visitor::visit(const lst::trace_class& trace_class)
380{
381 {
382 auto preamble_fragment = make_json_fragment("preamble");
383
384 preamble_fragment["version"] = 2;
385 preamble_fragment["uuid"] = trace_class.uuid;
386 append_metadata_fragment(preamble_fragment);
387 }
388
389 auto trace_class_fragment = make_json_fragment("trace-class");
390
391 ::ctf2::trace_environment_visitor environment_visitor;
392 trace_class.accept(environment_visitor);
c22ded12 393 trace_class_fragment["environment"] = environment_visitor.move_fragment();
da9dd521 394
4bcf2294 395 const auto packet_header = trace_class.packet_header();
da9dd521
JG
396 if (packet_header) {
397 ::ctf2::field_visitor field_visitor;
398
399 packet_header->accept(field_visitor);
c22ded12 400 trace_class_fragment["packet-header-field-class"] = field_visitor.move_fragment();
da9dd521
JG
401 }
402
403 append_metadata_fragment(trace_class_fragment);
404}
405
406void lsc::trace_class_visitor::visit(const lst::clock_class& clock_class)
407{
28ab034a 408 auto clock_class_fragment = make_json_fragment("clock-class");
da9dd521
JG
409
410 json::json offset;
28ab034a
JG
411 offset.update({ { "seconds", clock_class.offset / clock_class.frequency },
412 { "cycles", clock_class.offset % clock_class.frequency } });
da9dd521 413
28ab034a
JG
414 clock_class_fragment.update({ { "name", clock_class.name },
415 { "description", clock_class.description },
416 { "frequency", clock_class.frequency },
417 { "offset", std::move(offset) } });
da9dd521
JG
418
419 if (clock_class.uuid) {
420 clock_class_fragment["uuid"] = *clock_class.uuid;
421 }
422
423 append_metadata_fragment(clock_class_fragment);
424}
425
426void lsc::trace_class_visitor::visit(const lst::stream_class& stream_class)
427{
428 auto stream_class_fragment = make_json_fragment("data-stream-class");
429
430 stream_class_fragment["id"] = stream_class.id;
431 if (stream_class.default_clock_class_name) {
432 stream_class_fragment["default-clock-class-name"] =
28ab034a 433 *stream_class.default_clock_class_name;
da9dd521
JG
434 }
435
4bcf2294 436 const auto packet_context = stream_class.packet_context();
da9dd521
JG
437 if (packet_context) {
438 ::ctf2::field_visitor visitor;
439
440 packet_context->accept(visitor);
c22ded12 441 stream_class_fragment["packet-context-field-class"] = visitor.move_fragment();
da9dd521
JG
442 }
443
4bcf2294 444 const auto event_header = stream_class.event_header();
da9dd521
JG
445 if (event_header) {
446 ::ctf2::field_visitor visitor;
447
448 event_header->accept(visitor);
28ab034a 449 stream_class_fragment["event-record-header-field-class"] = visitor.move_fragment();
da9dd521
JG
450 }
451
4bcf2294 452 const auto event_context = stream_class.event_context();
da9dd521
JG
453 if (event_context) {
454 ::ctf2::field_visitor visitor;
455
456 event_context->accept(visitor);
457 stream_class_fragment["event-record-common-context-field-class"] =
28ab034a 458 visitor.move_fragment();
da9dd521
JG
459 }
460
461 append_metadata_fragment(stream_class_fragment);
462}
463
464void lsc::trace_class_visitor::visit(const lst::event_class& event_class)
465{
466 auto event_class_fragment = make_json_fragment("event-record-class");
467
468 event_class_fragment["id"] = event_class.id;
469 event_class_fragment["data-stream-class-id"] = event_class.stream_class_id;
470 event_class_fragment["name"] = event_class.name;
471
472 if (event_class.payload) {
473 ::ctf2::field_visitor visitor;
474
475 event_class.payload->accept(visitor);
c22ded12 476 event_class_fragment["payload-field-class"] = visitor.move_fragment();
da9dd521
JG
477 }
478
479 append_metadata_fragment(event_class_fragment);
480}
481
482void lsc::trace_class_visitor::append_metadata_fragment(const nlohmann::json& fragment) const
483{
484 _append_metadata_fragment(record_separator + fragment.dump(spaces_per_indent).c_str());
485}
This page took 0.054072 seconds and 4 git commands to generate.