clang-tidy: add Chrome-inspired checks
[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:
cd9adb8b 106 trace_environment_visitor() = default;
da9dd521 107
cd9adb8b 108 void visit(const lst::environment_field<int64_t>& field) override
da9dd521
JG
109 {
110 _visit(field);
111 }
112
cd9adb8b 113 void visit(const lst::environment_field<const char *>& field) override
da9dd521
JG
114 {
115 _visit(field);
116 }
117
118 /* Only call once. */
c22ded12 119 json::json move_fragment()
da9dd521
JG
120 {
121 return std::move(_environment);
122 }
123
124private:
125 template <class FieldType>
126 void _visit(const FieldType& field)
127 {
128 _environment[field.name] = field.value;
129 }
130
131 json::json _environment;
132};
133
134class field_visitor : public lttng::sessiond::trace::field_visitor,
135 public lttng::sessiond::trace::type_visitor {
136public:
cd9adb8b 137 field_visitor() = default;
da9dd521
JG
138
139 /* Only call once. */
c22ded12 140 json::json move_fragment()
da9dd521
JG
141 {
142 return std::move(_fragment);
143 }
144
145private:
cd9adb8b 146 void visit(const lst::field& field) final
da9dd521
JG
147 {
148 field_visitor field_type_visitor;
149 field.get_type().accept(field_type_visitor);
150
151 _fragment["name"] = field.name;
c22ded12 152 _fragment["field-class"] = field_type_visitor.move_fragment();
da9dd521
JG
153 }
154
cd9adb8b 155 void visit(const lst::integer_type& type) final
da9dd521
JG
156 {
157 _fragment["type"] = type.signedness_ == lst::integer_type::signedness::SIGNED ?
28ab034a
JG
158 "fixed-length-signed-integer" :
159 "fixed-length-unsigned-integer";
da9dd521
JG
160 _fragment["length"] = type.size;
161 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
162 "big-endian" :
163 "little-endian";
da9dd521
JG
164 _fragment["alignment"] = type.alignment;
165 _fragment["preferred-display-base"] = (unsigned int) type.base_;
166
167 if (type.roles_.size() > 0) {
168 json::json role_array = json::json::array();
169
170 for (const auto role : type.roles_) {
171 role_array.push_back(get_role_name(role));
172 }
173
174 _fragment["roles"] = std::move(role_array);
175 }
176 }
177
cd9adb8b 178 void visit(const lst::floating_point_type& type) final
da9dd521
JG
179 {
180 _fragment["type"] = "fixed-length-floating-point-number";
181 _fragment["length"] = type.exponent_digits + type.mantissa_digits;
182 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
183 "big-endian" :
184 "little-endian";
da9dd521
JG
185 _fragment["alignment"] = type.alignment;
186 }
187
188 template <class EnumerationType>
189 void visit_enumeration(const EnumerationType& type)
190 {
28ab034a
JG
191 _fragment["type"] =
192 std::is_signed<
193 typename EnumerationType::mapping::range_t::range_integer_t>::value ?
194 "fixed-length-signed-enumeration" :
195 "fixed-length-unsigned-enumeration";
da9dd521
JG
196 _fragment["length"] = type.size;
197 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
28ab034a
JG
198 "big-endian" :
199 "little-endian";
da9dd521
JG
200 _fragment["alignment"] = type.alignment;
201 _fragment["preferred-display-base"] = (unsigned int) type.base_;
202
203 if (type.roles_.size() > 0) {
204 if (std::is_signed<typename EnumerationType::mapping::range_t::
28ab034a
JG
205 range_integer_t>::value) {
206 LTTNG_THROW_ERROR(
207 fmt::format("Failed to serialize {}: unexpected role",
208 _fragment["type"]));
da9dd521
JG
209 }
210
211 auto role_array = json::json::array();
212
213 for (const auto role : type.roles_) {
214 role_array.push_back(get_role_name(role));
215 }
216
217 _fragment["roles"] = std::move(role_array);
218 }
219
220 if (type.mappings_->size() < 1) {
221 LTTNG_THROW_ERROR(fmt::format(
28ab034a
JG
222 "Failed to serialize {}: enumeration must have at least one mapping",
223 _fragment["type"]));
da9dd521
JG
224 }
225
226 json::json mappings_value;
28ab034a
JG
227 for (const auto& mapping : *type.mappings_) {
228 mappings_value[mapping.name] = { { mapping.range.begin,
229 mapping.range.end } };
da9dd521
JG
230 }
231
232 _fragment["mappings"] = std::move(mappings_value);
233 }
234
cd9adb8b 235 void visit(const lst::signed_enumeration_type& type) final
da9dd521
JG
236 {
237 visit_enumeration(type);
238 }
239
cd9adb8b 240 void visit(const lst::unsigned_enumeration_type& type) final
da9dd521
JG
241 {
242 visit_enumeration(type);
243 }
244
cd9adb8b 245 void visit(const lst::static_length_array_type& type) final
da9dd521
JG
246 {
247 _fragment["type"] = "static-length-array";
248
249 ::ctf2::field_visitor element_visitor;
250 type.element_type->accept(element_visitor);
c22ded12 251 _fragment["element-field-class"] = element_visitor.move_fragment();
da9dd521
JG
252
253 if (type.alignment != 0) {
254 _fragment["minimum-alignment"] = type.alignment;
255 }
256
257 _fragment["length"] = type.length;
258 }
259
cd9adb8b 260 void visit(const lst::dynamic_length_array_type& type) final
da9dd521
JG
261 {
262 _fragment["type"] = "dynamic-length-array";
263
264 ::ctf2::field_visitor element_visitor;
265 type.element_type->accept(element_visitor);
c22ded12 266 _fragment["element-field-class"] = element_visitor.move_fragment();
da9dd521
JG
267
268 if (type.alignment != 0) {
269 _fragment["minimum-alignment"] = type.alignment;
270 }
271
272 _fragment["length-field-location"] = to_json(type.length_field_location);
273 }
274
cd9adb8b 275 void visit(const lst::static_length_blob_type& type) final
da9dd521
JG
276 {
277 _fragment["type"] = "static-length-blob";
278 _fragment["length"] = type.length_bytes;
279
280 if (type.roles_.size() > 0) {
281 auto role_array = json::json::array();
282
283 for (const auto role : type.roles_) {
284 role_array.push_back(get_role_name(role));
285 }
286
287 _fragment["roles"] = std::move(role_array);
288 }
289 }
290
cd9adb8b 291 void visit(const lst::dynamic_length_blob_type& type) final
da9dd521
JG
292 {
293 _fragment["type"] = "dynamic-length-blob";
294 _fragment["length-field-location"] = to_json(type.length_field_location);
295 }
296
cd9adb8b 297 void visit(const lst::null_terminated_string_type& type __attribute__((unused))) final
da9dd521
JG
298 {
299 _fragment["type"] = "null-terminated-string";
300 }
301
cd9adb8b 302 void visit(const lst::structure_type& type) final
da9dd521
JG
303 {
304 _fragment["type"] = "structure";
305
306 if (type.alignment != 0) {
307 _fragment["minimum-alignment"] = type.alignment;
308 }
309
310 auto member_classes_value = json::json::array();
28ab034a 311 for (const auto& field : type.fields_) {
da9dd521
JG
312 ::ctf2::field_visitor member_visitor;
313 json::json member_class;
314
315 field->accept(member_visitor);
c22ded12 316 member_classes_value.emplace_back(member_visitor.move_fragment());
da9dd521
JG
317 }
318
319 _fragment["member-classes"] = std::move(member_classes_value);
320 }
321
322 template <class MappingIntegerType>
323 void visit_variant(const lst::variant_type<MappingIntegerType>& type)
324 {
325 _fragment["type"] = "variant";
326 _fragment["selector-field-location"] = to_json(type.selector_field_location);
327
328 auto options_value = json::json::array();
329 for (const auto& option : type.choices_) {
330 ::ctf2::field_visitor option_visitor;
331 json::json member_class;
332
333 /* TODO missing selector-field-range. */
28ab034a
JG
334 member_class["selector-field-ranges"] = { { option.first.range.begin,
335 option.first.range.end } };
da9dd521 336 option.second->accept(option_visitor);
c22ded12 337 member_class["field-class"] = option_visitor.move_fragment();
da9dd521
JG
338 options_value.emplace_back(std::move(member_class));
339 }
340
341 _fragment["options"] = std::move(options_value);
342 }
343
cd9adb8b 344 void visit(const lst::variant_type<int64_t>& type) final
da9dd521
JG
345 {
346 visit_variant(type);
347 }
348
cd9adb8b 349 void visit(const lst::variant_type<uint64_t>& type) final
da9dd521
JG
350 {
351 visit_variant(type);
352 }
353
cd9adb8b 354 void visit(const lst::static_length_string_type& type) final
da9dd521
JG
355 {
356 _fragment["type"] = "static-length-string";
357 _fragment["length"] = type.length;
358 }
359
cd9adb8b 360 void visit(const lst::dynamic_length_string_type& type) final
da9dd521
JG
361 {
362 _fragment["type"] = "dynamic-length-string";
363 _fragment["length-field-location"] = to_json(type.length_field_location);
364 }
365
366 json::json _fragment;
367};
368} /* namespace ctf2 */
369
370}; /* namespace */
371
4f2da8b8 372lsc::trace_class_visitor::trace_class_visitor(
28ab034a 373 lsc::append_metadata_fragment_function append_metadata_fragment) :
cd9adb8b 374 _append_metadata_fragment(std::move(append_metadata_fragment))
da9dd521
JG
375{
376}
377
378void lsc::trace_class_visitor::visit(const lst::trace_class& trace_class)
379{
380 {
381 auto preamble_fragment = make_json_fragment("preamble");
382
383 preamble_fragment["version"] = 2;
384 preamble_fragment["uuid"] = trace_class.uuid;
385 append_metadata_fragment(preamble_fragment);
386 }
387
388 auto trace_class_fragment = make_json_fragment("trace-class");
389
390 ::ctf2::trace_environment_visitor environment_visitor;
391 trace_class.accept(environment_visitor);
c22ded12 392 trace_class_fragment["environment"] = environment_visitor.move_fragment();
da9dd521 393
4bcf2294 394 const auto packet_header = trace_class.packet_header();
da9dd521
JG
395 if (packet_header) {
396 ::ctf2::field_visitor field_visitor;
397
398 packet_header->accept(field_visitor);
c22ded12 399 trace_class_fragment["packet-header-field-class"] = field_visitor.move_fragment();
da9dd521
JG
400 }
401
402 append_metadata_fragment(trace_class_fragment);
403}
404
405void lsc::trace_class_visitor::visit(const lst::clock_class& clock_class)
406{
28ab034a 407 auto clock_class_fragment = make_json_fragment("clock-class");
da9dd521
JG
408
409 json::json offset;
28ab034a
JG
410 offset.update({ { "seconds", clock_class.offset / clock_class.frequency },
411 { "cycles", clock_class.offset % clock_class.frequency } });
da9dd521 412
28ab034a
JG
413 clock_class_fragment.update({ { "name", clock_class.name },
414 { "description", clock_class.description },
415 { "frequency", clock_class.frequency },
416 { "offset", std::move(offset) } });
da9dd521
JG
417
418 if (clock_class.uuid) {
419 clock_class_fragment["uuid"] = *clock_class.uuid;
420 }
421
422 append_metadata_fragment(clock_class_fragment);
423}
424
425void lsc::trace_class_visitor::visit(const lst::stream_class& stream_class)
426{
427 auto stream_class_fragment = make_json_fragment("data-stream-class");
428
429 stream_class_fragment["id"] = stream_class.id;
430 if (stream_class.default_clock_class_name) {
431 stream_class_fragment["default-clock-class-name"] =
28ab034a 432 *stream_class.default_clock_class_name;
da9dd521
JG
433 }
434
4bcf2294 435 const auto packet_context = stream_class.packet_context();
da9dd521
JG
436 if (packet_context) {
437 ::ctf2::field_visitor visitor;
438
439 packet_context->accept(visitor);
c22ded12 440 stream_class_fragment["packet-context-field-class"] = visitor.move_fragment();
da9dd521
JG
441 }
442
4bcf2294 443 const auto event_header = stream_class.event_header();
da9dd521
JG
444 if (event_header) {
445 ::ctf2::field_visitor visitor;
446
447 event_header->accept(visitor);
28ab034a 448 stream_class_fragment["event-record-header-field-class"] = visitor.move_fragment();
da9dd521
JG
449 }
450
4bcf2294 451 const auto event_context = stream_class.event_context();
da9dd521
JG
452 if (event_context) {
453 ::ctf2::field_visitor visitor;
454
455 event_context->accept(visitor);
456 stream_class_fragment["event-record-common-context-field-class"] =
28ab034a 457 visitor.move_fragment();
da9dd521
JG
458 }
459
460 append_metadata_fragment(stream_class_fragment);
461}
462
463void lsc::trace_class_visitor::visit(const lst::event_class& event_class)
464{
465 auto event_class_fragment = make_json_fragment("event-record-class");
466
467 event_class_fragment["id"] = event_class.id;
468 event_class_fragment["data-stream-class-id"] = event_class.stream_class_id;
469 event_class_fragment["name"] = event_class.name;
470
471 if (event_class.payload) {
472 ::ctf2::field_visitor visitor;
473
474 event_class.payload->accept(visitor);
c22ded12 475 event_class_fragment["payload-field-class"] = visitor.move_fragment();
da9dd521
JG
476 }
477
478 append_metadata_fragment(event_class_fragment);
479}
480
481void lsc::trace_class_visitor::append_metadata_fragment(const nlohmann::json& fragment) const
482{
483 _append_metadata_fragment(record_separator + fragment.dump(spaces_per_indent).c_str());
484}
This page took 0.042934 seconds and 4 git commands to generate.