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(
202 struct details_comp
*details_comp
__attribute__((unused
)),
203 const bt_value
*params
, const char *param_name
,
204 bool default_value
, bool *opt_value
)
206 const bt_value
*value
;
208 *opt_value
= default_value
;
209 value
= bt_value_map_borrow_entry_value_const(params
, param_name
);
211 *opt_value
= (bool) bt_value_bool_get(value
);
215 static const char *color_choices
[] = { "never", "auto", "always", NULL
};
217 static const struct bt_param_validation_map_value_entry_descr details_params
[] = {
218 { COLOR_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { BT_VALUE_TYPE_STRING
, .string
= {
219 .choices
= color_choices
,
221 { WITH_METADATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
222 { WITH_DATA_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
223 { COMPACT_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
224 { WITH_TIME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
225 { WITH_TRACE_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
226 { WITH_STREAM_CLASS_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
227 { WITH_STREAM_NAME_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
228 { WITH_UUID_PARAM_NAME
, BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL
, { .type
= BT_VALUE_TYPE_BOOL
} },
229 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
233 bt_component_class_initialize_method_status
configure_details_comp(
234 struct details_comp
*details_comp
,
235 const bt_value
*params
)
237 bt_component_class_initialize_method_status status
;
238 const bt_value
*value
;
240 enum bt_param_validation_status validation_status
;
241 gchar
*validate_error
= NULL
;
243 validation_status
= bt_param_validation_validate(params
,
244 details_params
, &validate_error
);
245 if (validation_status
== BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR
) {
246 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
248 } else if (validation_status
== BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR
) {
249 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
250 BT_COMP_LOGE_APPEND_CAUSE(details_comp
->self_comp
,
251 "%s", validate_error
);
255 /* Colorize output? */
256 details_comp
->cfg
.with_color
= bt_common_colors_supported();
257 value
= bt_value_map_borrow_entry_value_const(params
, COLOR_PARAM_NAME
);
259 str
= bt_value_string_get(value
);
261 if (strcmp(str
, "never") == 0) {
262 details_comp
->cfg
.with_color
= false;
263 } else if (strcmp(str
, "auto") == 0) {
264 details_comp
->cfg
.with_color
=
265 bt_common_colors_supported();
267 BT_ASSERT(strcmp(str
, "always") == 0);
269 details_comp
->cfg
.with_color
= true;
273 /* With metadata objects? */
274 configure_bool_opt(details_comp
, params
, WITH_METADATA_PARAM_NAME
,
275 true, &details_comp
->cfg
.with_meta
);
277 /* With data objects? */
278 configure_bool_opt(details_comp
, params
, WITH_DATA_PARAM_NAME
,
279 true, &details_comp
->cfg
.with_data
);
282 configure_bool_opt(details_comp
, params
, COMPACT_PARAM_NAME
,
283 false, &details_comp
->cfg
.compact
);
286 configure_bool_opt(details_comp
, params
, WITH_TIME_PARAM_NAME
,
287 true, &details_comp
->cfg
.with_time
);
289 /* With trace name? */
290 configure_bool_opt(details_comp
, params
,
291 WITH_TRACE_NAME_PARAM_NAME
,
292 true, &details_comp
->cfg
.with_trace_name
);
294 /* With stream class name? */
295 configure_bool_opt(details_comp
, params
,
296 WITH_STREAM_CLASS_NAME_PARAM_NAME
,
297 true, &details_comp
->cfg
.with_stream_class_name
);
299 /* With stream name? */
300 configure_bool_opt(details_comp
, params
,
301 WITH_STREAM_NAME_PARAM_NAME
,
302 true, &details_comp
->cfg
.with_stream_name
);
305 configure_bool_opt(details_comp
, params
,
306 WITH_UUID_PARAM_NAME
, true, &details_comp
->cfg
.with_uuid
);
308 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
312 g_free(validate_error
);
318 void log_configuration(bt_self_component_sink
*comp
,
319 struct details_comp
*details_comp
)
321 BT_COMP_LOGI("Configuration for `sink.text.details` component `%s`:",
322 bt_component_get_name(bt_self_component_as_component(
323 bt_self_component_sink_as_self_component(comp
))));
324 BT_COMP_LOGI(" Colorize output: %d", details_comp
->cfg
.with_color
);
325 BT_COMP_LOGI(" Compact: %d", details_comp
->cfg
.compact
);
326 BT_COMP_LOGI(" With metadata: %d", details_comp
->cfg
.with_meta
);
327 BT_COMP_LOGI(" With time: %d", details_comp
->cfg
.with_time
);
328 BT_COMP_LOGI(" With trace name: %d", details_comp
->cfg
.with_trace_name
);
329 BT_COMP_LOGI(" With stream class name: %d",
330 details_comp
->cfg
.with_stream_class_name
);
331 BT_COMP_LOGI(" With stream name: %d", details_comp
->cfg
.with_stream_name
);
332 BT_COMP_LOGI(" With UUID: %d", details_comp
->cfg
.with_uuid
);
335 bt_component_class_initialize_method_status
details_init(
336 bt_self_component_sink
*comp
,
337 bt_self_component_sink_configuration
*config
__attribute__((unused
)),
338 const bt_value
*params
,
339 void *init_method_data
__attribute__((unused
)))
341 bt_component_class_initialize_method_status status
;
342 bt_self_component_add_port_status add_port_status
;
343 struct details_comp
*details_comp
;
344 bt_self_component
*self_comp
=
345 bt_self_component_sink_as_self_component(comp
);
346 bt_logging_level log_level
=
347 bt_component_get_logging_level(
348 bt_self_component_as_component(self_comp
));
350 details_comp
= create_details_comp(comp
);
353 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `details_comp` is not
356 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
357 "Failed to allocate component.");
358 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
359 self_comp
, "Failed to allocate component.");
360 status
= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
364 add_port_status
= bt_self_component_sink_add_input_port(comp
,
365 IN_PORT_NAME
, NULL
, NULL
);
366 if (add_port_status
!= BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
367 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to add input port.");
368 status
= (int) add_port_status
;
372 status
= configure_details_comp(details_comp
, params
);
373 if (status
!= BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
) {
374 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to configure component.");
378 log_configuration(comp
, details_comp
);
379 bt_self_component_set_data(
380 bt_self_component_sink_as_self_component(comp
), details_comp
);
384 destroy_details_comp(details_comp
);
390 bt_component_class_sink_graph_is_configured_method_status
391 details_graph_is_configured(bt_self_component_sink
*comp
)
393 bt_component_class_sink_graph_is_configured_method_status status
;
394 bt_message_iterator_create_from_sink_component_status
396 bt_message_iterator
*iterator
;
397 bt_self_component_port_input
*in_port
;
398 bt_self_component
*self_comp
=
399 bt_self_component_sink_as_self_component(comp
);
400 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
402 BT_ASSERT(details_comp
);
404 in_port
= bt_self_component_sink_borrow_input_port_by_name(comp
,
406 if (!bt_port_is_connected(bt_port_input_as_port_const(
407 bt_self_component_port_input_as_port_input(in_port
)))) {
408 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Single input port is not connected: "
409 "port-name=\"%s\"", IN_PORT_NAME
);
410 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR
;
414 msg_iter_status
= bt_message_iterator_create_from_sink_component(
415 comp
, in_port
, &iterator
);
416 if (msg_iter_status
!= BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK
) {
417 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to create message iterator: "
418 "port-name=\"%s\"", IN_PORT_NAME
);
419 status
= (int) msg_iter_status
;
423 BT_MESSAGE_ITERATOR_MOVE_REF(
424 details_comp
->msg_iter
, iterator
);
426 status
= BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK
;
432 bt_component_class_sink_consume_method_status
433 details_consume(bt_self_component_sink
*comp
)
435 bt_component_class_sink_consume_method_status status
;
436 bt_message_array_const msgs
;
438 bt_message_iterator_next_status next_status
;
440 bt_self_component
*self_comp
= bt_self_component_sink_as_self_component(comp
);
441 struct details_comp
*details_comp
= bt_self_component_get_data(self_comp
);
443 BT_ASSERT_DBG(details_comp
);
444 BT_ASSERT_DBG(details_comp
->msg_iter
);
446 /* Consume messages */
447 next_status
= bt_message_iterator_next(
448 details_comp
->msg_iter
, &msgs
, &count
);
449 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
450 status
= (int) next_status
;
454 for (i
= 0; i
< count
; i
++) {
455 int print_ret
= details_write_message(details_comp
,
459 for (; i
< count
; i
++) {
460 /* Put all remaining messages */
461 bt_message_put_ref(msgs
[i
]);
464 BT_COMP_LOGE_APPEND_CAUSE(self_comp
, "Failed to write message.");
465 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR
;
469 /* Print output buffer to standard output and flush */
470 if (details_comp
->str
->len
> 0) {
471 printf("%s", details_comp
->str
->str
);
473 details_comp
->printed_something
= true;
476 /* Put this message */
477 bt_message_put_ref(msgs
[i
]);
480 status
= BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK
;