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_CLASS_NAMESPACE_PARAM_NAME "with-stream-class-namespace"
30 #define WITH_STREAM_NAME_PARAM_NAME "with-stream-name"
31 #define WITH_UUID_PARAM_NAME "with-uuid"
32 #define WITH_UID_PARAM_NAME "with-uid"
33 #define COMPACT_PARAM_NAME "compact"
35 bt_component_class_get_supported_mip_versions_method_status
36 details_supported_mip_versions(
37 bt_self_component_class_sink
*self_component_class
__attribute__((unused
)),
38 const bt_value
*params
__attribute__((unused
)),
39 void *initialize_method_data
__attribute__((unused
)),
40 bt_logging_level logging_level
__attribute__((unused
)),
41 bt_integer_range_set_unsigned
*supported_versions
) {
42 return (int) bt_integer_range_set_unsigned_add_range(supported_versions
, 0, 1);
45 void details_destroy_details_trace_class_meta(
46 struct details_trace_class_meta
*details_tc_meta
)
48 if (!details_tc_meta
) {
52 if (details_tc_meta
->objects
) {
53 g_hash_table_destroy(details_tc_meta
->objects
);
54 details_tc_meta
->objects
= NULL
;
57 g_free(details_tc_meta
);
63 struct details_trace_class_meta
*details_create_details_trace_class_meta(void)
65 struct details_trace_class_meta
*details_tc_meta
=
66 g_new0(struct details_trace_class_meta
, 1);
68 if (!details_tc_meta
) {
72 details_tc_meta
->objects
= g_hash_table_new(
73 g_direct_hash
, g_direct_equal
);
74 if (!details_tc_meta
->objects
) {
75 details_destroy_details_trace_class_meta(details_tc_meta
);
76 details_tc_meta
= NULL
;
80 details_tc_meta
->tc_destruction_listener_id
= UINT64_C(-1);
83 return details_tc_meta
;
87 void destroy_details_comp(struct details_comp
*details_comp
)
96 if (details_comp
->meta
) {
98 * Remove trace class destruction listeners, because
99 * otherwise, when they are called, `details_comp`
100 * (their user data) won't exist anymore (we're
101 * destroying it here).
103 g_hash_table_iter_init(&iter
, details_comp
->meta
);
105 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
106 struct details_trace_class_meta
*details_tc_meta
=
109 if (details_tc_meta
->tc_destruction_listener_id
!=
111 if (bt_trace_class_remove_destruction_listener(
113 details_tc_meta
->tc_destruction_listener_id
)) {
114 bt_current_thread_clear_error();
119 g_hash_table_destroy(details_comp
->meta
);
120 details_comp
->meta
= NULL
;
123 if (details_comp
->traces
) {
125 * Remove trace destruction listeners, because
126 * otherwise, when they are called, `details_comp` won't
127 * exist anymore (we're destroying it here).
129 g_hash_table_iter_init(&iter
, details_comp
->traces
);
131 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
132 struct details_trace
*details_trace
= value
;
134 if (bt_trace_remove_destruction_listener(
136 details_trace
->trace_destruction_listener_id
)) {
137 bt_current_thread_clear_error();
141 g_hash_table_destroy(details_comp
->traces
);
142 details_comp
->traces
= NULL
;
145 if (details_comp
->str
) {
146 g_string_free(details_comp
->str
, TRUE
);
147 details_comp
->str
= NULL
;
150 BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
151 details_comp
->msg_iter
);
152 g_free(details_comp
);
159 struct details_comp
*create_details_comp(
160 bt_self_component_sink
*self_comp_sink
)
162 struct details_comp
*details_comp
= g_new0(struct details_comp
, 1);
163 bt_self_component
*self_comp
=
164 bt_self_component_sink_as_self_component(self_comp_sink
);
170 details_comp
->log_level
= bt_component_get_logging_level(
171 bt_self_component_as_component(self_comp
));
172 details_comp
->self_comp
= self_comp
;
173 details_comp
->mip_version
= bt_self_component_get_graph_mip_version(self_comp
);
174 details_comp
->meta
= g_hash_table_new_full(g_direct_hash
,
175 g_direct_equal
, NULL
,
176 (GDestroyNotify
) details_destroy_details_trace_class_meta
);
177 if (!details_comp
->meta
) {
181 details_comp
->traces
= g_hash_table_new_full(g_direct_hash
,
182 g_direct_equal
, NULL
, g_free
);
183 if (!details_comp
->traces
) {
187 details_comp
->str
= g_string_new(NULL
);
188 if (!details_comp
->str
) {
195 destroy_details_comp(details_comp
);
202 void details_finalize(bt_self_component_sink
*comp
)
204 struct details_comp
*details_comp
;
207 details_comp
= bt_self_component_get_data(
208 bt_self_component_sink_as_self_component(comp
));
209 BT_ASSERT(details_comp
);
210 destroy_details_comp(details_comp
);
214 void configure_bool_opt(const bt_value
*params
, const char *param_name
,
215 bool default_value
, bool *opt_value
)
217 const bt_value
*value
;
219 *opt_value
= default_value
;
220 value
= bt_value_map_borrow_entry_value_const(params
, param_name
);
222 *opt_value
= (bool) bt_value_bool_get(value
);
226 static const char *color_choices
[] = { "never", "auto", "always", NULL
};
228 static const struct bt_param_validation_map_value_entry_descr details_params
[] = {
229 { COLOR_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { BT_VALUE_TYPE_STRING
, .string
= {
230 .choices
= color_choices
,
232 { WITH_METADATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
233 { WITH_DATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
234 { COMPACT_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
235 { WITH_TIME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
236 { WITH_TRACE_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
237 { WITH_STREAM_CLASS_NAMESPACE_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
238 { WITH_STREAM_CLASS_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
239 { WITH_STREAM_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
240 { WITH_UUID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
241 { WITH_UID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
242 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
246 bt_component_class_initialize_method_status
configure_details_comp(
247 struct details_comp
*details_comp
,
248 const bt_value
*params
)
250 bt_component_class_initialize_method_status status
;
251 const bt_value
*value
;
253 enum bt_param_validation_status validation_status
;
254 gchar
*validate_error
= NULL
;
256 validation_status
= bt_param_validation_validate(params
,
257 details_params
, &validate_error
);
258 if (validation_status
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
259 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
261 } else if (validation_status
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
262 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
263 BT_COMP_LOGE_APPEND_CAUSE(details_comp
->self_comp
,
264 "%s", validate_error
);
268 /* Colorize output? */
269 details_comp
->cfg
.with_color
= bt_common_colors_supported();
270 value
= bt_value_map_borrow_entry_value_const(params
, COLOR_PARAM_NAME
);
272 str
= bt_value_string_get(value
);
274 if (strcmp(str
, "never") == 0) {
275 details_comp
->cfg
.with_color
= false;
276 } else if (strcmp(str
, "auto") == 0) {
277 details_comp
->cfg
.with_color
=
278 bt_common_colors_supported();
280 BT_ASSERT(strcmp(str
, "always") == 0);
282 details_comp
->cfg
.with_color
= true;
286 /* With metadata objects? */
287 configure_bool_opt(params
, WITH_METADATA_PARAM_NAME
, true,
288 &details_comp
->cfg
.with_meta
);
290 /* With data objects? */
291 configure_bool_opt(params
, WITH_DATA_PARAM_NAME
, true,
292 &details_comp
->cfg
.with_data
);
295 configure_bool_opt(params
, COMPACT_PARAM_NAME
, false,
296 &details_comp
->cfg
.compact
);
299 configure_bool_opt(params
, WITH_TIME_PARAM_NAME
, true,
300 &details_comp
->cfg
.with_time
);
302 /* With trace name? */
303 configure_bool_opt(params
, WITH_TRACE_NAME_PARAM_NAME
, true,
304 &details_comp
->cfg
.with_trace_name
);
306 /* With stream class name? */
307 configure_bool_opt(params
, WITH_STREAM_CLASS_NAME_PARAM_NAME
, true,
308 &details_comp
->cfg
.with_stream_class_name
);
310 /* With stream class namespace? */
311 configure_bool_opt(params
, WITH_STREAM_CLASS_NAMESPACE_PARAM_NAME
, true,
312 &details_comp
->cfg
.with_stream_class_ns
);
314 /* With stream name? */
315 configure_bool_opt(params
, WITH_STREAM_NAME_PARAM_NAME
, true,
316 &details_comp
->cfg
.with_stream_name
);
319 configure_bool_opt(params
, WITH_UUID_PARAM_NAME
, true,
320 &details_comp
->cfg
.with_uuid
);
323 configure_bool_opt(params
, WITH_UID_PARAM_NAME
, true,
324 &details_comp
->cfg
.with_uid
);
326 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
330 g_free(validate_error
);
336 void log_configuration(bt_self_component_sink
*comp
,
337 struct details_comp
*details_comp
)
339 BT_COMP_LOGI("Configuration for `sink.text.details` component `%s`:",
340 bt_component_get_name(bt_self_component_as_component(
341 bt_self_component_sink_as_self_component(comp
))));
342 BT_COMP_LOGI(" Colorize output: %d", details_comp
->cfg
.with_color
);
343 BT_COMP_LOGI(" Compact: %d", details_comp
->cfg
.compact
);
344 BT_COMP_LOGI(" With metadata: %d", details_comp
->cfg
.with_meta
);
345 BT_COMP_LOGI(" With time: %d", details_comp
->cfg
.with_time
);
346 BT_COMP_LOGI(" With trace name: %d", details_comp
->cfg
.with_trace_name
);
347 BT_COMP_LOGI(" With stream class namespace: %d",
348 details_comp
->cfg
.with_stream_class_ns
);
349 BT_COMP_LOGI(" With stream class name: %d",
350 details_comp
->cfg
.with_stream_class_name
);
351 BT_COMP_LOGI(" With stream name: %d", details_comp
->cfg
.with_stream_name
);
352 BT_COMP_LOGI(" With UUID: %d", details_comp
->cfg
.with_uuid
);
353 BT_COMP_LOGI(" With UID: %d", details_comp
->cfg
.with_uid
);
356 bt_component_class_initialize_method_status
details_init(
357 bt_self_component_sink
*comp
,
358 bt_self_component_sink_configuration
*config
__attribute__((unused
)),
359 const bt_value
*params
,
360 void *init_method_data
__attribute__((unused
)))
362 bt_component_class_initialize_method_status status
;
363 bt_self_component_add_port_status add_port_status
;
364 struct details_comp
*details_comp
;
365 bt_self_component
*self_comp
=
366 bt_self_component_sink_as_self_component(comp
);
367 bt_logging_level log_level
=
368 bt_component_get_logging_level(
369 bt_self_component_as_component(self_comp
));
371 details_comp
= create_details_comp(comp
);
374 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `details_comp` is not
377 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
378 "Failed to allocate component.");
379 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
380 self_comp
, "Failed to allocate component.");
381 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
385 add_port_status
= bt_self_component_sink_add_input_port(comp
,
386 IN_PORT_NAME
, NULL
, NULL
);
387 if (add_port_status
!= BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
388 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to add input port.");
389 status
= (int) add_port_status
;
393 status
= configure_details_comp(details_comp
, params
);
394 if (status
!= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
) {
395 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to configure component.");
399 log_configuration(comp
, details_comp
);
400 bt_self_component_set_data(
401 bt_self_component_sink_as_self_component(comp
), details_comp
);
405 destroy_details_comp(details_comp
);
411 bt_component_class_sink_graph_is_configured_method_status
412 details_graph_is_configured(bt_self_component_sink
*comp
)
414 bt_component_class_sink_graph_is_configured_method_status status
;
415 bt_message_iterator_create_from_sink_component_status
417 bt_message_iterator
*iterator
;
418 bt_self_component_port_input
*in_port
;
419 bt_self_component
*self_comp
=
420 bt_self_component_sink_as_self_component(comp
);
421 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
423 BT_ASSERT(details_comp
);
425 in_port
= bt_self_component_sink_borrow_input_port_by_name(comp
,
427 if (!bt_port_is_connected(bt_port_input_as_port_const(
428 bt_self_component_port_input_as_port_input(in_port
)))) {
429 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Single input port is not connected: "
430 "port-name=\"%s\"", IN_PORT_NAME
);
431 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR
;
435 msg_iter_status
= bt_message_iterator_create_from_sink_component(
436 comp
, in_port
, &iterator
);
437 if (msg_iter_status
!= BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK
) {
438 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to create message iterator: "
439 "port-name=\"%s\"", IN_PORT_NAME
);
440 status
= (int) msg_iter_status
;
444 BT_MESSAGE_ITERATOR_MOVE_REF(
445 details_comp
->msg_iter
, iterator
);
447 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK
;
453 bt_component_class_sink_consume_method_status
454 details_consume(bt_self_component_sink
*comp
)
456 bt_component_class_sink_consume_method_status status
;
457 bt_message_array_const msgs
;
459 bt_message_iterator_next_status next_status
;
461 bt_self_component
*self_comp
= bt_self_component_sink_as_self_component(comp
);
462 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
464 BT_ASSERT_DBG(details_comp
);
465 BT_ASSERT_DBG(details_comp
->msg_iter
);
467 /* Consume messages */
468 next_status
= bt_message_iterator_next(
469 details_comp
->msg_iter
, &msgs
, &count
);
470 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
471 status
= (int) next_status
;
475 for (i
= 0; i
< count
; i
++) {
476 int print_ret
= details_write_message(details_comp
,
480 for (; i
< count
; i
++) {
481 /* Put all remaining messages */
482 bt_message_put_ref(msgs
[i
]);
485 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to write message.");
486 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
490 /* Print output buffer to standard output and flush */
491 if (details_comp
->str
->len
> 0) {
492 printf("%s", details_comp
->str
->str
);
494 details_comp
->printed_something
= true;
497 /* Put this message */
498 bt_message_put_ref(msgs
[i
]);
501 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;