.gitignore: add some missing files
[babeltrace.git] / src / plugins / text / details / details.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
5 */
6
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"
11
12 #include <stdbool.h>
13
14 #include <babeltrace2/babeltrace.h>
15
16 #include "common/common.h"
17 #include "common/assert.h"
18 #include "details.h"
19 #include "write.h"
20 #include "plugins/common/param-validation/param-validation.h"
21
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"
34
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);
43 }
44
45 void details_destroy_details_trace_class_meta(
46 struct details_trace_class_meta *details_tc_meta)
47 {
48 if (!details_tc_meta) {
49 goto end;
50 }
51
52 if (details_tc_meta->objects) {
53 g_hash_table_destroy(details_tc_meta->objects);
54 details_tc_meta->objects = NULL;
55 }
56
57 g_free(details_tc_meta);
58
59 end:
60 return;
61 }
62
63 struct details_trace_class_meta *details_create_details_trace_class_meta(void)
64 {
65 struct details_trace_class_meta *details_tc_meta =
66 g_new0(struct details_trace_class_meta, 1);
67
68 if (!details_tc_meta) {
69 goto end;
70 }
71
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;
77 goto end;
78 }
79
80 details_tc_meta->tc_destruction_listener_id = UINT64_C(-1);
81
82 end:
83 return details_tc_meta;
84 }
85
86 static
87 void destroy_details_comp(struct details_comp *details_comp)
88 {
89 GHashTableIter iter;
90 gpointer key, value;
91
92 if (!details_comp) {
93 goto end;
94 }
95
96 if (details_comp->meta) {
97 /*
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).
102 */
103 g_hash_table_iter_init(&iter, details_comp->meta);
104
105 while (g_hash_table_iter_next(&iter, &key, &value)) {
106 struct details_trace_class_meta *details_tc_meta =
107 value;
108
109 if (details_tc_meta->tc_destruction_listener_id !=
110 UINT64_C(-1)) {
111 if (bt_trace_class_remove_destruction_listener(
112 (const void *) key,
113 details_tc_meta->tc_destruction_listener_id)) {
114 bt_current_thread_clear_error();
115 }
116 }
117 }
118
119 g_hash_table_destroy(details_comp->meta);
120 details_comp->meta = NULL;
121 }
122
123 if (details_comp->traces) {
124 /*
125 * Remove trace destruction listeners, because
126 * otherwise, when they are called, `details_comp` won't
127 * exist anymore (we're destroying it here).
128 */
129 g_hash_table_iter_init(&iter, details_comp->traces);
130
131 while (g_hash_table_iter_next(&iter, &key, &value)) {
132 struct details_trace *details_trace = value;
133
134 if (bt_trace_remove_destruction_listener(
135 (const void *) key,
136 details_trace->trace_destruction_listener_id)) {
137 bt_current_thread_clear_error();
138 }
139 }
140
141 g_hash_table_destroy(details_comp->traces);
142 details_comp->traces = NULL;
143 }
144
145 if (details_comp->str) {
146 g_string_free(details_comp->str, TRUE);
147 details_comp->str = NULL;
148 }
149
150 BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
151 details_comp->msg_iter);
152 g_free(details_comp);
153
154 end:
155 return;
156 }
157
158 static
159 struct details_comp *create_details_comp(
160 bt_self_component_sink *self_comp_sink)
161 {
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);
165
166 if (!details_comp) {
167 goto error;
168 }
169
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) {
178 goto error;
179 }
180
181 details_comp->traces = g_hash_table_new_full(g_direct_hash,
182 g_direct_equal, NULL, g_free);
183 if (!details_comp->traces) {
184 goto error;
185 }
186
187 details_comp->str = g_string_new(NULL);
188 if (!details_comp->str) {
189 goto error;
190 }
191
192 goto end;
193
194 error:
195 destroy_details_comp(details_comp);
196 details_comp = NULL;
197
198 end:
199 return details_comp;
200 }
201
202 void details_finalize(bt_self_component_sink *comp)
203 {
204 struct details_comp *details_comp;
205
206 BT_ASSERT(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);
211 }
212
213 static
214 void configure_bool_opt(const bt_value *params, const char *param_name,
215 bool default_value, bool *opt_value)
216 {
217 const bt_value *value;
218
219 *opt_value = default_value;
220 value = bt_value_map_borrow_entry_value_const(params, param_name);
221 if (value) {
222 *opt_value = (bool) bt_value_bool_get(value);
223 }
224 }
225
226 static const char *color_choices[] = { "never", "auto", "always", NULL };
227
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,
231 } } },
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
243 };
244
245 static
246 bt_component_class_initialize_method_status configure_details_comp(
247 struct details_comp *details_comp,
248 const bt_value *params)
249 {
250 bt_component_class_initialize_method_status status;
251 const bt_value *value;
252 const char *str;
253 enum bt_param_validation_status validation_status;
254 gchar *validate_error = NULL;
255
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;
260 goto end;
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);
265 goto end;
266 }
267
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);
271 if (value) {
272 str = bt_value_string_get(value);
273
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();
279 } else {
280 BT_ASSERT(strcmp(str, "always") == 0);
281
282 details_comp->cfg.with_color = true;
283 }
284 }
285
286 /* With metadata objects? */
287 configure_bool_opt(params, WITH_METADATA_PARAM_NAME, true,
288 &details_comp->cfg.with_meta);
289
290 /* With data objects? */
291 configure_bool_opt(params, WITH_DATA_PARAM_NAME, true,
292 &details_comp->cfg.with_data);
293
294 /* Compact? */
295 configure_bool_opt(params, COMPACT_PARAM_NAME, false,
296 &details_comp->cfg.compact);
297
298 /* With time? */
299 configure_bool_opt(params, WITH_TIME_PARAM_NAME, true,
300 &details_comp->cfg.with_time);
301
302 /* With trace name? */
303 configure_bool_opt(params, WITH_TRACE_NAME_PARAM_NAME, true,
304 &details_comp->cfg.with_trace_name);
305
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);
309
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);
313
314 /* With stream name? */
315 configure_bool_opt(params, WITH_STREAM_NAME_PARAM_NAME, true,
316 &details_comp->cfg.with_stream_name);
317
318 /* With UUID? */
319 configure_bool_opt(params, WITH_UUID_PARAM_NAME, true,
320 &details_comp->cfg.with_uuid);
321
322 /* With UID? */
323 configure_bool_opt(params, WITH_UID_PARAM_NAME, true,
324 &details_comp->cfg.with_uid);
325
326 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
327 goto end;
328
329 end:
330 g_free(validate_error);
331
332 return status;
333 }
334
335 static
336 void log_configuration(bt_self_component_sink *comp,
337 struct details_comp *details_comp)
338 {
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);
354 }
355
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)))
361 {
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));
370
371 details_comp = create_details_comp(comp);
372 if (!details_comp) {
373 /*
374 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `details_comp` is not
375 * initialized yet.
376 */
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;
382 goto error;
383 }
384
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;
390 goto error;
391 }
392
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.");
396 goto error;
397 }
398
399 log_configuration(comp, details_comp);
400 bt_self_component_set_data(
401 bt_self_component_sink_as_self_component(comp), details_comp);
402 goto end;
403
404 error:
405 destroy_details_comp(details_comp);
406
407 end:
408 return status;
409 }
410
411 bt_component_class_sink_graph_is_configured_method_status
412 details_graph_is_configured(bt_self_component_sink *comp)
413 {
414 bt_component_class_sink_graph_is_configured_method_status status;
415 bt_message_iterator_create_from_sink_component_status
416 msg_iter_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);
422
423 BT_ASSERT(details_comp);
424
425 in_port = bt_self_component_sink_borrow_input_port_by_name(comp,
426 IN_PORT_NAME);
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;
432 goto end;
433 }
434
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;
441 goto end;
442 }
443
444 BT_MESSAGE_ITERATOR_MOVE_REF(
445 details_comp->msg_iter, iterator);
446
447 status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
448
449 end:
450 return status;
451 }
452
453 bt_component_class_sink_consume_method_status
454 details_consume(bt_self_component_sink *comp)
455 {
456 bt_component_class_sink_consume_method_status status;
457 bt_message_array_const msgs;
458 uint64_t count;
459 bt_message_iterator_next_status next_status;
460 uint64_t i;
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);
463
464 BT_ASSERT_DBG(details_comp);
465 BT_ASSERT_DBG(details_comp->msg_iter);
466
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;
472 goto end;
473 }
474
475 for (i = 0; i < count; i++) {
476 int print_ret = details_write_message(details_comp,
477 msgs[i]);
478
479 if (print_ret) {
480 for (; i < count; i++) {
481 /* Put all remaining messages */
482 bt_message_put_ref(msgs[i]);
483 }
484
485 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to write message.");
486 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
487 goto end;
488 }
489
490 /* Print output buffer to standard output and flush */
491 if (details_comp->str->len > 0) {
492 printf("%s", details_comp->str->str);
493 fflush(stdout);
494 details_comp->printed_something = true;
495 }
496
497 /* Put this message */
498 bt_message_put_ref(msgs[i]);
499 }
500
501 status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
502
503 end:
504 return status;
505 }
This page took 0.04783 seconds and 5 git commands to generate.