Add the lttng view command
authorDavid Goulet <dgoulet@efficios.com>
Tue, 7 Feb 2012 19:13:20 +0000 (14:13 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Tue, 7 Feb 2012 21:01:03 +0000 (16:01 -0500)
This adds "view" to the lttng command line interface. It's used to
visualize traces with a given viewers (default: babeltrace).

The -e, --viewer options is available to override the default viewer
settings or add arguments to the viewer.

For example:

$ lttng view -e "babeltrace -n scope --no-delta --clock-raw"

The trace directory path is automatically appended using the current
session or the given session name to lttng view.

The default behavior is to simply spawn babeltrace with "-n all".

$ lttng view
[...]

LTTv support is now disabled but is planned for the stable release.

Signed-off-by: David Goulet <dgoulet@efficios.com>
configure.ac
extras/lttng-bash_completion
src/bin/lttng/Makefile.am
src/bin/lttng/command.h
src/bin/lttng/commands/view.c [new file with mode: 0644]
src/bin/lttng/lttng.c

index 42ecd040ea5ffa225f87a12eb71b28ad15fbfc29..e8c0e73faab0737597e147c7d229fda88dc511fe 100644 (file)
@@ -14,6 +14,22 @@ AC_CHECK_HEADERS([ \
        getopt.h sys/ipc.h sys/shm.h popt.h grp.h \
 ])
 
+# Babeltrace viewer check
+AC_ARG_WITH([babeltrace-bin],
+       AS_HELP_STRING([--with-babeltrace-bin],
+       [Location of the babeltrace viewer executable (including the filename)]),
+       [BABELTRACE_BIN="$withval"],
+       [BABELTRACE_BIN=''])
+AC_SUBST([BABELTRACE_BIN])
+
+# lttv-gui
+AC_ARG_WITH([lttv-gui-bin],
+       AS_HELP_STRING([--with-lttv-gui-bin],
+   [Location of the lttv GUI viewer executable (including the filename)]),
+   [LTTV_GUI_BIN="$withval"],
+   [LTTV_GUI_BIN=''])
+AC_SUBST([LTTV_GUI_BIN])
+
 AC_ARG_WITH([consumerd32-bin],
        AS_HELP_STRING([--with-consumerd32-bin],
        [Location of the 32-bit consumerd executable (including the filename)]),
@@ -46,6 +62,8 @@ AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_BIN], "$CONSUMERD32_BIN", [Location of th
 AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_BIN], "$CONSUMERD64_BIN", [Location of the 64-bit consumerd executable])
 AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD32_LIBDIR], "$CONSUMERD32_LIBDIR", [Search for consumerd 32-bit libraries in this location.])
 AC_DEFINE_UNQUOTED([CONFIG_CONSUMERD64_LIBDIR], "$CONSUMERD64_LIBDIR", [Search for consumerd 64-bit libraries in this location.])
