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