Remove component prefix from graph, connection and port filenames
[babeltrace.git] / plugins / text / text.c
1 /*
2 * text.c
3 *
4 * Babeltrace CTF Text Output Plugin
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #include <babeltrace/plugin/plugin-dev.h>
31 #include <babeltrace/component/component.h>
32 #include <babeltrace/component/component-sink.h>
33 #include <babeltrace/component/port.h>
34 #include <babeltrace/component/connection.h>
35 #include <babeltrace/component/notification/notification.h>
36 #include <babeltrace/component/notification/iterator.h>
37 #include <babeltrace/component/notification/event.h>
38 #include <babeltrace/values.h>
39 #include <babeltrace/compiler.h>
40 #include <babeltrace/common-internal.h>
41 #include <plugins-common.h>
42 #include <stdio.h>
43 #include <stdbool.h>
44 #include <glib.h>
45 #include "text.h"
46 #include <assert.h>
47
48 static
49 const char *plugin_options[] = {
50 "color",
51 "output-path",
52 "debug-info-dir",
53 "debug-info-target-prefix",
54 "debug-info-full-path",
55 "no-delta",
56 "clock-cycles",
57 "clock-seconds",
58 "clock-date",
59 "clock-gmt",
60 "verbose",
61 "name-default", /* show/hide */
62 "name-payload",
63 "name-context",
64 "name-scope",
65 "name-header",
66 "field-default", /* show/hide */
67 "field-trace",
68 "field-trace:hostname",
69 "field-trace:domain",
70 "field-trace:procname",
71 "field-trace:vpid",
72 "field-loglevel",
73 "field-emf",
74 };
75
76 static
77 void destroy_text_data(struct text_component *text)
78 {
79 bt_put(text->input_iterator);
80 (void) g_string_free(text->string, TRUE);
81 g_free(text->options.output_path);
82 g_free(text->options.debug_info_dir);
83 g_free(text->options.debug_info_target_prefix);
84 g_free(text);
85 }
86
87 static
88 struct text_component *create_text(void)
89 {
90 struct text_component *text;
91
92 text = g_new0(struct text_component, 1);
93 if (!text) {
94 goto end;
95 }
96 text->string = g_string_new("");
97 if (!text->string) {
98 goto error;
99 }
100 end:
101 return text;
102
103 error:
104 g_free(text);
105 return NULL;
106 }
107
108 static
109 void destroy_text(struct bt_component *component)
110 {
111 void *data = bt_component_get_private_data(component);
112
113 destroy_text_data(data);
114 }
115
116 static
117 enum bt_component_status handle_notification(struct text_component *text,
118 struct bt_notification *notification)
119 {
120 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
121
122 if (!text) {
123 ret = BT_COMPONENT_STATUS_ERROR;
124 goto end;
125 }
126
127 switch (bt_notification_get_type(notification)) {
128 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
129 puts("<packet>");
130 break;
131 case BT_NOTIFICATION_TYPE_PACKET_END:
132 puts("</packet>");
133 break;
134 case BT_NOTIFICATION_TYPE_EVENT:
135 {
136 struct bt_ctf_event *event = bt_notification_event_get_event(
137 notification);
138
139 if (!event) {
140 ret = BT_COMPONENT_STATUS_ERROR;
141 goto end;
142 }
143 ret = text_print_event(text, event);
144 bt_put(event);
145 if (ret != BT_COMPONENT_STATUS_OK) {
146 goto end;
147 }
148 break;
149 }
150 case BT_NOTIFICATION_TYPE_STREAM_END:
151 puts("</stream>");
152 break;
153 default:
154 puts("Unhandled notification type");
155 }
156 end:
157 return ret;
158 }
159
160 static
161 enum bt_component_status text_new_connection(struct bt_port *own_port,
162 struct bt_connection *connection)
163 {
164 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
165 struct bt_component *component;
166 struct text_component *text;
167
168 component = bt_port_get_component(own_port);
169 assert(component);
170 text = bt_component_get_private_data(component);
171 assert(text);
172 assert(!text->input_iterator);
173 text->input_iterator = bt_connection_create_notification_iterator(
174 connection);
175
176 if (!text->input_iterator) {
177 ret = BT_COMPONENT_STATUS_ERROR;
178 }
179 bt_put(component);
180 return ret;
181 }
182
183 static
184 enum bt_component_status run(struct bt_component *component)
185 {
186 enum bt_component_status ret;
187 struct bt_notification *notification = NULL;
188 struct bt_notification_iterator *it;
189 struct text_component *text = bt_component_get_private_data(component);
190
191 it = text->input_iterator;
192
193 if (likely(text->processed_first_event)) {
194 enum bt_notification_iterator_status it_ret;
195
196 it_ret = bt_notification_iterator_next(it);
197 switch (it_ret) {
198 case BT_NOTIFICATION_ITERATOR_STATUS_ERROR:
199 ret = BT_COMPONENT_STATUS_ERROR;
200 goto end;
201 case BT_NOTIFICATION_ITERATOR_STATUS_END:
202 ret = BT_COMPONENT_STATUS_END;
203 BT_PUT(text->input_iterator);
204 goto end;
205 default:
206 break;
207 }
208 }
209 notification = bt_notification_iterator_get_notification(it);
210 if (!notification) {
211 ret = BT_COMPONENT_STATUS_ERROR;
212 goto end;
213 }
214
215 ret = handle_notification(text, notification);
216 text->processed_first_event = true;
217 end:
218 bt_put(notification);
219 return ret;
220 }
221
222 static
223 enum bt_component_status add_params_to_map(struct bt_value *plugin_opt_map)
224 {
225 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
226 unsigned int i;
227
228 for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
229 const char *key = plugin_options[i];
230 enum bt_value_status status;
231
232 status = bt_value_map_insert(plugin_opt_map, key, bt_value_null);
233 switch (status) {
234 case BT_VALUE_STATUS_OK:
235 break;
236 default:
237 ret = BT_COMPONENT_STATUS_ERROR;
238 goto end;
239 }
240 }
241 end:
242 return ret;
243 }
244
245 static
246 bool check_param_exists(const char *key, struct bt_value *object, void *data)
247 {
248 struct text_component *text = data;
249 struct bt_value *plugin_opt_map = text->plugin_opt_map;
250
251 if (!bt_value_map_get(plugin_opt_map, key)) {
252 fprintf(text->err,
253 "[warning] Parameter \"%s\" unknown to \"text\" plugin\n", key);
254 }
255 return true;
256 }
257
258 static
259 enum bt_component_status apply_one_string(const char *key,
260 struct bt_value *params,
261 char **option)
262 {
263 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
264 struct bt_value *value = NULL;
265 enum bt_value_status status;
266 const char *str;
267
268 value = bt_value_map_get(params, key);
269 if (!value) {
270 goto end;
271 }
272 if (bt_value_is_null(value)) {
273 goto end;
274 }
275 status = bt_value_string_get(value, &str);
276 switch (status) {
277 case BT_VALUE_STATUS_OK:
278 break;
279 default:
280 ret = BT_COMPONENT_STATUS_ERROR;
281 goto end;
282 }
283 *option = g_strdup(str);
284 end:
285 bt_put(value);
286 return ret;
287 }
288
289 static
290 enum bt_component_status apply_one_bool(const char *key,
291 struct bt_value *params,
292 bool *option,
293 bool *found)
294 {
295 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
296 struct bt_value *value = NULL;
297 enum bt_value_status status;
298
299 value = bt_value_map_get(params, key);
300 if (!value) {
301 goto end;
302 }
303 status = bt_value_bool_get(value, option);
304 switch (status) {
305 case BT_VALUE_STATUS_OK:
306 break;
307 default:
308 ret = BT_COMPONENT_STATUS_ERROR;
309 goto end;
310 }
311 if (found) {
312 *found = true;
313 }
314 end:
315 bt_put(value);
316 return ret;
317 }
318
319 static
320 void warn_wrong_color_param(struct text_component *text)
321 {
322 fprintf(text->err,
323 "[warning] Accepted values for the \"color\" parameter are:\n \"always\", \"auto\", \"never\"\n");
324 }
325
326 static
327 enum bt_component_status apply_params(struct text_component *text,
328 struct bt_value *params)
329 {
330 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
331 enum bt_value_status status;
332 bool value, found;
333 char *str = NULL;
334
335 text->plugin_opt_map = bt_value_map_create();
336 if (!text->plugin_opt_map) {
337 ret = BT_COMPONENT_STATUS_ERROR;
338 goto end;
339 }
340 ret = add_params_to_map(text->plugin_opt_map);
341 if (ret != BT_COMPONENT_STATUS_OK) {
342 goto end;
343 }
344 /* Report unknown parameters. */
345 status = bt_value_map_foreach(params, check_param_exists, text);
346 switch (status) {
347 case BT_VALUE_STATUS_OK:
348 break;
349 default:
350 ret = BT_COMPONENT_STATUS_ERROR;
351 goto end;
352 }
353 /* Known parameters. */
354 text->options.color = TEXT_COLOR_OPT_AUTO;
355 if (bt_value_map_has_key(params, "color")) {
356 struct bt_value *color_value;
357 const char *color;
358
359 color_value = bt_value_map_get(params, "color");
360 if (!color_value) {
361 goto end;
362 }
363
364 ret = bt_value_string_get(color_value, &color);
365 if (ret) {
366 warn_wrong_color_param(text);
367 } else {
368 if (strcmp(color, "never") == 0) {
369 text->options.color = TEXT_COLOR_OPT_NEVER;
370 } else if (strcmp(color, "auto") == 0) {
371 text->options.color = TEXT_COLOR_OPT_AUTO;
372 } else if (strcmp(color, "always") == 0) {
373 text->options.color = TEXT_COLOR_OPT_ALWAYS;
374 } else {
375 warn_wrong_color_param(text);
376 }
377 }
378
379 bt_put(color_value);
380 }
381
382 ret = apply_one_string("output-path",
383 params,
384 &text->options.output_path);
385 if (ret != BT_COMPONENT_STATUS_OK) {
386 goto end;
387 }
388
389 ret = apply_one_string("debug-info-dir",
390 params,
391 &text->options.debug_info_dir);
392 if (ret != BT_COMPONENT_STATUS_OK) {
393 goto end;
394 }
395
396 ret = apply_one_string("debug-info-target-prefix",
397 params,
398 &text->options.debug_info_target_prefix);
399 if (ret != BT_COMPONENT_STATUS_OK) {
400 goto end;
401 }
402
403 value = false; /* Default. */
404 ret = apply_one_bool("debug-info-full-path", params, &value, NULL);
405 if (ret != BT_COMPONENT_STATUS_OK) {
406 goto end;
407 }
408 text->options.debug_info_full_path = value;
409
410 value = false; /* Default. */
411 ret = apply_one_bool("no-delta", params, &value, NULL);
412 if (ret != BT_COMPONENT_STATUS_OK) {
413 goto end;
414 }
415 text->options.print_delta_field = !value; /* Reverse logic. */
416
417 value = false; /* Default. */
418 ret = apply_one_bool("clock-cycles", params, &value, NULL);
419 if (ret != BT_COMPONENT_STATUS_OK) {
420 goto end;
421 }
422 text->options.print_timestamp_cycles = value;
423
424 value = false; /* Default. */
425 ret = apply_one_bool("clock-seconds", params, &value, NULL);
426 if (ret != BT_COMPONENT_STATUS_OK) {
427 goto end;
428 }
429 text->options.clock_seconds = value;
430
431 value = false; /* Default. */
432 ret = apply_one_bool("clock-date", params, &value, NULL);
433 if (ret != BT_COMPONENT_STATUS_OK) {
434 goto end;
435 }
436 text->options.clock_date = value;
437
438 value = false; /* Default. */
439 ret = apply_one_bool("clock-gmt", params, &value, NULL);
440 if (ret != BT_COMPONENT_STATUS_OK) {
441 goto end;
442 }
443 text->options.clock_gmt = value;
444
445 value = false; /* Default. */
446 ret = apply_one_bool("verbose", params, &value, NULL);
447 if (ret != BT_COMPONENT_STATUS_OK) {
448 goto end;
449 }
450 text->options.verbose = value;
451
452 /* Names. */
453 ret = apply_one_string("name-default", params, &str);
454 if (ret != BT_COMPONENT_STATUS_OK) {
455 goto end;
456 }
457 if (!str) {
458 text->options.name_default = TEXT_DEFAULT_UNSET;
459 } else if (!strcmp(str, "show")) {
460 text->options.name_default = TEXT_DEFAULT_SHOW;
461 } else if (!strcmp(str, "hide")) {
462 text->options.name_default = TEXT_DEFAULT_HIDE;
463 } else {
464 ret = BT_COMPONENT_STATUS_ERROR;
465 goto end;
466 }
467 g_free(str);
468 str = NULL;
469
470 switch (text->options.name_default) {
471 case TEXT_DEFAULT_UNSET:
472 text->options.print_payload_field_names = true;
473 text->options.print_context_field_names = true;
474 text->options.print_header_field_names = false;
475 text->options.print_scope_field_names = false;
476 break;
477 case TEXT_DEFAULT_SHOW:
478 text->options.print_payload_field_names = true;
479 text->options.print_context_field_names = true;
480 text->options.print_header_field_names = true;
481 text->options.print_scope_field_names = true;
482 break;
483 case TEXT_DEFAULT_HIDE:
484 text->options.print_payload_field_names = false;
485 text->options.print_context_field_names = false;
486 text->options.print_header_field_names = false;
487 text->options.print_scope_field_names = false;
488 break;
489 default:
490 ret = BT_COMPONENT_STATUS_ERROR;
491 goto end;
492 }
493
494 value = false;
495 found = false;
496 ret = apply_one_bool("name-payload", params, &value, &found);
497 if (ret != BT_COMPONENT_STATUS_OK) {
498 goto end;
499 }
500 if (found) {
501 text->options.print_payload_field_names = value;
502 }
503
504 value = false;
505 found = false;
506 ret = apply_one_bool("name-context", params, &value, &found);
507 if (ret != BT_COMPONENT_STATUS_OK) {
508 goto end;
509 }
510 if (found) {
511 text->options.print_context_field_names = value;
512 }
513
514 value = false;
515 found = false;
516 ret = apply_one_bool("name-header", params, &value, &found);
517 if (ret != BT_COMPONENT_STATUS_OK) {
518 goto end;
519 }
520 if (found) {
521 text->options.print_header_field_names = value;
522 }
523
524 value = false;
525 found = false;
526 ret = apply_one_bool("name-scope", params, &value, &found);
527 if (ret != BT_COMPONENT_STATUS_OK) {
528 goto end;
529 }
530 if (found) {
531 text->options.print_scope_field_names = value;
532 }
533
534 /* Fields. */
535 ret = apply_one_string("field-default", params, &str);
536 if (ret != BT_COMPONENT_STATUS_OK) {
537 goto end;
538 }
539 if (!str) {
540 text->options.field_default = TEXT_DEFAULT_UNSET;
541 } else if (!strcmp(str, "show")) {
542 text->options.field_default = TEXT_DEFAULT_SHOW;
543 } else if (!strcmp(str, "hide")) {
544 text->options.field_default = TEXT_DEFAULT_HIDE;
545 } else {
546 ret = BT_COMPONENT_STATUS_ERROR;
547 goto end;
548 }
549 g_free(str);
550 str = NULL;
551
552 switch (text->options.field_default) {
553 case TEXT_DEFAULT_UNSET:
554 text->options.print_trace_field = false;
555 text->options.print_trace_hostname_field = true;
556 text->options.print_trace_domain_field = false;
557 text->options.print_trace_procname_field = true;
558 text->options.print_trace_vpid_field = true;
559 text->options.print_loglevel_field = false;
560 text->options.print_emf_field = false;
561 text->options.print_emf_field = false;
562 break;
563 case TEXT_DEFAULT_SHOW:
564 text->options.print_trace_field = true;
565 text->options.print_trace_hostname_field = true;
566 text->options.print_trace_domain_field = true;
567 text->options.print_trace_procname_field = true;
568 text->options.print_trace_vpid_field = true;
569 text->options.print_loglevel_field = true;
570 text->options.print_emf_field = true;
571 text->options.print_emf_field = true;
572 break;
573 case TEXT_DEFAULT_HIDE:
574 text->options.print_trace_field = false;
575 text->options.print_trace_hostname_field = false;
576 text->options.print_trace_domain_field = false;
577 text->options.print_trace_procname_field = false;
578 text->options.print_trace_vpid_field = false;
579 text->options.print_loglevel_field = false;
580 text->options.print_emf_field = false;
581 text->options.print_emf_field = false;
582 break;
583 default:
584 ret = BT_COMPONENT_STATUS_ERROR;
585 goto end;
586 }
587
588 value = false;
589 found = false;
590 ret = apply_one_bool("field-trace", params, &value, &found);
591 if (ret != BT_COMPONENT_STATUS_OK) {
592 goto end;
593 }
594 if (found) {
595 text->options.print_trace_field = value;
596 }
597
598 value = false;
599 found = false;
600 ret = apply_one_bool("field-trace:hostname", params, &value, &found);
601 if (ret != BT_COMPONENT_STATUS_OK) {
602 goto end;
603 }
604 if (found) {
605 text->options.print_trace_hostname_field = value;
606 }
607
608 value = false;
609 found = false;
610 ret = apply_one_bool("field-trace:domain", params, &value, &found);
611 if (ret != BT_COMPONENT_STATUS_OK) {
612 goto end;
613 }
614 if (found) {
615 text->options.print_trace_domain_field = value;
616 }
617
618 value = false;
619 found = false;
620 ret = apply_one_bool("field-trace:procname", params, &value, &found);
621 if (ret != BT_COMPONENT_STATUS_OK) {
622 goto end;
623 }
624 if (found) {
625 text->options.print_trace_procname_field = value;
626 }
627
628 value = false;
629 found = false;
630 ret = apply_one_bool("field-trace:vpid", params, &value, &found);
631 if (ret != BT_COMPONENT_STATUS_OK) {
632 goto end;
633 }
634 if (found) {
635 text->options.print_trace_vpid_field = value;
636 }
637
638 value = false;
639 found = false;
640 ret = apply_one_bool("field-loglevel", params, &value, &found);
641 if (ret != BT_COMPONENT_STATUS_OK) {
642 goto end;
643 }
644 if (found) {
645 text->options.print_loglevel_field = value;
646 }
647
648 value = false;
649 found = false;
650 ret = apply_one_bool("field-emf", params, &value, &found);
651 if (ret != BT_COMPONENT_STATUS_OK) {
652 goto end;
653 }
654 if (found) {
655 text->options.print_emf_field = value;
656 }
657
658 value = false;
659 found = false;
660 ret = apply_one_bool("field-emf", params, &value, &found);
661 if (ret != BT_COMPONENT_STATUS_OK) {
662 goto end;
663 }
664 if (found) {
665 text->options.print_emf_field = value;
666 }
667
668 end:
669 bt_put(text->plugin_opt_map);
670 text->plugin_opt_map = NULL;
671 g_free(str);
672 return ret;
673 }
674
675 static
676 void set_use_colors(struct text_component *text)
677 {
678 switch (text->options.color) {
679 case TEXT_COLOR_OPT_ALWAYS:
680 text->use_colors = true;
681 break;
682 case TEXT_COLOR_OPT_AUTO:
683 text->use_colors = text->out == stdout &&
684 bt_common_colors_supported();
685 break;
686 case TEXT_COLOR_OPT_NEVER:
687 text->use_colors = false;
688 break;
689 }
690 }
691
692 static
693 void init_stream_packet_context_quarks(void)
694 {
695 stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
696 g_quark_from_string("timestamp_begin");
697 stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
698 g_quark_from_string("timestamp_begin");
699 stream_packet_context_quarks[Q_TIMESTAMP_END] =
700 g_quark_from_string("timestamp_end");
701 stream_packet_context_quarks[Q_EVENTS_DISCARDED] =
702 g_quark_from_string("events_discarded");
703 stream_packet_context_quarks[Q_CONTENT_SIZE] =
704 g_quark_from_string("content_size");
705 stream_packet_context_quarks[Q_PACKET_SIZE] =
706 g_quark_from_string("packet_size");
707 stream_packet_context_quarks[Q_PACKET_SEQ_NUM] =
708 g_quark_from_string("packet_seq_num");
709 }
710
711 static
712 enum bt_component_status text_component_init(
713 struct bt_component *component, struct bt_value *params,
714 UNUSED_VAR void *init_method_data)
715 {
716 enum bt_component_status ret;
717 struct text_component *text = create_text();
718
719 if (!text) {
720 ret = BT_COMPONENT_STATUS_NOMEM;
721 goto end;
722 }
723
724 text->out = stdout;
725 text->err = stderr;
726
727 text->delta_cycles = -1ULL;
728 text->last_cycles_timestamp = -1ULL;
729
730 text->delta_real_timestamp = -1ULL;
731 text->last_real_timestamp = -1ULL;
732
733 ret = apply_params(text, params);
734 if (ret != BT_COMPONENT_STATUS_OK) {
735 goto error;
736 }
737
738 set_use_colors(text);
739
740 ret = bt_component_set_private_data(component, text);
741 if (ret != BT_COMPONENT_STATUS_OK) {
742 goto error;
743 }
744
745 init_stream_packet_context_quarks();
746
747 end:
748 return ret;
749 error:
750 destroy_text_data(text);
751 return ret;
752 }
753
754 /* Initialize plug-in entry points. */
755 BT_PLUGIN(text);
756 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
757 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
758 BT_PLUGIN_LICENSE("MIT");
759 BT_PLUGIN_SINK_COMPONENT_CLASS(text, run);
760 BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(text, text_component_init);
761 BT_PLUGIN_SINK_COMPONENT_CLASS_NEW_CONNECTION_METHOD(text, text_new_connection);
762 BT_PLUGIN_SINK_COMPONENT_CLASS_DESTROY_METHOD(text, destroy_text);
763 BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(text,
764 "Formats CTF-IR to text. Formerly known as ctf-text.");
This page took 0.0468769999999999 seconds and 4 git commands to generate.