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/component/component.h>
32 #include <babeltrace/component/component-sink.h>
33 #include <babeltrace/component/notification/notification.h>
34 #include <babeltrace/component/notification/iterator.h>
35 #include <babeltrace/component/notification/event.h>
36 #include <babeltrace/values.h>
37 #include <babeltrace/compiler.h>
38 #include <plugins-common.h>
45 const char *plugin_options
[] = {
48 "debug-info-target-prefix",
49 "debug-info-full-path",
55 "name-default", /* show/hide */
60 "field-default", /* show/hide */
62 "field-trace:hostname",
64 "field-trace:procname",
71 void destroy_text_data(struct text_component
*text
)
73 (void) g_string_free(text
->string
, TRUE
);
74 g_free(text
->options
.output_path
);
75 g_free(text
->options
.debug_info_dir
);
76 g_free(text
->options
.debug_info_target_prefix
);
81 struct text_component
*create_text(void)
83 struct text_component
*text
;
85 text
= g_new0(struct text_component
, 1);
89 text
->string
= g_string_new("");
102 void destroy_text(struct bt_component
*component
)
104 void *data
= bt_component_get_private_data(component
);
106 destroy_text_data(data
);
110 enum bt_component_status
handle_notification(struct text_component
*text
,
111 struct bt_notification
*notification
)
113 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
116 ret
= BT_COMPONENT_STATUS_ERROR
;
120 switch (bt_notification_get_type(notification
)) {
121 case BT_NOTIFICATION_TYPE_PACKET_BEGIN
:
124 case BT_NOTIFICATION_TYPE_PACKET_END
:
127 case BT_NOTIFICATION_TYPE_EVENT
:
129 struct bt_ctf_event
*event
= bt_notification_event_get_event(
133 ret
= BT_COMPONENT_STATUS_ERROR
;
136 ret
= text_print_event(text
, event
);
138 if (ret
!= BT_COMPONENT_STATUS_OK
) {
143 case BT_NOTIFICATION_TYPE_STREAM_END
:
147 puts("Unhandled notification type");
154 enum bt_component_status
run(struct bt_component
*component
)
156 enum bt_component_status ret
;
157 struct bt_notification
*notification
= NULL
;
158 struct bt_notification_iterator
*it
;
159 struct text_component
*text
= bt_component_get_private_data(component
);
161 ret
= bt_component_sink_get_input_iterator(component
, 0, &it
);
162 if (ret
!= BT_COMPONENT_STATUS_OK
) {
166 if (likely(text
->processed_first_event
)) {
167 enum bt_notification_iterator_status it_ret
;
169 it_ret
= bt_notification_iterator_next(it
);
171 case BT_NOTIFICATION_ITERATOR_STATUS_ERROR
:
172 ret
= BT_COMPONENT_STATUS_ERROR
;
174 case BT_NOTIFICATION_ITERATOR_STATUS_END
:
175 ret
= BT_COMPONENT_STATUS_END
;
181 notification
= bt_notification_iterator_get_notification(it
);
183 ret
= BT_COMPONENT_STATUS_ERROR
;
187 ret
= handle_notification(text
, notification
);
188 text
->processed_first_event
= true;
191 bt_put(notification
);
196 enum bt_component_status
add_params_to_map(struct bt_value
*plugin_opt_map
)
198 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
201 for (i
= 0; i
< BT_ARRAY_SIZE(plugin_options
); i
++) {
202 const char *key
= plugin_options
[i
];
203 enum bt_value_status status
;
205 status
= bt_value_map_insert(plugin_opt_map
, key
, bt_value_null
);
207 case BT_VALUE_STATUS_OK
:
210 ret
= BT_COMPONENT_STATUS_ERROR
;
219 bool check_param_exists(const char *key
, struct bt_value
*object
, void *data
)
221 struct text_component
*text
= data
;
222 struct bt_value
*plugin_opt_map
= text
->plugin_opt_map
;
224 if (!bt_value_map_get(plugin_opt_map
, key
)) {
226 "[warning] Parameter \"%s\" unknown to \"text\" plugin\n", key
);
232 enum bt_component_status
apply_one_string(const char *key
,
233 struct bt_value
*params
,
236 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
237 struct bt_value
*value
= NULL
;
238 enum bt_value_status status
;
241 value
= bt_value_map_get(params
, key
);
245 if (bt_value_is_null(value
)) {
248 status
= bt_value_string_get(value
, &str
);
250 case BT_VALUE_STATUS_OK
:
253 ret
= BT_COMPONENT_STATUS_ERROR
;
256 *option
= g_strdup(str
);
263 enum bt_component_status
apply_one_bool(const char *key
,
264 struct bt_value
*params
,
268 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
269 struct bt_value
*value
= NULL
;
270 enum bt_value_status status
;
272 value
= bt_value_map_get(params
, key
);
276 status
= bt_value_bool_get(value
, option
);
278 case BT_VALUE_STATUS_OK
:
281 ret
= BT_COMPONENT_STATUS_ERROR
;
293 enum bt_component_status
apply_params(struct text_component
*text
,
294 struct bt_value
*params
)
296 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
297 enum bt_value_status status
;
301 text
->plugin_opt_map
= bt_value_map_create();
302 if (!text
->plugin_opt_map
) {
303 ret
= BT_COMPONENT_STATUS_ERROR
;
306 ret
= add_params_to_map(text
->plugin_opt_map
);
307 if (ret
!= BT_COMPONENT_STATUS_OK
) {
310 /* Report unknown parameters. */
311 status
= bt_value_map_foreach(params
, check_param_exists
, text
);
313 case BT_VALUE_STATUS_OK
:
316 ret
= BT_COMPONENT_STATUS_ERROR
;
319 /* Known parameters. */
320 ret
= apply_one_string("output-path",
322 &text
->options
.output_path
);
323 if (ret
!= BT_COMPONENT_STATUS_OK
) {
327 ret
= apply_one_string("debug-info-dir",
329 &text
->options
.debug_info_dir
);
330 if (ret
!= BT_COMPONENT_STATUS_OK
) {
334 ret
= apply_one_string("debug-info-target-prefix",
336 &text
->options
.debug_info_target_prefix
);
337 if (ret
!= BT_COMPONENT_STATUS_OK
) {
341 value
= false; /* Default. */
342 ret
= apply_one_bool("debug-info-full-path", params
, &value
, NULL
);
343 if (ret
!= BT_COMPONENT_STATUS_OK
) {
346 text
->options
.debug_info_full_path
= value
;
348 value
= false; /* Default. */
349 ret
= apply_one_bool("no-delta", params
, &value
, NULL
);
350 if (ret
!= BT_COMPONENT_STATUS_OK
) {
353 text
->options
.print_delta_field
= !value
; /* Reverse logic. */
355 value
= false; /* Default. */
356 ret
= apply_one_bool("clock-cycles", params
, &value
, NULL
);
357 if (ret
!= BT_COMPONENT_STATUS_OK
) {
360 text
->options
.print_timestamp_cycles
= value
;
362 value
= false; /* Default. */
363 ret
= apply_one_bool("clock-seconds", params
, &value
, NULL
);
364 if (ret
!= BT_COMPONENT_STATUS_OK
) {
367 text
->options
.clock_seconds
= value
;
369 value
= false; /* Default. */
370 ret
= apply_one_bool("clock-date", params
, &value
, NULL
);
371 if (ret
!= BT_COMPONENT_STATUS_OK
) {
374 text
->options
.clock_date
= value
;
376 value
= false; /* Default. */
377 ret
= apply_one_bool("clock-gmt", params
, &value
, NULL
);
378 if (ret
!= BT_COMPONENT_STATUS_OK
) {
381 text
->options
.clock_gmt
= value
;
384 ret
= apply_one_string("name-default", params
, &str
);
385 if (ret
!= BT_COMPONENT_STATUS_OK
) {
389 text
->options
.name_default
= TEXT_DEFAULT_UNSET
;
390 } else if (!strcmp(str
, "show")) {
391 text
->options
.name_default
= TEXT_DEFAULT_SHOW
;
392 } else if (!strcmp(str
, "hide")) {
393 text
->options
.name_default
= TEXT_DEFAULT_HIDE
;
395 ret
= BT_COMPONENT_STATUS_ERROR
;
401 switch (text
->options
.name_default
) {
402 case TEXT_DEFAULT_UNSET
:
403 text
->options
.print_payload_field_names
= true;
404 text
->options
.print_context_field_names
= true;
405 text
->options
.print_header_field_names
= false;
406 text
->options
.print_scope_field_names
= false;
408 case TEXT_DEFAULT_SHOW
:
409 text
->options
.print_payload_field_names
= true;
410 text
->options
.print_context_field_names
= true;
411 text
->options
.print_header_field_names
= true;
412 text
->options
.print_scope_field_names
= true;
414 case TEXT_DEFAULT_HIDE
:
415 text
->options
.print_payload_field_names
= false;
416 text
->options
.print_context_field_names
= false;
417 text
->options
.print_header_field_names
= false;
418 text
->options
.print_scope_field_names
= false;
421 ret
= BT_COMPONENT_STATUS_ERROR
;
427 ret
= apply_one_bool("name-payload", params
, &value
, &found
);
428 if (ret
!= BT_COMPONENT_STATUS_OK
) {
432 text
->options
.print_payload_field_names
= value
;
437 ret
= apply_one_bool("name-context", params
, &value
, &found
);
438 if (ret
!= BT_COMPONENT_STATUS_OK
) {
442 text
->options
.print_context_field_names
= value
;
447 ret
= apply_one_bool("name-header", params
, &value
, &found
);
448 if (ret
!= BT_COMPONENT_STATUS_OK
) {
452 text
->options
.print_header_field_names
= value
;
457 ret
= apply_one_bool("name-scope", params
, &value
, &found
);
458 if (ret
!= BT_COMPONENT_STATUS_OK
) {
462 text
->options
.print_scope_field_names
= value
;
466 ret
= apply_one_string("field-default", params
, &str
);
467 if (ret
!= BT_COMPONENT_STATUS_OK
) {
471 text
->options
.field_default
= TEXT_DEFAULT_UNSET
;
472 } else if (!strcmp(str
, "show")) {
473 text
->options
.field_default
= TEXT_DEFAULT_SHOW
;
474 } else if (!strcmp(str
, "hide")) {
475 text
->options
.field_default
= TEXT_DEFAULT_HIDE
;
477 ret
= BT_COMPONENT_STATUS_ERROR
;
483 switch (text
->options
.field_default
) {
484 case TEXT_DEFAULT_UNSET
:
485 text
->options
.print_trace_field
= false;
486 text
->options
.print_trace_hostname_field
= true;
487 text
->options
.print_trace_domain_field
= false;
488 text
->options
.print_trace_procname_field
= true;
489 text
->options
.print_trace_vpid_field
= true;
490 text
->options
.print_loglevel_field
= false;
491 text
->options
.print_emf_field
= false;
492 text
->options
.print_emf_field
= false;
494 case TEXT_DEFAULT_SHOW
:
495 text
->options
.print_trace_field
= true;
496 text
->options
.print_trace_hostname_field
= true;
497 text
->options
.print_trace_domain_field
= true;
498 text
->options
.print_trace_procname_field
= true;
499 text
->options
.print_trace_vpid_field
= true;
500 text
->options
.print_loglevel_field
= true;
501 text
->options
.print_emf_field
= true;
502 text
->options
.print_emf_field
= true;
504 case TEXT_DEFAULT_HIDE
:
505 text
->options
.print_trace_field
= false;
506 text
->options
.print_trace_hostname_field
= false;
507 text
->options
.print_trace_domain_field
= false;
508 text
->options
.print_trace_procname_field
= false;
509 text
->options
.print_trace_vpid_field
= false;
510 text
->options
.print_loglevel_field
= false;
511 text
->options
.print_emf_field
= false;
512 text
->options
.print_emf_field
= false;
515 ret
= BT_COMPONENT_STATUS_ERROR
;
521 ret
= apply_one_bool("field-trace", params
, &value
, &found
);
522 if (ret
!= BT_COMPONENT_STATUS_OK
) {
526 text
->options
.print_trace_field
= value
;
531 ret
= apply_one_bool("field-trace:hostname", params
, &value
, &found
);
532 if (ret
!= BT_COMPONENT_STATUS_OK
) {
536 text
->options
.print_trace_hostname_field
= value
;
541 ret
= apply_one_bool("field-trace:domain", params
, &value
, &found
);
542 if (ret
!= BT_COMPONENT_STATUS_OK
) {
546 text
->options
.print_trace_domain_field
= value
;
551 ret
= apply_one_bool("field-trace:procname", params
, &value
, &found
);
552 if (ret
!= BT_COMPONENT_STATUS_OK
) {
556 text
->options
.print_trace_procname_field
= value
;
561 ret
= apply_one_bool("field-trace:vpid", params
, &value
, &found
);
562 if (ret
!= BT_COMPONENT_STATUS_OK
) {
566 text
->options
.print_trace_vpid_field
= value
;
571 ret
= apply_one_bool("field-loglevel", params
, &value
, &found
);
572 if (ret
!= BT_COMPONENT_STATUS_OK
) {
576 text
->options
.print_loglevel_field
= value
;
581 ret
= apply_one_bool("field-emf", params
, &value
, &found
);
582 if (ret
!= BT_COMPONENT_STATUS_OK
) {
586 text
->options
.print_emf_field
= value
;
591 ret
= apply_one_bool("field-emf", params
, &value
, &found
);
592 if (ret
!= BT_COMPONENT_STATUS_OK
) {
596 text
->options
.print_emf_field
= value
;
600 bt_put(text
->plugin_opt_map
);
601 text
->plugin_opt_map
= NULL
;
607 enum bt_component_status
text_component_init(
608 struct bt_component
*component
, struct bt_value
*params
,
609 UNUSED_VAR
void *init_method_data
)
611 enum bt_component_status ret
;
612 struct text_component
*text
= create_text();
615 ret
= BT_COMPONENT_STATUS_NOMEM
;
622 text
->delta_cycles
= -1ULL;
623 text
->last_cycles_timestamp
= -1ULL;
625 text
->delta_real_timestamp
= -1ULL;
626 text
->last_real_timestamp
= -1ULL;
628 ret
= apply_params(text
, params
);
629 if (ret
!= BT_COMPONENT_STATUS_OK
) {
633 ret
= bt_component_set_private_data(component
, text
);
634 if (ret
!= BT_COMPONENT_STATUS_OK
) {
640 destroy_text_data(text
);
644 /* Initialize plug-in entry points. */
646 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
647 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
648 BT_PLUGIN_LICENSE("MIT");
649 BT_PLUGIN_SINK_COMPONENT_CLASS(text
, run
);
650 BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(text
, text_component_init
);
651 BT_PLUGIN_SINK_COMPONENT_CLASS_DESTROY_METHOD(text
, destroy_text
);
652 BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(text
,
653 "Formats CTF-IR to text. Formerly known as ctf-text.");