Allow NULL (unset) packet, stream and event headers, contexts
[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 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <babeltrace/plugin/plugin-macros.h>
30 #include <babeltrace/plugin/component.h>
31 #include <babeltrace/plugin/sink.h>
32 #include <babeltrace/plugin/notification/notification.h>
33 #include <babeltrace/plugin/notification/iterator.h>
34 #include <babeltrace/plugin/notification/event.h>
35 #include <babeltrace/values.h>
36 #include <babeltrace/compiler.h>
37 #include <stdio.h>
38 #include <stdbool.h>
39 #include <glib.h>
40 #include "text.h"
41
42 #define PLUGIN_NAME "text"
43
44 static
45 const char *plugin_options[] = {
46 "output-path",
47 "debug-info-dir",
48 "debug-info-target-prefix",
49 "debug-info-full-path",
50 "no-delta",
51 "clock-cycles",
52 "clock-seconds",
53 "clock-date",
54 "clock-gmt",
55 "name-default", /* show/hide */
56 "name-payload",
57 "name-context",
58 "name-scope",
59 "name-header",
60 "field-default", /* show/hide */
61 "field-trace",
62 "field-trace:hostname",
63 "field-trace:domain",
64 "field-trace:procname",
65 "field-trace:vpid",
66 "field-loglevel",
67 "field-emf",
68 "field-callsite",
69 };
70
71 static
72 const char *loglevel_str [] = {
73 [LOGLEVEL_EMERG] = "TRACE_EMERG",
74 [LOGLEVEL_ALERT] = "TRACE_ALERT",
75 [LOGLEVEL_CRIT] = "TRACE_CRIT",
76 [LOGLEVEL_ERR] = "TRACE_ERR",
77 [LOGLEVEL_WARNING] = "TRACE_WARNING",
78 [LOGLEVEL_NOTICE] = "TRACE_NOTICE",
79 [LOGLEVEL_INFO] = "TRACE_INFO",
80 [LOGLEVEL_DEBUG_SYSTEM] = "TRACE_DEBUG_SYSTEM",
81 [LOGLEVEL_DEBUG_PROGRAM] = "TRACE_DEBUG_PROGRAM",
82 [LOGLEVEL_DEBUG_PROCESS] = "TRACE_DEBUG_PROCESS",
83 [LOGLEVEL_DEBUG_MODULE] = "TRACE_DEBUG_MODULE",
84 [LOGLEVEL_DEBUG_UNIT] = "TRACE_DEBUG_UNIT",
85 [LOGLEVEL_DEBUG_FUNCTION] = "TRACE_DEBUG_FUNCTION",
86 [LOGLEVEL_DEBUG_LINE] = "TRACE_DEBUG_LINE",
87 [LOGLEVEL_DEBUG] = "TRACE_DEBUG",
88 };
89
90 static
91 void destroy_text_data(struct text_component *text)
92 {
93 (void) g_string_free(text->string, TRUE);
94 g_free(text->options.output_path);
95 g_free(text->options.debug_info_dir);
96 g_free(text->options.debug_info_target_prefix);
97 g_free(text);
98 }
99
100 static
101 struct text_component *create_text(void)
102 {
103 struct text_component *text;
104
105 text = g_new0(struct text_component, 1);
106 if (!text) {
107 goto end;
108 }
109 text->string = g_string_new("");
110 if (!text->string) {
111 goto error;
112 }
113 end:
114 return text;
115
116 error:
117 g_free(text);
118 return NULL;
119 }
120
121 static
122 void destroy_text(struct bt_component *component)
123 {
124 void *data = bt_component_get_private_data(component);
125
126 destroy_text_data(data);
127 }
128
129 static
130 enum bt_component_status handle_notification(struct text_component *text,
131 struct bt_notification *notification)
132 {
133 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
134
135 if (!text) {
136 ret = BT_COMPONENT_STATUS_ERROR;
137 goto end;
138 }
139
140 switch (bt_notification_get_type(notification)) {
141 case BT_NOTIFICATION_TYPE_PACKET_START:
142 puts("<packet>");
143 break;
144 case BT_NOTIFICATION_TYPE_PACKET_END:
145 puts("</packet>");
146 break;
147 case BT_NOTIFICATION_TYPE_EVENT:
148 {
149 struct bt_ctf_event *event = bt_notification_event_get_event(
150 notification);
151
152 if (!event) {
153 ret = BT_COMPONENT_STATUS_ERROR;
154 goto end;
155 }
156 ret = text_print_event(text, event);
157 bt_put(event);
158 if (ret != BT_COMPONENT_STATUS_OK) {
159 goto end;
160 }
161 break;
162 }
163 case BT_NOTIFICATION_TYPE_STREAM_END:
164 puts("</stream>");
165 break;
166 default:
167 puts("Unhandled notification type");
168 }
169 end:
170 return ret;
171 }
172
173 static
174 enum bt_component_status run(struct bt_component *component)
175 {
176 enum bt_component_status ret;
177 struct bt_notification *notification = NULL;
178 struct bt_notification_iterator *it;
179 struct text_component *text = bt_component_get_private_data(component);
180
181 ret = bt_component_sink_get_input_iterator(component, 0, &it);
182 if (ret != BT_COMPONENT_STATUS_OK) {
183 goto end;
184 }
185
186 if (!text->processed_first_event) {
187 ret = bt_notification_iterator_next(it);
188 if (ret != BT_COMPONENT_STATUS_OK) {
189 goto end;
190 }
191 } else {
192 text->processed_first_event = true;
193 }
194
195 notification = bt_notification_iterator_get_notification(it);
196 if (!notification) {
197 ret = BT_COMPONENT_STATUS_ERROR;
198 goto end;
199 }
200
201 ret = handle_notification(text, notification);
202 end:
203 bt_put(it);
204 bt_put(notification);
205 return ret;
206 }
207
208 static
209 enum bt_component_status add_params_to_map(struct bt_value *plugin_opt_map)
210 {
211 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
212 unsigned int i;
213
214 for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
215 const char *key = plugin_options[i];
216 enum bt_value_status status;
217
218 status = bt_value_map_insert(plugin_opt_map, key, bt_value_null);
219 switch (status) {
220 case BT_VALUE_STATUS_OK:
221 break;
222 default:
223 ret = BT_COMPONENT_STATUS_ERROR;
224 goto end;
225 }
226 }
227 end:
228 return ret;
229 }
230
231 static
232 bool check_param_exists(const char *key, struct bt_value *object, void *data)
233 {
234 struct text_component *text = data;
235 struct bt_value *plugin_opt_map = text->plugin_opt_map;
236
237 if (!bt_value_map_get(plugin_opt_map, key)) {
238 fprintf(text->err,
239 "[warning] Parameter \"%s\" unknown to \"%s\" plugin\n",
240 key, PLUGIN_NAME);
241 }
242 return true;
243 }
244
245 static
246 enum bt_component_status apply_one_string(const char *key,
247 struct bt_value *params,
248 char **option)
249 {
250 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
251 struct bt_value *value = NULL;
252 enum bt_value_status status;
253 const char *str;
254
255 value = bt_value_map_get(params, key);
256 if (!value) {
257 goto end;
258 }
259 if (bt_value_is_null(value)) {
260 goto end;
261 }
262 status = bt_value_string_get(value, &str);
263 switch (status) {
264 case BT_VALUE_STATUS_OK:
265 break;
266 default:
267 ret = BT_COMPONENT_STATUS_ERROR;
268 goto end;
269 }
270 *option = g_strdup(str);
271 end:
272 bt_put(value);
273 return ret;
274 }
275
276 static
277 enum bt_component_status apply_one_bool(const char *key,
278 struct bt_value *params,
279 bool *option,
280 bool *found)
281 {
282 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
283 struct bt_value *value = NULL;
284 enum bt_value_status status;
285
286 value = bt_value_map_get(params, key);
287 if (!value) {
288 goto end;
289 }
290 status = bt_value_bool_get(value, option);
291 switch (status) {
292 case BT_VALUE_STATUS_OK:
293 break;
294 default:
295 ret = BT_COMPONENT_STATUS_ERROR;
296 goto end;
297 }
298 if (found) {
299 *found = true;
300 }
301 end:
302 bt_put(value);
303 return ret;
304 }
305
306 static
307 enum bt_component_status apply_params(struct text_component *text,
308 struct bt_value *params)
309 {
310 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
311 enum bt_value_status status;
312 bool value, found;
313 char *str = NULL;
314
315 text->plugin_opt_map = bt_value_map_create();
316 if (!text->plugin_opt_map) {
317 ret = BT_COMPONENT_STATUS_ERROR;
318 goto end;
319 }
320 ret = add_params_to_map(text->plugin_opt_map);
321 if (ret != BT_COMPONENT_STATUS_OK) {
322 goto end;
323 }
324 /* Report unknown parameters. */
325 status = bt_value_map_foreach(params, check_param_exists, text);
326 switch (status) {
327 case BT_VALUE_STATUS_OK:
328 break;
329 default:
330 ret = BT_COMPONENT_STATUS_ERROR;
331 goto end;
332 }
333 /* Known parameters. */
334 ret = apply_one_string("output-path",
335 params,
336 &text->options.output_path);
337 if (ret != BT_COMPONENT_STATUS_OK) {
338 goto end;
339 }
340
341 ret = apply_one_string("debug-info-dir",
342 params,
343 &text->options.debug_info_dir);
344 if (ret != BT_COMPONENT_STATUS_OK) {
345 goto end;
346 }
347
348 ret = apply_one_string("debug-info-target-prefix",
349 params,
350 &text->options.debug_info_target_prefix);
351 if (ret != BT_COMPONENT_STATUS_OK) {
352 goto end;
353 }
354
355 value = false; /* Default. */
356 ret = apply_one_bool("debug-info-full-path", params, &value, NULL);
357 if (ret != BT_COMPONENT_STATUS_OK) {
358 goto end;
359 }
360 text->options.debug_info_full_path = value;
361
362 value = false; /* Default. */
363 ret = apply_one_bool("no-delta", params, &value, NULL);
364 if (ret != BT_COMPONENT_STATUS_OK) {
365 goto end;
366 }
367 text->options.print_delta_field = !value; /* Reverse logic. */
368
369 value = false; /* Default. */
370 ret = apply_one_bool("clock-cycles", params, &value, NULL);
371 if (ret != BT_COMPONENT_STATUS_OK) {
372 goto end;
373 }
374 text->options.print_timestamp_cycles = value;
375
376 value = false; /* Default. */
377 ret = apply_one_bool("clock-seconds", params, &value, NULL);
378 if (ret != BT_COMPONENT_STATUS_OK) {
379 goto end;
380 }
381 text->options.clock_seconds = value;
382
383 value = false; /* Default. */
384 ret = apply_one_bool("clock-date", params, &value, NULL);
385 if (ret != BT_COMPONENT_STATUS_OK) {
386 goto end;
387 }
388 text->options.clock_date = value;
389
390 value = false; /* Default. */
391 ret = apply_one_bool("clock-gmt", params, &value, NULL);
392 if (ret != BT_COMPONENT_STATUS_OK) {
393 goto end;
394 }
395 text->options.clock_gmt = value;
396
397 /* Names. */
398 ret = apply_one_string("name-default", params, &str);
399 if (ret != BT_COMPONENT_STATUS_OK) {
400 goto end;
401 }
402 if (!str) {
403 text->options.name_default = TEXT_DEFAULT_UNSET;
404 } else if (!strcmp(str, "show")) {
405 text->options.name_default = TEXT_DEFAULT_SHOW;
406 } else if (!strcmp(str, "hide")) {
407 text->options.name_default = TEXT_DEFAULT_HIDE;
408 } else {
409 ret = BT_COMPONENT_STATUS_ERROR;
410 goto end;
411 }
412 g_free(str);
413 str = NULL;
414
415 switch (text->options.name_default) {
416 case TEXT_DEFAULT_UNSET:
417 text->options.print_payload_field_names = true;
418 text->options.print_context_field_names = true;
419 text->options.print_header_field_names = false;
420 text->options.print_scope_field_names = false;
421 break;
422 case TEXT_DEFAULT_SHOW:
423 text->options.print_payload_field_names = true;
424 text->options.print_context_field_names = true;
425 text->options.print_header_field_names = true;
426 text->options.print_scope_field_names = true;
427 break;
428 case TEXT_DEFAULT_HIDE:
429 text->options.print_payload_field_names = false;
430 text->options.print_context_field_names = false;
431 text->options.print_header_field_names = false;
432 text->options.print_scope_field_names = false;
433 break;
434 default:
435 ret = BT_COMPONENT_STATUS_ERROR;
436 goto end;
437 }
438
439 value = false;
440 found = false;
441 ret = apply_one_bool("name-payload", params, &value, &found);
442 if (ret != BT_COMPONENT_STATUS_OK) {
443 goto end;
444 }
445 if (found) {
446 text->options.print_payload_field_names = value;
447 }
448
449 value = false;
450 found = false;
451 ret = apply_one_bool("name-context", params, &value, &found);
452 if (ret != BT_COMPONENT_STATUS_OK) {
453 goto end;
454 }
455 if (found) {
456 text->options.print_context_field_names = value;
457 }
458
459 value = false;
460 found = false;
461 ret = apply_one_bool("name-header", params, &value, &found);
462 if (ret != BT_COMPONENT_STATUS_OK) {
463 goto end;
464 }
465 if (found) {
466 text->options.print_header_field_names = value;
467 }
468
469 value = false;
470 found = false;
471 ret = apply_one_bool("name-scope", params, &value, &found);
472 if (ret != BT_COMPONENT_STATUS_OK) {
473 goto end;
474 }
475 if (found) {
476 text->options.print_scope_field_names = value;
477 }
478
479 /* Fields. */
480 ret = apply_one_string("field-default", params, &str);
481 if (ret != BT_COMPONENT_STATUS_OK) {
482 goto end;
483 }
484 if (!str) {
485 text->options.field_default = TEXT_DEFAULT_UNSET;
486 } else if (!strcmp(str, "show")) {
487 text->options.field_default = TEXT_DEFAULT_SHOW;
488 } else if (!strcmp(str, "hide")) {
489 text->options.field_default = TEXT_DEFAULT_HIDE;
490 } else {
491 ret = BT_COMPONENT_STATUS_ERROR;
492 goto end;
493 }
494 g_free(str);
495 str = NULL;
496
497 switch (text->options.field_default) {
498 case TEXT_DEFAULT_UNSET:
499 text->options.print_trace_field = false;
500 text->options.print_trace_hostname_field = true;
501 text->options.print_trace_domain_field = false;
502 text->options.print_trace_procname_field = true;
503 text->options.print_trace_vpid_field = true;
504 text->options.print_loglevel_field = false;
505 text->options.print_emf_field = false;
506 text->options.print_emf_field = false;
507 text->options.print_callsite_field = false;
508 break;
509 case TEXT_DEFAULT_SHOW:
510 text->options.print_trace_field = true;
511 text->options.print_trace_hostname_field = true;
512 text->options.print_trace_domain_field = true;
513 text->options.print_trace_procname_field = true;
514 text->options.print_trace_vpid_field = true;
515 text->options.print_loglevel_field = true;
516 text->options.print_emf_field = true;
517 text->options.print_emf_field = true;
518 text->options.print_callsite_field = true;
519 break;
520 case TEXT_DEFAULT_HIDE:
521 text->options.print_trace_field = false;
522 text->options.print_trace_hostname_field = false;
523 text->options.print_trace_domain_field = false;
524 text->options.print_trace_procname_field = false;
525 text->options.print_trace_vpid_field = false;
526 text->options.print_loglevel_field = false;
527 text->options.print_emf_field = false;
528 text->options.print_emf_field = false;
529 text->options.print_callsite_field = false;
530 break;
531 default:
532 ret = BT_COMPONENT_STATUS_ERROR;
533 goto end;
534 }
535
536 value = false;
537 found = false;
538 ret = apply_one_bool("field-trace", params, &value, &found);
539 if (ret != BT_COMPONENT_STATUS_OK) {
540 goto end;
541 }
542 if (found) {
543 text->options.print_trace_field = value;
544 }
545
546 value = false;
547 found = false;
548 ret = apply_one_bool("field-trace:hostname", params, &value, &found);
549 if (ret != BT_COMPONENT_STATUS_OK) {
550 goto end;
551 }
552 if (found) {
553 text->options.print_trace_hostname_field = value;
554 }
555
556 value = false;
557 found = false;
558 ret = apply_one_bool("field-trace:domain", params, &value, &found);
559 if (ret != BT_COMPONENT_STATUS_OK) {
560 goto end;
561 }
562 if (found) {
563 text->options.print_trace_domain_field = value;
564 }
565
566 value = false;
567 found = false;
568 ret = apply_one_bool("field-trace:procname", params, &value, &found);
569 if (ret != BT_COMPONENT_STATUS_OK) {
570 goto end;
571 }
572 if (found) {
573 text->options.print_trace_procname_field = value;
574 }
575
576 value = false;
577 found = false;
578 ret = apply_one_bool("field-trace:vpid", params, &value, &found);
579 if (ret != BT_COMPONENT_STATUS_OK) {
580 goto end;
581 }
582 if (found) {
583 text->options.print_trace_vpid_field = value;
584 }
585
586 value = false;
587 found = false;
588 ret = apply_one_bool("field-loglevel", params, &value, &found);
589 if (ret != BT_COMPONENT_STATUS_OK) {
590 goto end;
591 }
592 if (found) {
593 text->options.print_loglevel_field = value;
594 }
595
596 value = false;
597 found = false;
598 ret = apply_one_bool("field-emf", params, &value, &found);
599 if (ret != BT_COMPONENT_STATUS_OK) {
600 goto end;
601 }
602 if (found) {
603 text->options.print_emf_field = value;
604 }
605
606 value = false;
607 found = false;
608 ret = apply_one_bool("field-emf", params, &value, &found);
609 if (ret != BT_COMPONENT_STATUS_OK) {
610 goto end;
611 }
612 if (found) {
613 text->options.print_emf_field = value;
614 }
615
616 value = false;
617 found = false;
618 ret = apply_one_bool("field-callsite", params, &value, &found);
619 if (ret != BT_COMPONENT_STATUS_OK) {
620 goto end;
621 }
622 if (found) {
623 text->options.print_callsite_field = value;
624 }
625 end:
626 bt_put(text->plugin_opt_map);
627 text->plugin_opt_map = NULL;
628 g_free(str);
629 return ret;
630 }
631
632 static
633 enum bt_component_status text_component_init(
634 struct bt_component *component, struct bt_value *params)
635 {
636 enum bt_component_status ret;
637 struct text_component *text = create_text();
638
639 if (!text) {
640 ret = BT_COMPONENT_STATUS_NOMEM;
641 goto end;
642 }
643
644 text->out = stdout;
645 text->err = stderr;
646
647 ret = apply_params(text, params);
648 if (ret != BT_COMPONENT_STATUS_OK) {
649 goto error;
650 }
651
652 ret = bt_component_set_destroy_cb(component,
653 destroy_text);
654 if (ret != BT_COMPONENT_STATUS_OK) {
655 goto error;
656 }
657
658 ret = bt_component_set_private_data(component, text);
659 if (ret != BT_COMPONENT_STATUS_OK) {
660 goto error;
661 }
662
663 ret = bt_component_sink_set_consume_cb(component,
664 run);
665 if (ret != BT_COMPONENT_STATUS_OK) {
666 goto error;
667 }
668 end:
669 return ret;
670 error:
671 destroy_text_data(text);
672 return ret;
673 }
674
675 /* Initialize plug-in entry points. */
676 BT_PLUGIN_NAME("text");
677 BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
678 BT_PLUGIN_AUTHOR("Jérémie Galarneau");
679 BT_PLUGIN_LICENSE("MIT");
680
681 BT_PLUGIN_COMPONENT_CLASSES_BEGIN
682 BT_PLUGIN_SINK_COMPONENT_CLASS_ENTRY(PLUGIN_NAME,
683 "Formats CTF-IR to text. Formerly known as ctf-text.",
684 text_component_init)
685 BT_PLUGIN_COMPONENT_CLASSES_END
This page took 0.054037 seconds and 4 git commands to generate.