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