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(const bt_value
*params
, const char *param_name
,
202 bool default_value
, bool *opt_value
)
204 const bt_value
*value
;
206 *opt_value
= default_value
;
207 value
= bt_value_map_borrow_entry_value_const(params
, param_name
);
209 *opt_value
= (bool) bt_value_bool_get(value
);
213 static const char *color_choices
[] = { "never", "auto", "always", NULL
};
215 static const struct bt_param_validation_map_value_entry_descr details_params
[] = {
216 { COLOR_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { BT_VALUE_TYPE_STRING
, .string
= {
217 .choices
= color_choices
,
219 { WITH_METADATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
220 { WITH_DATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
221 { COMPACT_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
222 { WITH_TIME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
223 { WITH_TRACE_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
224 { WITH_STREAM_CLASS_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
225 { WITH_STREAM_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
226 { WITH_UUID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
227 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
231 bt_component_class_initialize_method_status
configure_details_comp(
232 struct details_comp
*details_comp
,
233 const bt_value
*params
)
235 bt_component_class_initialize_method_status status
;
236 const bt_value
*value
;
238 enum bt_param_validation_status validation_status
;
239 gchar
*validate_error
= NULL
;
241 validation_status
= bt_param_validation_validate(params
,
242 details_params
, &validate_error
);
243 if (validation_status
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
244 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
246 } else if (validation_status
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
247 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
248 BT_COMP_LOGE_APPEND_CAUSE(details_comp
->self_comp
,
249 "%s", validate_error
);
253 /* Colorize output? */
254 details_comp
->cfg
.with_color
= bt_common_colors_supported();
255 value
= bt_value_map_borrow_entry_value_const(params
, COLOR_PARAM_NAME
);
257 str
= bt_value_string_get(value
);
259 if (strcmp(str
, "never") == 0) {
260 details_comp
->cfg
.with_color
= false;
261 } else if (strcmp(str
, "auto") == 0) {
262 details_comp
->cfg
.with_color
=
263 bt_common_colors_supported();
265 BT_ASSERT(strcmp(str
, "always") == 0);
267 details_comp
->cfg
.with_color
= true;
271 /* With metadata objects? */
272 configure_bool_opt(params
, WITH_METADATA_PARAM_NAME
, true,
273 &details_comp
->cfg
.with_meta
);
275 /* With data objects? */
276 configure_bool_opt(params
, WITH_DATA_PARAM_NAME
, true,
277 &details_comp
->cfg
.with_data
);
280 configure_bool_opt(params
, COMPACT_PARAM_NAME
, false,
281 &details_comp
->cfg
.compact
);
284 configure_bool_opt(params
, WITH_TIME_PARAM_NAME
, true,
285 &details_comp
->cfg
.with_time
);
287 /* With trace name? */
288 configure_bool_opt(params
, WITH_TRACE_NAME_PARAM_NAME
, true,
289 &details_comp
->cfg
.with_trace_name
);
291 /* With stream class name? */
292 configure_bool_opt(params
, WITH_STREAM_CLASS_NAME_PARAM_NAME
, true,
293 &details_comp
->cfg
.with_stream_class_name
);
295 /* With stream name? */
296 configure_bool_opt(params
, WITH_STREAM_NAME_PARAM_NAME
, true,
297 &details_comp
->cfg
.with_stream_name
);
300 configure_bool_opt(params
, WITH_UUID_PARAM_NAME
, true,
301 &details_comp
->cfg
.with_uuid
);
303 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
307 g_free(validate_error
);
313 void log_configuration(bt_self_component_sink
*comp
,
314 struct details_comp
*details_comp
)
316 BT_COMP_LOGI("Configuration for `sink.text.details` component `%s`:",
317 bt_component_get_name(bt_self_component_as_component(
318 bt_self_component_sink_as_self_component(comp
))));
319 BT_COMP_LOGI(" Colorize output: %d", details_comp
->cfg
.with_color
);
320 BT_COMP_LOGI(" Compact: %d", details_comp
->cfg
.compact
);
321 BT_COMP_LOGI(" With metadata: %d", details_comp
->cfg
.with_meta
);
322 BT_COMP_LOGI(" With time: %d", details_comp
->cfg
.with_time
);
323 BT_COMP_LOGI(" With trace name: %d", details_comp
->cfg
.with_trace_name
);
324 BT_COMP_LOGI(" With stream class name: %d",
325 details_comp
->cfg
.with_stream_class_name
);
326 BT_COMP_LOGI(" With stream name: %d", details_comp
->cfg
.with_stream_name
);
327 BT_COMP_LOGI(" With UUID: %d", details_comp
->cfg
.with_uuid
);
330 bt_component_class_initialize_method_status
details_init(
331 bt_self_component_sink
*comp
,
332 bt_self_component_sink_configuration
*config
__attribute__((unused
)),
333 const bt_value
*params
,
334 void *init_method_data
__attribute__((unused
)))
336 bt_component_class_initialize_method_status status
;
337 bt_self_component_add_port_status add_port_status
;
338 struct details_comp
*details_comp
;
339 bt_self_component
*self_comp
=
340 bt_self_component_sink_as_self_component(comp
);
341 bt_logging_level log_level
=
342 bt_component_get_logging_level(
343 bt_self_component_as_component(self_comp
));
345 details_comp
= create_details_comp(comp
);
348 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `details_comp` is not
351 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
352 "Failed to allocate component.");
353 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
354 self_comp
, "Failed to allocate component.");
355 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
359 add_port_status
= bt_self_component_sink_add_input_port(comp
,
360 IN_PORT_NAME
, NULL
, NULL
);
361 if (add_port_status
!= BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
362 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to add input port.");
363 status
= (int) add_port_status
;
367 status
= configure_details_comp(details_comp
, params
);
368 if (status
!= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
) {
369 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to configure component.");
373 log_configuration(comp
, details_comp
);
374 bt_self_component_set_data(
375 bt_self_component_sink_as_self_component(comp
), details_comp
);
379 destroy_details_comp(details_comp
);
385 bt_component_class_sink_graph_is_configured_method_status
386 details_graph_is_configured(bt_self_component_sink
*comp
)
388 bt_component_class_sink_graph_is_configured_method_status status
;
389 bt_message_iterator_create_from_sink_component_status
391 bt_message_iterator
*iterator
;
392 bt_self_component_port_input
*in_port
;
393 bt_self_component
*self_comp
=
394 bt_self_component_sink_as_self_component(comp
);
395 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
397 BT_ASSERT(details_comp
);
399 in_port
= bt_self_component_sink_borrow_input_port_by_name(comp
,
401 if (!bt_port_is_connected(bt_port_input_as_port_const(
402 bt_self_component_port_input_as_port_input(in_port
)))) {
403 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Single input port is not connected: "
404 "port-name=\"%s\"", IN_PORT_NAME
);
405 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR
;
409 msg_iter_status
= bt_message_iterator_create_from_sink_component(
410 comp
, in_port
, &iterator
);
411 if (msg_iter_status
!= BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK
) {
412 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to create message iterator: "
413 "port-name=\"%s\"", IN_PORT_NAME
);
414 status
= (int) msg_iter_status
;
418 BT_MESSAGE_ITERATOR_MOVE_REF(
419 details_comp
->msg_iter
, iterator
);
421 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK
;
427 bt_component_class_sink_consume_method_status
428 details_consume(bt_self_component_sink
*comp
)
430 bt_component_class_sink_consume_method_status status
;
431 bt_message_array_const msgs
;
433 bt_message_iterator_next_status next_status
;
435 bt_self_component
*self_comp
= bt_self_component_sink_as_self_component(comp
);
436 struct details_comp
*details_comp
= bt_self_component_get_data(self_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 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
445 status
= (int) next_status
;
449 for (i
= 0; i
< count
; i
++) {
450 int print_ret
= details_write_message(details_comp
,
454 for (; i
< count
; i
++) {
455 /* Put all remaining messages */
456 bt_message_put_ref(msgs
[i
]);
459 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to write message.");
460 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
464 /* Print output buffer to standard output and flush */
465 if (details_comp
->str
->len
> 0) {
466 printf("%s", details_comp
->str
->str
);
468 details_comp
->printed_something
= true;
471 /* Put this message */
472 bt_message_put_ref(msgs
[i
]);
475 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;