163f3c2ced15c68f20a33f11eb602998cfe7fda1
[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/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 <babeltrace/common-internal.h>
39 #include <plugins-common.h>
40 #include <stdio.h>
41 #include <stdbool.h>
42 #include <glib.h>
43 #include "text.h"
44
45 static
46 const char *plugin_options[] = {
47 "color",
48 "output-path",
49 "debug-info-dir",
50 "debug-info-target-prefix",
51 "debug-info-full-path",
52 "no-delta",
53 "clock-cycles",
54 "clock-seconds",
55 "clock-date",
56 "clock-gmt",
57 "name-default", /* show/hide */
58 "name-payload",
59 "name-context",
60 "name-scope",
61 "name-header",
62 "field-default", /* show/hide */
63 "field-trace",
64 "field-trace:hostname",
65 "field-trace:domain",
66 "field-trace:procname",
67 "field-trace:vpid",
68 "field-loglevel",
69 "field-emf",
70 };
71
72 static
73 void destroy_text_data(struct text_component *text)
74 {
75 (void) g_string_free(text->string, TRUE);
76 g_free(text->options.output_path);
77 g_free(text->options.debug_info_dir);
78 g_free(text->options.debug_info_target_prefix);
79 g_free(text);
80 }
81
82 static
83 struct text_component *create_text(void)
84 {
85 struct text_component *text;
86
87 text = g_new0(struct text_component, 1);
88 if (!text) {
89 goto end;
90 }
91 text->string = g_string_new("");
92 if (!text->string) {
93 goto error;
94 }
95 end:
96 return text;
97
98 error:
99 g_free(text);
100 return NULL;
101 }
102
103 static
104 void destroy_text(struct bt_component *component)
105 {
106 void *data = bt_component_get_private_data(component);
107
108 destroy_text_data(data);
109 }
110
111 static
112 enum bt_component_status handle_notification(struct text_component *text,
113 struct bt_notification *notification)
114 {
115 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
116
117 if (!text) {
118 ret = BT_COMPONENT_STATUS_ERROR;
119 goto end;
120 }
121
122 switch (bt_notification_get_type(notification)) {
123 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
124 puts("<packet>");
125 break;
126 case BT_NOTIFICATION_TYPE_PACKET_END:
127 puts("</packet>");
128 break;
129 case BT_NOTIFICATION_TYPE_EVENT:
130 {
131 struct bt_ctf_event *event = bt_notification_event_get_event(
132 notification);
133
134 if (!event) {
135 ret = BT_COMPONENT_STATUS_ERROR;
136 goto end;
137 }
138 ret = text_print_event(text, event);
139 bt_put(event);
140 if (ret != BT_COMPONENT_STATUS_OK) {
141 goto end;
142 }
143 break;
144 }
145 case BT_NOTIFICATION_TYPE_STREAM_END:
146 puts("</stream>");
147 break;
148 default:
149 puts("Unhandled notification type");
150 }
151 end:
152 return ret;
153 }
154
155 static
156 enum bt_component_status run(struct bt_component *component)
157 {
158 enum bt_component_status ret;
159 struct bt_notification *notification = NULL;
160 struct bt_notification_iterator *it;
161 struct text_component *text = bt_component_get_private_data(component);
162
163 ret = bt_component_sink_get_input_iterator(component, 0, &it);
164 if (ret != BT_COMPONENT_STATUS_OK) {
165 goto end;
166 }
167
168 if (likely(text->processed_first_event)) {
169 enum bt_notification_iterator_status it_ret;
170
171 it_ret = bt_notification_iterator_next(it);
172 switch (it_ret) {
173 case BT_NOTIFICATION_ITERATOR_STATUS_ERROR:
174 ret = BT_COMPONENT_STATUS_ERROR;
175 goto end;
176 case BT_NOTIFICATION_ITERATOR_STATUS_END:
177 ret = BT_COMPONENT_STATUS_END;
178 goto end;
179 default:
180 break;
181 }
182 }
183 notification = bt_notification_iterator_get_notification(it);
184 if (!notification) {
185 ret = BT_COMPONENT_STATUS_ERROR;
186 goto end;
187 }
188
189 ret = handle_notification(text, notification);
190 text->processed_first_event = true;
191 end:
192 bt_put(it);
193 bt_put(notification);
194 return ret;
195 }
196
197 static
198 enum bt_component_status add_params_to_map(struct bt_value *plugin_opt_map)
199 {
200 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
201 unsigned int i;
202
203 for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
204 const char *key = plugin_options[i];
205 enum bt_value_status status;
206
207 status = bt_value_map_insert(plugin_opt_map, key, bt_value_null);
208 switch (status) {
209 case BT_VALUE_STATUS_OK:
210 break;
211 default:
212 ret = BT_COMPONENT_STATUS_ERROR;
213 goto end;
214 }
215 }
216 end:
217 return ret;
218 }
219
220 static
221 bool check_param_exists(const char *key, struct bt_value *object, void *data)
222 {
223 struct text_component *text = data;
224 struct bt_value *plugin_opt_map = text->plugin_opt_map;
225
226 if (!bt_value_map_get(plugin_opt_map, key)) {
227 fprintf(text->err,
228 "[warning] Parameter \"%s\" unknown to \"text\" plugin\n", key);
229 }
230 return true;
231 }
232
233 static
234 enum bt_component_status apply_one_string(const char *key,
235 struct bt_value *params,
236 char **option)
237 {
238 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
239 struct bt_value *value = NULL;
240 enum bt_value_status status;
241 const char *str;
242
243 value = bt_value_map_get(params, key);
244 if (!value) {
245 goto end;
246 }
247 if (bt_value_is_null(value)) {
248 goto end;
249 }
250 status = bt_value_string_get(value, &str);
251 switch (status) {
252 case BT_VALUE_STATUS_OK:
253 break;
254 default:
255 ret = BT_COMPONENT_STATUS_ERROR;
256 goto end;
257 }
258 *option = g_strdup(str);
259 end:
260 bt_put(value);
261 return ret;
262 }
263
264 static
265 enum bt_component_status apply_one_bool(const char *key,
266 struct bt_value *params,
267 bool *option,
268 bool *found)
269 {
270 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
271 struct bt_value *value = NULL;
272 enum bt_value_status status;
273
274 value = bt_value_map_get(params, key);
275 if (!value) {
276 goto end;
277 }
278 status = bt_value_bool_get(value, option);
279 switch (status) {
280 case BT_VALUE_STATUS_OK:
281 break;
282 default:
283 ret = BT_COMPONENT_STATUS_ERROR;
284 goto end;
285 }
286 if (found) {
287 *found = true;
288 }
289 end:
290 bt_put(value);
291 return ret;
292 }
293
294 static
295 void warn_wrong_color_param(struct text_component *text)
296 {
297 fprintf(text->err,
298 "[warning] Accepted values for the \"color\" parameter are:\n \"always\", \"auto\", \"never\"\n");
299 }
300
301 static
302 enum bt_component_status apply_params(struct text_component *text,
303 struct bt_value *params)
304 {
305 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
306 enum bt_value_status status;
307 bool value, found;
308 char *str = NULL;
309
310 text->plugin_opt_map = bt_value_map_create();
311 if (!text->plugin_opt_map) {
312 ret = BT_COMPONENT_STATUS_ERROR;
313 goto end;
314 }
315 ret = add_params_to_map(text->plugin_opt_map);
316 if (ret != BT_COMPONENT_STATUS_OK) {
317 goto end;
318 }
319 /* Report unknown parameters. */
320 status = bt_value_map_foreach(params, check_param_exists, text);
321 switch (status) {
322 case BT_VALUE_STATUS_OK:
323 break;
324 default:
325 ret = BT_COMPONENT_STATUS_ERROR;
326 goto end;
327 }
328 /* Known parameters. */
329 text->options.color = TEXT_COLOR_OPT_AUTO;
330 if (bt_value_map_has_key(params, "color")) {
331 struct bt_value *color_value;
332 const char *color;
333
334 color_value = bt_value_map_get(params, "color");
335 if (!color_value) {
336 goto end;
337 }
338
339 ret = bt_value_string_get(color_value, &color);
340 if (ret) {
341 warn_wrong_color_param(text);
342 } else {
343 if (strcmp(color, "never") == 0) {
344 text->options.color = TEXT_COLOR_OPT_NEVER;
345 } else if (strcmp(color, "auto") == 0) {
346 text->options.color = TEXT_COLOR_OPT_AUTO;
347 } else if (strcmp(color, "always") == 0) {
348 text->options.color = TEXT_COLOR_OPT_ALWAYS;
349 } else {
350 warn_wrong_color_param(text);
351 }
352 }
353
354 bt_put(color_value);
355 }
356
357 ret = apply_one_string("output-path",
358 params,
359 &text->options.output_path);
360 if (ret != BT_COMPONENT_STATUS_OK) {
361 goto end;
362 }
363
364 ret = apply_one_string("debug-info-dir",
365 params,
366 &text->options.debug_info_dir);
367 if (ret != BT_COMPONENT_STATUS_OK) {
368 goto end;
369 }
370
371 ret = apply_one_string("debug-info-target-prefix",
372 params,
373 &text->options.debug_info_target_prefix);
374 if (ret != BT_COMPONENT_STATUS_OK) {
375 goto end;
376 }
377
378 value = false; /* Default. */
379 ret = apply_one_bool("debug-info-full-path", params, &value, NULL);
380 if (ret != BT_COMPONENT_STATUS_OK) {
381 goto end;
382 }
383 text->options.debug_info_full_path = value;
384
385 value = false; /* Default. */
386 ret = apply_one_bool("no-delta", params, &value, NULL);
387 if (ret != BT_COMPONENT_STATUS_OK) {
388 goto end;
389 }
390 text->options.print_delta_field = !value; /* Reverse logic. */
391
392 value = false; /* Default. */
393 ret = apply_one_bool("clock-cycles", params, &value, NULL);
394 if (ret != BT_COMPONENT_STATUS_OK) {
395 goto end;
396 }
397 text->options.print_timestamp_cycles = value;
398
399 value = false; /* Default. */
400 ret = apply_one_bool("clock-seconds", params, &value, NULL);
401 if (ret != BT_COMPONENT_STATUS_OK) {
402 goto end;
403 }
404 text->options.clock_seconds = value;
405
406 value = false; /* Default. */
407 ret = apply_one_bool("clock-date", params, &value, NULL);
408 if (ret != BT_COMPONENT_STATUS_OK) {
409 goto end;
410 }
411 text->options.clock_date = value;
412
413 value = false; /* Default. */
414 ret = apply_one_bool("clock-gmt", params, &value, NULL);
415 if (ret != BT_COMPONENT_STATUS_OK) {
416 goto end;
417 }
418 text->options.clock_gmt = value;
419
420 /* Names. */
421 ret = apply_one_string("name-default", params, &str);
422 if (ret != BT_COMPONENT_STATUS_OK) {
423 goto end;
424 }
425 if (!str) {
426 text->options.name_default = TEXT_DEFAULT_UNSET;
427 } else if (!strcmp(str, "show")) {
428 text->options.name_default = TEXT_DEFAULT_SHOW;
429 } else if (!strcmp(str, "hide")) {
430 text->options.name_default = TEXT_DEFAULT_HIDE;
431 } else {
432 ret = BT_COMPONENT_STATUS_ERROR;
433 goto end;
434 }
435 g_free(str);
436 str = NULL;
437
438 switch (text->options.name_default) {
439 case TEXT_DEFAULT_UNSET:
440 text->options.print_payload_field_names = true;
441 text->options.print_context_field_names = true;
442 text->options.print_header_field_names = false;
443 text->options.print_scope_field_names = false;
444 break;
445 case TEXT_DEFAULT_SHOW:
446 text->options.print_payload_field_names = true;
447 text->options.print_context_field_names = true;
448 text->options.print_header_field_names = true;
449 text->options.print_scope_field_names = true;
450 break;
451 case TEXT_DEFAULT_HIDE:
452 text->options.print_payload_field_names = false;
453 text->options.print_context_field_names = false;
454 text->options.print_header_field_names = false;
455 text->options.print_scope_field_names = false;
456 break;
457 default:
458 ret = BT_COMPONENT_STATUS_ERROR;
459 goto end;
460 }
461
462 value = false;
463 found = false;
464 ret = apply_one_bool("name-payload", params, &value, &found);
465 if (ret != BT_COMPONENT_STATUS_OK) {
466 goto end;
467 }
468 if (found) {
469 text->options.print_payload_field_names = value;
470 }
471
472 value = false;
473 found = false;
474 ret = apply_one_bool("name-context", params, &value, &found);
475 if (ret != BT_COMPONENT_STATUS_OK) {
476 goto end;
477 }
478 if (found) {
479 text->options.print_context_field_names = value;
480 }
481
482 value = false;
483 found = false;
484 ret = apply_one_bool("name-header", params, &value, &found);
485 if (ret != BT_COMPONENT_STATUS_OK) {
486 goto end;
487 }
488 if (found) {
489 text->options.print_header_field_names = value;
490 }
491
492 value = false;
493 found = false;
494 ret = apply_one_bool("name-scope", params, &value, &found);
495 if (ret != BT_COMPONENT_STATUS_OK) {
496 goto end;
497 }
498 if (found) {
499 text->options.print_scope_field_names = value;
500 }
501
502 /* Fields. */
503 ret = apply_one_string("field-default", params, &str);
504 if (ret != BT_COMPONENT_STATUS_OK) {
505 goto end;
506 }
507 if (!str) {
508 text->options.field_default = TEXT_DEFAULT_UNSET;
509 } else if (!strcmp(str, "show")) {
510 text->options.field_default = TEXT_DEFAULT_SHOW;
511 } else if (!strcmp(str, "hide")) {
512 text->options.field_default = TEXT_DEFAULT_HIDE;
513 } else {
514 ret = BT_COMPONENT_STATUS_ERROR;
515 goto end;
516 }
517 g_free(str);
518 str = NULL;
519
520 switch (text->options.field_default) {
521 case TEXT_DEFAULT_UNSET:
522 text->options.print_trace_field = false;
523 text->options.print_trace_hostname_field = true;
524 text->options.print_trace_domain_field = false;
525 text->options.print_trace_procname_field = true;
526 text->options.print_trace_vpid_field = true;
527 text->options.print_loglevel_field = false;
528 text->options.print_emf_field = false;
529 text->options.print_emf_field = false;
530 break;
531 case TEXT_DEFAULT_SHOW:
532 text->options.print_trace_field = true;
533 text->options.print_trace_hostname_field = true;
534 text->options.print_trace_domain_field = true;
535 text->options.print_trace_procname_field = true;
536 text->options.print_trace_vpid_field = true;
537 text->options.print_loglevel_field = true;
538 text->options.print_emf_field = true;
539 text->options.print_emf_field = true;
540 break;
541 case TEXT_DEFAULT_HIDE:
542 text->options.print_trace_field = false;
543 text->options.print_trace_hostname_field = false;
544 text->options.print_trace_domain_field = false;
545 text->options.print_trace_procname_field = false;
546 text->options.print_trace_vpid_field = false;
547 text->options.print_loglevel_field = false;
548 text->options.print_emf_field = false;
549 text->options.print_emf_field = false;
550 break;
551 default:
552 ret = BT_COMPONENT_STATUS_ERROR;
553 goto end;
554 }
555
556 value = false;
557 found = false;
558 ret = apply_one_bool("field-trace", params, &value, &found);
559 if (ret != BT_COMPONENT_STATUS_OK) {
560 goto end;
561 }
562 if (found) {
563 text->options.print_trace_field = value;
564 }
565
566 value = false;
567 found = false;
568 ret = apply_one_bool("field-trace:hostname", params, &value, &found);
569 if (ret != BT_COMPONENT_STATUS_OK) {
570 goto end;
571 }
572 if (found) {
573 text->options.print_trace_hostname_field = value;
574 }
575
576 value = false;
577 found = false;
578 ret = apply_one_bool("field-trace:domain", params, &value, &found);
579 if (ret != BT_COMPONENT_STATUS_OK) {
580 goto end;
581 }
582 if (found) {
583 text->options.print_trace_domain_field = value;
584 }
585
586 value = false;
587 found = false;
588 ret = apply_one_bool("field-trace:procname", params, &value, &found);
589 if (ret != BT_COMPONENT_STATUS_OK) {
590 goto end;
591 }
592 if (found) {
593 text->options.print_trace_procname_field = value;
594 }
595
596 value = false;
597 found = false;
598 ret = apply_one_bool("field-trace:vpid", params, &value, &found);
599 if (ret != BT_COMPONENT_STATUS_OK) {
600 goto end;
601 }
602 if (found) {
603 text->options.print_trace_vpid_field = value;
604 }
605
606 value = false;
607 found = false;
608 ret = apply_one_bool("field-loglevel", params, &value, &found);
609 if (ret != BT_COMPONENT_STATUS_OK) {
610 goto end;
611 }
612 if (found) {
613 text->options.print_loglevel_field = value;
614 }
615
616 value = false;
617 found = false;
618 ret = apply_one_bool("field-emf", params, &value, &found);
619 if (ret != BT_COMPONENT_STATUS_OK) {
620 goto end;
621 }
622 if (found) {
623 text->options.print_emf_field = value;
624 }
625
626 value = false;
627 found = false;
628 ret = apply_one_bool("field-emf", params, &value, &found);
629 if (ret != BT_COMPONENT_STATUS_OK) {
630 goto end;
631 }
632 if (found) {
633 text->options.print_emf_field = value;
634 }
635
636 end:
637 bt_put(text->plugin_opt_map);
638 text->plugin_opt_map = NULL;
639 g_free(str);
640 return ret;
641 }
642
643 static
644 void set_use_colors(struct text_component *text)
645 {
646 switch (text->options.color) {
647 case TEXT_COLOR_OPT_ALWAYS:
648 text->use_colors = true;
649 break;
650 case TEXT_COLOR_OPT_AUTO:
651 text->use_colors = text->out == stdout &&
652 bt_common_colors_supported();
653 break;
654 case TEXT_COLOR_OPT_NEVER:
655 text->use_colors = false;
656 break;
657 }
658 }
659
660 static
661 enum bt_component_status text_component_init(
662 struct bt_component *component, struct bt_value *params,
663 UNUSED_VAR void *init_method_data)
664 {
665 enum bt_component_status ret;
666 struct text_component *text = create_text();
667
668 if (!text) {
669 ret = BT_COMPONENT_STATUS_NOMEM;
670 goto end;
671 }
672
673 text->out = stdout;
674 text->err = stderr;
675
676 text->delta_cycles = -1ULL;
677 text->last_cycles_timestamp = -1ULL;
678
679 text->delta_real_timestamp = -1ULL;
680 text->last_real_timestamp = -1ULL;
681
682 ret = apply_params(text, params);
683 if (ret != BT_COMPONENT_STATUS_OK) {
684 goto error;
685 }
686
687 set_use_colors(text);
688
689 ret = bt_component_set_private_data(component, text);
690 if (ret != BT_COMPONENT_STATUS_OK) {
691 goto error;
692 }
693 end:
694 return ret;
695 error:
696 destroy_text_data(text);
697 return ret;
698 }
699
700 /* Initialize plug-in entry points. */
701 BT_PLUGIN(text);
702 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
703 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
704 BT_PLUGIN_LICENSE("MIT");
705 BT_PLUGIN_SINK_COMPONENT_CLASS(text, run);
706 BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(text, text_component_init);
707 BT_PLUGIN_SINK_COMPONENT_CLASS_DESTROY_METHOD(text, destroy_text);
708 BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(text,
709 "Formats CTF-IR to text. Formerly known as ctf-text.");
710
This page took 0.041579 seconds and 3 git commands to generate.