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