From 523c4f8cdeb927b789710e3dafcb3f249751ccfd Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Wed, 26 May 2021 13:04:41 -0400 Subject: [PATCH] MI: {add, list, remove} trigger MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: Ie16c5c3a894b921e032a99ed3deda4ed5da17e78 --- src/bin/lttng/commands/add_trigger.c | 66 ++++++ src/bin/lttng/commands/list_triggers.c | 262 ++++++++++++++++++++---- src/bin/lttng/commands/remove_trigger.c | 64 ++++++ src/common/mi-lttng.c | 1 + src/common/mi-lttng.h | 1 + 5 files changed, 353 insertions(+), 41 deletions(-) diff --git a/src/bin/lttng/commands/add_trigger.c b/src/bin/lttng/commands/add_trigger.c index 73bb0167c..e7809dc52 100644 --- a/src/bin/lttng/commands/add_trigger.c +++ b/src/bin/lttng/commands/add_trigger.c @@ -15,6 +15,7 @@ #include "common/argpar/argpar.h" #include "common/dynamic-array.h" +#include "common/mi-lttng.h" #include "common/string-utils/string-utils.h" #include "common/utils.h" /* For lttng_event_rule_type_str(). */ @@ -2186,9 +2187,35 @@ int cmd_add_trigger(int argc, const char **argv) int i; char *owner_uid = NULL; enum lttng_error_code ret_code; + struct mi_writer *mi_writer = NULL; lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor); + if (lttng_opt_mi) { + mi_writer = mi_lttng_writer_create( + fileno(stdout), lttng_opt_mi); + if (!mi_writer) { + ret = CMD_ERROR; + goto error; + } + + /* Open command element. */ + ret = mi_lttng_writer_command_open(mi_writer, + mi_lttng_element_command_add_trigger); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Open output element. */ + ret = mi_lttng_writer_open_element( + mi_writer, mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto error; + } + } + while (true) { enum argpar_state_parse_next_status status; const struct argpar_item_opt *item_opt; @@ -2374,6 +2401,13 @@ int cmd_add_trigger(int argc, const char **argv) goto error; } + if (lttng_opt_mi) { + ret_code = lttng_trigger_mi_serialize(trigger, mi_writer, NULL); + if (ret_code != LTTNG_OK) { + goto error; + } + } + MSG("Trigger registered successfully."); ret = 0; @@ -2383,6 +2417,33 @@ error: ret = 1; end: + /* Mi closing. */ + if (lttng_opt_mi) { + int mi_ret; + + /* Close output element. */ + mi_ret = mi_lttng_writer_close_element(mi_writer); + if (mi_ret) { + ret = 1; + goto cleanup; + } + + mi_ret = mi_lttng_writer_write_element_bool(mi_writer, + mi_lttng_element_command_success, ret ? 0 : 1); + if (mi_ret) { + ret = 1; + goto cleanup; + } + + /* Command element close. */ + mi_ret = mi_lttng_writer_command_close(mi_writer); + if (mi_ret) { + ret = 1; + goto cleanup; + } + } + +cleanup: argpar_state_destroy(argpar_state); argpar_item_destroy(argpar_item); lttng_dynamic_pointer_array_reset(&actions); @@ -2393,5 +2454,10 @@ end: free(error); free(name); free(owner_uid); + if (mi_writer && mi_lttng_writer_destroy(mi_writer)) { + /* Preserve original error code. */ + ret = ret ? ret : CMD_ERROR; + } + return ret; } diff --git a/src/bin/lttng/commands/list_triggers.c b/src/bin/lttng/commands/list_triggers.c index a456afc89..59db1c5d4 100644 --- a/src/bin/lttng/commands/list_triggers.c +++ b/src/bin/lttng/commands/list_triggers.c @@ -1146,11 +1146,9 @@ int compare_triggers_by_name(const void *a, const void *b) return strcmp(name_a, name_b); } -int cmd_list_triggers(int argc, const char **argv) +static int print_sorted_triggers(const struct lttng_triggers *triggers) { int ret; - struct argpar_parse_ret argpar_parse_ret = {}; - struct lttng_triggers *triggers = NULL; int i; struct lttng_dynamic_pointer_array sorted_triggers; enum lttng_trigger_status trigger_status; @@ -1158,6 +1156,166 @@ int cmd_list_triggers(int argc, const char **argv) lttng_dynamic_pointer_array_init(&sorted_triggers, NULL); + trigger_status = lttng_triggers_get_count(triggers, &num_triggers); + if (trigger_status != LTTNG_TRIGGER_STATUS_OK) { + ERR("Failed to get trigger count."); + goto error; + } + + for (i = 0; i < num_triggers; i++) { + int add_ret; + const char *unused_name; + const struct lttng_trigger *trigger = + lttng_triggers_get_at_index(triggers, i); + + trigger_status = lttng_trigger_get_name(trigger, &unused_name); + switch (trigger_status) { + case LTTNG_TRIGGER_STATUS_OK: + break; + case LTTNG_TRIGGER_STATUS_UNSET: + /* Don't list anonymous triggers. */ + continue; + default: + abort(); + } + + add_ret = lttng_dynamic_pointer_array_add_pointer( + &sorted_triggers, (void *) trigger); + if (add_ret) { + ERR("Failed to allocate array of struct lttng_trigger *."); + goto error; + } + } + + qsort(sorted_triggers.array.buffer.data, num_triggers, + sizeof(struct lttng_trigger *), + compare_triggers_by_name); + + for (i = 0; i < num_triggers; i++) { + const struct lttng_trigger *trigger_to_print = + (const struct lttng_trigger *) + lttng_dynamic_pointer_array_get_pointer( + &sorted_triggers, i); + + print_one_trigger(trigger_to_print); + } + + ret = 0; + goto end; +error: + ret = 1; + +end: + lttng_dynamic_pointer_array_reset(&sorted_triggers); + return ret; +} + +static enum lttng_error_code mi_error_query_trigger_callback( + const struct lttng_trigger *trigger, + struct lttng_error_query_results **results) +{ + enum lttng_error_code ret_code; + struct lttng_error_query *query = + lttng_error_query_trigger_create(trigger); + + assert(results); + assert(query); + + ret_code = lttng_error_query_execute( + query, lttng_session_daemon_command_endpoint, results); + if (ret_code != LTTNG_OK) { + enum lttng_trigger_status trigger_status; + const char *trigger_name; + uid_t trigger_uid; + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + trigger_status = lttng_trigger_get_owner_uid( + trigger, &trigger_uid); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s", + trigger_name, (int) trigger_uid, + lttng_strerror(-ret_code)); + } + + return ret_code; +} + +static enum lttng_error_code mi_error_query_action_callback( + const struct lttng_trigger *trigger, + const struct lttng_action_path *action_path, + struct lttng_error_query_results **results) +{ + enum lttng_error_code ret_code; + struct lttng_error_query *query = + lttng_error_query_action_create(trigger, action_path); + + assert(results); + assert(query); + + ret_code = lttng_error_query_execute( + query, lttng_session_daemon_command_endpoint, results); + if (ret_code != LTTNG_OK) { + enum lttng_trigger_status trigger_status; + const char *trigger_name; + uid_t trigger_uid; + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + trigger_status = lttng_trigger_get_owner_uid( + trigger, &trigger_uid); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + ERR("Failed to query errors of an action for trigger '%s' (owner uid: %d): %s", + trigger_name, (int) trigger_uid, + lttng_strerror(-ret_code)); + } + return ret_code; +} + +static enum lttng_error_code mi_error_query_condition_callback( + const struct lttng_trigger *trigger, + struct lttng_error_query_results **results) +{ + enum lttng_error_code ret_code; + struct lttng_error_query *query = + lttng_error_query_condition_create(trigger); + + assert(results); + assert(query); + + ret_code = lttng_error_query_execute( + query, lttng_session_daemon_command_endpoint, results); + if (ret_code != LTTNG_OK) { + enum lttng_trigger_status trigger_status; + const char *trigger_name; + uid_t trigger_uid; + + trigger_status = lttng_trigger_get_name(trigger, &trigger_name); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + trigger_status = lttng_trigger_get_owner_uid( + trigger, &trigger_uid); + assert(trigger_status == LTTNG_TRIGGER_STATUS_OK); + + ERR("Failed to query errors of of condition for condition of trigger '%s' (owner uid: %d): %s", + trigger_name, (int) trigger_uid, + lttng_strerror(-ret_code)); + } + + return ret_code; +} +int cmd_list_triggers(int argc, const char **argv) +{ + int ret; + struct argpar_parse_ret argpar_parse_ret = {}; + struct lttng_triggers *triggers = NULL; + int i; + struct mi_writer *mi_writer = NULL; + argpar_parse_ret = argpar_parse( argc - 1, argv + 1, list_trigger_options, true); if (!argpar_parse_ret.items) { @@ -1180,8 +1338,8 @@ int cmd_list_triggers(int argc, const char **argv) goto end; case OPT_LIST_OPTIONS: - list_cmd_options_argpar(stdout, - list_trigger_options); + list_cmd_options_argpar( + stdout, list_trigger_options); ret = 0; goto end; @@ -1203,49 +1361,68 @@ int cmd_list_triggers(int argc, const char **argv) goto error; } - trigger_status = lttng_triggers_get_count(triggers, &num_triggers); - if (trigger_status != LTTNG_TRIGGER_STATUS_OK) { - ERR("Failed to get trigger count."); - goto error; - } - - for (i = 0; i < num_triggers; i++) { - int add_ret; - const char *unused_name; - const struct lttng_trigger *trigger = - lttng_triggers_get_at_index(triggers, i); + if (lttng_opt_mi) { + mi_writer = mi_lttng_writer_create( + fileno(stdout), lttng_opt_mi); + if (!mi_writer) { + ret = CMD_ERROR; + goto end; + } - trigger_status = lttng_trigger_get_name(trigger, &unused_name); - switch (trigger_status) { - case LTTNG_TRIGGER_STATUS_OK: - break; - case LTTNG_TRIGGER_STATUS_UNSET: - /* Don't list anonymous triggers. */ - continue; - default: - abort(); + /* Open command element. */ + ret = mi_lttng_writer_command_open(mi_writer, + mi_lttng_element_command_list_trigger); + if (ret) { + ret = CMD_ERROR; + goto end; } - add_ret = lttng_dynamic_pointer_array_add_pointer( - &sorted_triggers, (void *) trigger); + /* Open output element. */ + ret = mi_lttng_writer_open_element( + mi_writer, mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto end; + } + } - if (add_ret) { - ERR("Failed to allocate array of struct lttng_trigger *."); + if (lttng_opt_mi) { + const struct mi_lttng_error_query_callbacks callbacks = { + .trigger_cb = mi_error_query_trigger_callback, + .action_cb = mi_error_query_action_callback, + .condition_cb = mi_error_query_condition_callback, + }; + + ret = lttng_triggers_mi_serialize( + triggers, mi_writer, &callbacks); + if (ret != LTTNG_OK) { + ERR("Error printing MI triggers: %s.", + lttng_strerror(-ret)); + goto error; + } + } else { + ret = print_sorted_triggers(triggers); + if (ret) { + ERR("Error printing triggers"); goto error; } } - qsort(sorted_triggers.array.buffer.data, num_triggers, - sizeof(struct lttng_trigger *), - compare_triggers_by_name); - - for (i = 0; i < num_triggers; i++) { - const struct lttng_trigger *trigger_to_print = - (const struct lttng_trigger *) - lttng_dynamic_pointer_array_get_pointer( - &sorted_triggers, i); + /* Mi closing. */ + if (lttng_opt_mi) { + /* Close output element. */ + ret = mi_lttng_writer_close_element(mi_writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } - print_one_trigger(trigger_to_print); + /* Command element close. */ + ret = mi_lttng_writer_command_close(mi_writer); + if (ret) { + ret = CMD_ERROR; + goto end; + } } ret = 0; @@ -1257,7 +1434,10 @@ error: end: argpar_parse_ret_fini(&argpar_parse_ret); lttng_triggers_destroy(triggers); - lttng_dynamic_pointer_array_reset(&sorted_triggers); - + /* Mi clean-up. */ + if (mi_writer && mi_lttng_writer_destroy(mi_writer)) { + /* Preserve original error code. */ + ret = ret ? ret : CMD_ERROR; + } return ret; } diff --git a/src/bin/lttng/commands/remove_trigger.c b/src/bin/lttng/commands/remove_trigger.c index 5586eb963..3c6e2b3f0 100644 --- a/src/bin/lttng/commands/remove_trigger.c +++ b/src/bin/lttng/commands/remove_trigger.c @@ -7,6 +7,7 @@ #include "../command.h" #include "common/argpar/argpar.h" +#include "common/mi-lttng.h" #include #include @@ -58,6 +59,7 @@ end: int cmd_remove_trigger(int argc, const char **argv) { + enum lttng_error_code ret_code; int ret; struct argpar_parse_ret argpar_parse_ret = {}; const char *name = NULL; @@ -68,6 +70,32 @@ int cmd_remove_trigger(int argc, const char **argv) const struct lttng_trigger *trigger_to_remove = NULL; char *owner_uid = NULL; long long uid; + struct mi_writer *mi_writer = NULL; + + if (lttng_opt_mi) { + mi_writer = mi_lttng_writer_create( + fileno(stdout), lttng_opt_mi); + if (!mi_writer) { + ret = CMD_ERROR; + goto error; + } + + /* Open command element. */ + ret = mi_lttng_writer_command_open(mi_writer, + mi_lttng_element_command_remove_trigger); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Open output element. */ + ret = mi_lttng_writer_open_element( + mi_writer, mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto error; + } + } argpar_parse_ret = argpar_parse(argc - 1, argv + 1, remove_trigger_options, true); @@ -182,6 +210,13 @@ int cmd_remove_trigger(int argc, const char **argv) goto error; } + if (lttng_opt_mi) { + ret_code = lttng_trigger_mi_serialize( + trigger_to_remove, mi_writer, NULL); + if (ret_code != LTTNG_OK) { + goto error; + } + } MSG("Removed trigger `%s`.", name); ret = 0; @@ -191,9 +226,38 @@ error: ret = 1; end: + /* Mi closing. */ + if (lttng_opt_mi) { + /* Close output element. */ + int mi_ret = mi_lttng_writer_close_element(mi_writer); + if (mi_ret) { + ret = 1; + goto cleanup; + } + + mi_ret = mi_lttng_writer_write_element_bool(mi_writer, + mi_lttng_element_command_success, ret ? 0 : 1); + if (mi_ret) { + ret = 1; + goto cleanup; + } + + /* Command element close. */ + mi_ret = mi_lttng_writer_command_close(mi_writer); + if (mi_ret) { + ret = 1; + goto cleanup; + } + } + +cleanup: argpar_parse_ret_fini(&argpar_parse_ret); lttng_triggers_destroy(triggers); free(owner_uid); + if (mi_writer && mi_lttng_writer_destroy(mi_writer)) { + /* Preserve original error code. */ + ret = ret ? ret : CMD_ERROR; + } return ret; } diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c index 627d07207..4da97deed 100644 --- a/src/common/mi-lttng.c +++ b/src/common/mi-lttng.c @@ -47,6 +47,7 @@ const char * const mi_lttng_element_command_disable_event = "disable-event"; const char * const mi_lttng_element_command_enable_channels = "enable-channel"; const char * const mi_lttng_element_command_enable_event = "enable-event"; const char * const mi_lttng_element_command_list = "list"; +const char *const mi_lttng_element_command_list_trigger = "list-trigger"; const char * const mi_lttng_element_command_load = "load"; LTTNG_HIDDEN const char * const mi_lttng_element_command_metadata = "metadata"; LTTNG_HIDDEN const char * const mi_lttng_element_command_metadata_action = "metadata_action"; diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h index d655f6fb8..7fbf7b53e 100644 --- a/src/common/mi-lttng.h +++ b/src/common/mi-lttng.h @@ -69,6 +69,7 @@ extern const char * const mi_lttng_element_command_disable_event; extern const char * const mi_lttng_element_command_enable_channels; extern const char * const mi_lttng_element_command_enable_event; extern const char * const mi_lttng_element_command_list; +extern const char *const mi_lttng_element_command_list_trigger; extern const char * const mi_lttng_element_command_load; extern const char * const mi_lttng_element_command_metadata; extern const char * const mi_lttng_element_command_metadata_action; -- 2.34.1