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