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