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