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