2 * SPDX-License-Identifier: MIT
4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
7 #define BT_COMP_LOG_SELF_COMP (details_comp->self_comp)
8 #define BT_LOG_OUTPUT_LEVEL (details_comp->log_level)
9 #define BT_LOG_TAG "PLUGIN/SINK.TEXT.DETAILS"
10 #include "logging/comp-logging.h"
14 #include <babeltrace2/babeltrace.h>
16 #include "common/common.h"
17 #include "common/assert.h"
20 #include "plugins/common/param-validation/param-validation.h"
22 #define IN_PORT_NAME "in"
23 #define COLOR_PARAM_NAME "color"
24 #define WITH_METADATA_PARAM_NAME "with-metadata"
25 #define WITH_DATA_PARAM_NAME "with-data"
26 #define WITH_TIME_PARAM_NAME "with-time"
27 #define WITH_TRACE_NAME_PARAM_NAME "with-trace-name"
28 #define WITH_STREAM_CLASS_NAME_PARAM_NAME "with-stream-class-name"
29 #define WITH_STREAM_NAME_PARAM_NAME "with-stream-name"
30 #define WITH_UUID_PARAM_NAME "with-uuid"
31 #define COMPACT_PARAM_NAME "compact"
34 void details_destroy_details_trace_class_meta(
35 struct details_trace_class_meta
*details_tc_meta
)
37 if (!details_tc_meta
) {
41 if (details_tc_meta
->objects
) {
42 g_hash_table_destroy(details_tc_meta
->objects
);
43 details_tc_meta
->objects
= NULL
;
46 g_free(details_tc_meta
);
53 struct details_trace_class_meta
*details_create_details_trace_class_meta(void)
55 struct details_trace_class_meta
*details_tc_meta
=
56 g_new0(struct details_trace_class_meta
, 1);
58 if (!details_tc_meta
) {
62 details_tc_meta
->objects
= g_hash_table_new(
63 g_direct_hash
, g_direct_equal
);
64 if (!details_tc_meta
->objects
) {
65 details_destroy_details_trace_class_meta(details_tc_meta
);
66 details_tc_meta
= NULL
;
70 details_tc_meta
->tc_destruction_listener_id
= UINT64_C(-1);
73 return details_tc_meta
;
77 void destroy_details_comp(struct details_comp
*details_comp
)
86 if (details_comp
->meta
) {
88 * Remove trace class destruction listeners, because
89 * otherwise, when they are called, `details_comp`
90 * (their user data) won't exist anymore (we're
91 * destroying it here).
93 g_hash_table_iter_init(&iter
, details_comp
->meta
);
95 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
96 struct details_trace_class_meta
*details_tc_meta
=
99 if (details_tc_meta
->tc_destruction_listener_id
!=
101 if (bt_trace_class_remove_destruction_listener(
103 details_tc_meta
->tc_destruction_listener_id
)) {
104 bt_current_thread_clear_error();
109 g_hash_table_destroy(details_comp
->meta
);
110 details_comp
->meta
= NULL
;
113 if (details_comp
->traces
) {
115 * Remove trace destruction listeners, because
116 * otherwise, when they are called, `details_comp` won't
117 * exist anymore (we're destroying it here).
119 g_hash_table_iter_init(&iter
, details_comp
->traces
);
121 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
122 struct details_trace
*details_trace
= value
;
124 if (bt_trace_remove_destruction_listener(
126 details_trace
->trace_destruction_listener_id
)) {
127 bt_current_thread_clear_error();
131 g_hash_table_destroy(details_comp
->traces
);
132 details_comp
->traces
= NULL
;
135 if (details_comp
->str
) {
136 g_string_free(details_comp
->str
, TRUE
);
137 details_comp
->str
= NULL
;
140 BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
141 details_comp
->msg_iter
);
142 g_free(details_comp
);
149 struct details_comp
*create_details_comp(
150 bt_self_component_sink
*self_comp_sink
)
152 struct details_comp
*details_comp
= g_new0(struct details_comp
, 1);
153 bt_self_component
*self_comp
=
154 bt_self_component_sink_as_self_component(self_comp_sink
);
160 details_comp
->log_level
= bt_component_get_logging_level(
161 bt_self_component_as_component(self_comp
));
162 details_comp
->self_comp
= self_comp
;
163 details_comp
->meta
= g_hash_table_new_full(g_direct_hash
,
164 g_direct_equal
, NULL
,
165 (GDestroyNotify
) details_destroy_details_trace_class_meta
);
166 if (!details_comp
->meta
) {
170 details_comp
->traces
= g_hash_table_new_full(g_direct_hash
,
171 g_direct_equal
, NULL
, g_free
);
172 if (!details_comp
->traces
) {
176 details_comp
->str
= g_string_new(NULL
);
177 if (!details_comp
->str
) {
184 destroy_details_comp(details_comp
);
192 void details_finalize(bt_self_component_sink
*comp
)
194 struct details_comp
*details_comp
;
197 details_comp
= bt_self_component_get_data(
198 bt_self_component_sink_as_self_component(comp
));
199 BT_ASSERT(details_comp
);
200 destroy_details_comp(details_comp
);
204 void configure_bool_opt(struct details_comp
*details_comp
,
205 const bt_value
*params
, const char *param_name
,
206 bool default_value
, bool *opt_value
)
208 const bt_value
*value
;
210 *opt_value
= default_value
;
211 value
= bt_value_map_borrow_entry_value_const(params
, param_name
);
213 *opt_value
= (bool) bt_value_bool_get(value
);
217 static const char *color_choices
[] = { "never", "auto", "always", NULL
};
219 static const struct bt_param_validation_map_value_entry_descr details_params
[] = {
220 { COLOR_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { BT_VALUE_TYPE_STRING
, .string
= {
221 .choices
= color_choices
,
223 { WITH_METADATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
224 { WITH_DATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
225 { COMPACT_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
226 { WITH_TIME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
227 { WITH_TRACE_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
228 { WITH_STREAM_CLASS_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
229 { WITH_STREAM_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
230 { WITH_UUID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
231 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
235 bt_component_class_initialize_method_status
configure_details_comp(
236 struct details_comp
*details_comp
,
237 const bt_value
*params
)
239 bt_component_class_initialize_method_status status
;
240 const bt_value
*value
;
242 enum bt_param_validation_status validation_status
;
243 gchar
*validate_error
= NULL
;
245 validation_status
= bt_param_validation_validate(params
,
246 details_params
, &validate_error
);
247 if (validation_status
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
248 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
250 } else if (validation_status
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
251 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
252 BT_COMP_LOGE_APPEND_CAUSE(details_comp
->self_comp
,
253 "%s", validate_error
);
257 /* Colorize output? */
258 details_comp
->cfg
.with_color
= bt_common_colors_supported();
259 value
= bt_value_map_borrow_entry_value_const(params
, COLOR_PARAM_NAME
);
261 str
= bt_value_string_get(value
);
263 if (strcmp(str
, "never") == 0) {
264 details_comp
->cfg
.with_color
= false;
265 } else if (strcmp(str
, "auto") == 0) {
266 details_comp
->cfg
.with_color
=
267 bt_common_colors_supported();
269 BT_ASSERT(strcmp(str
, "always") == 0);
271 details_comp
->cfg
.with_color
= true;
275 /* With metadata objects? */
276 configure_bool_opt(details_comp
, params
, WITH_METADATA_PARAM_NAME
,
277 true, &details_comp
->cfg
.with_meta
);
279 /* With data objects? */
280 configure_bool_opt(details_comp
, params
, WITH_DATA_PARAM_NAME
,
281 true, &details_comp
->cfg
.with_data
);
284 configure_bool_opt(details_comp
, params
, COMPACT_PARAM_NAME
,
285 false, &details_comp
->cfg
.compact
);
288 configure_bool_opt(details_comp
, params
, WITH_TIME_PARAM_NAME
,
289 true, &details_comp
->cfg
.with_time
);
291 /* With trace name? */
292 configure_bool_opt(details_comp
, params
,
293 WITH_TRACE_NAME_PARAM_NAME
,
294 true, &details_comp
->cfg
.with_trace_name
);
296 /* With stream class name? */
297 configure_bool_opt(details_comp
, params
,
298 WITH_STREAM_CLASS_NAME_PARAM_NAME
,
299 true, &details_comp
->cfg
.with_stream_class_name
);
301 /* With stream name? */
302 configure_bool_opt(details_comp
, params
,
303 WITH_STREAM_NAME_PARAM_NAME
,
304 true, &details_comp
->cfg
.with_stream_name
);
307 configure_bool_opt(details_comp
, params
,
308 WITH_UUID_PARAM_NAME
, true, &details_comp
->cfg
.with_uuid
);
310 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
314 g_free(validate_error
);
320 void log_configuration(bt_self_component_sink
*comp
,
321 struct details_comp
*details_comp
)
323 BT_COMP_LOGI("Configuration for `sink.text.details` component `%s`:",
324 bt_component_get_name(bt_self_component_as_component(
325 bt_self_component_sink_as_self_component(comp
))));
326 BT_COMP_LOGI(" Colorize output: %d", details_comp
->cfg
.with_color
);
327 BT_COMP_LOGI(" Compact: %d", details_comp
->cfg
.compact
);
328 BT_COMP_LOGI(" With metadata: %d", details_comp
->cfg
.with_meta
);
329 BT_COMP_LOGI(" With time: %d", details_comp
->cfg
.with_time
);
330 BT_COMP_LOGI(" With trace name: %d", details_comp
->cfg
.with_trace_name
);
331 BT_COMP_LOGI(" With stream class name: %d",
332 details_comp
->cfg
.with_stream_class_name
);
333 BT_COMP_LOGI(" With stream name: %d", details_comp
->cfg
.with_stream_name
);
334 BT_COMP_LOGI(" With UUID: %d", details_comp
->cfg
.with_uuid
);
338 bt_component_class_initialize_method_status
details_init(
339 bt_self_component_sink
*comp
,
340 bt_self_component_sink_configuration
*config
,
341 const bt_value
*params
,
342 __attribute__((unused
)) void *init_method_data
)
344 bt_component_class_initialize_method_status status
=
345 BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
346 bt_self_component_add_port_status add_port_status
;
347 struct details_comp
*details_comp
= NULL
;
349 add_port_status
= bt_self_component_sink_add_input_port(comp
,
350 IN_PORT_NAME
, NULL
, NULL
);
351 if (add_port_status
!= BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
352 status
= (int) add_port_status
;
356 details_comp
= create_details_comp(comp
);
358 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
362 if (configure_details_comp(details_comp
, params
)) {
363 BT_COMP_LOGE_STR("Failed to configure component.");
367 log_configuration(comp
, details_comp
);
368 bt_self_component_set_data(
369 bt_self_component_sink_as_self_component(comp
), details_comp
);
373 if (status
== BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
) {
374 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
377 destroy_details_comp(details_comp
);
384 bt_component_class_sink_graph_is_configured_method_status
385 details_graph_is_configured(bt_self_component_sink
*comp
)
387 bt_component_class_sink_graph_is_configured_method_status status
;
388 bt_message_iterator_create_from_sink_component_status
390 bt_message_iterator
*iterator
;
391 struct details_comp
*details_comp
;
392 bt_self_component_port_input
*in_port
;
394 details_comp
= bt_self_component_get_data(
395 bt_self_component_sink_as_self_component(comp
));
396 BT_ASSERT(details_comp
);
397 in_port
= bt_self_component_sink_borrow_input_port_by_name(comp
,
399 if (!bt_port_is_connected(bt_port_input_as_port_const(
400 bt_self_component_port_input_as_port_input(in_port
)))) {
401 BT_COMP_LOGE("Single input port is not connected: "
402 "port-name=\"%s\"", IN_PORT_NAME
);
403 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR
;
407 msg_iter_status
= bt_message_iterator_create_from_sink_component(
408 comp
, bt_self_component_sink_borrow_input_port_by_name(comp
,
409 IN_PORT_NAME
), &iterator
);
410 if (msg_iter_status
!= BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK
) {
411 status
= (int) msg_iter_status
;
415 BT_MESSAGE_ITERATOR_MOVE_REF(
416 details_comp
->msg_iter
, iterator
);
418 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK
;
425 bt_component_class_sink_consume_method_status
426 details_consume(bt_self_component_sink
*comp
)
428 bt_component_class_sink_consume_method_status ret
=
429 BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;
430 bt_message_array_const msgs
;
432 struct details_comp
*details_comp
;
433 bt_message_iterator_next_status next_status
;
436 details_comp
= bt_self_component_get_data(
437 bt_self_component_sink_as_self_component(comp
));
438 BT_ASSERT_DBG(details_comp
);
439 BT_ASSERT_DBG(details_comp
->msg_iter
);
441 /* Consume messages */
442 next_status
= bt_message_iterator_next(
443 details_comp
->msg_iter
, &msgs
, &count
);
444 switch (next_status
) {
445 case BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
:
446 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;
448 for (i
= 0; i
< count
; i
++) {
449 int print_ret
= details_write_message(details_comp
,
453 for (; i
< count
; i
++) {
454 /* Put all remaining messages */
455 bt_message_put_ref(msgs
[i
]);
458 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
462 /* Print output buffer to standard output and flush */
463 if (details_comp
->str
->len
> 0) {
464 printf("%s", details_comp
->str
->str
);
466 details_comp
->printed_something
= true;
469 /* Put this message */
470 bt_message_put_ref(msgs
[i
]);
474 case BT_MESSAGE_ITERATOR_NEXT_STATUS_AGAIN
:
475 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_AGAIN
;
477 case BT_MESSAGE_ITERATOR_NEXT_STATUS_END
:
478 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_END
;
480 case BT_MESSAGE_ITERATOR_NEXT_STATUS_ERROR
:
481 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
483 case BT_MESSAGE_ITERATOR_NEXT_STATUS_MEMORY_ERROR
:
484 ret
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_MEMORY_ERROR
;