From c7e35b037773dbbfe10178c946ba44feefb226e1 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Sun, 6 Apr 2014 15:30:32 -0400 Subject: [PATCH] Mi: mi backend + mi for command version MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The machine interface option is now available for version. Other commands will shortly follow. Mi backend is expected to grow with addition of mi support to other commands. How to use: lttng --mi This syntax will be the same for all commands. Currently *only xml is supported as machine interface output.* As for errors handling, if an error/warning occurs while using mi it will be reported on stderr as normal. The integrity of the mi output cannot be guaranteed if an error/warning occurs. The error output format is consistent and easy for a machine client to parse. Thus no mi output format is required for error output. Example: lttng --mi xml version Output: version 2.4.0-rc2 2 4 0 Époque Opaque The Époque Opaque is a black IPA from Trou du Diable brewery. The nose is eerily reminiscent of the coffee crisp candy from of our childhood. These strong mocha accents are present on the palate, which are quickly subdued by Japanese and Australian hops leading to a final state of satisfaction enjoyable for any fan of bitter beer. http://lttng.org lttng is free software and under the GPL license and part LGPL Signed-off-by: Olivier Cotte Signed-off-by: Jonathan Rajotte Signed-off-by: David Goulet --- include/lttng/lttng-error.h | 5 +- include/lttng/lttng.h | 5 + src/bin/lttng-consumerd/lttng-consumerd.c | 2 + src/bin/lttng/commands/add_context.c | 7 + src/bin/lttng/commands/calibrate.c | 7 + src/bin/lttng/commands/create.c | 7 + src/bin/lttng/commands/destroy.c | 7 + src/bin/lttng/commands/disable_channels.c | 7 + src/bin/lttng/commands/disable_events.c | 7 + src/bin/lttng/commands/enable_channels.c | 7 + src/bin/lttng/commands/enable_events.c | 7 + src/bin/lttng/commands/list.c | 7 + src/bin/lttng/commands/load.c | 7 + src/bin/lttng/commands/save.c | 7 + src/bin/lttng/commands/set_session.c | 7 + src/bin/lttng/commands/snapshot.c | 7 + src/bin/lttng/commands/start.c | 7 + src/bin/lttng/commands/stop.c | 7 + src/bin/lttng/commands/version.c | 94 ++++++- src/bin/lttng/commands/view.c | 4 + src/bin/lttng/lttng.c | 31 ++- src/common/Makefile.am | 6 +- src/common/error.c | 3 + src/common/error.h | 11 +- src/common/mi-lttng.c | 286 ++++++++++++++++++++++ src/common/mi-lttng.h | 228 +++++++++++++++++ src/lib/lttng-ctl/lttng-ctl.c | 1 + tests/unit/ini_config/ini_config.c | 1 + tests/unit/test_kernel_data.c | 1 + tests/unit/test_session.c | 1 + tests/unit/test_uri.c | 1 + tests/unit/test_ust_data.c | 1 + tests/unit/test_utils_expand_path.c | 1 + tests/unit/test_utils_parse_size_suffix.c | 1 + 34 files changed, 778 insertions(+), 10 deletions(-) create mode 100644 src/common/mi-lttng.c create mode 100644 src/common/mi-lttng.h diff --git a/include/lttng/lttng-error.h b/include/lttng/lttng-error.h index e18fb00e8..608395913 100644 --- a/include/lttng/lttng-error.h +++ b/include/lttng/lttng-error.h @@ -111,8 +111,9 @@ enum lttng_error_code { LTTNG_ERR_LOAD_IO_FAIL = 88, /* IO error while reading a session configuration */ LTTNG_ERR_LOAD_SESSION_NOENT = 89, /* Session file not found */ LTTNG_ERR_MAX_SIZE_INVALID = 90, /* Snapshot max size is invalid. */ - /* 91 */ - /* 92 */ + LTTNG_ERR_MI_OUTPUT_TYPE = 91, /* Invalid MI output format */ + LTTNG_ERR_MI_IO_FAIL = 92, /* IO error while writing machine interface output */ + LTTNG_ERR_MI_NOT_IMPLEMENTED = 93, /* Mi feature not implemented */ /* 93 */ /* 94 */ /* 95 */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 944675206..c5be66128 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -43,6 +43,11 @@ enum lttng_calibrate_type { LTTNG_CALIBRATE_FUNCTION = 0, }; +/* Machine interface output type */ +enum lttng_mi_output_type { + LTTNG_MI_XML = 1 /* XML output */ +}; + #define LTTNG_CALIBRATE_PADDING1 16 struct lttng_calibrate { enum lttng_calibrate_type type; diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c index 88ce19019..5d5703064 100644 --- a/src/bin/lttng-consumerd/lttng-consumerd.c +++ b/src/bin/lttng-consumerd/lttng-consumerd.c @@ -65,6 +65,8 @@ static int sigintcount = 0; /* Argument variables */ int lttng_opt_quiet; /* not static in error.h */ int lttng_opt_verbose; /* not static in error.h */ +int lttng_opt_mi; /* not static in error.h */ + static int opt_daemon; static const char *progname; static char command_sock_path[PATH_MAX]; /* Global command socket path */ diff --git a/src/bin/lttng/commands/add_context.c b/src/bin/lttng/commands/add_context.c index b1f81e6b3..2f7559c30 100644 --- a/src/bin/lttng/commands/add_context.c +++ b/src/bin/lttng/commands/add_context.c @@ -647,6 +647,13 @@ int cmd_add_context(int argc, const char **argv) goto end; } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); diff --git a/src/bin/lttng/commands/calibrate.c b/src/bin/lttng/commands/calibrate.c index 092632cd7..7d4de2909 100644 --- a/src/bin/lttng/commands/calibrate.c +++ b/src/bin/lttng/commands/calibrate.c @@ -133,6 +133,13 @@ static int calibrate_lttng(void) goto error; } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto error; + } + handle = lttng_create_handle(NULL, &dom); if (handle == NULL) { ret = CMD_ERROR; diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index e02b14142..c43ce59b9 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -515,6 +515,13 @@ int cmd_create(int argc, const char **argv) } } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + if (opt_no_consumer) { MSG("The option --no-consumer is obsolete. Use --no-output now."); ret = CMD_WARNING; diff --git a/src/bin/lttng/commands/destroy.c b/src/bin/lttng/commands/destroy.c index 3fb5fb232..26548b9e1 100644 --- a/src/bin/lttng/commands/destroy.c +++ b/src/bin/lttng/commands/destroy.c @@ -148,6 +148,13 @@ int cmd_destroy(int argc, const char **argv) goto end; } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + /* Ignore session name in case all sessions are to be destroyed */ if (opt_destroy_all) { ret = destroy_all_sessions(); diff --git a/src/bin/lttng/commands/disable_channels.c b/src/bin/lttng/commands/disable_channels.c index 1aa3916ae..da53d25c9 100644 --- a/src/bin/lttng/commands/disable_channels.c +++ b/src/bin/lttng/commands/disable_channels.c @@ -167,6 +167,13 @@ int cmd_disable_channels(int argc, const char **argv) } } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + opt_channels = (char*) poptGetArg(pc); if (opt_channels == NULL) { ERR("Missing channel name(s).\n"); diff --git a/src/bin/lttng/commands/disable_events.c b/src/bin/lttng/commands/disable_events.c index e71234342..fb96b8060 100644 --- a/src/bin/lttng/commands/disable_events.c +++ b/src/bin/lttng/commands/disable_events.c @@ -212,6 +212,13 @@ int cmd_disable_events(int argc, const char **argv) } } + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + opt_event_list = (char*) poptGetArg(pc); if (opt_event_list == NULL && opt_disable_all == 0) { ERR("Missing event name(s).\n"); diff --git a/src/bin/lttng/commands/enable_channels.c b/src/bin/lttng/commands/enable_channels.c index 7f25a6e91..1fdaada99 100644 --- a/src/bin/lttng/commands/enable_channels.c +++ b/src/bin/lttng/commands/enable_channels.c @@ -329,6 +329,13 @@ int cmd_enable_channels(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/enable_events.c b/src/bin/lttng/commands/enable_events.c index 1547d7086..9b16d7c86 100644 --- a/src/bin/lttng/commands/enable_events.c +++ b/src/bin/lttng/commands/enable_events.c @@ -975,6 +975,13 @@ int cmd_enable_events(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + /* Default event type */ opt_event_type = LTTNG_EVENT_ALL; diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c index f56adf482..d25b5632b 100644 --- a/src/bin/lttng/commands/list.c +++ b/src/bin/lttng/commands/list.c @@ -888,6 +888,13 @@ int cmd_list(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/load.c b/src/bin/lttng/commands/load.c index 2a3c65795..347e4ca08 100644 --- a/src/bin/lttng/commands/load.c +++ b/src/bin/lttng/commands/load.c @@ -77,6 +77,13 @@ int cmd_load(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, load_opts, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c index 9be710326..fdc0da6bf 100644 --- a/src/bin/lttng/commands/save.c +++ b/src/bin/lttng/commands/save.c @@ -73,6 +73,13 @@ int cmd_save(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, save_opts, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/set_session.c b/src/bin/lttng/commands/set_session.c index 4238016e4..54320df2a 100644 --- a/src/bin/lttng/commands/set_session.c +++ b/src/bin/lttng/commands/set_session.c @@ -92,6 +92,13 @@ int cmd_set_session(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c index 2d250afc3..564651e09 100644 --- a/src/bin/lttng/commands/snapshot.c +++ b/src/bin/lttng/commands/snapshot.c @@ -452,6 +452,13 @@ int cmd_snapshot(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/start.c b/src/bin/lttng/commands/start.c index 82122cc63..82b3f5f86 100644 --- a/src/bin/lttng/commands/start.c +++ b/src/bin/lttng/commands/start.c @@ -118,6 +118,13 @@ int cmd_start(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/stop.c b/src/bin/lttng/commands/stop.c index cb45f12ce..965ab94fe 100644 --- a/src/bin/lttng/commands/stop.c +++ b/src/bin/lttng/commands/stop.c @@ -141,6 +141,13 @@ int cmd_stop(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + /* TODO: mi support */ + if (lttng_opt_mi) { + ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED; + ERR("mi option not supported"); + goto end; + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/commands/version.c b/src/bin/lttng/commands/version.c index f2f435e4b..d27013689 100644 --- a/src/bin/lttng/commands/version.c +++ b/src/bin/lttng/commands/version.c @@ -25,6 +25,8 @@ #include #include +#include + #include "../command.h" enum { @@ -32,6 +34,8 @@ enum { OPT_LIST_OPTIONS, }; +static const char *lttng_license = "lttng is free software and under the GPL license and part LGPL"; + static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, @@ -52,6 +56,84 @@ static void usage(FILE *ofp) fprintf(ofp, "\n"); } +/* + * create_version + */ +static void create_version(struct mi_lttng_version *version) +{ + strncpy(version->version, VERSION, NAME_MAX); + version->version_major = VERSION_MAJOR; + version->version_minor = VERSION_MINOR; + version->version_patchlevel = VERSION_PATCHLEVEL; + strncpy(version->version_name, VERSION_NAME, NAME_MAX); + strncpy(version->package_url, PACKAGE_URL, NAME_MAX); +} + +/* + * Print the machine interface output of this command. + */ +static int print_mi() +{ + int ret = CMD_SUCCESS; + struct mi_writer *writer = NULL; + struct mi_lttng_version version; + + create_version(&version); + + writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); + if (!writer) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* Open the command element */ + ret = mi_lttng_writer_command_open(writer, + mi_lttng_element_command_version); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Beginning of output */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_command_output); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Print the machine interface of version */ + ret = mi_lttng_version(writer, &version, + VERSION_DESCRIPTION, lttng_license); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Close the output element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + ret = CMD_ERROR; + goto error; + } + + /* Close the command */ + ret = mi_lttng_writer_command_close(writer); + if (ret) { + ret = CMD_ERROR; + } + +error: + /* Cleanup */ + if (writer && mi_lttng_writer_destroy(writer)) { + /* Preserve original error code */ + ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; + } + +end: + return ret; +} + /* * cmd_version */ @@ -78,10 +160,14 @@ int cmd_version(int argc, const char **argv) } } - MSG("lttng version " FULL_VERSION " - " VERSION_NAME); - MSG("\n" VERSION_DESCRIPTION "\n"); - MSG("Web site: http://lttng.org"); - MSG("\nlttng is free software and under the GPL license and part LGPL"); + if (lttng_opt_mi) { + ret = print_mi(); + } else { + MSG("lttng version " FULL_VERSION " - " VERSION_NAME); + MSG("\n" VERSION_DESCRIPTION "\n"); + MSG("Web site: http://lttng.org"); + MSG("\n%s", lttng_license); + } end: poptFreeContext(pc); diff --git a/src/bin/lttng/commands/view.c b/src/bin/lttng/commands/view.c index adedf2989..dcd4d6624 100644 --- a/src/bin/lttng/commands/view.c +++ b/src/bin/lttng/commands/view.c @@ -445,6 +445,10 @@ int cmd_view(int argc, const char **argv) pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); + if (lttng_opt_mi) { + WARN("mi does not apply to view command"); + } + while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index d4d40f077..bad57fd9a 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -55,6 +55,7 @@ static struct option long_options[] = { {"group", 1, NULL, 'g'}, {"verbose", 0, NULL, 'v'}, {"quiet", 0, NULL, 'q'}, + {"mi", 1, NULL, 'm'}, {"no-sessiond", 0, NULL, 'n'}, {"sessiond-path", 1, NULL, OPT_SESSION_PATH}, {"relayd-path", 1, NULL, OPT_RELAYD_PATH}, @@ -99,6 +100,8 @@ static void usage(FILE *ofp) fprintf(ofp, " --list-commands Simple listing of lttng commands\n"); fprintf(ofp, " -v, --verbose Increase verbosity\n"); fprintf(ofp, " -q, --quiet Quiet mode\n"); + fprintf(ofp, " -m, --mi TYPE Machine Interface mode.\n"); + fprintf(ofp, " Type: xml\n"); fprintf(ofp, " -g, --group NAME Unix tracing group name. (default: tracing)\n"); fprintf(ofp, " -n, --no-sessiond Don't spawn a session daemon\n"); fprintf(ofp, " --sessiond-path PATH Session daemon full path\n"); @@ -135,6 +138,25 @@ static void version(FILE *ofp) progname); } +/* + * Find the MI output type enum from a string. This function is for the support + * of machine interface output. + */ +static int mi_output_type(const char *output_type) +{ + int ret = 0; + + if (!strncasecmp("xml", output_type, 3)) { + ret = LTTNG_MI_XML; + } else { + /* Invalid output format */ + ERR("MI output format not supported"); + ret = -LTTNG_ERR_MI_OUTPUT_TYPE; + } + + return ret; +} + /* * list_options * @@ -426,7 +448,7 @@ static int parse_args(int argc, char **argv) clean_exit(EXIT_FAILURE); } - while ((opt = getopt_long(argc, argv, "+Vhnvqg:", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) { switch (opt) { case 'V': version(stdout); @@ -445,6 +467,13 @@ static int parse_args(int argc, char **argv) case 'q': lttng_opt_quiet = 1; break; + case 'm': + lttng_opt_mi = mi_output_type(optarg); + if (lttng_opt_mi < 0) { + ret = lttng_opt_mi; + goto error; + } + break; case 'g': lttng_set_tracing_group(optarg); break; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 6aa0a8ab0..4b623c837 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -16,8 +16,12 @@ noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = error.h error.c utils.c utils.h runas.c runas.h \ common.h futex.c futex.h uri.c uri.h defaults.c \ pipe.c pipe.h readwrite.c readwrite.h \ + mi-lttng.h mi-lttng.c \ daemonize.c daemonize.h -libcommon_la_LIBADD = -luuid -lrt +libcommon_la_LIBADD = \ + -luuid \ + -lrt \ + $(top_builddir)/src/common/config/libconfig.la # Consumer library noinst_LTLIBRARIES += libconsumer.la diff --git a/src/common/error.c b/src/common/error.c index 26dc06798..6e283ccb6 100644 --- a/src/common/error.c +++ b/src/common/error.c @@ -161,6 +161,9 @@ static const char *error_string_array[] = { [ ERROR_INDEX(LTTNG_ERR_LOAD_IO_FAIL) ] = "IO error while reading a session configuration", [ ERROR_INDEX(LTTNG_ERR_LOAD_SESSION_NOENT) ] = "Session file not found", [ ERROR_INDEX(LTTNG_ERR_MAX_SIZE_INVALID) ] = "Snapshot max size is invalid", + [ ERROR_INDEX(LTTNG_ERR_MI_OUTPUT_TYPE) ] = "Invalid MI output format", + [ ERROR_INDEX(LTTNG_ERR_MI_IO_FAIL) ] = "IO error while writing MI output", + [ ERROR_INDEX(LTTNG_ERR_MI_NOT_IMPLEMENTED) ] = "Mi feature not implemented", /* Last element */ [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code" diff --git a/src/common/error.h b/src/common/error.h index 684ff5e5f..1ee6e675a 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -49,6 +49,7 @@ extern DECLARE_URCU_TLS(struct log_time, error_log_time); extern int lttng_opt_quiet; extern int lttng_opt_verbose; +extern int lttng_opt_mi; /* Error type. */ #define PRINT_ERR 0x1 @@ -61,12 +62,18 @@ extern int lttng_opt_verbose; /* * Macro for printing message depending on command line option and verbosity. + * + * Machine interface: + * We use lttng_opt_mi to suppress all normal msg to stdout. We don't + * want any nested msg to show up when printing mi to stdout(if it's the case). + * All warnings and errors should be printed to stderr as normal. */ #define __lttng_print(type, fmt, args...) \ do { \ - if (lttng_opt_quiet == 0 && type == PRINT_MSG) { \ + if (lttng_opt_quiet == 0 && lttng_opt_mi == 0 && \ + type == PRINT_MSG) { \ fprintf(stdout, fmt, ## args); \ - } else if (lttng_opt_quiet == 0 && \ + } else if (lttng_opt_quiet == 0 && lttng_opt_mi == 0 && \ (((type & PRINT_DBG) && lttng_opt_verbose == 1) || \ ((type & (PRINT_DBG | PRINT_DBG2)) && \ lttng_opt_verbose == 2) || \ diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c new file mode 100644 index 000000000..052b5425e --- /dev/null +++ b/src/common/mi-lttng.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2014 - Jonathan Rajotte + * - Olivier Cotte + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include "mi-lttng.h" + +/* Strings related to command */ +const char * const mi_lttng_element_command = "command"; +const char * const mi_lttng_element_command_version = "version"; +const char * const mi_lttng_element_command_list = "list"; +const char * const mi_lttng_element_command_name = "name"; +const char * const mi_lttng_element_command_output = "output"; + +/* Strings related to command: version */ +const char * const mi_lttng_element_version = "version"; +const char * const mi_lttng_element_version_str = "string"; +const char * const mi_lttng_element_version_web = "url"; +const char * const mi_lttng_element_version_major = "major"; +const char * const mi_lttng_element_version_minor = "minor"; +const char * const mi_lttng_element_version_license = "license"; +const char * const mi_lttng_element_version_patch_level = "patchLevel"; +const char * const mi_lttng_element_version_description = "description"; + +LTTNG_HIDDEN +struct mi_writer *mi_lttng_writer_create(int fd_output, int mi_output_type) +{ + struct mi_writer *mi_writer; + + mi_writer = zmalloc(sizeof(struct mi_writer)); + if (!mi_writer) { + PERROR("zmalloc mi_writer_create"); + goto end; + } + if (mi_output_type == LTTNG_MI_XML) { + mi_writer->writer = config_writer_create(fd_output); + if (!mi_writer->writer) { + goto err_destroy; + } + mi_writer->type = LTTNG_MI_XML; + } else { + goto err_destroy; + } + +end: + return mi_writer; + +err_destroy: + free(mi_writer); + return NULL; +} + +LTTNG_HIDDEN +int mi_lttng_writer_destroy(struct mi_writer *writer) +{ + int ret; + + if (!writer) { + ret = -EINVAL; + goto end; + } + + ret = config_writer_destroy(writer->writer); + if (ret < 0) { + goto end; + } + + free(writer); +end: + return ret; +} + +LTTNG_HIDDEN +int mi_lttng_writer_command_open(struct mi_writer *writer, const char *command) +{ + int ret; + + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command); + if (ret) { + goto end; + } + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_command_name, command); +end: + return ret; +} + +LTTNG_HIDDEN +int mi_lttng_writer_command_close(struct mi_writer *writer) +{ + return mi_lttng_writer_close_element(writer); +} + +LTTNG_HIDDEN +int mi_lttng_writer_open_element(struct mi_writer *writer, + const char *element_name) +{ + return config_writer_open_element(writer->writer, element_name); +} + +LTTNG_HIDDEN +int mi_lttng_writer_close_element(struct mi_writer *writer) +{ + return config_writer_close_element(writer->writer); +} + +LTTNG_HIDDEN +int mi_lttng_writer_write_element_unsigned_int(struct mi_writer *writer, + const char *element_name, uint64_t value) +{ + return config_writer_write_element_unsigned_int(writer->writer, + element_name, value); +} + +LTTNG_HIDDEN +int mi_lttng_writer_write_element_signed_int(struct mi_writer *writer, + const char *element_name, int64_t value) +{ + return config_writer_write_element_signed_int(writer->writer, + element_name, value); +} + +LTTNG_HIDDEN +int mi_lttng_writer_write_element_bool(struct mi_writer *writer, + const char *element_name, int value) +{ + return config_writer_write_element_bool(writer->writer, + element_name, value); +} + +LTTNG_HIDDEN +int mi_lttng_writer_write_element_string(struct mi_writer *writer, + const char *element_name, const char *value) +{ + return config_writer_write_element_string(writer->writer, + element_name, value); +} + +LTTNG_HIDDEN +int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version, + const char *lttng_description, const char *lttng_license) +{ + int ret; + + /* Open version */ + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_version); + if (ret) { + goto end; + } + + /* Version string (contain info like rc etc.) */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_version_str, VERSION); + if (ret) { + goto end; + } + + /* Major version number */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + mi_lttng_element_version_major, version->version_major); + if (ret) { + goto end; + } + + /* Minor version number */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + mi_lttng_element_version_minor, version->version_minor); + if (ret) { + goto end; + } + + /* Patch number */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + mi_lttng_element_version_patch_level, version->version_patchlevel); + if (ret) { + goto end; + } + + /* Name of the version */ + ret = mi_lttng_writer_write_element_string(writer, + config_element_name, version->version_name); + if (ret) { + goto end; + } + + /* Description mostly related to beer... */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_version_description, lttng_description); + if (ret) { + goto end; + } + + /* url */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_version_web, version->package_url); + if (ret) { + goto end; + } + + /* License: free as in free beer...no...*speech* */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_version_license, lttng_license); + if (ret) { + goto end; + } + + /* Close version element */ + ret = mi_lttng_writer_close_element(writer); + +end: + return ret; +} + +LTTNG_HIDDEN +int mi_lttng_session(struct mi_writer *writer, + struct lttng_session *session, int is_open) +{ + int ret; + + /* open sessions element */ + ret = mi_lttng_writer_open_element(writer, + config_element_session); + if (ret) { + goto end; + } + + /* Name of the session */ + ret = mi_lttng_writer_write_element_string(writer, + config_element_name, session->name); + if (ret) { + goto end; + } + + /* path */ + ret = mi_lttng_writer_write_element_string(writer, + config_element_path, session->path); + if (ret) { + goto end; + } + + /* enabled ? */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_enabled, session->enabled); + if (ret) { + goto end; + } + + /* snapshot mode */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_snapshot_mode, session->snapshot_mode); + if (ret) { + goto end; + } + + /* live timer interval in usec */ + ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_live_timer_interval, + session->live_timer_interval); + if (ret) { + goto end; + } + + if (!is_open) { + /* Closing session element */ + ret = mi_lttng_writer_close_element(writer); + } +end: + return ret; + +} diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h new file mode 100644 index 000000000..bdc4a052a --- /dev/null +++ b/src/common/mi-lttng.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2014 - Jonathan Rajotte + * - Olivier Cotte + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _MI_LTTNG_H +#define _MI_LTTNG_H + +#include + +#include +#include +#include +#include + +/* Instance of a machine interface writer. */ +struct mi_writer { + struct config_writer *writer; + enum lttng_mi_output_type type; +}; + +/* + * Version information for the machine interface. + */ +struct mi_lttng_version { + char version[NAME_MAX]; /* Version number of package */ + uint32_t version_major; /* LTTng-Tools major version number */ + uint32_t version_minor; /* LTTng-Tools minor version number */ + uint32_t version_patchlevel; /* LTTng-Tools patchlevel version number */ + char version_name[NAME_MAX]; + char package_url[NAME_MAX]; /* Define to the home page for this package. */ +}; + +/* Strings related to command */ +const char * const mi_lttng_element_command; +const char * const mi_lttng_element_command_version; +const char * const mi_lttng_element_command_list; +const char * const mi_lttng_element_command_name; +const char * const mi_lttng_element_command_output; + +/* Strings related to command: version */ +const char * const mi_lttng_element_version; +const char * const mi_lttng_element_version_str; +const char * const mi_lttng_element_version_web; +const char * const mi_lttng_element_version_major; +const char * const mi_lttng_element_version_minor; +const char * const mi_lttng_element_version_license; +const char * const mi_lttng_element_version_patch_level; +const char * const mi_lttng_element_version_description; + +/* + * Create an instance of a machine interface writer. + * + * fd_output File to which the XML content must be written. The file will be + * closed once the mi_writer has been destroyed. + * + * Returns an instance of a machine interface writer on success, NULL on + * error. + */ +struct mi_writer *mi_lttng_writer_create(int fd_output, int mi_output_type); + +/* + * Destroy an instance of a machine interface writer. + * + * writer An instance of a machine interface writer. + * + * Returns zero if the XML document could be closed cleanly. Negative values + * indicate an error. + */ +int mi_lttng_writer_destroy(struct mi_writer *writer); + +/* + * Open a command tag and add it's name node. + * + * writer An instance of a machine interface writer. + * + * command The command name. + * + * Returns zero if the XML document could be closed cleanly. + * Negative values indicate an error. + */ +int mi_lttng_writer_command_open(struct mi_writer *writer, const char *command); + +/* + * Close a command tag. + * + * writer An instance of a machine interface writer. + * + * Returns zero if the XML document could be closed cleanly. + * Negative values indicate an error. + */ +int mi_lttng_writer_command_close(struct mi_writer *writer); + +/* + * Open an element tag. + * + * writer An instance of a machine interface writer. + * + * element_name Element tag name. + * + * Returns zero if the XML document could be closed cleanly. + * Negative values indicate an error. + */ +int mi_lttng_writer_open_element(struct mi_writer *writer, + const char *element_name); + +/* + * Close the current element tag. + * + * writer An instance of a machine interface writer. + * + * Returns zero if the XML document could be closed cleanly. + * Negative values indicate an error. + */ +int mi_lttng_writer_close_element(struct mi_writer *writer); + +/* + * Write an element of type unsigned int. + * + * writer An instance of a machine interface writer. + * + * element_name Element name. + * + * value Unsigned int value of the element + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_writer_write_element_unsigned_int(struct mi_writer *writer, + const char *element_name, uint64_t value); + +/* + * Write an element of type signed int. + * + * writer An instance of a machine interface writer. + * + * element_name Element name. + * + * value Signed int value of the element + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_writer_write_element_signed_int(struct mi_writer *writer, + const char *element_name, int64_t value); + +/* + * Write an element of type boolean. + * + * writer An instance of a machine interface writer. + * + * element_name Element name. + * + * value Boolean value of the element + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_writer_write_element_bool(struct mi_writer *writer, + const char *element_name, int value); + +/* + * Write an element of type string. + * + * writer An instance of a machine interface writer. + * + * element_name Element name. + * + * value String value of the element + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_writer_write_element_string(struct mi_writer *writer, + const char *element_name, const char *value); + +/* + * Machine interface of struct version. + * + * writer An instance of a machine interface writer. + * + * version Version struct. + * + * lttng_description String value of the version description. + * + * lttng_license String value of the version license. + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version, + const char *lttng_description, const char *lttng_license); + +/* + * Machine interface of struct session. + * + * writer An instance of a machine interface writer + * + * session An instance of a session + * + * isOpen Define if we close the session element + * This should be use carefully and the client + * need to close the session element. + * Use case: nested addition information on a session + * ex: domain,channel event. + * 0-> False + * 1-> True + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_session(struct mi_writer *writer, + struct lttng_session *session, int isOpen); + +#endif /* _MI_LTTNG_H */ diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index a92bf3912..536d41baa 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -74,6 +74,7 @@ static int connected; */ int lttng_opt_quiet; int lttng_opt_verbose; +int lttng_opt_mi; /* * Copy string from src to dst and enforce null terminated byte. diff --git a/tests/unit/ini_config/ini_config.c b/tests/unit/ini_config/ini_config.c index 38fe5f4f2..29935ef1c 100644 --- a/tests/unit/ini_config/ini_config.c +++ b/tests/unit/ini_config/ini_config.c @@ -31,6 +31,7 @@ struct state { int lttng_opt_quiet = 1; int lttng_opt_verbose = 0; +int lttng_opt_mi; int entry_handler(const struct config_entry *entry, struct state *state) diff --git a/tests/unit/test_kernel_data.c b/tests/unit/test_kernel_data.c index 5b82672d7..ca53c7d48 100644 --- a/tests/unit/test_kernel_data.c +++ b/tests/unit/test_kernel_data.c @@ -38,6 +38,7 @@ /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose; +int lttng_opt_mi; int ust_consumerd32_fd; int ust_consumerd64_fd; diff --git a/tests/unit/test_session.c b/tests/unit/test_session.c index a0e84e9ea..4f90c3347 100644 --- a/tests/unit/test_session.c +++ b/tests/unit/test_session.c @@ -46,6 +46,7 @@ static struct ltt_session_list *session_list; /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose = 0; +int lttng_opt_mi; int ust_consumerd32_fd; int ust_consumerd64_fd; diff --git a/tests/unit/test_uri.c b/tests/unit/test_uri.c index 7cac95d98..432e2b3fc 100644 --- a/tests/unit/test_uri.c +++ b/tests/unit/test_uri.c @@ -25,6 +25,7 @@ /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose = 3; +int lttng_opt_mi; /* Number of TAP tests in this file */ #define NUM_TESTS 11 diff --git a/tests/unit/test_ust_data.c b/tests/unit/test_ust_data.c index 150d5dafb..dd0008926 100644 --- a/tests/unit/test_ust_data.c +++ b/tests/unit/test_ust_data.c @@ -44,6 +44,7 @@ /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose; +int lttng_opt_mi; int ust_consumerd32_fd; int ust_consumerd64_fd; diff --git a/tests/unit/test_utils_expand_path.c b/tests/unit/test_utils_expand_path.c index fe709acf5..f863b5d9a 100644 --- a/tests/unit/test_utils_expand_path.c +++ b/tests/unit/test_utils_expand_path.c @@ -31,6 +31,7 @@ /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose = 3; +int lttng_opt_mi; struct valid_test_input { char *input; diff --git a/tests/unit/test_utils_parse_size_suffix.c b/tests/unit/test_utils_parse_size_suffix.c index 45a87b06c..2d3bbfc45 100644 --- a/tests/unit/test_utils_parse_size_suffix.c +++ b/tests/unit/test_utils_parse_size_suffix.c @@ -26,6 +26,7 @@ /* For error.h */ int lttng_opt_quiet = 1; int lttng_opt_verbose = 3; +int lttng_opt_mi; struct valid_test_input { char *input; -- 2.34.1