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