lib: decouple variant FC option names from selector FC mapping names
[babeltrace.git] / src / plugins / text / pretty / print.c
1 /*
2 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include <babeltrace2/babeltrace.h>
27 #include "compat/bitfield.h"
28 #include "common/common.h"
29 #include "common/uuid.h"
30 #include "compat/time.h"
31 #include "common/assert.h"
32 #include <inttypes.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include "pretty.h"
36
37 #define NSEC_PER_SEC 1000000000LL
38
39 #define COLOR_NAME BT_COMMON_COLOR_BOLD
40 #define COLOR_FIELD_NAME BT_COMMON_COLOR_FG_CYAN
41 #define COLOR_RST BT_COMMON_COLOR_RESET
42 #define COLOR_STRING_VALUE BT_COMMON_COLOR_BOLD
43 #define COLOR_NUMBER_VALUE BT_COMMON_COLOR_BOLD
44 #define COLOR_ENUM_MAPPING_NAME BT_COMMON_COLOR_BOLD
45 #define COLOR_UNKNOWN BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_RED
46 #define COLOR_EVENT_NAME BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_MAGENTA
47 #define COLOR_TIMESTAMP BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_YELLOW
48
49 struct timestamp {
50 int64_t real_timestamp; /* Relative to UNIX epoch. */
51 uint64_t clock_snapshot; /* In cycles. */
52 };
53
54 static
55 int print_field(struct pretty_component *pretty,
56 const bt_field *field, bool print_names,
57 GQuark *filters_fields, int filter_array_len);
58
59 static
60 void print_name_equal(struct pretty_component *pretty, const char *name)
61 {
62 if (pretty->use_colors) {
63 g_string_append_printf(pretty->string, "%s%s%s = ", COLOR_NAME,
64 name, COLOR_RST);
65 } else {
66 g_string_append_printf(pretty->string, "%s = ", name);
67 }
68 }
69
70 static
71 void print_field_name_equal(struct pretty_component *pretty, const char *name)
72 {
73 if (pretty->use_colors) {
74 g_string_append_printf(pretty->string, "%s%s%s = ",
75 COLOR_FIELD_NAME, name, COLOR_RST);
76 } else {
77 g_string_append_printf(pretty->string, "%s = ", name);
78 }
79 }
80
81 static
82 void print_timestamp_cycles(struct pretty_component *pretty,
83 const bt_clock_snapshot *clock_snapshot, bool update_last)
84 {
85 uint64_t cycles;
86
87 cycles = bt_clock_snapshot_get_value(clock_snapshot);
88 g_string_append_printf(pretty->string, "%020" PRIu64, cycles);
89
90 if (update_last) {
91 if (pretty->last_cycles_timestamp != -1ULL) {
92 pretty->delta_cycles = cycles - pretty->last_cycles_timestamp;
93 }
94
95 pretty->last_cycles_timestamp = cycles;
96 }
97 }
98
99 static
100 void print_timestamp_wall(struct pretty_component *pretty,
101 const bt_clock_snapshot *clock_snapshot, bool update_last)
102 {
103 int ret;
104 int64_t ts_nsec = 0; /* add configurable offset */
105 int64_t ts_sec = 0; /* add configurable offset */
106 uint64_t ts_sec_abs, ts_nsec_abs;
107 bool is_negative;
108
109 if (!clock_snapshot) {
110 g_string_append(pretty->string, "??:??:??.?????????");
111 return;
112 }
113
114 ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, &ts_nsec);
115 if (ret) {
116 // TODO: log, this is unexpected
117 g_string_append(pretty->string, "Error");
118 return;
119 }
120
121 if (update_last) {
122 if (pretty->last_real_timestamp != -1ULL) {
123 pretty->delta_real_timestamp = ts_nsec - pretty->last_real_timestamp;
124 }
125
126 pretty->last_real_timestamp = ts_nsec;
127 }
128
129 ts_sec += ts_nsec / NSEC_PER_SEC;
130 ts_nsec = ts_nsec % NSEC_PER_SEC;
131
132 if (ts_sec >= 0 && ts_nsec >= 0) {
133 is_negative = false;
134 ts_sec_abs = ts_sec;
135 ts_nsec_abs = ts_nsec;
136 } else if (ts_sec > 0 && ts_nsec < 0) {
137 is_negative = false;
138 ts_sec_abs = ts_sec - 1;
139 ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
140 } else if (ts_sec == 0 && ts_nsec < 0) {
141 is_negative = true;
142 ts_sec_abs = ts_sec;
143 ts_nsec_abs = -ts_nsec;
144 } else if (ts_sec < 0 && ts_nsec > 0) {
145 is_negative = true;
146 ts_sec_abs = -(ts_sec + 1);
147 ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
148 } else if (ts_sec < 0 && ts_nsec == 0) {
149 is_negative = true;
150 ts_sec_abs = -ts_sec;
151 ts_nsec_abs = ts_nsec;
152 } else { /* (ts_sec < 0 && ts_nsec < 0) */
153 is_negative = true;
154 ts_sec_abs = -ts_sec;
155 ts_nsec_abs = -ts_nsec;
156 }
157
158 if (!pretty->options.clock_seconds) {
159 struct tm tm;
160 time_t time_s = (time_t) ts_sec_abs;
161
162 if (is_negative && !pretty->negative_timestamp_warning_done) {
163 // TODO: log instead
164 fprintf(stderr, "[warning] Fallback to [sec.ns] to print negative time value. Use --clock-seconds.\n");
165 pretty->negative_timestamp_warning_done = true;
166 goto seconds;
167 }
168
169 if (!pretty->options.clock_gmt) {
170 struct tm *res;
171
172 res = bt_localtime_r(&time_s, &tm);
173 if (!res) {
174 // TODO: log instead
175 fprintf(stderr, "[warning] Unable to get localtime.\n");
176 goto seconds;
177 }
178 } else {
179 struct tm *res;
180
181 res = bt_gmtime_r(&time_s, &tm);
182 if (!res) {
183 // TODO: log instead
184 fprintf(stderr, "[warning] Unable to get gmtime.\n");
185 goto seconds;
186 }
187 }
188 if (pretty->options.clock_date) {
189 char timestr[26];
190 size_t res;
191
192 /* Print date and time */
193 res = strftime(timestr, sizeof(timestr),
194 "%Y-%m-%d ", &tm);
195 if (!res) {
196 // TODO: log instead
197 fprintf(stderr, "[warning] Unable to print ascii time.\n");
198 goto seconds;
199 }
200
201 g_string_append(pretty->string, timestr);
202 }
203
204 /* Print time in HH:MM:SS.ns */
205 g_string_append_printf(pretty->string,
206 "%02d:%02d:%02d.%09" PRIu64, tm.tm_hour, tm.tm_min,
207 tm.tm_sec, ts_nsec_abs);
208 goto end;
209 }
210 seconds:
211 g_string_append_printf(pretty->string, "%s%" PRId64 ".%09" PRIu64,
212 is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
213 end:
214 return;
215 }
216
217 static
218 int print_event_timestamp(struct pretty_component *pretty,
219 const bt_message *event_msg, bool *start_line)
220 {
221 bool print_names = pretty->options.print_header_field_names;
222 int ret = 0;
223 const bt_clock_snapshot *clock_snapshot = NULL;
224
225 if (!bt_message_event_borrow_stream_class_default_clock_class_const(
226 event_msg)) {
227 /* No default clock class: skip the timestamp without an error */
228 goto end;
229 }
230
231 clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(event_msg);
232
233 if (print_names) {
234 print_name_equal(pretty, "timestamp");
235 } else {
236 g_string_append(pretty->string, "[");
237 }
238 if (pretty->use_colors) {
239 g_string_append(pretty->string, COLOR_TIMESTAMP);
240 }
241 if (pretty->options.print_timestamp_cycles) {
242 print_timestamp_cycles(pretty, clock_snapshot, true);
243 } else {
244 print_timestamp_wall(pretty, clock_snapshot, true);
245 }
246 if (pretty->use_colors) {
247 g_string_append(pretty->string, COLOR_RST);
248 }
249
250 if (!print_names)
251 g_string_append(pretty->string, "] ");
252
253 if (pretty->options.print_delta_field) {
254 if (print_names) {
255 g_string_append(pretty->string, ", ");
256 print_name_equal(pretty, "delta");
257 } else {
258 g_string_append(pretty->string, "(");
259 }
260 if (pretty->options.print_timestamp_cycles) {
261 if (pretty->delta_cycles == -1ULL) {
262 g_string_append(pretty->string,
263 "+??????????\?\?"); /* Not a trigraph. */
264 } else {
265 g_string_append_printf(pretty->string,
266 "+%012" PRIu64, pretty->delta_cycles);
267 }
268 } else {
269 if (pretty->delta_real_timestamp != -1ULL) {
270 uint64_t delta_sec, delta_nsec, delta;
271
272 delta = pretty->delta_real_timestamp;
273 delta_sec = delta / NSEC_PER_SEC;
274 delta_nsec = delta % NSEC_PER_SEC;
275 g_string_append_printf(pretty->string,
276 "+%" PRIu64 ".%09" PRIu64,
277 delta_sec, delta_nsec);
278 } else {
279 g_string_append(pretty->string, "+?.?????????");
280 }
281 }
282 if (!print_names) {
283 g_string_append(pretty->string, ") ");
284 }
285 }
286 *start_line = !print_names;
287
288 end:
289 return ret;
290 }
291
292 static
293 int print_event_header(struct pretty_component *pretty,
294 const bt_message *event_msg)
295 {
296 bool print_names = pretty->options.print_header_field_names;
297 int ret = 0;
298 const bt_event_class *event_class = NULL;
299 const bt_stream *stream = NULL;
300 const bt_trace *trace = NULL;
301 const bt_event *event = bt_message_event_borrow_event_const(event_msg);
302 const char *ev_name;
303 int dom_print = 0;
304 bt_property_availability prop_avail;
305
306 event_class = bt_event_borrow_class_const(event);
307 stream = bt_event_borrow_stream_const(event);
308 trace = bt_stream_borrow_trace_const(stream);
309 ret = print_event_timestamp(pretty, event_msg, &pretty->start_line);
310 if (ret) {
311 goto end;
312 }
313 if (pretty->options.print_trace_field) {
314 const char *name;
315
316 name = bt_trace_get_name(trace);
317 if (name) {
318 if (!pretty->start_line) {
319 g_string_append(pretty->string, ", ");
320 }
321 if (print_names) {
322 print_name_equal(pretty, "trace");
323 }
324
325 g_string_append(pretty->string, name);
326
327 if (print_names) {
328 g_string_append(pretty->string, ", ");
329 }
330 }
331 }
332 if (pretty->options.print_trace_hostname_field) {
333 const bt_value *hostname_str;
334
335 hostname_str = bt_trace_borrow_environment_entry_value_by_name_const(
336 trace, "hostname");
337 if (hostname_str) {
338 const char *str;
339
340 if (!pretty->start_line) {
341 g_string_append(pretty->string, ", ");
342 }
343 if (print_names) {
344 print_name_equal(pretty, "trace:hostname");
345 }
346 str = bt_value_string_get(hostname_str);
347 g_string_append(pretty->string, str);
348 dom_print = 1;
349 }
350 }
351 if (pretty->options.print_trace_domain_field) {
352 const bt_value *domain_str;
353
354 domain_str = bt_trace_borrow_environment_entry_value_by_name_const(
355 trace, "domain");
356 if (domain_str) {
357 const char *str;
358
359 if (!pretty->start_line) {
360 g_string_append(pretty->string, ", ");
361 }
362 if (print_names) {
363 print_name_equal(pretty, "trace:domain");
364 } else if (dom_print) {
365 g_string_append(pretty->string, ":");
366 }
367 str = bt_value_string_get(domain_str);
368 g_string_append(pretty->string, str);
369 dom_print = 1;
370 }
371 }
372 if (pretty->options.print_trace_procname_field) {
373 const bt_value *procname_str;
374
375 procname_str = bt_trace_borrow_environment_entry_value_by_name_const(
376 trace, "procname");
377 if (procname_str) {
378 const char *str;
379
380 if (!pretty->start_line) {
381 g_string_append(pretty->string, ", ");
382 }
383 if (print_names) {
384 print_name_equal(pretty, "trace:procname");
385 } else if (dom_print) {
386 g_string_append(pretty->string, ":");
387 }
388 str = bt_value_string_get(procname_str);
389 g_string_append(pretty->string, str);
390 dom_print = 1;
391 }
392 }
393 if (pretty->options.print_trace_vpid_field) {
394 const bt_value *vpid_value;
395
396 vpid_value = bt_trace_borrow_environment_entry_value_by_name_const(
397 trace, "vpid");
398 if (vpid_value) {
399 int64_t value;
400
401 if (!pretty->start_line) {
402 g_string_append(pretty->string, ", ");
403 }
404 if (print_names) {
405 print_name_equal(pretty, "trace:vpid");
406 } else if (dom_print) {
407 g_string_append(pretty->string, ":");
408 }
409 value = bt_value_signed_integer_get(vpid_value);
410 g_string_append_printf(pretty->string,
411 "(%" PRId64 ")", value);
412 dom_print = 1;
413 }
414 }
415 if (pretty->options.print_loglevel_field) {
416 static const char *log_level_names[] = {
417 [ BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY ] = "TRACE_EMERG",
418 [ BT_EVENT_CLASS_LOG_LEVEL_ALERT ] = "TRACE_ALERT",
419 [ BT_EVENT_CLASS_LOG_LEVEL_CRITICAL ] = "TRACE_CRIT",
420 [ BT_EVENT_CLASS_LOG_LEVEL_ERROR ] = "TRACE_ERR",
421 [ BT_EVENT_CLASS_LOG_LEVEL_WARNING ] = "TRACE_WARNING",
422 [ BT_EVENT_CLASS_LOG_LEVEL_NOTICE ] = "TRACE_NOTICE",
423 [ BT_EVENT_CLASS_LOG_LEVEL_INFO ] = "TRACE_INFO",
424 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM ] = "TRACE_DEBUG_SYSTEM",
425 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM ] = "TRACE_DEBUG_PROGRAM",
426 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS ] = "TRACE_DEBUG_PROCESS",
427 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE ] = "TRACE_DEBUG_MODULE",
428 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT ] = "TRACE_DEBUG_UNIT",
429 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION ] = "TRACE_DEBUG_FUNCTION",
430 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE ] = "TRACE_DEBUG_LINE",
431 [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG ] = "TRACE_DEBUG",
432 };
433 bt_event_class_log_level log_level;
434 const char *log_level_str = NULL;
435
436 prop_avail = bt_event_class_get_log_level(event_class,
437 &log_level);
438 if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
439 log_level_str = log_level_names[log_level];
440 BT_ASSERT(log_level_str);
441
442 if (!pretty->start_line) {
443 g_string_append(pretty->string, ", ");
444 }
445 if (print_names) {
446 print_name_equal(pretty, "loglevel");
447 } else if (dom_print) {
448 g_string_append(pretty->string, ":");
449 }
450
451 g_string_append(pretty->string, log_level_str);
452 g_string_append_printf(
453 pretty->string, " (%d)", (int) log_level);
454 dom_print = 1;
455 }
456 }
457 if (pretty->options.print_emf_field) {
458 const char *uri_str;
459
460 uri_str = bt_event_class_get_emf_uri(event_class);
461 if (uri_str) {
462 if (!pretty->start_line) {
463 g_string_append(pretty->string, ", ");
464 }
465 if (print_names) {
466 print_name_equal(pretty, "model.emf.uri");
467 } else if (dom_print) {
468 g_string_append(pretty->string, ":");
469 }
470
471 g_string_append(pretty->string, uri_str);
472 dom_print = 1;
473 }
474 }
475 if (dom_print && !print_names) {
476 g_string_append(pretty->string, " ");
477 }
478 if (!pretty->start_line) {
479 g_string_append(pretty->string, ", ");
480 }
481 pretty->start_line = true;
482 if (print_names) {
483 print_name_equal(pretty, "name");
484 }
485 ev_name = bt_event_class_get_name(event_class);
486 if (pretty->use_colors) {
487 if (ev_name) {
488 g_string_append(pretty->string, COLOR_EVENT_NAME);
489 } else {
490 g_string_append(pretty->string, COLOR_UNKNOWN);
491 }
492 }
493 if (ev_name) {
494 g_string_append(pretty->string, ev_name);
495 } else {
496 g_string_append(pretty->string, "<unknown>");
497 }
498 if (pretty->use_colors) {
499 g_string_append(pretty->string, COLOR_RST);
500 }
501 if (!print_names) {
502 g_string_append(pretty->string, ": ");
503 } else {
504 g_string_append(pretty->string, ", ");
505 }
506
507 end:
508 return ret;
509 }
510
511 static
512 int print_integer(struct pretty_component *pretty,
513 const bt_field *field)
514 {
515 int ret = 0;
516 bt_field_class_integer_preferred_display_base base;
517 const bt_field_class *int_fc;
518 union {
519 uint64_t u;
520 int64_t s;
521 } v;
522 bool rst_color = false;
523 bt_field_class_type ft_type;
524
525 int_fc = bt_field_borrow_class_const(field);
526 BT_ASSERT(int_fc);
527 ft_type = bt_field_get_class_type(field);
528 if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
529 ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
530 v.u = bt_field_unsigned_integer_get_value(field);
531 } else {
532 v.s = bt_field_signed_integer_get_value(field);
533 }
534
535 if (pretty->use_colors) {
536 g_string_append(pretty->string, COLOR_NUMBER_VALUE);
537 rst_color = true;
538 }
539
540 base = bt_field_class_integer_get_preferred_display_base(int_fc);
541 switch (base) {
542 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
543 {
544 int bitnr, len;
545
546 len = bt_field_class_integer_get_field_value_range(int_fc);
547 g_string_append(pretty->string, "0b");
548 _bt_safe_lshift(v.u, 64 - len);
549 for (bitnr = 0; bitnr < len; bitnr++) {
550 g_string_append_printf(pretty->string, "%u", (v.u & (1ULL << 63)) ? 1 : 0);
551 _bt_safe_lshift(v.u, 1);
552 }
553 break;
554 }
555 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
556 {
557 if (ft_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
558 ft_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
559 int len;
560
561 len = bt_field_class_integer_get_field_value_range(
562 int_fc);
563 if (len < 64) {
564 size_t rounded_len;
565
566 BT_ASSERT(len != 0);
567 /* Round length to the nearest 3-bit */
568 rounded_len = (((len - 1) / 3) + 1) * 3;
569 v.u &= ((uint64_t) 1 << rounded_len) - 1;
570 }
571 }
572
573 g_string_append_printf(pretty->string, "0%" PRIo64, v.u);
574 break;
575 }
576 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
577 if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
578 ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
579 g_string_append_printf(pretty->string, "%" PRIu64, v.u);
580 } else {
581 g_string_append_printf(pretty->string, "%" PRId64, v.s);
582 }
583 break;
584 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
585 {
586 int len;
587
588 len = bt_field_class_integer_get_field_value_range(int_fc);
589 if (len < 64) {
590 /* Round length to the nearest nibble */
591 uint8_t rounded_len = ((len + 3) & ~0x3);
592
593 v.u &= ((uint64_t) 1 << rounded_len) - 1;
594 }
595
596 g_string_append_printf(pretty->string, "0x%" PRIX64, v.u);
597 break;
598 }
599 default:
600 ret = -1;
601 goto end;
602 }
603 end:
604 if (rst_color) {
605 g_string_append(pretty->string, COLOR_RST);
606 }
607 return ret;
608 }
609
610 static
611 void print_escape_string(struct pretty_component *pretty, const char *str)
612 {
613 int i;
614
615 g_string_append_c(pretty->string, '"');
616
617 for (i = 0; i < strlen(str); i++) {
618 /* Escape sequences not recognized by iscntrl(). */
619 switch (str[i]) {
620 case '\\':
621 g_string_append(pretty->string, "\\\\");
622 continue;
623 case '\'':
624 g_string_append(pretty->string, "\\\'");
625 continue;
626 case '\"':
627 g_string_append(pretty->string, "\\\"");
628 continue;
629 case '\?':
630 g_string_append(pretty->string, "\\\?");
631 continue;
632 }
633
634 /* Standard characters. */
635 if (!iscntrl(str[i])) {
636 g_string_append_c(pretty->string, str[i]);
637 continue;
638 }
639
640 switch (str[i]) {
641 case '\0':
642 g_string_append(pretty->string, "\\0");
643 break;
644 case '\a':
645 g_string_append(pretty->string, "\\a");
646 break;
647 case '\b':
648 g_string_append(pretty->string, "\\b");
649 break;
650 case '\e':
651 g_string_append(pretty->string, "\\e");
652 break;
653 case '\f':
654 g_string_append(pretty->string, "\\f");
655 break;
656 case '\n':
657 g_string_append(pretty->string, "\\n");
658 break;
659 case '\r':
660 g_string_append(pretty->string, "\\r");
661 break;
662 case '\t':
663 g_string_append(pretty->string, "\\t");
664 break;
665 case '\v':
666 g_string_append(pretty->string, "\\v");
667 break;
668 default:
669 /* Unhandled control-sequence, print as hex. */
670 g_string_append_printf(pretty->string, "\\x%02x", str[i]);
671 break;
672 }
673 }
674
675 g_string_append_c(pretty->string, '"');
676 }
677
678 static
679 int print_enum(struct pretty_component *pretty,
680 const bt_field *field)
681 {
682 int ret = 0;
683 const bt_field_class *enumeration_field_class = NULL;
684 bt_field_class_enumeration_mapping_label_array label_array;
685 uint64_t label_count;
686 uint64_t i;
687
688 enumeration_field_class = bt_field_borrow_class_const(field);
689 if (!enumeration_field_class) {
690 ret = -1;
691 goto end;
692 }
693
694 switch (bt_field_get_class_type(field)) {
695 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
696 ret = bt_field_unsigned_enumeration_get_mapping_labels(field,
697 &label_array, &label_count);
698 break;
699 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
700 ret = bt_field_signed_enumeration_get_mapping_labels(field,
701 &label_array, &label_count);
702 break;
703 default:
704 abort();
705 }
706
707 if (ret) {
708 ret = -1;
709 goto end;
710 }
711
712 g_string_append(pretty->string, "( ");
713 if (label_count == 0) {
714 if (pretty->use_colors) {
715 g_string_append(pretty->string, COLOR_UNKNOWN);
716 }
717 g_string_append(pretty->string, "<unknown>");
718 if (pretty->use_colors) {
719 g_string_append(pretty->string, COLOR_RST);
720 }
721 goto skip_loop;
722 }
723 for (i = 0; i < label_count; i++) {
724 const char *mapping_name = label_array[i];
725
726 if (i != 0) {
727 g_string_append(pretty->string, ", ");
728 }
729 if (pretty->use_colors) {
730 g_string_append(pretty->string, COLOR_ENUM_MAPPING_NAME);
731 }
732 print_escape_string(pretty, mapping_name);
733 if (pretty->use_colors) {
734 g_string_append(pretty->string, COLOR_RST);
735 }
736 }
737 skip_loop:
738 g_string_append(pretty->string, " : container = ");
739 ret = print_integer(pretty, field);
740 if (ret != 0) {
741 goto end;
742 }
743 g_string_append(pretty->string, " )");
744 end:
745 return ret;
746 }
747
748 static
749 int filter_field_name(struct pretty_component *pretty, const char *field_name,
750 GQuark *filter_fields, int filter_array_len)
751 {
752 int i;
753 GQuark field_quark = g_quark_try_string(field_name);
754
755 if (!field_quark || pretty->options.verbose) {
756 return 1;
757 }
758
759 for (i = 0; i < filter_array_len; i++) {
760 if (field_quark == filter_fields[i]) {
761 return 0;
762 }
763 }
764 return 1;
765 }
766
767 static
768 int print_struct_field(struct pretty_component *pretty,
769 const bt_field *_struct,
770 const bt_field_class *struct_class,
771 uint64_t i, bool print_names, uint64_t *nr_printed_fields,
772 GQuark *filter_fields, int filter_array_len)
773 {
774 int ret = 0;
775 const char *field_name;
776 const bt_field *field = NULL;
777 const bt_field_class_structure_member *member;
778
779 field = bt_field_structure_borrow_member_field_by_index_const(_struct, i);
780 if (!field) {
781 ret = -1;
782 goto end;
783 }
784
785 member = bt_field_class_structure_borrow_member_by_index_const(
786 struct_class, i);
787 field_name = bt_field_class_structure_member_get_name(member);
788
789 if (filter_fields && !filter_field_name(pretty, field_name,
790 filter_fields, filter_array_len)) {
791 ret = 0;
792 goto end;
793 }
794
795 if (*nr_printed_fields > 0) {
796 g_string_append(pretty->string, ", ");
797 } else {
798 g_string_append(pretty->string, " ");
799 }
800 if (print_names) {
801 print_field_name_equal(pretty, field_name);
802 }
803 ret = print_field(pretty, field, print_names, NULL, 0);
804 *nr_printed_fields += 1;
805
806 end:
807 return ret;
808 }
809
810 static
811 int print_struct(struct pretty_component *pretty,
812 const bt_field *_struct, bool print_names,
813 GQuark *filter_fields, int filter_array_len)
814 {
815 int ret = 0;
816 const bt_field_class *struct_class = NULL;
817 uint64_t nr_fields, i, nr_printed_fields;
818
819 struct_class = bt_field_borrow_class_const(_struct);
820 if (!struct_class) {
821 ret = -1;
822 goto end;
823 }
824
825 nr_fields = bt_field_class_structure_get_member_count(struct_class);
826
827 g_string_append(pretty->string, "{");
828 pretty->depth++;
829 nr_printed_fields = 0;
830 for (i = 0; i < nr_fields; i++) {
831 ret = print_struct_field(pretty, _struct, struct_class, i,
832 print_names, &nr_printed_fields, filter_fields,
833 filter_array_len);
834 if (ret != 0) {
835 goto end;
836 }
837 }
838 pretty->depth--;
839 g_string_append(pretty->string, " }");
840
841 end:
842 return ret;
843 }
844
845 static
846 int print_array_field(struct pretty_component *pretty,
847 const bt_field *array, uint64_t i, bool print_names)
848 {
849 const bt_field *field = NULL;
850
851 if (i != 0) {
852 g_string_append(pretty->string, ", ");
853 } else {
854 g_string_append(pretty->string, " ");
855 }
856 if (print_names) {
857 g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
858 }
859
860 field = bt_field_array_borrow_element_field_by_index_const(array, i);
861 BT_ASSERT(field);
862 return print_field(pretty, field, print_names, NULL, 0);
863 }
864
865 static
866 int print_array(struct pretty_component *pretty,
867 const bt_field *array, bool print_names)
868 {
869 int ret = 0;
870 const bt_field_class *array_class = NULL;
871 uint64_t len;
872 uint64_t i;
873
874 array_class = bt_field_borrow_class_const(array);
875 if (!array_class) {
876 ret = -1;
877 goto end;
878 }
879 len = bt_field_array_get_length(array);
880 g_string_append(pretty->string, "[");
881 pretty->depth++;
882 for (i = 0; i < len; i++) {
883 ret = print_array_field(pretty, array, i, print_names);
884 if (ret != 0) {
885 goto end;
886 }
887 }
888 pretty->depth--;
889 g_string_append(pretty->string, " ]");
890
891 end:
892 return ret;
893 }
894
895 static
896 int print_sequence_field(struct pretty_component *pretty,
897 const bt_field *seq, uint64_t i, bool print_names)
898 {
899 const bt_field *field = NULL;
900
901 if (i != 0) {
902 g_string_append(pretty->string, ", ");
903 } else {
904 g_string_append(pretty->string, " ");
905 }
906 if (print_names) {
907 g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
908 }
909
910 field = bt_field_array_borrow_element_field_by_index_const(seq, i);
911 BT_ASSERT(field);
912 return print_field(pretty, field, print_names, NULL, 0);
913 }
914
915 static
916 int print_sequence(struct pretty_component *pretty,
917 const bt_field *seq, bool print_names)
918 {
919 int ret = 0;
920 uint64_t len;
921 uint64_t i;
922
923 len = bt_field_array_get_length(seq);
924 g_string_append(pretty->string, "[");
925
926 pretty->depth++;
927 for (i = 0; i < len; i++) {
928 ret = print_sequence_field(pretty, seq, i, print_names);
929 if (ret != 0) {
930 goto end;
931 }
932 }
933 pretty->depth--;
934 g_string_append(pretty->string, " ]");
935
936 end:
937 return ret;
938 }
939
940 static
941 int print_variant(struct pretty_component *pretty,
942 const bt_field *variant, bool print_names)
943 {
944 int ret = 0;
945 const bt_field *field = NULL;
946
947 field = bt_field_variant_borrow_selected_option_field_const(variant);
948 BT_ASSERT(field);
949 g_string_append(pretty->string, "{ ");
950 pretty->depth++;
951 if (print_names) {
952 // TODO: find tag's name using field path
953 // print_field_name_equal(pretty, tag_choice);
954 }
955 ret = print_field(pretty, field, print_names, NULL, 0);
956 if (ret != 0) {
957 goto end;
958 }
959 pretty->depth--;
960 g_string_append(pretty->string, " }");
961
962 end:
963 return ret;
964 }
965
966 static
967 int print_field(struct pretty_component *pretty,
968 const bt_field *field, bool print_names,
969 GQuark *filter_fields, int filter_array_len)
970 {
971 bt_field_class_type class_id;
972
973 class_id = bt_field_get_class_type(field);
974 switch (class_id) {
975 case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
976 case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
977 return print_integer(pretty, field);
978 case BT_FIELD_CLASS_TYPE_REAL:
979 {
980 double v;
981
982 v = bt_field_real_get_value(field);
983 if (pretty->use_colors) {
984 g_string_append(pretty->string, COLOR_NUMBER_VALUE);
985 }
986 g_string_append_printf(pretty->string, "%g", v);
987 if (pretty->use_colors) {
988 g_string_append(pretty->string, COLOR_RST);
989 }
990 return 0;
991 }
992 case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
993 case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
994 return print_enum(pretty, field);
995 case BT_FIELD_CLASS_TYPE_STRING:
996 {
997 const char *str;
998
999 str = bt_field_string_get_value(field);
1000 if (!str) {
1001 return -1;
1002 }
1003
1004 if (pretty->use_colors) {
1005 g_string_append(pretty->string, COLOR_STRING_VALUE);
1006 }
1007 print_escape_string(pretty, str);
1008 if (pretty->use_colors) {
1009 g_string_append(pretty->string, COLOR_RST);
1010 }
1011 return 0;
1012 }
1013 case BT_FIELD_CLASS_TYPE_STRUCTURE:
1014 return print_struct(pretty, field, print_names, filter_fields,
1015 filter_array_len);
1016 case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR:
1017 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR:
1018 case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR:
1019 return print_variant(pretty, field, print_names);
1020 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1021 return print_array(pretty, field, print_names);
1022 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1023 return print_sequence(pretty, field, print_names);
1024 default:
1025 // TODO: log instead
1026 fprintf(pretty->err, "[error] Unknown type id: %d\n", (int) class_id);
1027 return -1;
1028 }
1029 }
1030
1031 static
1032 int print_stream_packet_context(struct pretty_component *pretty,
1033 const bt_event *event)
1034 {
1035 int ret = 0;
1036 const bt_packet *packet = NULL;
1037 const bt_field *main_field = NULL;
1038
1039 packet = bt_event_borrow_packet_const(event);
1040 if (!packet) {
1041 goto end;
1042 }
1043 main_field = bt_packet_borrow_context_field_const(packet);
1044 if (!main_field) {
1045 goto end;
1046 }
1047 if (!pretty->start_line) {
1048 g_string_append(pretty->string, ", ");
1049 }
1050 pretty->start_line = false;
1051 if (pretty->options.print_scope_field_names) {
1052 print_name_equal(pretty, "stream.packet.context");
1053 }
1054 ret = print_field(pretty, main_field,
1055 pretty->options.print_context_field_names,
1056 stream_packet_context_quarks,
1057 STREAM_PACKET_CONTEXT_QUARKS_LEN);
1058
1059 end:
1060 return ret;
1061 }
1062
1063 static
1064 int print_stream_event_context(struct pretty_component *pretty,
1065 const bt_event *event)
1066 {
1067 int ret = 0;
1068 const bt_field *main_field = NULL;
1069
1070 main_field = bt_event_borrow_common_context_field_const(event);
1071 if (!main_field) {
1072 goto end;
1073 }
1074 if (!pretty->start_line) {
1075 g_string_append(pretty->string, ", ");
1076 }
1077 pretty->start_line = false;
1078 if (pretty->options.print_scope_field_names) {
1079 print_name_equal(pretty, "stream.event.context");
1080 }
1081 ret = print_field(pretty, main_field,
1082 pretty->options.print_context_field_names, NULL, 0);
1083
1084 end:
1085 return ret;
1086 }
1087
1088 static
1089 int print_event_context(struct pretty_component *pretty,
1090 const bt_event *event)
1091 {
1092 int ret = 0;
1093 const bt_field *main_field = NULL;
1094
1095 main_field = bt_event_borrow_specific_context_field_const(event);
1096 if (!main_field) {
1097 goto end;
1098 }
1099 if (!pretty->start_line) {
1100 g_string_append(pretty->string, ", ");
1101 }
1102 pretty->start_line = false;
1103 if (pretty->options.print_scope_field_names) {
1104 print_name_equal(pretty, "event.context");
1105 }
1106 ret = print_field(pretty, main_field,
1107 pretty->options.print_context_field_names, NULL, 0);
1108
1109 end:
1110 return ret;
1111 }
1112
1113 static
1114 int print_event_payload(struct pretty_component *pretty,
1115 const bt_event *event)
1116 {
1117 int ret = 0;
1118 const bt_field *main_field = NULL;
1119
1120 main_field = bt_event_borrow_payload_field_const(event);
1121 if (!main_field) {
1122 goto end;
1123 }
1124 if (!pretty->start_line) {
1125 g_string_append(pretty->string, ", ");
1126 }
1127 pretty->start_line = false;
1128 if (pretty->options.print_scope_field_names) {
1129 print_name_equal(pretty, "event.fields");
1130 }
1131 ret = print_field(pretty, main_field,
1132 pretty->options.print_payload_field_names, NULL, 0);
1133
1134 end:
1135 return ret;
1136 }
1137
1138 static
1139 int flush_buf(FILE *stream, struct pretty_component *pretty)
1140 {
1141 int ret = 0;
1142
1143 if (pretty->string->len == 0) {
1144 goto end;
1145 }
1146
1147 if (fwrite(pretty->string->str, pretty->string->len, 1, stream) != 1) {
1148 ret = -1;
1149 }
1150
1151 end:
1152 return ret;
1153 }
1154
1155 BT_HIDDEN
1156 int pretty_print_event(struct pretty_component *pretty,
1157 const bt_message *event_msg)
1158 {
1159 int ret;
1160 const bt_event *event =
1161 bt_message_event_borrow_event_const(event_msg);
1162
1163 BT_ASSERT(event);
1164 pretty->start_line = true;
1165 g_string_assign(pretty->string, "");
1166 ret = print_event_header(pretty, event_msg);
1167 if (ret != 0) {
1168 goto end;
1169 }
1170
1171 ret = print_stream_packet_context(pretty, event);
1172 if (ret != 0) {
1173 goto end;
1174 }
1175
1176 ret = print_stream_event_context(pretty, event);
1177 if (ret != 0) {
1178 goto end;
1179 }
1180
1181 ret = print_event_context(pretty, event);
1182 if (ret != 0) {
1183 goto end;
1184 }
1185
1186 ret = print_event_payload(pretty, event);
1187 if (ret != 0) {
1188 goto end;
1189 }
1190
1191 g_string_append_c(pretty->string, '\n');
1192 if (flush_buf(pretty->out, pretty)) {
1193 ret = -1;
1194 goto end;
1195 }
1196
1197 end:
1198 return ret;
1199 }
1200
1201 static
1202 int print_discarded_elements_msg(struct pretty_component *pretty,
1203 const bt_stream *stream,
1204 const bt_clock_snapshot *begin_clock_snapshot,
1205 const bt_clock_snapshot *end_clock_snapshot,
1206 uint64_t count, const char *elem_type)
1207 {
1208 int ret = 0;
1209 const bt_stream_class *stream_class = NULL;
1210 const bt_trace *trace = NULL;
1211 const char *stream_name;
1212 const char *trace_name;
1213 bt_uuid trace_uuid;
1214 int64_t stream_class_id;
1215 int64_t stream_id;
1216 const char *init_msg;
1217
1218 /* Stream name */
1219 stream_name = bt_stream_get_name(stream);
1220 if (!stream_name) {
1221 stream_name = "(unknown)";
1222 }
1223
1224 /* Stream class ID */
1225 stream_class = bt_stream_borrow_class_const(stream);
1226 BT_ASSERT(stream_class);
1227 stream_class_id = bt_stream_class_get_id(stream_class);
1228
1229 /* Stream ID */
1230 stream_id = bt_stream_get_id(stream);
1231
1232 /* Trace name */
1233 trace = bt_stream_borrow_trace_const(stream);
1234 BT_ASSERT(trace);
1235 trace_name = bt_trace_get_name(trace);
1236 if (!trace_name) {
1237 trace_name = "(unknown)";
1238 }
1239
1240 /* Trace UUID */
1241 trace_uuid = bt_trace_get_uuid(trace);
1242
1243 /* Format message */
1244 g_string_assign(pretty->string, "");
1245
1246 if (count == UINT64_C(-1)) {
1247 init_msg = "Tracer may have discarded";
1248 } else {
1249 init_msg = "Tracer discarded";
1250 }
1251
1252 g_string_append_printf(pretty->string,
1253 "%s%sWARNING%s%s: %s ",
1254 bt_common_color_fg_yellow(),
1255 bt_common_color_bold(),
1256 bt_common_color_reset(),
1257 bt_common_color_fg_yellow(), init_msg);
1258
1259 if (count == UINT64_C(-1)) {
1260 g_string_append_printf(pretty->string, "%ss", elem_type);
1261 } else {
1262 g_string_append_printf(pretty->string,
1263 "%" PRIu64 " %s%s", count, elem_type,
1264 count == 1 ? "" : "s");
1265 }
1266
1267 g_string_append_c(pretty->string, ' ');
1268
1269 if (begin_clock_snapshot && end_clock_snapshot) {
1270 g_string_append(pretty->string, "between [");
1271 print_timestamp_wall(pretty, begin_clock_snapshot, false);
1272 g_string_append(pretty->string, "] and [");
1273 print_timestamp_wall(pretty, end_clock_snapshot, false);
1274 g_string_append(pretty->string, "]");
1275 } else {
1276 g_string_append(pretty->string, "(unknown time range)");
1277 }
1278
1279 g_string_append_printf(pretty->string, " in trace \"%s\" ", trace_name);
1280
1281 if (trace_uuid) {
1282 g_string_append_printf(pretty->string,
1283 "(UUID: " BT_UUID_FMT ") ",
1284 BT_UUID_FMT_VALUES(trace_uuid));
1285 } else {
1286 g_string_append(pretty->string, "(no UUID) ");
1287 }
1288
1289 g_string_append_printf(pretty->string,
1290 "within stream \"%s\" (stream class ID: %" PRIu64 ", ",
1291 stream_name, stream_class_id);
1292
1293 if (stream_id >= 0) {
1294 g_string_append_printf(pretty->string,
1295 "stream ID: %" PRIu64, stream_id);
1296 } else {
1297 g_string_append(pretty->string, "no stream ID");
1298 }
1299
1300 g_string_append_printf(pretty->string, ").%s\n",
1301 bt_common_color_reset());
1302
1303 /*
1304 * Print to standard error stream to remain backward compatible
1305 * with Babeltrace 1.
1306 */
1307 if (flush_buf(stderr, pretty)) {
1308 ret = -1;
1309 }
1310
1311 return ret;
1312 }
1313
1314 BT_HIDDEN
1315 int pretty_print_discarded_items(struct pretty_component *pretty,
1316 const bt_message *msg)
1317 {
1318 const bt_clock_snapshot *begin = NULL;
1319 const bt_clock_snapshot *end = NULL;
1320 const bt_stream *stream;
1321 const bt_stream_class *stream_class;
1322 uint64_t count = UINT64_C(-1);
1323 const char *elem_type;
1324
1325 switch (bt_message_get_type(msg)) {
1326 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1327 stream = bt_message_discarded_events_borrow_stream_const(msg);
1328
1329 if (bt_message_discarded_events_get_count(msg, &count) ==
1330 BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
1331 count = UINT64_C(-1);
1332 }
1333
1334 elem_type = "event";
1335 break;
1336 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1337 stream = bt_message_discarded_packets_borrow_stream_const(msg);
1338
1339 if (bt_message_discarded_packets_get_count(msg, &count) ==
1340 BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
1341 count = UINT64_C(-1);
1342 }
1343
1344 elem_type = "packet";
1345 break;
1346 default:
1347 abort();
1348 }
1349
1350 BT_ASSERT(stream);
1351 stream_class = bt_stream_borrow_class_const(stream);
1352
1353 switch (bt_message_get_type(msg)) {
1354 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1355 if (bt_stream_class_discarded_events_have_default_clock_snapshots(
1356 stream_class)) {
1357 begin = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
1358 msg);
1359 end = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
1360 msg);
1361 }
1362
1363 break;
1364 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1365 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
1366 stream_class)) {
1367 begin = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
1368 msg);
1369 end = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
1370 msg);
1371 }
1372
1373 break;
1374 default:
1375 abort();
1376 }
1377
1378 print_discarded_elements_msg(pretty, stream, begin, end,
1379 count, elem_type);
1380 return 0;
1381 }
This page took 0.058465 seconds and 4 git commands to generate.