cdb15e231387e5e1eb77c07f0b47a5fb7a061521
[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:
1017 return print_variant(pretty, field, print_names);
1018 case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
1019 return print_array(pretty, field, print_names);
1020 case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
1021 return print_sequence(pretty, field, print_names);
1022 default:
1023 // TODO: log instead
1024 fprintf(pretty->err, "[error] Unknown type id: %d\n", (int) class_id);
1025 return -1;
1026 }
1027 }
1028
1029 static
1030 int print_stream_packet_context(struct pretty_component *pretty,
1031 const bt_event *event)
1032 {
1033 int ret = 0;
1034 const bt_packet *packet = NULL;
1035 const bt_field *main_field = NULL;
1036
1037 packet = bt_event_borrow_packet_const(event);
1038 if (!packet) {
1039 goto end;
1040 }
1041 main_field = bt_packet_borrow_context_field_const(packet);
1042 if (!main_field) {
1043 goto end;
1044 }
1045 if (!pretty->start_line) {
1046 g_string_append(pretty->string, ", ");
1047 }
1048 pretty->start_line = false;
1049 if (pretty->options.print_scope_field_names) {
1050 print_name_equal(pretty, "stream.packet.context");
1051 }
1052 ret = print_field(pretty, main_field,
1053 pretty->options.print_context_field_names,
1054 stream_packet_context_quarks,
1055 STREAM_PACKET_CONTEXT_QUARKS_LEN);
1056
1057 end:
1058 return ret;
1059 }
1060
1061 static
1062 int print_stream_event_context(struct pretty_component *pretty,
1063 const bt_event *event)
1064 {
1065 int ret = 0;
1066 const bt_field *main_field = NULL;
1067
1068 main_field = bt_event_borrow_common_context_field_const(event);
1069 if (!main_field) {
1070 goto end;
1071 }
1072 if (!pretty->start_line) {
1073 g_string_append(pretty->string, ", ");
1074 }
1075 pretty->start_line = false;
1076 if (pretty->options.print_scope_field_names) {
1077 print_name_equal(pretty, "stream.event.context");
1078 }
1079 ret = print_field(pretty, main_field,
1080 pretty->options.print_context_field_names, NULL, 0);
1081
1082 end:
1083 return ret;
1084 }
1085
1086 static
1087 int print_event_context(struct pretty_component *pretty,
1088 const bt_event *event)
1089 {
1090 int ret = 0;
1091 const bt_field *main_field = NULL;
1092
1093 main_field = bt_event_borrow_specific_context_field_const(event);
1094 if (!main_field) {
1095 goto end;
1096 }
1097 if (!pretty->start_line) {
1098 g_string_append(pretty->string, ", ");
1099 }
1100 pretty->start_line = false;
1101 if (pretty->options.print_scope_field_names) {
1102 print_name_equal(pretty, "event.context");
1103 }
1104 ret = print_field(pretty, main_field,
1105 pretty->options.print_context_field_names, NULL, 0);
1106
1107 end:
1108 return ret;
1109 }
1110
1111 static
1112 int print_event_payload(struct pretty_component *pretty,
1113 const bt_event *event)
1114 {
1115 int ret = 0;
1116 const bt_field *main_field = NULL;
1117
1118 main_field = bt_event_borrow_payload_field_const(event);
1119 if (!main_field) {
1120 goto end;
1121 }
1122 if (!pretty->start_line) {
1123 g_string_append(pretty->string, ", ");
1124 }
1125 pretty->start_line = false;
1126 if (pretty->options.print_scope_field_names) {
1127 print_name_equal(pretty, "event.fields");
1128 }
1129 ret = print_field(pretty, main_field,
1130 pretty->options.print_payload_field_names, NULL, 0);
1131
1132 end:
1133 return ret;
1134 }
1135
1136 static
1137 int flush_buf(FILE *stream, struct pretty_component *pretty)
1138 {
1139 int ret = 0;
1140
1141 if (pretty->string->len == 0) {
1142 goto end;
1143 }
1144
1145 if (fwrite(pretty->string->str, pretty->string->len, 1, stream) != 1) {
1146 ret = -1;
1147 }
1148
1149 end:
1150 return ret;
1151 }
1152
1153 BT_HIDDEN
1154 int pretty_print_event(struct pretty_component *pretty,
1155 const bt_message *event_msg)
1156 {
1157 int ret;
1158 const bt_event *event =
1159 bt_message_event_borrow_event_const(event_msg);
1160
1161 BT_ASSERT(event);
1162 pretty->start_line = true;
1163 g_string_assign(pretty->string, "");
1164 ret = print_event_header(pretty, event_msg);
1165 if (ret != 0) {
1166 goto end;
1167 }
1168
1169 ret = print_stream_packet_context(pretty, event);
1170 if (ret != 0) {
1171 goto end;
1172 }
1173
1174 ret = print_stream_event_context(pretty, event);
1175 if (ret != 0) {
1176 goto end;
1177 }
1178
1179 ret = print_event_context(pretty, event);
1180 if (ret != 0) {
1181 goto end;
1182 }
1183
1184 ret = print_event_payload(pretty, event);
1185 if (ret != 0) {
1186 goto end;
1187 }
1188
1189 g_string_append_c(pretty->string, '\n');
1190 if (flush_buf(pretty->out, pretty)) {
1191 ret = -1;
1192 goto end;
1193 }
1194
1195 end:
1196 return ret;
1197 }
1198
1199 static
1200 int print_discarded_elements_msg(struct pretty_component *pretty,
1201 const bt_stream *stream,
1202 const bt_clock_snapshot *begin_clock_snapshot,
1203 const bt_clock_snapshot *end_clock_snapshot,
1204 uint64_t count, const char *elem_type)
1205 {
1206 int ret = 0;
1207 const bt_stream_class *stream_class = NULL;
1208 const bt_trace *trace = NULL;
1209 const char *stream_name;
1210 const char *trace_name;
1211 bt_uuid trace_uuid;
1212 int64_t stream_class_id;
1213 int64_t stream_id;
1214 const char *init_msg;
1215
1216 /* Stream name */
1217 stream_name = bt_stream_get_name(stream);
1218 if (!stream_name) {
1219 stream_name = "(unknown)";
1220 }
1221
1222 /* Stream class ID */
1223 stream_class = bt_stream_borrow_class_const(stream);
1224 BT_ASSERT(stream_class);
1225 stream_class_id = bt_stream_class_get_id(stream_class);
1226
1227 /* Stream ID */
1228 stream_id = bt_stream_get_id(stream);
1229
1230 /* Trace name */
1231 trace = bt_stream_borrow_trace_const(stream);
1232 BT_ASSERT(trace);
1233 trace_name = bt_trace_get_name(trace);
1234 if (!trace_name) {
1235 trace_name = "(unknown)";
1236 }
1237
1238 /* Trace UUID */
1239 trace_uuid = bt_trace_get_uuid(trace);
1240
1241 /* Format message */
1242 g_string_assign(pretty->string, "");
1243
1244 if (count == UINT64_C(-1)) {
1245 init_msg = "Tracer may have discarded";
1246 } else {
1247 init_msg = "Tracer discarded";
1248 }
1249
1250 g_string_append_printf(pretty->string,
1251 "%s%sWARNING%s%s: %s ",
1252 bt_common_color_fg_yellow(),
1253 bt_common_color_bold(),
1254 bt_common_color_reset(),
1255 bt_common_color_fg_yellow(), init_msg);
1256
1257 if (count == UINT64_C(-1)) {
1258 g_string_append_printf(pretty->string, "%ss", elem_type);
1259 } else {
1260 g_string_append_printf(pretty->string,
1261 "%" PRIu64 " %s%s", count, elem_type,
1262 count == 1 ? "" : "s");
1263 }
1264
1265 g_string_append_c(pretty->string, ' ');
1266
1267 if (begin_clock_snapshot && end_clock_snapshot) {
1268 g_string_append(pretty->string, "between [");
1269 print_timestamp_wall(pretty, begin_clock_snapshot, false);
1270 g_string_append(pretty->string, "] and [");
1271 print_timestamp_wall(pretty, end_clock_snapshot, false);
1272 g_string_append(pretty->string, "]");
1273 } else {
1274 g_string_append(pretty->string, "(unknown time range)");
1275 }
1276
1277 g_string_append_printf(pretty->string, " in trace \"%s\" ", trace_name);
1278
1279 if (trace_uuid) {
1280 g_string_append_printf(pretty->string,
1281 "(UUID: " BT_UUID_FMT ") ",
1282 BT_UUID_FMT_VALUES(trace_uuid));
1283 } else {
1284 g_string_append(pretty->string, "(no UUID) ");
1285 }
1286
1287 g_string_append_printf(pretty->string,
1288 "within stream \"%s\" (stream class ID: %" PRIu64 ", ",
1289 stream_name, stream_class_id);
1290
1291 if (stream_id >= 0) {
1292 g_string_append_printf(pretty->string,
1293 "stream ID: %" PRIu64, stream_id);
1294 } else {
1295 g_string_append(pretty->string, "no stream ID");
1296 }
1297
1298 g_string_append_printf(pretty->string, ").%s\n",
1299 bt_common_color_reset());
1300
1301 /*
1302 * Print to standard error stream to remain backward compatible
1303 * with Babeltrace 1.
1304 */
1305 if (flush_buf(stderr, pretty)) {
1306 ret = -1;
1307 }
1308
1309 return ret;
1310 }
1311
1312 BT_HIDDEN
1313 int pretty_print_discarded_items(struct pretty_component *pretty,
1314 const bt_message *msg)
1315 {
1316 const bt_clock_snapshot *begin = NULL;
1317 const bt_clock_snapshot *end = NULL;
1318 const bt_stream *stream;
1319 const bt_stream_class *stream_class;
1320 uint64_t count = UINT64_C(-1);
1321 const char *elem_type;
1322
1323 switch (bt_message_get_type(msg)) {
1324 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1325 stream = bt_message_discarded_events_borrow_stream_const(msg);
1326
1327 if (bt_message_discarded_events_get_count(msg, &count) ==
1328 BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
1329 count = UINT64_C(-1);
1330 }
1331
1332 elem_type = "event";
1333 break;
1334 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1335 stream = bt_message_discarded_packets_borrow_stream_const(msg);
1336
1337 if (bt_message_discarded_packets_get_count(msg, &count) ==
1338 BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
1339 count = UINT64_C(-1);
1340 }
1341
1342 elem_type = "packet";
1343 break;
1344 default:
1345 abort();
1346 }
1347
1348 BT_ASSERT(stream);
1349 stream_class = bt_stream_borrow_class_const(stream);
1350
1351 switch (bt_message_get_type(msg)) {
1352 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
1353 if (bt_stream_class_discarded_events_have_default_clock_snapshots(
1354 stream_class)) {
1355 begin = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
1356 msg);
1357 end = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
1358 msg);
1359 }
1360
1361 break;
1362 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
1363 if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
1364 stream_class)) {
1365 begin = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
1366 msg);
1367 end = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
1368 msg);
1369 }
1370
1371 break;
1372 default:
1373 abort();
1374 }
1375
1376 print_discarded_elements_msg(pretty, stream, begin, end,
1377 count, elem_type);
1378 return 0;
1379 }
This page took 0.081218 seconds and 3 git commands to generate.