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