4 * Babeltrace CTF Text Output Plugin
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
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:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
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
30 #include <babeltrace/plugin/plugin-dev.h>
31 #include <babeltrace/graph/component.h>
32 #include <babeltrace/graph/private-component.h>
33 #include <babeltrace/graph/component-sink.h>
34 #include <babeltrace/graph/port.h>
35 #include <babeltrace/graph/private-port.h>
36 #include <babeltrace/graph/connection.h>
37 #include <babeltrace/graph/private-connection.h>
38 #include <babeltrace/graph/notification.h>
39 #include <babeltrace/graph/notification-iterator.h>
40 #include <babeltrace/graph/notification-event.h>
41 #include <babeltrace/values.h>
42 #include <babeltrace/compiler-internal.h>
43 #include <babeltrace/common-internal.h>
44 #include <plugins-common.h>
52 const char *plugin_options
[] = {
56 "debug-info-target-prefix",
57 "debug-info-full-path",
64 "name-default", /* show/hide */
69 "field-default", /* show/hide */
71 "field-trace:hostname",
73 "field-trace:procname",
81 void destroy_text_data(struct text_component
*text
)
83 bt_put(text
->input_iterator
);
84 (void) g_string_free(text
->string
, TRUE
);
85 if (text
->out
!= stdout
) {
88 ret
= fclose(text
->out
);
90 perror("close output file");
93 g_free(text
->options
.output_path
);
94 g_free(text
->options
.debug_info_dir
);
95 g_free(text
->options
.debug_info_target_prefix
);
100 struct text_component
*create_text(void)
102 struct text_component
*text
;
104 text
= g_new0(struct text_component
, 1);
108 text
->string
= g_string_new("");
121 void finalize_text(struct bt_private_component
*component
)
123 void *data
= bt_private_component_get_user_data(component
);
125 destroy_text_data(data
);
129 enum bt_component_status
handle_notification(struct text_component
*text
,
130 struct bt_notification
*notification
)
132 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
135 ret
= BT_COMPONENT_STATUS_ERROR
;
139 switch (bt_notification_get_type(notification
)) {
140 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
142 case BT_NOTIFICATION_TYPE_PACKET_END
:
144 case BT_NOTIFICATION_TYPE_EVENT
:
146 struct bt_ctf_event
*event
= bt_notification_event_get_event(
150 ret
= BT_COMPONENT_STATUS_ERROR
;
153 ret
= text_print_event(text
, event
);
155 if (ret
!= BT_COMPONENT_STATUS_OK
) {
160 case BT_NOTIFICATION_TYPE_STREAM_END
:
163 puts("Unhandled notification type");
170 enum bt_component_status
text_accept_port_connection(
171 struct bt_private_component
*component
,
172 struct bt_private_port
*self_port
,
173 struct bt_port
*other_port
)
175 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
176 struct bt_private_connection
*connection
;
177 struct text_component
*text
;
179 text
= bt_private_component_get_user_data(component
);
181 assert(!text
->input_iterator
);
182 connection
= bt_private_port_get_private_connection(self_port
);
184 text
->input_iterator
=
185 bt_private_connection_create_notification_iterator(connection
);
187 if (!text
->input_iterator
) {
188 ret
= BT_COMPONENT_STATUS_ERROR
;
196 enum bt_component_status
run(struct bt_private_component
*component
)
198 enum bt_component_status ret
;
199 struct bt_notification
*notification
= NULL
;
200 struct bt_notification_iterator
*it
;
201 struct text_component
*text
=
202 bt_private_component_get_user_data(component
);
203 enum bt_notification_iterator_status it_ret
;
205 it
= text
->input_iterator
;
207 it_ret
= bt_notification_iterator_next(it
);
209 case BT_NOTIFICATION_ITERATOR_STATUS_ERROR
:
210 ret
= BT_COMPONENT_STATUS_ERROR
;
212 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
213 ret
= BT_COMPONENT_STATUS_END
;
214 BT_PUT(text
->input_iterator
);
220 notification
= bt_notification_iterator_get_notification(it
);
221 assert(notification
);
222 ret
= handle_notification(text
, notification
);
223 text
->processed_first_event
= true;
225 bt_put(notification
);
230 enum bt_component_status
add_params_to_map(struct bt_value
*plugin_opt_map
)
232 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
235 for (i
= 0; i
< BT_ARRAY_SIZE(plugin_options
); i
++) {
236 const char *key
= plugin_options
[i
];
237 enum bt_value_status status
;
239 status
= bt_value_map_insert(plugin_opt_map
, key
, bt_value_null
);
241 case BT_VALUE_STATUS_OK
:
244 ret
= BT_COMPONENT_STATUS_ERROR
;
253 bool check_param_exists(const char *key
, struct bt_value
*object
, void *data
)
255 struct text_component
*text
= data
;
256 struct bt_value
*plugin_opt_map
= text
->plugin_opt_map
;
258 if (!bt_value_map_get(plugin_opt_map
, key
)) {
260 "[warning] Parameter \"%s\" unknown to \"text\" plugin\n", key
);
266 enum bt_component_status
apply_one_string(const char *key
,
267 struct bt_value
*params
,
270 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
271 struct bt_value
*value
= NULL
;
272 enum bt_value_status status
;
275 value
= bt_value_map_get(params
, key
);
279 if (bt_value_is_null(value
)) {
282 status
= bt_value_string_get(value
, &str
);
284 case BT_VALUE_STATUS_OK
:
287 ret
= BT_COMPONENT_STATUS_ERROR
;
290 *option
= g_strdup(str
);
297 enum bt_component_status
apply_one_bool(const char *key
,
298 struct bt_value
*params
,
302 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
303 struct bt_value
*value
= NULL
;
304 enum bt_value_status status
;
306 value
= bt_value_map_get(params
, key
);
310 status
= bt_value_bool_get(value
, option
);
312 case BT_VALUE_STATUS_OK
:
315 ret
= BT_COMPONENT_STATUS_ERROR
;
327 void warn_wrong_color_param(struct text_component
*text
)
330 "[warning] Accepted values for the \"color\" parameter are:\n \"always\", \"auto\", \"never\"\n");
334 enum bt_component_status
open_output_file(struct text_component
*text
)
336 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
338 if (!text
->options
.output_path
) {
342 text
->out
= fopen(text
->options
.output_path
, "w");
350 ret
= BT_COMPONENT_STATUS_ERROR
;
356 enum bt_component_status
apply_params(struct text_component
*text
,
357 struct bt_value
*params
)
359 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
360 enum bt_value_status status
;
364 text
->plugin_opt_map
= bt_value_map_create();
365 if (!text
->plugin_opt_map
) {
366 ret
= BT_COMPONENT_STATUS_ERROR
;
369 ret
= add_params_to_map(text
->plugin_opt_map
);
370 if (ret
!= BT_COMPONENT_STATUS_OK
) {
373 /* Report unknown parameters. */
374 status
= bt_value_map_foreach(params
, check_param_exists
, text
);
376 case BT_VALUE_STATUS_OK
:
379 ret
= BT_COMPONENT_STATUS_ERROR
;
382 /* Known parameters. */
383 text
->options
.color
= TEXT_COLOR_OPT_AUTO
;
384 if (bt_value_map_has_key(params
, "color")) {
385 struct bt_value
*color_value
;
388 color_value
= bt_value_map_get(params
, "color");
393 status
= bt_value_string_get(color_value
, &color
);
395 warn_wrong_color_param(text
);
397 if (strcmp(color
, "never") == 0) {
398 text
->options
.color
= TEXT_COLOR_OPT_NEVER
;
399 } else if (strcmp(color
, "auto") == 0) {
400 text
->options
.color
= TEXT_COLOR_OPT_AUTO
;
401 } else if (strcmp(color
, "always") == 0) {
402 text
->options
.color
= TEXT_COLOR_OPT_ALWAYS
;
404 warn_wrong_color_param(text
);
411 ret
= apply_one_string("output-path",
413 &text
->options
.output_path
);
414 if (ret
!= BT_COMPONENT_STATUS_OK
) {
417 ret
= open_output_file(text
);
418 if (ret
!= BT_COMPONENT_STATUS_OK
) {
422 ret
= apply_one_string("debug-info-dir",
424 &text
->options
.debug_info_dir
);
425 if (ret
!= BT_COMPONENT_STATUS_OK
) {
429 ret
= apply_one_string("debug-info-target-prefix",
431 &text
->options
.debug_info_target_prefix
);
432 if (ret
!= BT_COMPONENT_STATUS_OK
) {
436 value
= false; /* Default. */
437 ret
= apply_one_bool("debug-info-full-path", params
, &value
, NULL
);
438 if (ret
!= BT_COMPONENT_STATUS_OK
) {
441 text
->options
.debug_info_full_path
= value
;
443 value
= false; /* Default. */
444 ret
= apply_one_bool("no-delta", params
, &value
, NULL
);
445 if (ret
!= BT_COMPONENT_STATUS_OK
) {
448 text
->options
.print_delta_field
= !value
; /* Reverse logic. */
450 value
= false; /* Default. */
451 ret
= apply_one_bool("clock-cycles", params
, &value
, NULL
);
452 if (ret
!= BT_COMPONENT_STATUS_OK
) {
455 text
->options
.print_timestamp_cycles
= value
;
457 value
= false; /* Default. */
458 ret
= apply_one_bool("clock-seconds", params
, &value
, NULL
);
459 if (ret
!= BT_COMPONENT_STATUS_OK
) {
462 text
->options
.clock_seconds
= value
;
464 value
= false; /* Default. */
465 ret
= apply_one_bool("clock-date", params
, &value
, NULL
);
466 if (ret
!= BT_COMPONENT_STATUS_OK
) {
469 text
->options
.clock_date
= value
;
471 value
= false; /* Default. */
472 ret
= apply_one_bool("clock-gmt", params
, &value
, NULL
);
473 if (ret
!= BT_COMPONENT_STATUS_OK
) {
476 text
->options
.clock_gmt
= value
;
478 value
= false; /* Default. */
479 ret
= apply_one_bool("verbose", params
, &value
, NULL
);
480 if (ret
!= BT_COMPONENT_STATUS_OK
) {
483 text
->options
.verbose
= value
;
486 ret
= apply_one_string("name-default", params
, &str
);
487 if (ret
!= BT_COMPONENT_STATUS_OK
) {
491 text
->options
.name_default
= TEXT_DEFAULT_UNSET
;
492 } else if (!strcmp(str
, "show")) {
493 text
->options
.name_default
= TEXT_DEFAULT_SHOW
;
494 } else if (!strcmp(str
, "hide")) {
495 text
->options
.name_default
= TEXT_DEFAULT_HIDE
;
497 ret
= BT_COMPONENT_STATUS_ERROR
;
503 switch (text
->options
.name_default
) {
504 case TEXT_DEFAULT_UNSET
:
505 text
->options
.print_payload_field_names
= true;
506 text
->options
.print_context_field_names
= true;
507 text
->options
.print_header_field_names
= false;
508 text
->options
.print_scope_field_names
= false;
510 case TEXT_DEFAULT_SHOW
:
511 text
->options
.print_payload_field_names
= true;
512 text
->options
.print_context_field_names
= true;
513 text
->options
.print_header_field_names
= true;
514 text
->options
.print_scope_field_names
= true;
516 case TEXT_DEFAULT_HIDE
:
517 text
->options
.print_payload_field_names
= false;
518 text
->options
.print_context_field_names
= false;
519 text
->options
.print_header_field_names
= false;
520 text
->options
.print_scope_field_names
= false;
523 ret
= BT_COMPONENT_STATUS_ERROR
;
529 ret
= apply_one_bool("name-payload", params
, &value
, &found
);
530 if (ret
!= BT_COMPONENT_STATUS_OK
) {
534 text
->options
.print_payload_field_names
= value
;
539 ret
= apply_one_bool("name-context", params
, &value
, &found
);
540 if (ret
!= BT_COMPONENT_STATUS_OK
) {
544 text
->options
.print_context_field_names
= value
;
549 ret
= apply_one_bool("name-header", params
, &value
, &found
);
550 if (ret
!= BT_COMPONENT_STATUS_OK
) {
554 text
->options
.print_header_field_names
= value
;
559 ret
= apply_one_bool("name-scope", params
, &value
, &found
);
560 if (ret
!= BT_COMPONENT_STATUS_OK
) {
564 text
->options
.print_scope_field_names
= value
;
568 ret
= apply_one_string("field-default", params
, &str
);
569 if (ret
!= BT_COMPONENT_STATUS_OK
) {
573 text
->options
.field_default
= TEXT_DEFAULT_UNSET
;
574 } else if (!strcmp(str
, "show")) {
575 text
->options
.field_default
= TEXT_DEFAULT_SHOW
;
576 } else if (!strcmp(str
, "hide")) {
577 text
->options
.field_default
= TEXT_DEFAULT_HIDE
;
579 ret
= BT_COMPONENT_STATUS_ERROR
;
585 switch (text
->options
.field_default
) {
586 case TEXT_DEFAULT_UNSET
:
587 text
->options
.print_trace_field
= false;
588 text
->options
.print_trace_hostname_field
= true;
589 text
->options
.print_trace_domain_field
= false;
590 text
->options
.print_trace_procname_field
= true;
591 text
->options
.print_trace_vpid_field
= true;
592 text
->options
.print_loglevel_field
= false;
593 text
->options
.print_emf_field
= false;
594 text
->options
.print_callsite_field
= false;
596 case TEXT_DEFAULT_SHOW
:
597 text
->options
.print_trace_field
= true;
598 text
->options
.print_trace_hostname_field
= true;
599 text
->options
.print_trace_domain_field
= true;
600 text
->options
.print_trace_procname_field
= true;
601 text
->options
.print_trace_vpid_field
= true;
602 text
->options
.print_loglevel_field
= true;
603 text
->options
.print_emf_field
= true;
604 text
->options
.print_callsite_field
= true;
606 case TEXT_DEFAULT_HIDE
:
607 text
->options
.print_trace_field
= false;
608 text
->options
.print_trace_hostname_field
= false;
609 text
->options
.print_trace_domain_field
= false;
610 text
->options
.print_trace_procname_field
= false;
611 text
->options
.print_trace_vpid_field
= false;
612 text
->options
.print_loglevel_field
= false;
613 text
->options
.print_emf_field
= false;
614 text
->options
.print_callsite_field
= false;
617 ret
= BT_COMPONENT_STATUS_ERROR
;
623 ret
= apply_one_bool("field-trace", params
, &value
, &found
);
624 if (ret
!= BT_COMPONENT_STATUS_OK
) {
628 text
->options
.print_trace_field
= value
;
633 ret
= apply_one_bool("field-trace:hostname", params
, &value
, &found
);
634 if (ret
!= BT_COMPONENT_STATUS_OK
) {
638 text
->options
.print_trace_hostname_field
= value
;
643 ret
= apply_one_bool("field-trace:domain", params
, &value
, &found
);
644 if (ret
!= BT_COMPONENT_STATUS_OK
) {
648 text
->options
.print_trace_domain_field
= value
;
653 ret
= apply_one_bool("field-trace:procname", params
, &value
, &found
);
654 if (ret
!= BT_COMPONENT_STATUS_OK
) {
658 text
->options
.print_trace_procname_field
= value
;
663 ret
= apply_one_bool("field-trace:vpid", params
, &value
, &found
);
664 if (ret
!= BT_COMPONENT_STATUS_OK
) {
668 text
->options
.print_trace_vpid_field
= value
;
673 ret
= apply_one_bool("field-loglevel", params
, &value
, &found
);
674 if (ret
!= BT_COMPONENT_STATUS_OK
) {
678 text
->options
.print_loglevel_field
= value
;
683 ret
= apply_one_bool("field-emf", params
, &value
, &found
);
684 if (ret
!= BT_COMPONENT_STATUS_OK
) {
688 text
->options
.print_emf_field
= value
;
693 ret
= apply_one_bool("field-callsite", params
, &value
, &found
);
694 if (ret
!= BT_COMPONENT_STATUS_OK
) {
698 text
->options
.print_callsite_field
= value
;
702 bt_put(text
->plugin_opt_map
);
703 text
->plugin_opt_map
= NULL
;
709 void set_use_colors(struct text_component
*text
)
711 switch (text
->options
.color
) {
712 case TEXT_COLOR_OPT_ALWAYS
:
713 text
->use_colors
= true;
715 case TEXT_COLOR_OPT_AUTO
:
716 text
->use_colors
= text
->out
== stdout
&&
717 bt_common_colors_supported();
719 case TEXT_COLOR_OPT_NEVER
:
720 text
->use_colors
= false;
726 void init_stream_packet_context_quarks(void)
728 stream_packet_context_quarks
[Q_TIMESTAMP_BEGIN
] =
729 g_quark_from_string("timestamp_begin");
730 stream_packet_context_quarks
[Q_TIMESTAMP_BEGIN
] =
731 g_quark_from_string("timestamp_begin");
732 stream_packet_context_quarks
[Q_TIMESTAMP_END
] =
733 g_quark_from_string("timestamp_end");
734 stream_packet_context_quarks
[Q_EVENTS_DISCARDED
] =
735 g_quark_from_string("events_discarded");
736 stream_packet_context_quarks
[Q_CONTENT_SIZE
] =
737 g_quark_from_string("content_size");
738 stream_packet_context_quarks
[Q_PACKET_SIZE
] =
739 g_quark_from_string("packet_size");
740 stream_packet_context_quarks
[Q_PACKET_SEQ_NUM
] =
741 g_quark_from_string("packet_seq_num");
745 enum bt_component_status
text_component_init(
746 struct bt_private_component
*component
,
747 struct bt_value
*params
,
748 UNUSED_VAR
void *init_method_data
)
750 enum bt_component_status ret
;
751 struct text_component
*text
= create_text();
754 ret
= BT_COMPONENT_STATUS_NOMEM
;
761 text
->delta_cycles
= -1ULL;
762 text
->last_cycles_timestamp
= -1ULL;
764 text
->delta_real_timestamp
= -1ULL;
765 text
->last_real_timestamp
= -1ULL;
767 ret
= apply_params(text
, params
);
768 if (ret
!= BT_COMPONENT_STATUS_OK
) {
772 set_use_colors(text
);
774 ret
= bt_private_component_set_user_data(component
, text
);
775 if (ret
!= BT_COMPONENT_STATUS_OK
) {
779 init_stream_packet_context_quarks();
784 destroy_text_data(text
);
788 /* Initialize plug-in entry points. */
790 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
791 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
792 BT_PLUGIN_LICENSE("MIT");
793 BT_PLUGIN_SINK_COMPONENT_CLASS(text
, run
);
794 BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(text
, text_component_init
);
795 BT_PLUGIN_SINK_COMPONENT_CLASS_ACCEPT_PORT_CONNECTION_METHOD(text
, text_accept_port_connection
);
796 BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(text
, finalize_text
);
797 BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(text
,
798 "Formats CTF-IR to text. Formerly known as ctf-text.");