+AC_DEFINE_UNQUOTED([CONFIG_BABELTRACE_BIN], "$BABELTRACE_BIN", [Location of the babeltrace viewer executable.])
+AC_DEFINE_UNQUOTED([CONFIG_LTTV_GUI_BIN], "$LTTV_GUI_BIN", [Location of the lttv GUI viewer executable.])
 
 # Check for pthread
 AC_CHECK_LIB([pthread], [pthread_create], [],
index ac57e4d83c4372105dedd273ea5b6a106d31e3cb..9aacb029491793d471b65810b5e1281e06fd2de7 100644 (file)
@@ -249,6 +249,17 @@ _lttng_cmd_calibrate() {
        esac
 }
 
+_lttng_cmd_view() {
+       local view_opts
+               view_opts=$(lttng view --list-options)
+
+               case $cur in
+               -*)
+               COMPREPLY=( $(compgen -W "${view_opts}" -- $cur) )
+               ;;
+       esac
+}
+
 _lttng_opts() {
        local opts
        opts=$(lttng --list-options)
index 282ef9a4eb3012469ba1c70cfbca671eb3fb7d39..e2040d8c39ef102151f8f6f6b46a351b6139a9ca 100644 (file)
@@ -8,6 +8,7 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \
                                commands/disable_events.c commands/enable_channels.c \
                                commands/disable_channels.c commands/add_context.c \
                                commands/set_session.c commands/version.c \
-                               commands/calibrate.c utils.c utils.h lttng.c
+                               commands/calibrate.c commands/view.c \
+                               utils.c utils.h lttng.c
 
 lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
index dcad0a1383524eb5f6a856547d8d88a16f1eb872..fa3e217468abba881c4a8f806547a7ef9a9ca0b3 100644 (file)
@@ -52,5 +52,6 @@ extern int cmd_add_context(int argc, const char **argv);
 extern int cmd_set_session(int argc, const char **argv);
 extern int cmd_version(int argc, const char **argv);
 extern int cmd_calibrate(int argc, const char **argv);
+extern int cmd_view(int argc, const char **argv);
 
 #endif /* _LTTNG_CMD_H */
diff --git a/src/bin/lttng/commands/view.c b/src/bin/lttng/commands/view.c
new file mode 100644 (file)
index 0000000..a146a91
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../command.h"
+#include <config.h>
+
+static char *opt_session_name;
+static char *opt_viewer;
+static const char *babeltrace_bin = CONFIG_BABELTRACE_BIN;
+//static const char *lttv_gui_bin = CONFIG_LTTV_GUI_BIN;
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0,  POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"viewer",      'e', POPT_ARG_STRING, &opt_viewer, 0, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * This is needed for each viewer since we are using execvp().
+ */
+static const char *babeltrace_opts[] = { "babeltrace", "-n", "all", };
+//static const char *lttv_gui_opts[] = { "lttv-gui", "-t", };
+
+/*
+ * Type is also use as the index in the viewers array. So please, make sure
+ * your enum value is in the right order in the array below.
+ */
+enum viewer_type {
+       VIEWER_BABELTRACE    = 0,
+       VIEWER_LTTV_GUI      = 1,
+       VIEWER_USER_DEFINED  = 2,
+};
+
+/*
+ * NOTE: "lttv" is a shell command and it's not working for exec() family
+ * functions so we might think of removing this wrapper or using bash.
+ */
+static struct viewers {
+       const char *exec_name;
+       enum viewer_type type;
+} viewers[] = {
+       { "babeltrace", VIEWER_BABELTRACE },
+       { "lttv-gui", VIEWER_LTTV_GUI },
+       { NULL, VIEWER_USER_DEFINED },
+};
+
+/*
+ * usage
+ */
+static void usage(FILE *ofp)
+{
+       fprintf(ofp, "usage: lttng view [SESSION_NAME] [OPTIONS]\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "By default, the babeltrace viewer will be used for text viewing\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Where SESSION_NAME is an optional session name. If not specified, lttng will\n");
+       fprintf(ofp, "get it from the configuration file (.lttngrc).\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "  -h, --help               Show this help\n");
+       fprintf(ofp, "      --list-options       Simple listing of options\n");
+       fprintf(ofp, "  -e, --viewer CMD         Specify viewer and/or options to use\n");
+       fprintf(ofp, "                           This will completely override the default viewers so\n");
+       fprintf(ofp, "                           please make sure to specify the full command.\n");
+       fprintf(ofp, "\n");
+}
+
+static struct viewers *parse_options(void)
+{
+       if (opt_viewer == NULL) {
+               /* Default is babeltrace */
+               return &(viewers[VIEWER_BABELTRACE]);
+       }
+
+#if 0
+       if (strstr(opt_viewer, viewers[VIEWER_LTTV_GUI].exec_name) == 0) {
+               return &(viewers[VIEWER_LTTV_GUI]);
+       }
+#endif
+
+       /*
+        * This means that if -e, --viewers is used, we just override everything
+        * with it. For supported viewers like lttv, we could simply detect if "-t"
+        * is passed and if not, add the trace directory to it.
+        */
+       return &(viewers[VIEWER_USER_DEFINED]);
+}
+
+/*
+ * Alloc an array of string pointer from a simple string having all options
+ * seperated by spaces. Also adds the trace path to the arguments.
+ *
+ * The returning pointer is ready to be passed to execvp().
+ */
+static char **alloc_argv_from_user_opts(char *opts, const char *trace_path)
+{
+       int i = 0, ignore_space = 0;
+       unsigned int num_opts = 1;
+       char **argv, *token = opts;
+
+       /* Count number of arguments. */
+       do {
+               if (*token == ' ') {
+                       /* Use to ignore consecutive spaces */
+                       if (!ignore_space) {
+                               num_opts++;
+                       }
+                       ignore_space = 1;
+               } else {
+                       ignore_space = 0;
+               }
+               token++;
+       } while (*token != '\0');
+
+       /* Add two here for the NULL terminating element and trace path */
+       argv = malloc(sizeof(char *) * (num_opts + 2));
+       if (argv == NULL) {
+               goto error;
+       }
+
+       token = strtok(opts, " ");
+       while (token != NULL) {
+               argv[i] = strdup(token);
+               token = strtok(NULL, " ");
+               i++;
+       }
+
+       argv[num_opts] = (char *) trace_path;
+       argv[num_opts + 1] = NULL;
+
+       return argv;
+
+error:
+       return NULL;
+}
+
+/*
+ * Alloc an array of string pointer from an array of strings. It also adds
+ * the trace path to the argv.
+ *
+ * The returning pointer is ready to be passed to execvp().
+ */
+static char **alloc_argv_from_local_opts(const char **opts, size_t opts_len,
+               const char *trace_path)
+{
+       char **argv;
+       size_t size;
+
+       size = sizeof(char *) * opts_len;
+
+       /* Add two here for the trace_path and the NULL terminating element. */
+       argv = malloc(size + 2);
+       if (argv == NULL) {
+               goto error;
+       }
+
+       memcpy(argv, opts, size);
+
+       argv[opts_len] = (char *)trace_path;
+       argv[opts_len + 1] = NULL;
+
+error:
+       return argv;
+}
+
+/*
+ * Spawn viewer with the trace directory path.
+ */
+static int spawn_viewer(const char *trace_path)
+{
+       int ret = 0;
+       pid_t pid;
+       struct stat status;
+       const char *viewer_bin = NULL;
+       struct viewers *viewer;
+       char **argv = NULL;
+
+       /* Check for --viewer options */
+       viewer = parse_options();
+       if (viewer == NULL) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       pid = fork();
+       if (pid == 0) {
+               switch (viewer->type) {
+               case VIEWER_BABELTRACE:
+                       if (stat(babeltrace_bin, &status) == 0) {
+                               viewer_bin = babeltrace_bin;
+                       } else {
+                               viewer_bin = viewer->exec_name;
+                       }
+                       argv = alloc_argv_from_local_opts(babeltrace_opts,
+                                       ARRAY_SIZE(babeltrace_opts), trace_path);
+                       break;
+#if 0
+               case VIEWER_LTTV_GUI:
+                       if (stat(lttv_gui_bin, &status) == 0) {
+                               viewer_bin = lttv_gui_bin;
+                       } else {
+                               viewer_bin = viewer->exec_name;
+                       }
+                       argv = alloc_argv_from_local_opts(lttv_gui_opts,
+                                       ARRAY_SIZE(lttv_gui_opts), trace_path);
+                       break;
+#endif
+               case VIEWER_USER_DEFINED:
+                       argv = alloc_argv_from_user_opts(opt_viewer, trace_path);
+                       if (argv) {
+                               viewer_bin = argv[0];
+                       }
+                       break;
+               default:
+                       viewer_bin = viewers[VIEWER_BABELTRACE].exec_name;
+                       argv = alloc_argv_from_local_opts(babeltrace_opts,
+                                       ARRAY_SIZE(babeltrace_opts), trace_path);
+                       break;
+               }
+
+               if (argv == NULL) {
+                       ret = CMD_FATAL;
+                       goto error;
+               }
+
+               DBG("Using %s viewer", viewer_bin);
+
+               ret = execvp(viewer_bin, argv);
+               if (ret) {
+                       PERROR("exec: %s", viewer_bin);
+                       free(argv);
+                       ret = CMD_FATAL;
+                       goto error;
+               }
+       } else if (pid > 0) {
+               ret = CMD_SUCCESS;
+       } else {
+               PERROR("Fork trace viewer");
+               ret = CMD_FATAL;
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * Exec viewer if found and use session name path.
+ */
+static int view_trace(void)
+{
+       int ret, count, i, found = 0;
+       char *session_name;
+       struct lttng_session *sessions = NULL;
+
+       /*
+        * Safety net. If lttng is suid at some point for *any* useless reasons,
+        * this prevent any bad execution of binraries.
+        */
+       if (getuid() != 0) {
+               if (getuid() != geteuid()) {
+                       ERR("UID does not match effective UID.");
+                       goto error;
+               } else if (getgid() != getegid()) {
+                       ERR("GID does not match effective GID.");
+                       goto error;
+               }
+       }
+
+       if (opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       DBG("Viewing trace for session %s", session_name);
+
+       /* Getting all sessions */
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ERR("Unable to list sessions. Session name %s not found.",
+                               session_name);
+               MSG("Is there a session daemon running?");
+               ret = CMD_ERROR;
+               goto free_error;
+       }
+
+       /* Find our session listed by the session daemon */
+       for (i = 0; i < count; i++) {
+               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               MSG("Session name %s not found", session_name);
+               goto free_sessions;
+       }
+
+       MSG("Trace directory: %s\n", sessions[i].path);
+
+       ret = spawn_viewer(sessions[i].path);
+       if (ret < 0) {
+               /* Don't set ret so lttng can interpret the sessiond error. */
+               goto free_sessions;
+       }
+
+       ret = CMD_SUCCESS;
+
+free_sessions:
+       if (sessions) {
+               free(sessions);
+       }
+free_error:
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+error:
+       return ret;
+}
+
+/*
+ * The 'view <options>' first level command
+ */
+int cmd_view(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 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, long_options);
+                       goto end;
+               default:
+                       usage(stderr);
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       ret = view_trace();
+
+end:
+       poptFreeContext(pc);
+       return ret;
+}
index f84ba63d7e8de48e4a9b6f44c79bbeffa72a7a89..1c1d5a82631e27ec45487fe66aa7c4ba795fb1bc 100644 (file)
@@ -76,6 +76,7 @@ static struct cmd_struct commands[] =  {
        { "set-session", cmd_set_session},
        { "version", cmd_version},
        { "calibrate", cmd_calibrate},
+       { "view", cmd_view},
        { NULL, NULL}   /* Array closure */
 };
 
@@ -108,6 +109,7 @@ static void usage(FILE *ofp)
        fprintf(ofp, "    start           Start tracing\n");
        fprintf(ofp, "    stop            Stop tracing\n");
        fprintf(ofp, "    version         Show version information\n");
+       fprintf(ofp, "    view            Start trace viewer\n");
        fprintf(ofp, "\n");
        fprintf(ofp, "Each command also has its own -h, --help option.\n");
        fprintf(ofp, "\n");
@@ -381,6 +383,7 @@ static int check_sessiond(void)
        }
 
 end:
+       printf("HIT essiond %d\n", ret);
        return ret;
 }
 
@@ -399,7 +402,8 @@ static int check_args_no_sessiond(int argc, char **argv)
                                strncmp(argv[i], "--h", sizeof("--h")) == 0 ||
                                strncmp(argv[i], "--list-options", sizeof("--list-options")) == 0 ||
                                strncmp(argv[i], "--list-commands", sizeof("--list-commands")) == 0 ||
-                               strncmp(argv[i], "version", sizeof("version")) == 0) {
+                               strncmp(argv[i], "version", sizeof("version")) == 0 ||
+                               strncmp(argv[i], "view", sizeof("view")) == 0) {
                        return 1;
                }
        }
This page took 0.031926 seconds and 4 git commands to generate.