From 57f272edb1b4ccb8869e3f5b69eb5461bcb56101 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 18 Apr 2013 15:41:16 -0400 Subject: [PATCH] Add snapshot command to lttng UI Signed-off-by: David Goulet --- src/bin/lttng/Makefile.am | 1 + src/bin/lttng/command.h | 1 + src/bin/lttng/commands/snapshot.c | 473 ++++++++++++++++++++++++++++++ src/bin/lttng/lttng.c | 2 + 4 files changed, 477 insertions(+) create mode 100644 src/bin/lttng/commands/snapshot.c diff --git a/src/bin/lttng/Makefile.am b/src/bin/lttng/Makefile.am index 21eebab7d..b7aa05d28 100644 --- a/src/bin/lttng/Makefile.am +++ b/src/bin/lttng/Makefile.am @@ -11,6 +11,7 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \ commands/set_session.c commands/version.c \ commands/calibrate.c commands/view.c \ commands/enable_consumer.c commands/disable_consumer.c \ + commands/snapshot.c \ utils.c utils.h lttng.c lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \ diff --git a/src/bin/lttng/command.h b/src/bin/lttng/command.h index 21585383f..7965f55ce 100644 --- a/src/bin/lttng/command.h +++ b/src/bin/lttng/command.h @@ -55,5 +55,6 @@ extern int cmd_calibrate(int argc, const char **argv); extern int cmd_view(int argc, const char **argv); extern int cmd_enable_consumer(int argc, const char **argv); extern int cmd_disable_consumer(int argc, const char **argv); +extern int cmd_snapshot(int argc, const char **argv); #endif /* _LTTNG_CMD_H */ diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c new file mode 100644 index 000000000..866b55a38 --- /dev/null +++ b/src/bin/lttng/commands/snapshot.c @@ -0,0 +1,473 @@ +/* + * Copyright (C) 2013 - David Goulet + * + * 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. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../command.h" + +static const char *opt_session_name; +static const char *opt_output_name; +static const char *opt_data_url; +static const char *opt_ctrl_url; +static const char *current_session_name; +static uint64_t opt_max_size; + +/* Stub for the cmd struct actions. */ +static int cmd_add_output(int argc, const char **argv); +static int cmd_del_output(int argc, const char **argv); +static int cmd_list_output(int argc, const char **argv); +static int cmd_record(int argc, const char **argv); + +static const char *indent4 = " "; + +enum { + OPT_HELP = 1, + OPT_LIST_OPTIONS, + OPT_MAX_SIZE, +}; + +static struct poptOption snapshot_opts[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, + {"ctrl-url", 'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0}, + {"data-url", 'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0}, + {"name", 'n', POPT_ARG_STRING, &opt_output_name, 0, 0, 0}, + {"max-size", 'm', POPT_ARG_DOUBLE, 0, OPT_MAX_SIZE, 0, 0}, + {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {0, 0, 0, 0, 0, 0, 0} +}; + +static struct cmd_struct actions[] = { + { "add-output", cmd_add_output }, + { "del-output", cmd_del_output }, + { "list-output", cmd_list_output }, + { "record", cmd_record }, + { NULL, NULL } /* Array closure */ +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng snapshot [ACTION]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Actions:\n"); + fprintf(ofp, " add-output [-m ] [-s ] [-n ] | -C -D \n"); + fprintf(ofp, " Setup and add an snapshot output for a session.\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " del-output ID [-s ]\n"); + fprintf(ofp, " Delete an output for a session using the ID.\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " list-output [-s ]\n"); + fprintf(ofp, " List the output of a session.\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " record [-m ] [-s ] [-n ] [ | -C -D ]\n"); + fprintf(ofp, " Snapshot a session's buffer(s) for all domains. If an URL is\n"); + fprintf(ofp, " specified, it is used instead of a previously added output.\n"); + fprintf(ofp, " The snapshot is saved in the session directory in snapshot/ with\n"); + fprintf(ofp, " the top directory being NAME or the default: snapshot-ID/\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Options:\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " --list-options Simple listing of options\n"); + fprintf(ofp, " -s, --session NAME Apply to session name\n"); + fprintf(ofp, " -n, --name NAME Name of the output or snapshot\n"); + fprintf(ofp, " -m, --max-size SIZE Maximum bytes size of the snapshot\n"); + fprintf(ofp, " -C, --ctrl-url URL Set control path URL. (Must use -D also)\n"); + fprintf(ofp, " -D, --data-url URL Set data path URL. (Must use -C also)\n"); + fprintf(ofp, "\n"); +} + +/* + * Count and return the number of arguments in argv. + */ +static int count_arguments(const char **argv) +{ + int i = 0; + + assert(argv); + + while (argv[i] != NULL) { + i++; + } + + return i; +} + +/* + * Create a snapshot output object from arguments using the given URL. + * + * Return a newly allocated object or NULL on error. + */ +static struct lttng_snapshot_output *create_output_from_args(const char *url) +{ + int ret = 0; + struct lttng_snapshot_output *output = NULL; + + output = lttng_snapshot_output_create(); + if (!output) { + goto error_create; + } + + if (url) { + ret = lttng_snapshot_output_set_ctrl_url(url, output); + if (ret < 0) { + goto error; + } + } else if (opt_ctrl_url) { + ret = lttng_snapshot_output_set_ctrl_url(opt_ctrl_url, output); + if (ret < 0) { + goto error; + } + } + + if (opt_data_url) { + ret = lttng_snapshot_output_set_data_url(opt_data_url, output); + if (ret < 0) { + goto error; + } + } + + if (opt_max_size) { + ret = lttng_snapshot_output_set_size(opt_max_size, output); + if (ret < 0) { + goto error; + } + } + + if (opt_output_name) { + ret = lttng_snapshot_output_set_name(opt_output_name, output); + if (ret < 0) { + goto error; + } + } + + return output; + +error: + lttng_snapshot_output_destroy(output); +error_create: + return NULL; +} + +static int list_output(void) +{ + int ret, output_seen = 0; + struct lttng_snapshot_output *s_iter; + struct lttng_snapshot_output_list *list; + + ret = lttng_snapshot_list_output(current_session_name, &list); + if (ret < 0) { + goto error; + } + + MSG("Snapshot output list for session %s", current_session_name); + + while ((s_iter = lttng_snapshot_output_list_get_next(list)) != NULL) { + MSG("%s[%" PRIu32 "] %s: %s", indent4, + lttng_snapshot_output_get_id(s_iter), + lttng_snapshot_output_get_name(s_iter), + lttng_snapshot_output_get_ctrl_url(s_iter)); + output_seen = 1; + } + + lttng_snapshot_output_list_destroy(list); + + if (!output_seen) { + MSG("%sNone", indent4); + } + +error: + return ret; +} + +/* + * Delete output by ID. + */ +static int del_output(uint32_t id) +{ + int ret; + struct lttng_snapshot_output *output = NULL; + + output = lttng_snapshot_output_create(); + if (!output) { + ret = CMD_FATAL; + goto error; + } + + ret = lttng_snapshot_output_set_id(id, output); + if (ret < 0) { + ret = CMD_FATAL; + goto error; + } + + ret = lttng_snapshot_del_output(current_session_name, output); + if (ret < 0) { + goto error; + } + + MSG("Snapshot output id %" PRIu32 " successfully deleted for session %s", + id, current_session_name); + +error: + lttng_snapshot_output_destroy(output); + return ret; +} + +/* + * Add output from the user URL. + */ +static int add_output(const char *url) +{ + int ret; + struct lttng_snapshot_output *output = NULL; + + if (!url && (!opt_data_url || !opt_ctrl_url)) { + ret = CMD_ERROR; + goto error; + } + + output = create_output_from_args(url); + if (!output) { + ret = CMD_FATAL; + goto error; + } + + /* This call, if successful, populates the id of the output object. */ + ret = lttng_snapshot_add_output(current_session_name, output); + if (ret < 0) { + goto error; + } + + MSG("Snapshot output successfully added for session %s", + current_session_name); + MSG(" [%" PRIu32 "] %s: %s (max-size: %" PRId64 ")", + lttng_snapshot_output_get_id(output), + lttng_snapshot_output_get_name(output), + lttng_snapshot_output_get_ctrl_url(output), + lttng_snapshot_output_get_maxsize(output)); +error: + lttng_snapshot_output_destroy(output); + return ret; +} + +static int cmd_add_output(int argc, const char **argv) +{ + int ret = CMD_SUCCESS; + + if (argc < 2 && (!opt_data_url || !opt_ctrl_url)) { + usage(stderr); + ret = CMD_ERROR; + goto end; + } + + ret = add_output(argv[1]); + +end: + return ret; +} + +static int cmd_del_output(int argc, const char **argv) +{ + int ret = CMD_SUCCESS; + + if (argc < 2) { + usage(stderr); + ret = CMD_ERROR; + goto end; + } + + ret = del_output(atoi(argv[1])); + +end: + return ret; +} + +static int cmd_list_output(int argc, const char **argv) +{ + return list_output(); +} + +/* + * Do a snapshot record with the URL if one is given. + */ +static int record(const char *url) +{ + int ret; + struct lttng_snapshot_output *output = NULL; + + if (url || (opt_ctrl_url && opt_data_url)) { + output = create_output_from_args(url); + if (!output) { + ret = CMD_FATAL; + goto error; + } + } + + ret = lttng_snapshot_record(current_session_name, output, 0); + if (ret < 0) { + goto error; + } + + MSG("Snapshot recorded successfully for session %s", current_session_name); + + if (url) { + MSG("Snapshot written at: %s", url); + } else if (opt_ctrl_url) { + MSG("Snapshot written to ctrl: %s, data: %s", opt_ctrl_url, + opt_data_url); + } else { + MSG("Snapshot written in session directory."); + } + +error: + return ret; +} + +static int cmd_record(int argc, const char **argv) +{ + int ret; + + if (argc == 2) { + /* With a given URL */ + ret = record(argv[1]); + } else { + ret = record(NULL); + } + + return ret; +} + +static int handle_command(const char **argv) +{ + int ret, i = 0, argc; + struct cmd_struct *cmd; + + if (argv == NULL || (!opt_ctrl_url && opt_data_url) || + (opt_ctrl_url && !opt_data_url)) { + usage(stderr); + ret = CMD_ERROR; + goto end; + } + + argc = count_arguments(argv); + + cmd = &actions[i]; + while (cmd->func != NULL) { + /* Find command */ + if (strcmp(argv[0], cmd->name) == 0) { + ret = cmd->func(argc, argv); + goto end; + } + i++; + cmd = &actions[i]; + } + + /* Command not found */ + ret = CMD_UNDEFINED; + +end: + return ret; +} + +/* + * The 'snapshot ' first level command + */ +int cmd_snapshot(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS; + char *session_name = NULL; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stdout); + goto end; + case OPT_LIST_OPTIONS: + list_cmd_options(stdout, snapshot_opts); + goto end; + case OPT_MAX_SIZE: + { + long long int val; + char *endptr; + const char *opt = poptGetOptArg(pc); + + val = strtoll(opt, &endptr, 10); + if ((errno == ERANGE && (val == LLONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + ERR("Unable to handle max-size value %s", opt); + ret = CMD_ERROR; + goto end; + } + + if (endptr == opt) { + ERR("No digits were found in %s", opt); + ret = CMD_ERROR; + goto end; + } + opt_max_size = val; + + break; + } + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + if (!opt_session_name) { + session_name = get_session_name(); + if (session_name == NULL) { + ret = CMD_ERROR; + goto end; + } + current_session_name = session_name; + } else { + current_session_name = opt_session_name; + } + + ret = handle_command(poptGetArgs(pc)); + if (ret < 0) { + ERR("%s", lttng_strerror(ret)); + goto end; + } + +end: + if (!opt_session_name) { + free(session_name); + } + poptFreeContext(pc); + return ret; +} diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index c5198bda1..5755db637 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -75,6 +75,7 @@ static struct cmd_struct commands[] = { { "version", cmd_version}, { "calibrate", cmd_calibrate}, { "view", cmd_view}, + { "snapshot", cmd_snapshot}, { "enable-consumer", cmd_enable_consumer}, /* OBSOLETE */ { "disable-consumer", cmd_disable_consumer}, /* OBSOLETE */ { NULL, NULL} /* Array closure */ @@ -107,6 +108,7 @@ static void usage(FILE *ofp) fprintf(ofp, " disable-event Disable tracing event\n"); fprintf(ofp, " list List possible tracing options\n"); fprintf(ofp, " set-session Set current session name\n"); + fprintf(ofp, " snapshot Snapshot buffers of current session name\n"); fprintf(ofp, " start Start tracing\n"); fprintf(ofp, " stop Stop tracing\n"); fprintf(ofp, " version Show version information\n"); -- 2.34.1