.gitignore: add some missing files
[babeltrace.git] / src / plugins / text / pretty / pretty.c
... / ...
CommitLineData
1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 */
7
8#define BT_COMP_LOG_SELF_COMP (pretty->self_comp)
9#define BT_LOG_OUTPUT_LEVEL (pretty->log_level)
10#define BT_LOG_TAG "PLUGIN/SINK.TEXT.PRETTY"
11#include "logging/comp-logging.h"
12
13#include <babeltrace2/babeltrace.h>
14#include "compat/compiler.h"
15#include "common/common.h"
16#include <stdio.h>
17#include <stdbool.h>
18#include <glib.h>
19#include <string.h>
20#include "common/assert.h"
21#include "plugins/common/param-validation/param-validation.h"
22
23#include "pretty.h"
24
25static
26const char * const in_port_name = "in";
27
28bt_component_class_get_supported_mip_versions_method_status
29pretty_supported_mip_versions(
30 bt_self_component_class_sink *self_component_class __attribute__((unused)),
31 const bt_value *params __attribute__((unused)),
32 void *initialize_method_data __attribute__((unused)),
33 bt_logging_level logging_level __attribute__((unused)),
34 bt_integer_range_set_unsigned *supported_versions)
35{
36 return (int) bt_integer_range_set_unsigned_add_range(supported_versions, 0, 1);
37}
38
39static
40void destroy_pretty_data(struct pretty_component *pretty)
41{
42 uint64_t i;
43 if (!pretty) {
44 goto end;
45 }
46
47 bt_message_iterator_put_ref(pretty->iterator);
48
49 if (pretty->string) {
50 (void) g_string_free(pretty->string, TRUE);
51 }
52
53 if (pretty->tmp_string) {
54 (void) g_string_free(pretty->tmp_string, TRUE);
55 }
56
57 if (pretty->out != stdout) {
58 int ret;
59
60 ret = fclose(pretty->out);
61 if (ret) {
62 perror("close output file");
63 }
64 }
65
66 for (i = 0; i < ENUMERATION_MAX_BITFLAGS_COUNT; i++) {
67 if (pretty->enum_bit_labels[i]) {
68 g_ptr_array_free(pretty->enum_bit_labels[i], true);
69 }
70 }
71
72 g_free(pretty->options.output_path);
73 g_free(pretty);
74
75end:
76 return;
77}
78
79static
80struct pretty_component *create_pretty(void)
81{
82 struct pretty_component *pretty;
83
84 pretty = g_new0(struct pretty_component, 1);
85 if (!pretty) {
86 goto end;
87 }
88 pretty->string = g_string_new("");
89 if (!pretty->string) {
90 goto error;
91 }
92 pretty->tmp_string = g_string_new("");
93 if (!pretty->tmp_string) {
94 goto error;
95 }
96end:
97 return pretty;
98
99error:
100 g_free(pretty);
101 return NULL;
102}
103
104void pretty_finalize(bt_self_component_sink *comp)
105{
106 destroy_pretty_data(
107 bt_self_component_get_data(
108 bt_self_component_sink_as_self_component(comp)));
109}
110
111static
112bt_message_iterator_class_next_method_status handle_message(
113 struct pretty_component *pretty,
114 const bt_message *message)
115{
116 bt_message_iterator_class_next_method_status ret =
117 BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
118
119 BT_ASSERT_DBG(pretty);
120
121 switch (bt_message_get_type(message)) {
122 case BT_MESSAGE_TYPE_EVENT:
123 if (pretty_print_event(pretty, message)) {
124 BT_COMP_LOGE_APPEND_CAUSE(pretty->self_comp,
125 "Failed to print one event.");
126 ret = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
127 }
128 break;
129 case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
130 case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
131 if (pretty_print_discarded_items(pretty, message)) {
132 BT_COMP_LOGE_APPEND_CAUSE(pretty->self_comp,
133 "Failed to print discarded items.");
134 ret = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
135 }
136 break;
137 default:
138 break;
139 }
140
141 return ret;
142}
143
144bt_component_class_sink_graph_is_configured_method_status
145pretty_graph_is_configured(bt_self_component_sink *self_comp_sink)
146{
147 bt_component_class_sink_graph_is_configured_method_status status;
148 bt_message_iterator_create_from_sink_component_status
149 msg_iter_status;
150 struct pretty_component *pretty;
151 bt_self_component *self_comp =
152 bt_self_component_sink_as_self_component(self_comp_sink);
153 bt_self_component_port_input *in_port;
154
155 pretty = bt_self_component_get_data(self_comp);
156 BT_ASSERT(pretty);
157 BT_ASSERT(!pretty->iterator);
158
159 in_port = bt_self_component_sink_borrow_input_port_by_name(self_comp_sink,
160 in_port_name);
161 if (!bt_port_is_connected(bt_port_input_as_port_const(
162 bt_self_component_port_input_as_port_input(in_port)))) {
163 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Single input port is not connected: "
164 "port-name=\"%s\"", in_port_name);
165 status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR;
166 goto end;
167 }
168
169 msg_iter_status = bt_message_iterator_create_from_sink_component(
170 self_comp_sink, in_port, &pretty->iterator);
171 if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK) {
172 status = (int) msg_iter_status;
173 goto end;
174 }
175
176 status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
177
178end:
179 return status;
180}
181
182bt_component_class_sink_consume_method_status pretty_consume(
183 bt_self_component_sink *comp)
184{
185 bt_component_class_sink_consume_method_status status;
186 bt_message_array_const msgs;
187 bt_message_iterator *it;
188 struct pretty_component *pretty = bt_self_component_get_data(
189 bt_self_component_sink_as_self_component(comp));
190 bt_message_iterator_next_status next_status;
191 uint64_t count = 0;
192 uint64_t i = 0;
193
194 it = pretty->iterator;
195 next_status = bt_message_iterator_next(it,
196 &msgs, &count);
197 if (next_status != BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) {
198 status = (int) next_status;
199 goto end;
200 }
201
202 for (i = 0; i < count; i++) {
203 status = (int) handle_message(pretty, msgs[i]);
204 if (status) {
205 goto end;
206 }
207
208 bt_message_put_ref(msgs[i]);
209 }
210
211 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
212
213end:
214 for (; i < count; i++) {
215 bt_message_put_ref(msgs[i]);
216 }
217
218 return status;
219}
220
221static
222void apply_one_string(const char *key, const bt_value *params, char **option)
223{
224 const bt_value *value = NULL;
225 const char *str;
226
227 value = bt_value_map_borrow_entry_value_const(params, key);
228 if (!value) {
229 goto end;
230 }
231
232 str = bt_value_string_get(value);
233 *option = g_strdup(str);
234
235end:
236 return;
237}
238
239/*
240 * Apply parameter with key `key` to `option`. Use `def` as the value, if
241 * the parameter is not specified.
242 */
243
244static
245void apply_one_bool_with_default(const char *key, const bt_value *params,
246 bool *option, bool def)
247{
248 const bt_value *value;
249
250 value = bt_value_map_borrow_entry_value_const(params, key);
251 if (value) {
252 bt_bool bool_val = bt_value_bool_get(value);
253
254 *option = (bool) bool_val;
255 } else {
256 *option = def;
257 }
258}
259
260static
261void apply_one_bool_if_specified(const char *key, const bt_value *params, bool *option)
262{
263 const bt_value *value;
264
265 value = bt_value_map_borrow_entry_value_const(params, key);
266 if (value) {
267 bt_bool bool_val = bt_value_bool_get(value);
268
269 *option = (bool) bool_val;
270 }
271}
272
273static
274int open_output_file(struct pretty_component *pretty)
275{
276 int ret = 0;
277
278 if (!pretty->options.output_path) {
279 goto end;
280 }
281
282 pretty->out = fopen(pretty->options.output_path, "w");
283 if (!pretty->out) {
284 goto error;
285 }
286
287 goto end;
288
289error:
290 ret = -1;
291
292end:
293 return ret;
294}
295
296static const char *color_choices[] = { "never", "auto", "always", NULL };
297static const char *show_hide_choices[] = { "show", "hide", NULL };
298
299static
300struct bt_param_validation_map_value_entry_descr pretty_params[] = {
301 { "color", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { BT_VALUE_TYPE_STRING, .string = {
302 .choices = color_choices,
303 } } },
304 { "path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } },
305 { "no-delta", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
306 { "clock-cycles", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
307 { "clock-seconds", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
308 { "clock-date", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
309 { "clock-gmt", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
310 { "verbose", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
311
312 { "name-default", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { BT_VALUE_TYPE_STRING, .string = {
313 .choices = show_hide_choices,
314 } } },
315 { "name-payload", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
316 { "name-context", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
317 { "name-scope", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
318 { "name-header", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
319
320 { "field-default", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { BT_VALUE_TYPE_STRING, .string = {
321 .choices = show_hide_choices,
322 } } },
323 { "field-trace", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
324 { "field-trace:hostname", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
325 { "field-trace:domain", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
326 { "field-trace:procname", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
327 { "field-trace:vpid", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
328 { "field-loglevel", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
329 { "field-emf", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
330 { "field-callsite", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
331 { "print-enum-flags", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
332 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
333};
334
335static
336bt_component_class_initialize_method_status apply_params(
337 struct pretty_component *pretty, const bt_value *params)
338{
339 int ret;
340 const bt_value *value;
341 bt_component_class_initialize_method_status status;
342 enum bt_param_validation_status validation_status;
343 gchar *validate_error = NULL;
344
345 validation_status = bt_param_validation_validate(params,
346 pretty_params, &validate_error);
347 if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
348 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
349 goto end;
350 } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
351 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
352 BT_COMP_LOGE_APPEND_CAUSE(pretty->self_comp, "%s", validate_error);
353 goto end;
354 }
355
356 /* Known parameters. */
357 pretty->options.color = PRETTY_COLOR_OPT_AUTO;
358 value = bt_value_map_borrow_entry_value_const(params, "color");
359 if (value) {
360 const char *color = bt_value_string_get(value);
361
362 if (strcmp(color, "never") == 0) {
363 pretty->options.color = PRETTY_COLOR_OPT_NEVER;
364 } else if (strcmp(color, "auto") == 0) {
365 pretty->options.color = PRETTY_COLOR_OPT_AUTO;
366 } else {
367 BT_ASSERT(strcmp(color, "always") == 0);
368 pretty->options.color = PRETTY_COLOR_OPT_ALWAYS;
369 }
370 }
371
372 apply_one_string("path", params, &pretty->options.output_path);
373 ret = open_output_file(pretty);
374 if (ret) {
375 BT_COMP_LOGE_APPEND_CAUSE(pretty->self_comp,
376 "Failed to open output file: %s", validate_error);
377 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
378 goto end;
379 }
380
381 apply_one_bool_with_default("no-delta", params,
382 &pretty->options.print_delta_field, false);
383 /* Reverse logic. */
384 pretty->options.print_delta_field = !pretty->options.print_delta_field;
385
386 apply_one_bool_with_default("clock-cycles", params,
387 &pretty->options.print_timestamp_cycles, false);
388
389 apply_one_bool_with_default("clock-seconds", params,
390 &pretty->options.clock_seconds , false);
391
392 apply_one_bool_with_default("clock-date", params,
393 &pretty->options.clock_date, false);
394
395 apply_one_bool_with_default("clock-gmt", params,
396 &pretty->options.clock_gmt, false);
397
398 apply_one_bool_with_default("verbose", params,
399 &pretty->options.verbose, false);
400
401 apply_one_bool_with_default("print-enum-flags", params,
402 &pretty->options.print_enum_flags, false);
403
404 /* Names. */
405 value = bt_value_map_borrow_entry_value_const(params, "name-default");
406 if (value) {
407 const char *str = bt_value_string_get(value);
408
409 if (strcmp(str, "show") == 0) {
410 pretty->options.name_default = PRETTY_DEFAULT_SHOW;
411 } else {
412 BT_ASSERT(strcmp(str, "hide") == 0);
413 pretty->options.name_default = PRETTY_DEFAULT_HIDE;
414 }
415 } else {
416 pretty->options.name_default = PRETTY_DEFAULT_UNSET;
417 }
418
419 switch (pretty->options.name_default) {
420 case PRETTY_DEFAULT_UNSET:
421 pretty->options.print_payload_field_names = true;
422 pretty->options.print_context_field_names = true;
423 pretty->options.print_header_field_names = false;
424 pretty->options.print_scope_field_names = false;
425 break;
426 case PRETTY_DEFAULT_SHOW:
427 pretty->options.print_payload_field_names = true;
428 pretty->options.print_context_field_names = true;
429 pretty->options.print_header_field_names = true;
430 pretty->options.print_scope_field_names = true;
431 break;
432 case PRETTY_DEFAULT_HIDE:
433 pretty->options.print_payload_field_names = false;
434 pretty->options.print_context_field_names = false;
435 pretty->options.print_header_field_names = false;
436 pretty->options.print_scope_field_names = false;
437 break;
438 default:
439 bt_common_abort();
440 }
441
442 apply_one_bool_if_specified("name-payload", params,
443 &pretty->options.print_payload_field_names);
444
445 apply_one_bool_if_specified("name-context", params,
446 &pretty->options.print_context_field_names);
447
448 apply_one_bool_if_specified("name-header", params,
449 &pretty->options.print_header_field_names);
450
451 apply_one_bool_if_specified("name-scope", params,
452 &pretty->options.print_scope_field_names);
453
454 /* Fields. */
455 value = bt_value_map_borrow_entry_value_const(params, "field-default");
456 if (value) {
457 const char *str = bt_value_string_get(value);
458
459 if (strcmp(str, "show") == 0) {
460 pretty->options.field_default = PRETTY_DEFAULT_SHOW;
461 } else {
462 BT_ASSERT(strcmp(str, "hide") == 0);
463 pretty->options.field_default = PRETTY_DEFAULT_HIDE;
464 }
465 } else {
466 pretty->options.field_default = PRETTY_DEFAULT_UNSET;
467 }
468
469 switch (pretty->options.field_default) {
470 case PRETTY_DEFAULT_UNSET:
471 pretty->options.print_trace_field = false;
472 pretty->options.print_trace_hostname_field = true;
473 pretty->options.print_trace_domain_field = false;
474 pretty->options.print_trace_procname_field = true;
475 pretty->options.print_trace_vpid_field = true;
476 pretty->options.print_loglevel_field = false;
477 pretty->options.print_emf_field = false;
478 pretty->options.print_callsite_field = false;
479 break;
480 case PRETTY_DEFAULT_SHOW:
481 pretty->options.print_trace_field = true;
482 pretty->options.print_trace_hostname_field = true;
483 pretty->options.print_trace_domain_field = true;
484 pretty->options.print_trace_procname_field = true;
485 pretty->options.print_trace_vpid_field = true;
486 pretty->options.print_loglevel_field = true;
487 pretty->options.print_emf_field = true;
488 pretty->options.print_callsite_field = true;
489 break;
490 case PRETTY_DEFAULT_HIDE:
491 pretty->options.print_trace_field = false;
492 pretty->options.print_trace_hostname_field = false;
493 pretty->options.print_trace_domain_field = false;
494 pretty->options.print_trace_procname_field = false;
495 pretty->options.print_trace_vpid_field = false;
496 pretty->options.print_loglevel_field = false;
497 pretty->options.print_emf_field = false;
498 pretty->options.print_callsite_field = false;
499 break;
500 default:
501 bt_common_abort();
502 }
503
504 apply_one_bool_if_specified("field-trace", params,
505 &pretty->options.print_trace_field);
506
507 apply_one_bool_if_specified("field-trace:hostname", params,
508 &pretty->options.print_trace_hostname_field);
509
510 apply_one_bool_if_specified("field-trace:domain", params,
511 &pretty->options.print_trace_domain_field);
512
513 apply_one_bool_if_specified("field-trace:procname", params,
514 &pretty->options.print_trace_procname_field);
515
516 apply_one_bool_if_specified("field-trace:vpid", params,
517 &pretty->options.print_trace_vpid_field);
518
519 apply_one_bool_if_specified("field-loglevel", params,
520 &pretty->options.print_loglevel_field);
521
522 apply_one_bool_if_specified("field-emf", params,
523 &pretty->options.print_emf_field);
524
525 apply_one_bool_if_specified("field-callsite", params,
526 &pretty->options.print_callsite_field);
527
528 pretty_print_init();
529 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
530
531end:
532 g_free(validate_error);
533
534 return status;
535}
536
537static
538void set_use_colors(struct pretty_component *pretty)
539{
540 switch (pretty->options.color) {
541 case PRETTY_COLOR_OPT_ALWAYS:
542 pretty->use_colors = true;
543 break;
544 case PRETTY_COLOR_OPT_AUTO:
545 pretty->use_colors = pretty->out == stdout &&
546 bt_common_colors_supported();
547 break;
548 case PRETTY_COLOR_OPT_NEVER:
549 pretty->use_colors = false;
550 break;
551 }
552}
553
554bt_component_class_initialize_method_status pretty_init(
555 bt_self_component_sink *self_comp_sink,
556 bt_self_component_sink_configuration *config __attribute__((unused)),
557 const bt_value *params,
558 void *init_method_data __attribute__((unused)))
559{
560 bt_component_class_initialize_method_status status;
561 bt_self_component_add_port_status add_port_status;
562 struct pretty_component *pretty = create_pretty();
563 bt_self_component *self_comp =
564 bt_self_component_sink_as_self_component(self_comp_sink);
565 const bt_component *comp = bt_self_component_as_component(self_comp);
566 bt_logging_level log_level = bt_component_get_logging_level(comp);
567
568 if (!pretty) {
569 /*
570 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `pretty` is not
571 * initialized yet.
572 */
573 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
574 "Failed to allocate component.");
575 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
576 self_comp, "Failed to allocate component.");
577 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
578 goto error;
579 }
580
581 pretty->self_comp = self_comp;
582 pretty->log_level = log_level;
583
584 add_port_status = bt_self_component_sink_add_input_port(self_comp_sink,
585 in_port_name, NULL, NULL);
586 if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
587 status = (int) add_port_status;
588 goto error;
589 }
590
591 pretty->out = stdout;
592 pretty->err = stderr;
593
594 pretty->delta_cycles = -1ULL;
595 pretty->last_cycles_timestamp = -1ULL;
596
597 pretty->delta_real_timestamp = -1ULL;
598 pretty->last_real_timestamp = -1ULL;
599
600 status = apply_params(pretty, params);
601 if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
602 goto error;
603 }
604
605 set_use_colors(pretty);
606
607 if (pretty->options.print_enum_flags) {
608 uint64_t i;
609 /*
610 * Allocate all label arrays during the initialization of the
611 * component and reuse the same set of arrays for all
612 * enumerations.
613 */
614 for (i = 0; i < ENUMERATION_MAX_BITFLAGS_COUNT; i++) {
615 pretty->enum_bit_labels[i] = g_ptr_array_new();
616 }
617 }
618 bt_self_component_set_data(self_comp, pretty);
619
620 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
621 goto end;
622
623error:
624 destroy_pretty_data(pretty);
625
626end:
627 return status;
628}
This page took 0.026737 seconds and 5 git commands to generate.