common: session load: use session descriptor for session creation
[lttng-tools.git] / src / bin / lttng-sessiond / tsdl-trace-class-visitor.cpp
CommitLineData
d7bfb9b0
JG
1/*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
d7bfb9b0 8#include "tsdl-trace-class-visitor.hpp"
24ed18f2 9#include "clock-class.hpp"
d7bfb9b0
JG
10
11#include <common/exception.hpp>
12#include <common/format.hpp>
13#include <common/make-unique.hpp>
14#include <common/uuid.hpp>
15
24ed18f2
JG
16#include <vendor/optional.hpp>
17
18#include <algorithm>
d7bfb9b0 19#include <array>
d7bfb9b0 20#include <locale>
2f35b2f5
JG
21#include <queue>
22#include <set>
24ed18f2 23#include <stack>
d7bfb9b0
JG
24
25namespace lst = lttng::sessiond::trace;
26namespace tsdl = lttng::sessiond::tsdl;
27
28namespace {
29const auto ctf_spec_major = 1;
30const auto ctf_spec_minor = 8;
31
2f35b2f5
JG
32/*
33 * Although the CTF v1.8 specification recommends ignoring any leading underscore, Some readers,
34 * such as Babeltrace 1.x, expect special identifiers without a prepended underscore.
35 */
24ed18f2
JG
36const std::set<std::string> safe_tsdl_identifiers = {
37 "stream_id",
38 "packet_size",
39 "content_size",
40 "id",
41 "v",
42 "timestamp",
43 "events_discarded",
44 "packet_seq_num",
45 "timestamp_begin",
46 "timestamp_end",
47 "cpu_id",
48 "magic",
49 "uuid",
50 "stream_instance_id"
51};
2f35b2f5 52
d7bfb9b0
JG
53/*
54 * A previous implementation always prepended '_' to the identifiers in order to
55 * side-step the problem of escaping TSDL keywords and ensuring identifiers
56 * started with an alphabetic character.
57 *
58 * Changing this behaviour to a smarter algorithm would break readers that have
59 * come to expect this initial underscore.
60 */
61std::string escape_tsdl_identifier(const std::string& original_identifier)
62{
63 if (original_identifier.size() == 0) {
64 LTTNG_THROW_ERROR("Invalid 0-length identifier used in trace description");
65 }
66
2f35b2f5
JG
67 if (safe_tsdl_identifiers.find(original_identifier) != safe_tsdl_identifiers.end()) {
68 return original_identifier;
69 }
70
d7bfb9b0
JG
71 std::string new_identifier;
72 /* Optimisticly assume most identifiers are valid and allocate the same length. */
73 new_identifier.reserve(original_identifier.size());
74 new_identifier = "_";
75
76 /* Replace illegal characters by '_'. */
77 std::locale c_locale{"C"};
78 for (const auto current_char : original_identifier) {
79 if (!std::isalnum(current_char, c_locale) && current_char != '_') {
80 new_identifier += '_';
81 } else {
82 new_identifier += current_char;
83 }
84 }
85
86 return new_identifier;
87}
88
89std::string escape_tsdl_env_string_value(const std::string& original_string)
90{
91 std::string escaped_string;
92
93 escaped_string.reserve(original_string.size());
94
95 for (const auto c : original_string) {
96 switch (c) {
97 case '\n':
98 escaped_string += "\\n";
99 break;
100 case '\\':
101 escaped_string += "\\\\";
102 break;
103 case '"':
104 escaped_string += "\"";
105 break;
106 default:
107 escaped_string += c;
108 break;
109 }
110 }
111
112 return escaped_string;
113}
114
115class tsdl_field_visitor : public lttng::sessiond::trace::field_visitor,
116 public lttng::sessiond::trace::type_visitor {
117public:
24ed18f2
JG
118 tsdl_field_visitor(const lst::abi& abi,
119 unsigned int indentation_level,
120 const nonstd::optional<std::string>& in_default_clock_class_name =
121 nonstd::nullopt) :
122 _indentation_level{indentation_level},
123 _trace_abi{abi},
124 _bypass_identifier_escape{false},
125 _default_clock_class_name{in_default_clock_class_name ?
126 in_default_clock_class_name->c_str() :
127 nullptr}
d7bfb9b0
JG
128 {
129 }
130
da9dd521
JG
131 /* Only call once. */
132 std::string transfer_description()
d7bfb9b0 133 {
da9dd521 134 return std::move(_description);
d7bfb9b0
JG
135 }
136
137private:
138 virtual void visit(const lst::field& field) override final
139 {
140 /*
141 * Hack: keep the name of the field being visited since
142 * the tracers can express sequences, variants, and arrays with an alignment
143 * constraint, which is not expressible in TSDL. To work around this limitation, an
144 * empty structure declaration is inserted when needed to express the aligment
145 * constraint. The name of this structure is generated using the field's name.
146 */
24ed18f2
JG
147 _current_field_name.push(_bypass_identifier_escape ?
148 field.name : escape_tsdl_identifier(field.name));
d7bfb9b0 149
45110cdd 150 field.get_type().accept(*this);
d7bfb9b0 151 _description += " ";
24ed18f2
JG
152 _description += _current_field_name.top();
153 _current_field_name.pop();
d7bfb9b0
JG
154
155 /*
156 * Some types requires suffixes to be appended (e.g. the length of arrays
157 * and sequences, the mappings of enumerations).
158 */
159 while (!_type_suffixes.empty()) {
160 _description += _type_suffixes.front();
161 _type_suffixes.pop();
162 }
163
164 _description += ";";
d7bfb9b0
JG
165 }
166
167 virtual void visit(const lst::integer_type& type) override final
168 {
169 _description += "integer { ";
170
171 /* Mandatory properties (no defaults). */
172 _description += fmt::format("size = {size}; align = {alignment};",
173 fmt::arg("size", type.size),
174 fmt::arg("alignment", type.alignment));
175
176 /* Defaults to unsigned. */
65cd3c0c 177 if (type.signedness_ == lst::integer_type::signedness::SIGNED) {
d7bfb9b0
JG
178 _description += " signed = true;";
179 }
180
181 /* Defaults to 10. */
65cd3c0c 182 if (type.base_ != lst::integer_type::base::DECIMAL) {
d7bfb9b0
JG
183 unsigned int base;
184
65cd3c0c 185 switch (type.base_) {
d7bfb9b0
JG
186 case lst::integer_type::base::BINARY:
187 base = 2;
188 break;
189 case lst::integer_type::base::OCTAL:
190 base = 8;
191 break;
192 case lst::integer_type::base::HEXADECIMAL:
193 base = 16;
194 break;
195 default:
196 LTTNG_THROW_ERROR(fmt::format(
197 "Unexpected base encountered while serializing integer type to TSDL: base = {}",
65cd3c0c 198 (int) type.base_));
d7bfb9b0
JG
199 }
200
201 _description += fmt::format(" base = {};", base);
202 }
203
204 /* Defaults to the trace's native byte order. */
205 if (type.byte_order != _trace_abi.byte_order) {
206 const auto byte_order_str = type.byte_order == lst::byte_order::BIG_ENDIAN_ ? "be" : "le";
207
208 _description += fmt::format(" byte_order = {};", byte_order_str);
209 }
210
211 if (_current_integer_encoding_override) {
212 const char *encoding_str;
213
214 switch (*_current_integer_encoding_override) {
215 case lst::string_type::encoding::ASCII:
216 encoding_str = "ASCII";
217 break;
218 case lst::string_type::encoding::UTF8:
219 encoding_str = "UTF8";
220 break;
221 default:
222 LTTNG_THROW_ERROR(fmt::format(
223 "Unexpected encoding encountered while serializing integer type to TSDL: encoding = {}",
224 (int) *_current_integer_encoding_override));
225 }
226
227 _description += fmt::format(" encoding = {};", encoding_str);
228 _current_integer_encoding_override.reset();
229 }
230
24ed18f2
JG
231 if (std::find(type.roles_.begin(), type.roles_.end(),
232 lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP) !=
233 type.roles_.end() ||
234 std::find(type.roles_.begin(), type.roles_.end(),
235 lst::integer_type::role::
236 PACKET_END_DEFAULT_CLOCK_TIMESTAMP) !=
237 type.roles_.end()) {
238 LTTNG_ASSERT(_default_clock_class_name);
239 _description += fmt::format(
240 " map = clock.{}.value;", _default_clock_class_name);
241 }
242
d7bfb9b0
JG
243 _description += " }";
244 }
245
246 virtual void visit(const lst::floating_point_type& type) override final
247 {
248 _description += fmt::format(
249 "floating_point {{ align = {alignment}; mant_dig = {mantissa_digits}; exp_dig = {exponent_digits};",
250 fmt::arg("alignment", type.alignment),
251 fmt::arg("mantissa_digits", type.mantissa_digits),
252 fmt::arg("exponent_digits", type.exponent_digits));
253
254 /* Defaults to the trace's native byte order. */
255 if (type.byte_order != _trace_abi.byte_order) {
256 const auto byte_order_str = type.byte_order == lst::byte_order::BIG_ENDIAN_ ? "be" : "le";
257
258 _description += fmt::format(" byte_order = {};", byte_order_str);
259 }
260
261 _description += " }";
262 }
263
264 template <class EnumerationType>
265 void visit_enumeration(const EnumerationType& type)
266 {
267 /* name follows, when applicable. */
268 _description += "enum : ";
269
270 tsdl_field_visitor integer_visitor{_trace_abi, _indentation_level};
271
272 integer_visitor.visit(static_cast<const lst::integer_type&>(type));
da9dd521 273 _description += integer_visitor.transfer_description() + " {\n";
d7bfb9b0
JG
274
275 const auto mappings_indentation_level = _indentation_level + 1;
276
277 bool first_mapping = true;
da9dd521 278 for (const auto& mapping : *type.mappings_) {
d7bfb9b0
JG
279 if (!first_mapping) {
280 _description += ",\n";
281 }
282
283 _description.resize(_description.size() + mappings_indentation_level, '\t');
da9dd521 284 if (mapping.range.begin == mapping.range.end) {
d7bfb9b0
JG
285 _description += fmt::format(
286 "\"{mapping_name}\" = {mapping_value}",
287 fmt::arg("mapping_name", mapping.name),
da9dd521 288 fmt::arg("mapping_value", mapping.range.begin));
d7bfb9b0
JG
289 } else {
290 _description += fmt::format(
291 "\"{mapping_name}\" = {mapping_range_begin} ... {mapping_range_end}",
292 fmt::arg("mapping_name", mapping.name),
293 fmt::arg("mapping_range_begin",
da9dd521
JG
294 mapping.range.begin),
295 fmt::arg("mapping_range_end", mapping.range.end));
d7bfb9b0
JG
296 }
297
298 first_mapping = false;
299 }
300
301 _description += "\n";
302 _description.resize(_description.size() + _indentation_level, '\t');
303 _description += "}";
304 }
305
306 virtual void visit(const lst::signed_enumeration_type& type) override final
307 {
308 visit_enumeration(type);
309 }
310
311 virtual void visit(const lst::unsigned_enumeration_type& type) override final
312 {
313 visit_enumeration(type);
314 }
315
316 virtual void visit(const lst::static_length_array_type& type) override final
317 {
318 if (type.alignment != 0) {
24ed18f2 319 LTTNG_ASSERT(_current_field_name.size() > 0);
d7bfb9b0
JG
320 _description += fmt::format(
321 "struct {{ }} align({alignment}) {field_name}_padding;\n",
322 fmt::arg("alignment", type.alignment),
24ed18f2 323 fmt::arg("field_name", _current_field_name.top()));
d7bfb9b0
JG
324 _description.resize(_description.size() + _indentation_level, '\t');
325 }
326
327 type.element_type->accept(*this);
328 _type_suffixes.emplace(fmt::format("[{}]", type.length));
329 }
330
331 virtual void visit(const lst::dynamic_length_array_type& type) override final
332 {
333 if (type.alignment != 0) {
334 /*
335 * Note that this doesn't support nested sequences. For
336 * the moment, tracers can't express those. However, we
337 * could wrap nested sequences in structures, which
338 * would allow us to express alignment constraints.
339 */
24ed18f2 340 LTTNG_ASSERT(_current_field_name.size() > 0);
d7bfb9b0
JG
341 _description += fmt::format(
342 "struct {{ }} align({alignment}) {field_name}_padding;\n",
343 fmt::arg("alignment", type.alignment),
24ed18f2 344 fmt::arg("field_name", _current_field_name.top()));
d7bfb9b0
JG
345 _description.resize(_description.size() + _indentation_level, '\t');
346 }
347
348 type.element_type->accept(*this);
24ed18f2
JG
349 _type_suffixes.emplace(fmt::format("[{}]",
350 _bypass_identifier_escape ?
eda1aa02
JG
351 *(type.length_field_location.elements_.end() - 1) :
352 escape_tsdl_identifier(*(type.length_field_location.elements_.end() - 1))));
d7bfb9b0
JG
353 }
354
e7360180
JG
355 virtual void visit(const lst::static_length_blob_type& type) override final
356 {
357 /* This type doesn't exist in CTF 1.x, express it as a static length array of uint8_t. */
358 std::unique_ptr<const lst::type> uint8_element = lttng::make_unique<lst::integer_type>(8,
359 _trace_abi.byte_order, 8, lst::integer_type::signedness::UNSIGNED,
360 lst::integer_type::base::HEXADECIMAL);
361 const auto array = lttng::make_unique<lst::static_length_array_type>(
362 type.alignment, std::move(uint8_element), type.length_bytes);
363
364 visit(*array);
365 }
366
367 virtual void visit(const lst::dynamic_length_blob_type& type) override final
368 {
369 /* This type doesn't exist in CTF 1.x, express it as a dynamic length array of uint8_t. */
370 std::unique_ptr<const lst::type> uint8_element = lttng::make_unique<lst::integer_type>(0,
371 _trace_abi.byte_order, 8, lst::integer_type::signedness::UNSIGNED,
372 lst::integer_type::base::HEXADECIMAL);
373 const auto array = lttng::make_unique<lst::dynamic_length_array_type>(
eda1aa02 374 type.alignment, std::move(uint8_element), type.length_field_location);
e7360180
JG
375
376 visit(*array);
377 }
378
d7bfb9b0
JG
379 virtual void visit(const lst::null_terminated_string_type& type) override final
380 {
24ed18f2 381 /* Defaults to UTF-8. */
65cd3c0c 382 if (type.encoding_ == lst::null_terminated_string_type::encoding::ASCII) {
d7bfb9b0
JG
383 _description += "string { encoding = ASCII }";
384 } else {
385 _description += "string";
386 }
387 }
388
389 virtual void visit(const lst::structure_type& type) override final
390 {
391 _indentation_level++;
392 _description += "struct {";
393
24ed18f2
JG
394 const auto previous_bypass_identifier_escape = _bypass_identifier_escape;
395 _bypass_identifier_escape = false;
da9dd521 396 for (const auto& field : type.fields_) {
d7bfb9b0
JG
397 _description += "\n";
398 _description.resize(_description.size() + _indentation_level, '\t');
399 field->accept(*this);
400 }
401
24ed18f2
JG
402 _bypass_identifier_escape = previous_bypass_identifier_escape;
403
d7bfb9b0 404 _indentation_level--;
da9dd521 405 if (type.fields_.size() != 0) {
d7bfb9b0
JG
406 _description += "\n";
407 _description.resize(_description.size() + _indentation_level, '\t');
408 }
409
24ed18f2 410 _description += "}";
d7bfb9b0
JG
411 }
412
45110cdd
JG
413 template <class MappingIntegerType>
414 void visit_variant(const lst::variant_type<MappingIntegerType>& type)
d7bfb9b0
JG
415 {
416 if (type.alignment != 0) {
24ed18f2 417 LTTNG_ASSERT(_current_field_name.size() > 0);
d7bfb9b0
JG
418 _description += fmt::format(
419 "struct {{ }} align({alignment}) {field_name}_padding;\n",
420 fmt::arg("alignment", type.alignment),
24ed18f2 421 fmt::arg("field_name", _current_field_name.top()));
d7bfb9b0
JG
422 _description.resize(_description.size() + _indentation_level, '\t');
423 }
424
425 _indentation_level++;
24ed18f2
JG
426 _description += fmt::format("variant <{}> {{\n",
427 _bypass_identifier_escape ?
eda1aa02
JG
428 *(type.selector_field_location.elements_.end() - 1) :
429 escape_tsdl_identifier(*(type.selector_field_location.elements_.end() - 1)));
d7bfb9b0 430
24ed18f2
JG
431 /*
432 * The CTF 1.8 specification only recommends that implementations ignore
433 * leading underscores in field names. Both babeltrace 1 and 2 expect the
434 * variant choice and enumeration mapping name to match perfectly. Given that we
435 * don't have access to the tag in this context, we have to assume they match.
436 */
437 const auto previous_bypass_identifier_escape = _bypass_identifier_escape;
438 _bypass_identifier_escape = true;
da9dd521
JG
439 for (const auto& field : type.choices_
440) {
d7bfb9b0 441 _description.resize(_description.size() + _indentation_level, '\t');
45110cdd
JG
442 field.second->accept(*this);
443 _description += fmt::format(" {};\n", field.first.name);
d7bfb9b0
JG
444 }
445
24ed18f2
JG
446 _bypass_identifier_escape = previous_bypass_identifier_escape;
447
d7bfb9b0 448 _indentation_level--;
24ed18f2
JG
449 _description.resize(_description.size() + _indentation_level, '\t');
450 _description += "}";
d7bfb9b0
JG
451 }
452
45110cdd
JG
453 virtual void visit(const lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>& type) override final
454 {
455 visit_variant(type);
456 }
457
458 virtual void visit(const lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) override final
459 {
460 visit_variant(type);
461 }
462
d7bfb9b0
JG
463 lst::type::cuptr create_character_type(enum lst::string_type::encoding encoding)
464 {
465 _current_integer_encoding_override = encoding;
466 return lttng::make_unique<lst::integer_type>(8, _trace_abi.byte_order, 8,
467 lst::integer_type::signedness::UNSIGNED,
468 lst::integer_type::base::DECIMAL);
469 }
470
471 virtual void visit(const lst::static_length_string_type& type) override final
472 {
473 /*
474 * TSDL expresses static-length strings as arrays of 8-bit integer with
475 * an encoding specified.
476 */
477 const auto char_array = lttng::make_unique<lst::static_length_array_type>(
65cd3c0c 478 type.alignment, create_character_type(type.encoding_), type.length);
d7bfb9b0
JG
479
480 visit(*char_array);
481 }
482
483 virtual void visit(const lst::dynamic_length_string_type& type) override final
484 {
485 /*
486 * TSDL expresses dynamic-length strings as arrays of 8-bit integer with
487 * an encoding specified.
488 */
489 const auto char_sequence = lttng::make_unique<lst::dynamic_length_array_type>(
65cd3c0c 490 type.alignment, create_character_type(type.encoding_),
eda1aa02 491 type.length_field_location);
d7bfb9b0
JG
492
493 visit(*char_sequence);
494 }
495
24ed18f2 496 std::stack<std::string> _current_field_name;
d7bfb9b0
JG
497 /*
498 * Encoding to specify for the next serialized integer type.
499 * Since the integer_type does not allow an encoding to be specified (it is a TSDL-specific
500 * concept), this attribute is used when expressing static or dynamic length strings as
501 * arrays/sequences of bytes with an encoding.
502 */
503 nonstd::optional<enum lst::string_type::encoding> _current_integer_encoding_override;
504
505 unsigned int _indentation_level;
506 const lst::abi& _trace_abi;
507
508 std::queue<std::string> _type_suffixes;
509
510 /* Description in TSDL format. */
511 std::string _description;
24ed18f2
JG
512
513 bool _bypass_identifier_escape;
514 const char *_default_clock_class_name;
d7bfb9b0 515};
da9dd521
JG
516
517class tsdl_trace_environment_visitor : public lst::trace_class_environment_visitor {
518public:
519 tsdl_trace_environment_visitor() : _environment{"env {\n"}
520 {
521 }
522
523 virtual void visit(const lst::environment_field<int64_t>& field) override
524 {
525 _environment += fmt::format(" {} = {};\n", field.name, field.value);
526 }
527
528 virtual void visit(const lst::environment_field<const char *>& field) override
529 {
530 _environment += fmt::format(" {} = \"{}\";\n", field.name,
531 escape_tsdl_env_string_value(field.value));
532 }
533
534 /* Only call once. */
535 std::string transfer_description()
536 {
537 _environment += "};\n\n";
538 return std::move(_environment);
539 }
540
541private:
542 std::string _environment;
543};
d7bfb9b0
JG
544} /* namespace */
545
546tsdl::trace_class_visitor::trace_class_visitor(const lst::abi& trace_abi,
547 tsdl::append_metadata_fragment_function append_metadata_fragment) :
24ed18f2
JG
548 _trace_abi{trace_abi},
549 _append_metadata_fragment(append_metadata_fragment)
d7bfb9b0
JG
550{
551}
552
553void tsdl::trace_class_visitor::append_metadata_fragment(const std::string& fragment) const
554{
555 _append_metadata_fragment(fragment);
556}
557
558void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::trace_class& trace_class)
559{
24ed18f2
JG
560 tsdl_field_visitor packet_header_visitor(trace_class.abi, 1);
561
562 trace_class.get_packet_header()->accept(packet_header_visitor);
563
d7bfb9b0
JG
564 /* Declare type aliases, trace class, and packet header. */
565 auto trace_class_tsdl = fmt::format(
566 "/* CTF {ctf_major}.{ctf_minor} */\n\n"
d7bfb9b0
JG
567 "trace {{\n"
568 " major = {ctf_major};\n"
569 " minor = {ctf_minor};\n"
570 " uuid = \"{uuid}\";\n"
571 " byte_order = {byte_order};\n"
24ed18f2 572 " packet.header := {packet_header_layout};\n"
d7bfb9b0
JG
573 "}};\n\n",
574 fmt::arg("ctf_major", ctf_spec_major),
575 fmt::arg("ctf_minor", ctf_spec_minor),
576 fmt::arg("uint8_t_alignment", trace_class.abi.uint8_t_alignment),
577 fmt::arg("uint16_t_alignment", trace_class.abi.uint16_t_alignment),
578 fmt::arg("uint32_t_alignment", trace_class.abi.uint32_t_alignment),
579 fmt::arg("uint64_t_alignment", trace_class.abi.uint64_t_alignment),
580 fmt::arg("long_alignment", trace_class.abi.long_alignment),
581 fmt::arg("long_size", trace_class.abi.long_alignment),
582 fmt::arg("bits_per_long", trace_class.abi.bits_per_long),
583 fmt::arg("uuid", lttng::utils::uuid_to_str(trace_class.uuid)),
584 fmt::arg("byte_order",
24ed18f2 585 trace_class.abi.byte_order == lst::byte_order::BIG_ENDIAN_ ? "be" : "le"),
da9dd521 586 fmt::arg("packet_header_layout", packet_header_visitor.transfer_description()));
d7bfb9b0
JG
587
588 /* Declare trace scope and type aliases. */
a57c248a 589 append_metadata_fragment(trace_class_tsdl);
da9dd521
JG
590
591 tsdl_trace_environment_visitor environment_visitor;
592 trace_class.accept(environment_visitor);
593 append_metadata_fragment(environment_visitor.transfer_description());
d7bfb9b0
JG
594}
595
596void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::clock_class& clock_class)
597{
598 auto uuid_str = clock_class.uuid ?
599 fmt::format(" uuid = \"{}\";\n",
600 lttng::utils::uuid_to_str(*clock_class.uuid)) :
601 "";
602
603 /* Assumes a single clock that maps to specific stream class fields/roles. */
604 auto clock_class_str = fmt::format(
605 "clock {{\n"
606 " name = \"{name}\";\n"
607 /* Optional uuid. */
608 "{uuid}"
609 " description = \"{description}\";\n"
610 " freq = {frequency};\n"
611 " offset = {offset};\n"
612 "}};\n"
24ed18f2 613 "\n",
d7bfb9b0
JG
614 fmt::arg("name", clock_class.name),
615 fmt::arg("uuid", uuid_str),
616 fmt::arg("description", clock_class.description),
617 fmt::arg("frequency", clock_class.frequency),
24ed18f2 618 fmt::arg("offset", clock_class.offset));
d7bfb9b0 619
a57c248a 620 append_metadata_fragment(clock_class_str);
d7bfb9b0
JG
621}
622
623void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::stream_class& stream_class)
624{
d7bfb9b0 625 auto stream_class_str = fmt::format("stream {{\n"
24ed18f2 626 " id = {};\n", stream_class.id);
d7bfb9b0 627
24ed18f2
JG
628 const auto *event_header = stream_class.get_event_header();
629 if (event_header) {
630 auto event_header_visitor = tsdl_field_visitor(
631 _trace_abi, 1, stream_class.default_clock_class_name);
d7bfb9b0 632
24ed18f2
JG
633 event_header->accept(event_header_visitor);
634 stream_class_str += fmt::format(" event.header := {};\n",
da9dd521 635 event_header_visitor.transfer_description());
24ed18f2
JG
636 }
637
638 const auto *packet_context = stream_class.get_packet_context();
639 if (packet_context) {
640 auto packet_context_visitor = tsdl_field_visitor(
641 _trace_abi, 1, stream_class.default_clock_class_name);
642
643 packet_context->accept(packet_context_visitor);
644 stream_class_str += fmt::format(" packet.context := {};\n",
da9dd521 645 packet_context_visitor.transfer_description());
24ed18f2
JG
646 }
647
648 const auto *event_context = stream_class.get_event_context();
649 if (event_context) {
650 auto event_context_visitor = tsdl_field_visitor(_trace_abi, 1);
651
652 event_context->accept(event_context_visitor);
653 stream_class_str += fmt::format(" event.context := {};\n",
da9dd521 654 event_context_visitor.transfer_description());
24ed18f2 655 }
d7bfb9b0 656
24ed18f2 657 stream_class_str += "};\n\n";
d7bfb9b0
JG
658
659 append_metadata_fragment(stream_class_str);
660}
661
662void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::event_class& event_class)
663{
664 auto event_class_str = fmt::format("event {{\n"
665 " name = \"{name}\";\n"
666 " id = {id};\n"
667 " stream_id = {stream_class_id};\n"
668 " loglevel = {log_level};\n",
669 fmt::arg("name", event_class.name),
670 fmt::arg("id", event_class.id),
671 fmt::arg("stream_class_id", event_class.stream_class_id),
672 fmt::arg("log_level", event_class.log_level));
673
674 if (event_class.model_emf_uri) {
675 event_class_str += fmt::format(
676 " model.emf.uri = \"{}\";\n", *event_class.model_emf_uri);
677 }
678
679 auto payload_visitor = tsdl_field_visitor(_trace_abi, 1);
680
681 event_class.payload->accept(static_cast<lst::type_visitor&>(payload_visitor));
682
683 event_class_str += fmt::format(
da9dd521 684 " fields := {};\n}};\n\n", payload_visitor.transfer_description());
d7bfb9b0
JG
685
686 append_metadata_fragment(event_class_str);
687}
This page took 0.055695 seconds and 4 git commands to generate.