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"
33 void details_destroy_details_trace_class_meta(
34 struct details_trace_class_meta
*details_tc_meta
)
36 if (!details_tc_meta
) {
40 if (details_tc_meta
->objects
) {
41 g_hash_table_destroy(details_tc_meta
->objects
);
42 details_tc_meta
->objects
= NULL
;
45 g_free(details_tc_meta
);
51 struct details_trace_class_meta
*details_create_details_trace_class_meta(void)
53 struct details_trace_class_meta
*details_tc_meta
=
54 g_new0(struct details_trace_class_meta
, 1);
56 if (!details_tc_meta
) {
60 details_tc_meta
->objects
= g_hash_table_new(
61 g_direct_hash
, g_direct_equal
);
62 if (!details_tc_meta
->objects
) {
63 details_destroy_details_trace_class_meta(details_tc_meta
);
64 details_tc_meta
= NULL
;
68 details_tc_meta
->tc_destruction_listener_id
= UINT64_C(-1);
71 return details_tc_meta
;
75 void destroy_details_comp(struct details_comp
*details_comp
)
84 if (details_comp
->meta
) {
86 * Remove trace class destruction listeners, because
87 * otherwise, when they are called, `details_comp`
88 * (their user data) won't exist anymore (we're
89 * destroying it here).
91 g_hash_table_iter_init(&iter
, details_comp
->meta
);
93 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
94 struct details_trace_class_meta
*details_tc_meta
=
97 if (details_tc_meta
->tc_destruction_listener_id
!=
99 if (bt_trace_class_remove_destruction_listener(
101 details_tc_meta
->tc_destruction_listener_id
)) {
102 bt_current_thread_clear_error();
107 g_hash_table_destroy(details_comp
->meta
);
108 details_comp
->meta
= NULL
;
111 if (details_comp
->traces
) {
113 * Remove trace destruction listeners, because
114 * otherwise, when they are called, `details_comp` won't
115 * exist anymore (we're destroying it here).
117 g_hash_table_iter_init(&iter
, details_comp
->traces
);
119 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
120 struct details_trace
*details_trace
= value
;
122 if (bt_trace_remove_destruction_listener(
124 details_trace
->trace_destruction_listener_id
)) {
125 bt_current_thread_clear_error();
129 g_hash_table_destroy(details_comp
->traces
);
130 details_comp
->traces
= NULL
;
133 if (details_comp
->str
) {
134 g_string_free(details_comp
->str
, TRUE
);
135 details_comp
->str
= NULL
;
138 BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
139 details_comp
->msg_iter
);
140 g_free(details_comp
);
147 struct details_comp
*create_details_comp(
148 bt_self_component_sink
*self_comp_sink
)
150 struct details_comp
*details_comp
= g_new0(struct details_comp
, 1);
151 bt_self_component
*self_comp
=
152 bt_self_component_sink_as_self_component(self_comp_sink
);
158 details_comp
->log_level
= bt_component_get_logging_level(
159 bt_self_component_as_component(self_comp
));
160 details_comp
->self_comp
= self_comp
;
161 details_comp
->meta
= g_hash_table_new_full(g_direct_hash
,
162 g_direct_equal
, NULL
,
163 (GDestroyNotify
) details_destroy_details_trace_class_meta
);
164 if (!details_comp
->meta
) {
168 details_comp
->traces
= g_hash_table_new_full(g_direct_hash
,
169 g_direct_equal
, NULL
, g_free
);
170 if (!details_comp
->traces
) {
174 details_comp
->str
= g_string_new(NULL
);
175 if (!details_comp
->str
) {
182 destroy_details_comp(details_comp
);
189 void details_finalize(bt_self_component_sink
*comp
)
191 struct details_comp
*details_comp
;
194 details_comp
= bt_self_component_get_data(
195 bt_self_component_sink_as_self_component(comp
));
196 BT_ASSERT(details_comp
);
197 destroy_details_comp(details_comp
);
201 void configure_bool_opt(struct details_comp
*details_comp
,
202 const bt_value
*params
, const char *param_name
,
203 bool default_value
, bool *opt_value
)
205 const bt_value
*value
;
207 *opt_value
= default_value
;
208 value
= bt_value_map_borrow_entry_value_const(params
, param_name
);
210 *opt_value
= (bool) bt_value_bool_get(value
);
214 static const char *color_choices
[] = { "never", "auto", "always", NULL
};
216 static const struct bt_param_validation_map_value_entry_descr details_params
[] = {
217 { COLOR_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { BT_VALUE_TYPE_STRING
, .string
= {
218 .choices
= color_choices
,
220 { WITH_METADATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
221 { WITH_DATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
222 { COMPACT_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
223 { WITH_TIME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
224 { WITH_TRACE_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
225 { WITH_STREAM_CLASS_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
226 { WITH_STREAM_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
227 { WITH_UUID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
228 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
232 bt_component_class_initialize_method_status
configure_details_comp(
233 struct details_comp
*details_comp
,
234 const bt_value
*params
)
236 bt_component_class_initialize_method_status status
;
237 const bt_value
*value
;
239 enum bt_param_validation_status validation_status
;
240 gchar
*validate_error
= NULL
;
242 validation_status
= bt_param_validation_validate(params
,
243 details_params
, &validate_error
);
244 if (validation_status
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
245 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
247 } else if (validation_status
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
248 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
249 BT_COMP_LOGE_APPEND_CAUSE(details_comp
->self_comp
,
250 "%s", validate_error
);
254 /* Colorize output? */
255 details_comp
->cfg
.with_color
= bt_common_colors_supported();
256 value
= bt_value_map_borrow_entry_value_const(params
, COLOR_PARAM_NAME
);
258 str
= bt_value_string_get(value
);
260 if (strcmp(str
, "never") == 0) {
261 details_comp
->cfg
.with_color
= false;
262 } else if (strcmp(str
, "auto") == 0) {
263 details_comp
->cfg
.with_color
=
264 bt_common_colors_supported();
266 BT_ASSERT(strcmp(str
, "always") == 0);
268 details_comp
->cfg
.with_color
= true;
272 /* With metadata objects? */
273 configure_bool_opt(details_comp
, params
, WITH_METADATA_PARAM_NAME
,
274 true, &details_comp
->cfg
.with_meta
);
276 /* With data objects? */
277 configure_bool_opt(details_comp
, params
, WITH_DATA_PARAM_NAME
,
278 true, &details_comp
->cfg
.with_data
);
281 configure_bool_opt(details_comp
, params
, COMPACT_PARAM_NAME
,
282 false, &details_comp
->cfg
.compact
);
285 configure_bool_opt(details_comp
, params
, WITH_TIME_PARAM_NAME
,
286 true, &details_comp
->cfg
.with_time
);
288 /* With trace name? */
289 configure_bool_opt(details_comp
, params
,
290 WITH_TRACE_NAME_PARAM_NAME
,
291 true, &details_comp
->cfg
.with_trace_name
);
293 /* With stream class name? */
294 configure_bool_opt(details_comp
, params
,
295 WITH_STREAM_CLASS_NAME_PARAM_NAME
,
296 true, &details_comp
->cfg
.with_stream_class_name
);
298 /* With stream name? */
299 configure_bool_opt(details_comp
, params
,
300 WITH_STREAM_NAME_PARAM_NAME
,
301 true, &details_comp
->cfg
.with_stream_name
);
304 configure_bool_opt(details_comp
, params
,
305 WITH_UUID_PARAM_NAME
, true, &details_comp
->cfg
.with_uuid
);
307 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
311 g_free(validate_error
);
317 void log_configuration(bt_self_component_sink
*comp
,
318 struct details_comp
*details_comp
)
320 BT_COMP_LOGI("Configuration for `sink.text.details` component `%s`:",
321 bt_component_get_name(bt_self_component_as_component(
322 bt_self_component_sink_as_self_component(comp
))));
323 BT_COMP_LOGI(" Colorize output: %d", details_comp
->cfg
.with_color
);
324 BT_COMP_LOGI(" Compact: %d", details_comp
->cfg
.compact
);
325 BT_COMP_LOGI(" With metadata: %d", details_comp
->cfg
.with_meta
);
326 BT_COMP_LOGI(" With time: %d", details_comp
->cfg
.with_time
);
327 BT_COMP_LOGI(" With trace name: %d", details_comp
->cfg
.with_trace_name
);
328 BT_COMP_LOGI(" With stream class name: %d",
329 details_comp
->cfg
.with_stream_class_name
);
330 BT_COMP_LOGI(" With stream name: %d", details_comp
->cfg
.with_stream_name
);
331 BT_COMP_LOGI(" With UUID: %d", details_comp
->cfg
.with_uuid
);
334 bt_component_class_initialize_method_status
details_init(
335 bt_self_component_sink
*comp
,
336 bt_self_component_sink_configuration
*config
,
337 const bt_value
*params
,
338 __attribute__((unused
)) void *init_method_data
)
340 bt_component_class_initialize_method_status status
;
341 bt_self_component_add_port_status add_port_status
;
342 struct details_comp
*details_comp
;
343 bt_self_component
*self_comp
=
344 bt_self_component_sink_as_self_component(comp
);
345 bt_logging_level log_level
=
346 bt_component_get_logging_level(
347 bt_self_component_as_component(self_comp
));
349 details_comp
= create_details_comp(comp
);
352 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `details_comp` is not
355 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
356 "Failed to allocate component.");
357 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
358 self_comp
, "Failed to allocate component.");
359 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
363 add_port_status
= bt_self_component_sink_add_input_port(comp
,
364 IN_PORT_NAME
, NULL
, NULL
);
365 if (add_port_status
!= BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
366 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to add input port.");
367 status
= (int) add_port_status
;
371 status
= configure_details_comp(details_comp
, params
);
372 if (status
!= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
) {
373 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to configure component.");
377 log_configuration(comp
, details_comp
);
378 bt_self_component_set_data(
379 bt_self_component_sink_as_self_component(comp
), details_comp
);
383 destroy_details_comp(details_comp
);
389 bt_component_class_sink_graph_is_configured_method_status
390 details_graph_is_configured(bt_self_component_sink
*comp
)
392 bt_component_class_sink_graph_is_configured_method_status status
;
393 bt_message_iterator_create_from_sink_component_status
395 bt_message_iterator
*iterator
;
396 bt_self_component_port_input
*in_port
;
397 bt_self_component
*self_comp
=
398 bt_self_component_sink_as_self_component(comp
);
399 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
401 BT_ASSERT(details_comp
);
403 in_port
= bt_self_component_sink_borrow_input_port_by_name(comp
,
405 if (!bt_port_is_connected(bt_port_input_as_port_const(
406 bt_self_component_port_input_as_port_input(in_port
)))) {
407 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Single input port is not connected: "
408 "port-name=\"%s\"", IN_PORT_NAME
);
409 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR
;
413 msg_iter_status
= bt_message_iterator_create_from_sink_component(
414 comp
, in_port
, &iterator
);
415 if (msg_iter_status
!= BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK
) {
416 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to create message iterator: "
417 "port-name=\"%s\"", IN_PORT_NAME
);
418 status
= (int) msg_iter_status
;
422 BT_MESSAGE_ITERATOR_MOVE_REF(
423 details_comp
->msg_iter
, iterator
);
425 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK
;
431 bt_component_class_sink_consume_method_status
432 details_consume(bt_self_component_sink
*comp
)
434 bt_component_class_sink_consume_method_status status
;
435 bt_message_array_const msgs
;
437 bt_message_iterator_next_status next_status
;
439 bt_self_component
*self_comp
= bt_self_component_sink_as_self_component(comp
);
440 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
442 BT_ASSERT_DBG(details_comp
);
443 BT_ASSERT_DBG(details_comp
->msg_iter
);
445 /* Consume messages */
446 next_status
= bt_message_iterator_next(
447 details_comp
->msg_iter
, &msgs
, &count
);
448 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
449 status
= (int) next_status
;
453 for (i
= 0; i
< count
; i
++) {
454 int print_ret
= details_write_message(details_comp
,
458 for (; i
< count
; i
++) {
459 /* Put all remaining messages */
460 bt_message_put_ref(msgs
[i
]);
463 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to write message.");
464 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
468 /* Print output buffer to standard output and flush */
469 if (details_comp
->str
->len
> 0) {
470 printf("%s", details_comp
->str
->str
);
472 details_comp
->printed_something
= true;
475 /* Put this message */
476 bt_message_put_ref(msgs
[i
]);
479 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;