babeltrace(1): add --connect option and connection management
[babeltrace.git] / plugins / text / text.c
CommitLineData
7a278c8e 1/*
5dac767a 2 * text.c
7a278c8e 3 *
5dac767a 4 * Babeltrace CTF Text Output Plugin
7a278c8e 5 *
2e339de1 6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
f504043c 7 * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7a278c8e
JG
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
33b34c43
PP
30#include <babeltrace/plugin/plugin-dev.h>
31#include <babeltrace/component/component.h>
d71dcf2c 32#include <babeltrace/component/component-sink.h>
33b34c43
PP
33#include <babeltrace/component/notification/notification.h>
34#include <babeltrace/component/notification/iterator.h>
35#include <babeltrace/component/notification/event.h>
6e1bc0df
MD
36#include <babeltrace/values.h>
37#include <babeltrace/compiler.h>
7d61fa8e 38#include <plugins-common.h>
bfd20a42 39#include <stdio.h>
39cfa40f 40#include <stdbool.h>
bac67f0f 41#include <glib.h>
541b0a11 42#include "text.h"
6405967d 43
6e1bc0df
MD
44static
45const 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",
6e1bc0df
MD
68};
69
bfd20a42 70static
541b0a11 71void destroy_text_data(struct text_component *text)
bac67f0f 72{
6a18b281 73 (void) g_string_free(text->string, TRUE);
6e1bc0df
MD
74 g_free(text->options.output_path);
75 g_free(text->options.debug_info_dir);
76 g_free(text->options.debug_info_target_prefix);
541b0a11 77 g_free(text);
bac67f0f
JG
78}
79
b25bd455 80static
541b0a11 81struct text_component *create_text(void)
bac67f0f 82{
541b0a11
JG
83 struct text_component *text;
84
85 text = g_new0(struct text_component, 1);
86 if (!text) {
87 goto end;
88 }
6a18b281
MD
89 text->string = g_string_new("");
90 if (!text->string) {
91 goto error;
92 }
541b0a11
JG
93end:
94 return text;
6a18b281
MD
95
96error:
97 g_free(text);
98 return NULL;
bac67f0f
JG
99}
100
fec2a9f2
JG
101static
102void destroy_text(struct bt_component *component)
b25bd455
JG
103{
104 void *data = bt_component_get_private_data(component);
105
106 destroy_text_data(data);
107}
108
bac67f0f 109static
fec2a9f2 110enum bt_component_status handle_notification(struct text_component *text,
6e1bc0df 111 struct bt_notification *notification)
4c1456f0 112{
541b0a11 113 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
541b0a11
JG
114
115 if (!text) {
116 ret = BT_COMPONENT_STATUS_ERROR;
117 goto end;
118 }
119
78586d8a 120 switch (bt_notification_get_type(notification)) {
ea0e619e 121 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
78586d8a
JG
122 puts("<packet>");
123 break;
124 case BT_NOTIFICATION_TYPE_PACKET_END:
125 puts("</packet>");
126 break;
127 case BT_NOTIFICATION_TYPE_EVENT:
541b0a11
JG
128 {
129 struct bt_ctf_event *event = bt_notification_event_get_event(
130 notification);
131
541b0a11
JG
132 if (!event) {
133 ret = BT_COMPONENT_STATUS_ERROR;
134 goto end;
135 }
136 ret = text_print_event(text, event);
fec2a9f2 137 bt_put(event);
541b0a11
JG
138 if (ret != BT_COMPONENT_STATUS_OK) {
139 goto end;
140 }
043e2020 141 break;
541b0a11 142 }
043e2020
JG
143 case BT_NOTIFICATION_TYPE_STREAM_END:
144 puts("</stream>");
78586d8a
JG
145 break;
146 default:
147 puts("Unhandled notification type");
148 }
541b0a11
JG
149end:
150 return ret;
4c1456f0 151}
bac67f0f 152
fec2a9f2
JG
153static
154enum bt_component_status run(struct bt_component *component)
155{
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);
160
161 ret = bt_component_sink_get_input_iterator(component, 0, &it);
162 if (ret != BT_COMPONENT_STATUS_OK) {
163 goto end;
164 }
165
f48bc732
JG
166 if (likely(text->processed_first_event)) {
167 enum bt_notification_iterator_status it_ret;
168
169 it_ret = bt_notification_iterator_next(it);
170 switch (it_ret) {
171 case BT_NOTIFICATION_ITERATOR_STATUS_ERROR:
172 ret = BT_COMPONENT_STATUS_ERROR;
fec2a9f2 173 goto end;
f48bc732
JG
174 case BT_NOTIFICATION_ITERATOR_STATUS_END:
175 ret = BT_COMPONENT_STATUS_END;
176 goto end;
177 default:
178 break;
fec2a9f2 179 }
fec2a9f2 180 }
fec2a9f2
JG
181 notification = bt_notification_iterator_get_notification(it);
182 if (!notification) {
183 ret = BT_COMPONENT_STATUS_ERROR;
184 goto end;
185 }
186
187 ret = handle_notification(text, notification);
f48bc732 188 text->processed_first_event = true;
fec2a9f2
JG
189end:
190 bt_put(it);
191 bt_put(notification);
192 return ret;
193}
194
6e1bc0df
MD
195static
196enum bt_component_status add_params_to_map(struct bt_value *plugin_opt_map)
197{
198 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
199 unsigned int i;
200
201 for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
202 const char *key = plugin_options[i];
203 enum bt_value_status status;
204
205 status = bt_value_map_insert(plugin_opt_map, key, bt_value_null);
206 switch (status) {
207 case BT_VALUE_STATUS_OK:
208 break;
209 default:
210 ret = BT_COMPONENT_STATUS_ERROR;
211 goto end;
212 }
213 }
214end:
215 return ret;
216}
217
218static
219bool check_param_exists(const char *key, struct bt_value *object, void *data)
220{
221 struct text_component *text = data;
222 struct bt_value *plugin_opt_map = text->plugin_opt_map;
223
224 if (!bt_value_map_get(plugin_opt_map, key)) {
225 fprintf(text->err,
6ba0b073 226 "[warning] Parameter \"%s\" unknown to \"text\" plugin\n", key);
6e1bc0df
MD
227 }
228 return true;
229}
230
231static
232enum bt_component_status apply_one_string(const char *key,
233 struct bt_value *params,
234 char **option)
235{
236 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
237 struct bt_value *value = NULL;
238 enum bt_value_status status;
239 const char *str;
240
241 value = bt_value_map_get(params, key);
242 if (!value) {
243 goto end;
244 }
245 if (bt_value_is_null(value)) {
246 goto end;
247 }
248 status = bt_value_string_get(value, &str);
249 switch (status) {
250 case BT_VALUE_STATUS_OK:
251 break;
252 default:
253 ret = BT_COMPONENT_STATUS_ERROR;
254 goto end;
255 }
256 *option = g_strdup(str);
257end:
258 bt_put(value);
259 return ret;
260}
261
262static
263enum bt_component_status apply_one_bool(const char *key,
264 struct bt_value *params,
265 bool *option,
266 bool *found)
267{
268 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
269 struct bt_value *value = NULL;
270 enum bt_value_status status;
271
272 value = bt_value_map_get(params, key);
273 if (!value) {
274 goto end;
275 }
276 status = bt_value_bool_get(value, option);
277 switch (status) {
278 case BT_VALUE_STATUS_OK:
279 break;
280 default:
281 ret = BT_COMPONENT_STATUS_ERROR;
282 goto end;
283 }
284 if (found) {
285 *found = true;
286 }
287end:
288 bt_put(value);
289 return ret;
290}
291
292static
293enum bt_component_status apply_params(struct text_component *text,
294 struct bt_value *params)
295{
296 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
297 enum bt_value_status status;
298 bool value, found;
299 char *str = NULL;
300
301 text->plugin_opt_map = bt_value_map_create();
302 if (!text->plugin_opt_map) {
303 ret = BT_COMPONENT_STATUS_ERROR;
304 goto end;
305 }
306 ret = add_params_to_map(text->plugin_opt_map);
307 if (ret != BT_COMPONENT_STATUS_OK) {
308 goto end;
309 }
310 /* Report unknown parameters. */
311 status = bt_value_map_foreach(params, check_param_exists, text);
312 switch (status) {
313 case BT_VALUE_STATUS_OK:
314 break;
315 default:
316 ret = BT_COMPONENT_STATUS_ERROR;
317 goto end;
318 }
319 /* Known parameters. */
320 ret = apply_one_string("output-path",
321 params,
322 &text->options.output_path);
323 if (ret != BT_COMPONENT_STATUS_OK) {
324 goto end;
325 }
326
327 ret = apply_one_string("debug-info-dir",
328 params,
329 &text->options.debug_info_dir);
330 if (ret != BT_COMPONENT_STATUS_OK) {
331 goto end;
332 }
333
334 ret = apply_one_string("debug-info-target-prefix",
335 params,
336 &text->options.debug_info_target_prefix);
337 if (ret != BT_COMPONENT_STATUS_OK) {
338 goto end;
339 }
340
341 value = false; /* Default. */
342 ret = apply_one_bool("debug-info-full-path", params, &value, NULL);
343 if (ret != BT_COMPONENT_STATUS_OK) {
344 goto end;
345 }
346 text->options.debug_info_full_path = value;
347
348 value = false; /* Default. */
349 ret = apply_one_bool("no-delta", params, &value, NULL);
350 if (ret != BT_COMPONENT_STATUS_OK) {
351 goto end;
352 }
353 text->options.print_delta_field = !value; /* Reverse logic. */
354
355 value = false; /* Default. */
356 ret = apply_one_bool("clock-cycles", params, &value, NULL);
357 if (ret != BT_COMPONENT_STATUS_OK) {
358 goto end;
359 }
360 text->options.print_timestamp_cycles = value;
361
362 value = false; /* Default. */
363 ret = apply_one_bool("clock-seconds", params, &value, NULL);
364 if (ret != BT_COMPONENT_STATUS_OK) {
365 goto end;
366 }
367 text->options.clock_seconds = value;
368
369 value = false; /* Default. */
370 ret = apply_one_bool("clock-date", params, &value, NULL);
371 if (ret != BT_COMPONENT_STATUS_OK) {
372 goto end;
373 }
374 text->options.clock_date = value;
375
376 value = false; /* Default. */
377 ret = apply_one_bool("clock-gmt", params, &value, NULL);
378 if (ret != BT_COMPONENT_STATUS_OK) {
379 goto end;
380 }
381 text->options.clock_gmt = value;
382
383 /* Names. */
384 ret = apply_one_string("name-default", params, &str);
385 if (ret != BT_COMPONENT_STATUS_OK) {
386 goto end;
387 }
388 if (!str) {
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;
394 } else {
395 ret = BT_COMPONENT_STATUS_ERROR;
396 goto end;
397 }
398 g_free(str);
399 str = NULL;
400
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;
407 break;
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;
413 break;
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;
419 break;
420 default:
421 ret = BT_COMPONENT_STATUS_ERROR;
422 goto end;
423 }
424
425 value = false;
426 found = false;
427 ret = apply_one_bool("name-payload", params, &value, &found);
428 if (ret != BT_COMPONENT_STATUS_OK) {
429 goto end;
430 }
431 if (found) {
432 text->options.print_payload_field_names = value;
433 }
434
435 value = false;
436 found = false;
437 ret = apply_one_bool("name-context", params, &value, &found);
438 if (ret != BT_COMPONENT_STATUS_OK) {
439 goto end;
440 }
441 if (found) {
442 text->options.print_context_field_names = value;
443 }
444
445 value = false;
446 found = false;
447 ret = apply_one_bool("name-header", params, &value, &found);
448 if (ret != BT_COMPONENT_STATUS_OK) {
449 goto end;
450 }
451 if (found) {
452 text->options.print_header_field_names = value;
453 }
454
455 value = false;
456 found = false;
457 ret = apply_one_bool("name-scope", params, &value, &found);
458 if (ret != BT_COMPONENT_STATUS_OK) {
459 goto end;
460 }
461 if (found) {
462 text->options.print_scope_field_names = value;
463 }
464
465 /* Fields. */
466 ret = apply_one_string("field-default", params, &str);
467 if (ret != BT_COMPONENT_STATUS_OK) {
468 goto end;
469 }
470 if (!str) {
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;
476 } else {
477 ret = BT_COMPONENT_STATUS_ERROR;
478 goto end;
479 }
480 g_free(str);
481 str = NULL;
482
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;
6e1bc0df
MD
493 break;
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;
6e1bc0df
MD
503 break;
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;
6e1bc0df
MD
513 break;
514 default:
515 ret = BT_COMPONENT_STATUS_ERROR;
516 goto end;
517 }
518
519 value = false;
520 found = false;
521 ret = apply_one_bool("field-trace", params, &value, &found);
522 if (ret != BT_COMPONENT_STATUS_OK) {
523 goto end;
524 }
525 if (found) {
526 text->options.print_trace_field = value;
527 }
528
529 value = false;
530 found = false;
531 ret = apply_one_bool("field-trace:hostname", params, &value, &found);
532 if (ret != BT_COMPONENT_STATUS_OK) {
533 goto end;
534 }
535 if (found) {
536 text->options.print_trace_hostname_field = value;
537 }
538
539 value = false;
540 found = false;
541 ret = apply_one_bool("field-trace:domain", params, &value, &found);
542 if (ret != BT_COMPONENT_STATUS_OK) {
543 goto end;
544 }
545 if (found) {
546 text->options.print_trace_domain_field = value;
547 }
548
549 value = false;
550 found = false;
551 ret = apply_one_bool("field-trace:procname", params, &value, &found);
552 if (ret != BT_COMPONENT_STATUS_OK) {
553 goto end;
554 }
555 if (found) {
556 text->options.print_trace_procname_field = value;
557 }
558
559 value = false;
560 found = false;
561 ret = apply_one_bool("field-trace:vpid", params, &value, &found);
562 if (ret != BT_COMPONENT_STATUS_OK) {
563 goto end;
564 }
565 if (found) {
566 text->options.print_trace_vpid_field = value;
567 }
568
569 value = false;
570 found = false;
571 ret = apply_one_bool("field-loglevel", params, &value, &found);
572 if (ret != BT_COMPONENT_STATUS_OK) {
573 goto end;
574 }
575 if (found) {
576 text->options.print_loglevel_field = value;
577 }
578
579 value = false;
580 found = false;
581 ret = apply_one_bool("field-emf", params, &value, &found);
582 if (ret != BT_COMPONENT_STATUS_OK) {
583 goto end;
584 }
585 if (found) {
586 text->options.print_emf_field = value;
587 }
588
589 value = false;
590 found = false;
591 ret = apply_one_bool("field-emf", params, &value, &found);
592 if (ret != BT_COMPONENT_STATUS_OK) {
593 goto end;
594 }
595 if (found) {
596 text->options.print_emf_field = value;
597 }
598
6e1bc0df
MD
599end:
600 bt_put(text->plugin_opt_map);
601 text->plugin_opt_map = NULL;
602 g_free(str);
603 return ret;
604}
605
bac67f0f
JG
606static
607enum bt_component_status text_component_init(
6358c163 608 struct bt_component *component, struct bt_value *params,
7d61fa8e 609 UNUSED_VAR void *init_method_data)
bac67f0f
JG
610{
611 enum bt_component_status ret;
612 struct text_component *text = create_text();
613
614 if (!text) {
615 ret = BT_COMPONENT_STATUS_NOMEM;
616 goto end;
617 }
618
6e1bc0df
MD
619 text->out = stdout;
620 text->err = stderr;
621
3af83b5a
MD
622 text->delta_cycles = -1ULL;
623 text->last_cycles_timestamp = -1ULL;
624
625 text->delta_real_timestamp = -1ULL;
626 text->last_real_timestamp = -1ULL;
627
6e1bc0df
MD
628 ret = apply_params(text, params);
629 if (ret != BT_COMPONENT_STATUS_OK) {
630 goto error;
631 }
632
bac67f0f
JG
633 ret = bt_component_set_private_data(component, text);
634 if (ret != BT_COMPONENT_STATUS_OK) {
635 goto error;
636 }
bac67f0f
JG
637end:
638 return ret;
639error:
b25bd455 640 destroy_text_data(text);
bac67f0f
JG
641 return ret;
642}
643
bac67f0f 644/* Initialize plug-in entry points. */
6ba0b073 645BT_PLUGIN(text);
bac67f0f
JG
646BT_PLUGIN_DESCRIPTION("Babeltrace text output plug-in.");
647BT_PLUGIN_AUTHOR("Jérémie Galarneau");
648BT_PLUGIN_LICENSE("MIT");
d3e4dcd8
PP
649BT_PLUGIN_SINK_COMPONENT_CLASS(text, run);
650BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(text, text_component_init);
651BT_PLUGIN_SINK_COMPONENT_CLASS_DESTROY_METHOD(text, destroy_text);
652BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(text,
6ba0b073 653 "Formats CTF-IR to text. Formerly known as ctf-text.");
d3e4dcd8 654
This page took 0.054769 seconds and 4 git commands to generate.