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