3fcd466018f6ab668bbcd523000e40f1453e024d
[babeltrace.git] / src / plugins / text / details / details.c
1 /*
2 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #define BT_LOG_TAG "PLUGIN-TEXT-DETAILS-SINK"
24 #include "logging.h"
25
26 #include <babeltrace2/babeltrace.h>
27
28 #include "common/common.h"
29 #include "common/assert.h"
30 #include "details.h"
31 #include "write.h"
32
33 #define LOG_WRONG_PARAM_TYPE(_name, _value, _exp_type) \
34 do { \
35 BT_LOGE("Wrong `%s` parameter type: type=%s, " \
36 "expected-type=%s", \
37 (_name), bt_common_value_type_string( \
38 bt_value_get_type(_value)), \
39 bt_common_value_type_string(_exp_type)); \
40 } while (0)
41
42 static
43 const char * const in_port_name = "in";
44
45 static
46 const char * const color_param_name = "color";
47
48 static
49 const char * const with_metadata_param_name = "with-metadata";
50
51 static
52 const char * const with_time_param_name = "with-time";
53
54 static
55 const char * const with_trace_class_name_param_name = "with-trace-class-name";
56
57 static
58 const char * const with_trace_name_param_name = "with-trace-name";
59
60 static
61 const char * const with_stream_class_name_param_name = "with-stream-class-name";
62
63 static
64 const char * const with_stream_name_param_name = "with-stream-name";
65
66 static
67 const char * const with_uuid_param_name = "with-uuid";
68
69 static
70 const char * const compact_param_name = "compact";
71
72 BT_HIDDEN
73 void details_destroy_details_trace_class_meta(
74 struct details_trace_class_meta *details_tc_meta)
75 {
76 if (!details_tc_meta) {
77 goto end;
78 }
79
80 if (details_tc_meta->objects) {
81 g_hash_table_destroy(details_tc_meta->objects);
82 details_tc_meta->objects = NULL;
83 }
84
85 g_free(details_tc_meta);
86
87 end:
88 return;
89 }
90
91 BT_HIDDEN
92 struct details_trace_class_meta *details_create_details_trace_class_meta(void)
93 {
94 struct details_trace_class_meta *details_tc_meta =
95 g_new0(struct details_trace_class_meta, 1);
96
97 if (!details_tc_meta) {
98 goto end;
99 }
100
101 details_tc_meta->objects = g_hash_table_new(
102 g_direct_hash, g_direct_equal);
103 if (!details_tc_meta->objects) {
104 details_destroy_details_trace_class_meta(details_tc_meta);
105 details_tc_meta = NULL;
106 goto end;
107 }
108
109 details_tc_meta->tc_destruction_listener_id = UINT64_C(-1);
110
111 end:
112 return details_tc_meta;
113 }
114
115 static
116 void destroy_details_comp(struct details_comp *details_comp)
117 {
118 GHashTableIter iter;
119 gpointer key, value;
120
121 if (!details_comp) {
122 goto end;
123 }
124
125 if (details_comp->meta) {
126 /*
127 * Remove trace class destruction listeners, because
128 * otherwise, when they are called, `details_comp`
129 * (their user data) won't exist anymore (we're
130 * destroying it here).
131 */
132 g_hash_table_iter_init(&iter, details_comp->meta);
133
134 while (g_hash_table_iter_next(&iter, &key, &value)) {
135 struct details_trace_class_meta *details_tc_meta =
136 value;
137
138 if (details_tc_meta->tc_destruction_listener_id !=
139 UINT64_C(-1)) {
140 bt_trace_class_remove_destruction_listener(
141 (const void *) key,
142 details_tc_meta->tc_destruction_listener_id);
143 }
144 }
145
146 g_hash_table_destroy(details_comp->meta);
147 details_comp->meta = NULL;
148 }
149
150 if (details_comp->traces) {
151 /*
152 * Remove trace destruction listeners, because
153 * otherwise, when they are called, `details_comp` won't
154 * exist anymore (we're destroying it here).
155 */
156 g_hash_table_iter_init(&iter, details_comp->traces);
157
158 while (g_hash_table_iter_next(&iter, &key, &value)) {
159 struct details_trace *details_trace = value;
160
161 bt_trace_remove_destruction_listener(
162 (const void *) key,
163 details_trace->trace_destruction_listener_id);
164 }
165
166 g_hash_table_destroy(details_comp->traces);
167 details_comp->traces = NULL;
168 }
169
170 if (details_comp->str) {
171 g_string_free(details_comp->str, TRUE);
172 details_comp->str = NULL;
173 }
174
175 BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
176 details_comp->msg_iter);
177 g_free(details_comp);
178
179 end:
180 return;
181 }
182
183 static
184 struct details_comp *create_details_comp(void)
185 {
186 struct details_comp *details_comp = g_new0(struct details_comp, 1);
187
188 if (!details_comp) {
189 goto error;
190 }
191
192 details_comp->meta = g_hash_table_new_full(g_direct_hash,
193 g_direct_equal, NULL,
194 (GDestroyNotify) details_destroy_details_trace_class_meta);
195 if (!details_comp->meta) {
196 goto error;
197 }
198
199 details_comp->traces = g_hash_table_new_full(g_direct_hash,
200 g_direct_equal, NULL, g_free);
201 if (!details_comp->traces) {
202 goto error;
203 }
204
205 details_comp->str = g_string_new(NULL);
206 if (!details_comp->str) {
207 goto error;
208 }
209
210 goto end;
211
212 error:
213 destroy_details_comp(details_comp);
214 details_comp = NULL;
215
216 end:
217 return details_comp;
218 }
219
220 BT_HIDDEN
221 void details_finalize(bt_self_component_sink *comp)
222 {
223 struct details_comp *details_comp;
224
225 BT_ASSERT(comp);
226 details_comp = bt_self_component_get_data(
227 bt_self_component_sink_as_self_component(comp));
228 BT_ASSERT(details_comp);
229 destroy_details_comp(details_comp);
230 }
231
232 static
233 int configure_bool_opt(struct details_comp *details_comp,
234 const bt_value *params, const char *param_name,
235 bool default_value, bool *opt_value)
236 {
237 int ret = 0;
238 const bt_value *value;
239
240 *opt_value = default_value;
241 value = bt_value_map_borrow_entry_value_const(params, param_name);
242 if (value) {
243 if (!bt_value_is_bool(value)) {
244 LOG_WRONG_PARAM_TYPE(param_name, value,
245 BT_VALUE_TYPE_BOOL);
246 ret = -1;
247 goto end;
248 }
249
250 *opt_value = (bool) bt_value_bool_get(value);
251 }
252
253 end:
254 return ret;
255 }
256
257 static
258 int configure_details_comp(struct details_comp *details_comp,
259 const bt_value *params)
260 {
261 int ret = 0;
262 const bt_value *value;
263 const char *str;
264
265 /* Colorize output? */
266 details_comp->cfg.with_color = bt_common_colors_supported();
267 value = bt_value_map_borrow_entry_value_const(params, color_param_name);
268 if (value) {
269 if (!bt_value_is_string(value)) {
270 LOG_WRONG_PARAM_TYPE(color_param_name, value,
271 BT_VALUE_TYPE_STRING);
272 goto error;
273 }
274
275 str = bt_value_string_get(value);
276
277 if (strcmp(str, "never") == 0) {
278 details_comp->cfg.with_color = false;
279 } else if (strcmp(str, "auto") == 0) {
280 details_comp->cfg.with_color =
281 bt_common_colors_supported();
282 } else if (strcmp(str, "always") == 0) {
283 details_comp->cfg.with_color = true;
284 } else {
285 BT_LOGE("Invalid `%s` parameter: unknown value "
286 "(expecting `never`, `auto`, or `always`): "
287 "value=\"%s\"", color_param_name, str);
288 goto error;
289 }
290 }
291
292 /* With metadata objects? */
293 ret = configure_bool_opt(details_comp, params, with_metadata_param_name,
294 true, &details_comp->cfg.with_meta);
295 if (ret) {
296 goto error;
297 }
298
299 /* Compact? */
300 ret = configure_bool_opt(details_comp, params, compact_param_name,
301 false, &details_comp->cfg.compact);
302 if (ret) {
303 goto error;
304 }
305
306 /* With time? */
307 ret = configure_bool_opt(details_comp, params, with_time_param_name,
308 true, &details_comp->cfg.with_time);
309 if (ret) {
310 goto error;
311 }
312
313 /* With trace class name? */
314 ret = configure_bool_opt(details_comp, params,
315 with_trace_class_name_param_name,
316 true, &details_comp->cfg.with_trace_class_name);
317 if (ret) {
318 goto error;
319 }
320
321 /* With trace name? */
322 ret = configure_bool_opt(details_comp, params,
323 with_trace_name_param_name,
324 true, &details_comp->cfg.with_trace_name);
325 if (ret) {
326 goto error;
327 }
328
329 /* With stream class name? */
330 ret = configure_bool_opt(details_comp, params,
331 with_stream_class_name_param_name,
332 true, &details_comp->cfg.with_stream_class_name);
333 if (ret) {
334 goto error;
335 }
336
337 /* With stream name? */
338 ret = configure_bool_opt(details_comp, params,
339 with_stream_name_param_name,
340 true, &details_comp->cfg.with_stream_name);
341 if (ret) {
342 goto error;
343 }
344
345 /* With UUID? */
346 ret = configure_bool_opt(details_comp, params,
347 with_uuid_param_name, true, &details_comp->cfg.with_uuid);
348 if (ret) {
349 goto error;
350 }
351
352 goto end;
353
354 error:
355 ret = -1;
356
357 end:
358 return ret;
359 }
360
361 static
362 void log_configuration(bt_self_component_sink *comp,
363 struct details_comp *details_comp)
364 {
365 BT_LOGI("Configuration for `sink.text.details` component `%s`:",
366 bt_component_get_name(bt_self_component_as_component(
367 bt_self_component_sink_as_self_component(comp))));
368 BT_LOGI(" Colorize output: %d", details_comp->cfg.with_color);
369 BT_LOGI(" Compact: %d", details_comp->cfg.compact);
370 BT_LOGI(" With metadata: %d", details_comp->cfg.with_meta);
371 BT_LOGI(" With time: %d", details_comp->cfg.with_time);
372 BT_LOGI(" With trace class name: %d",
373 details_comp->cfg.with_trace_class_name);
374 BT_LOGI(" With trace name: %d", details_comp->cfg.with_trace_name);
375 BT_LOGI(" With stream class name: %d",
376 details_comp->cfg.with_stream_class_name);
377 BT_LOGI(" With stream name: %d", details_comp->cfg.with_stream_name);
378 BT_LOGI(" With UUID: %d", details_comp->cfg.with_uuid);
379 }
380
381 BT_HIDDEN
382 bt_self_component_status details_init(bt_self_component_sink *comp,
383 const bt_value *params,
384 __attribute__((unused)) void *init_method_data)
385 {
386 bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
387 struct details_comp *details_comp = NULL;
388
389 status = bt_self_component_sink_add_input_port(comp, in_port_name,
390 NULL, NULL);
391 if (status != BT_SELF_COMPONENT_STATUS_OK) {
392 goto error;
393 }
394
395 details_comp = create_details_comp();
396 if (!details_comp) {
397 status = BT_SELF_COMPONENT_STATUS_NOMEM;
398 goto error;
399 }
400
401 if (configure_details_comp(details_comp, params)) {
402 BT_LOGE_STR("Failed to configure component.");
403 goto error;
404 }
405
406 log_configuration(comp, details_comp);
407 bt_self_component_set_data(
408 bt_self_component_sink_as_self_component(comp), details_comp);
409 goto end;
410
411 error:
412 if (status == BT_SELF_COMPONENT_STATUS_OK) {
413 status = BT_SELF_COMPONENT_STATUS_ERROR;
414 }
415
416 destroy_details_comp(details_comp);
417
418 end:
419 return status;
420 }
421
422 BT_HIDDEN
423 bt_self_component_status details_graph_is_configured(
424 bt_self_component_sink *comp)
425 {
426 bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
427 bt_self_component_port_input_message_iterator *iterator;
428 struct details_comp *details_comp;
429 bt_self_component_port_input *in_port;
430
431 details_comp = bt_self_component_get_data(
432 bt_self_component_sink_as_self_component(comp));
433 BT_ASSERT(details_comp);
434 in_port = bt_self_component_sink_borrow_input_port_by_name(comp,
435 in_port_name);
436 if (!bt_port_is_connected(bt_port_input_as_port_const(
437 bt_self_component_port_input_as_port_input(in_port)))) {
438 BT_LOGE("Single input port is not connected: "
439 "port-name=\"%s\"", in_port_name);
440 status = BT_SELF_COMPONENT_STATUS_ERROR;
441 goto end;
442 }
443
444 iterator = bt_self_component_port_input_message_iterator_create(
445 bt_self_component_sink_borrow_input_port_by_name(comp,
446 in_port_name));
447 if (!iterator) {
448 status = BT_SELF_COMPONENT_STATUS_NOMEM;
449 goto end;
450 }
451
452 BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
453 details_comp->msg_iter, iterator);
454
455 end:
456 return status;
457 }
458
459 BT_HIDDEN
460 bt_self_component_status details_consume(bt_self_component_sink *comp)
461 {
462 bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
463 bt_message_array_const msgs;
464 uint64_t count;
465 struct details_comp *details_comp;
466 bt_message_iterator_status it_ret;
467 uint64_t i;
468
469 details_comp = bt_self_component_get_data(
470 bt_self_component_sink_as_self_component(comp));
471 BT_ASSERT(details_comp);
472 BT_ASSERT(details_comp->msg_iter);
473
474 /* Consume messages */
475 it_ret = bt_self_component_port_input_message_iterator_next(
476 details_comp->msg_iter, &msgs, &count);
477 switch (it_ret) {
478 case BT_MESSAGE_ITERATOR_STATUS_OK:
479 ret = BT_SELF_COMPONENT_STATUS_OK;
480
481 for (i = 0; i < count; i++) {
482 int print_ret = details_write_message(details_comp,
483 msgs[i]);
484
485 if (print_ret) {
486 for (; i < count; i++) {
487 /* Put all remaining messages */
488 bt_message_put_ref(msgs[i]);
489 }
490
491 ret = BT_SELF_COMPONENT_STATUS_ERROR;
492 goto end;
493 }
494
495 /* Print output buffer to standard output and flush */
496 if (details_comp->str->len > 0) {
497 printf("%s", details_comp->str->str);
498 fflush(stdout);
499 details_comp->printed_something = true;
500 }
501
502 /* Put this message */
503 bt_message_put_ref(msgs[i]);
504 }
505
506 break;
507 case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
508 ret = BT_SELF_COMPONENT_STATUS_AGAIN;
509 goto end;
510 case BT_MESSAGE_ITERATOR_STATUS_END:
511 ret = BT_SELF_COMPONENT_STATUS_END;
512 goto end;
513 case BT_MESSAGE_ITERATOR_STATUS_ERROR:
514 ret = BT_SELF_COMPONENT_STATUS_ERROR;
515 goto end;
516 case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
517 ret = BT_SELF_COMPONENT_STATUS_NOMEM;
518 goto end;
519 default:
520 abort();
521 }
522
523 end:
524 return ret;
525 }
This page took 0.038844 seconds and 3 git commands to generate.