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